Version in base suite: 0.4.7.16-1 Base version: tor_0.4.7.16-1 Target version: tor_0.4.9.6-0+deb12u1 Base file: /srv/ftp-master.debian.org/ftp/pool/main/t/tor/tor_0.4.7.16-1.dsc Target file: /srv/ftp-master.debian.org/policy/pool/main/t/tor/tor_0.4.9.6-0+deb12u1.dsc CODE_OF_CONDUCT | 3 ChangeLog | 1823 LICENSE | 27 Makefile.am | 46 Makefile.in | 2310 Makefile.nmake | 19 README.md | 13 ReleaseNotes | 1340 acinclude.m4 | 5 aclocal.m4 | 1 configure | 1441 configure.ac | 188 contrib/client-tools/torify | 19 contrib/win32build/tor-mingw.nsi.in | 10 contrib/win32build/tor.nsi.in | 4 debian/.debian-ci.yml | 178 debian/changelog | 168 debian/copyright | 6 debian/micro-revision.i | 2 debian/misc/backport | 6 debian/misc/build-tor-sources | 561 debian/misc/new-tor-release | 14 debian/misc/new-tor-release-prepare | 8 debian/rules | 3 debian/tests/control | 2 debian/tests/setup-onion-service | 10 debian/tor.postinst | 90 doc/HACKING/ReleasingTor.md | 34 doc/HACKING/WritingTests.md | 2 doc/HACKING/tracing/EventsCircuit.md | 139 doc/HACKING/tracing/README.md | 163 doc/asciidoc-helper.sh | 6 doc/include.am | 8 doc/man/tor-gencert.1.in | 4 doc/man/tor-print-ed-signing-cert.1.in | 4 doc/man/tor-resolve.1.in | 4 doc/man/tor.1.in | 196 doc/man/tor.1.txt | 218 doc/man/tor.html.in | 323 doc/man/torify.1.in | 4 m4/ax_check_compile_flag.m4 | 53 orconfig.h.in | 61 scripts/maint/checkOptionDocs.pl.in | 9 scripts/maint/practracker/practracker.py | 4 src/app/config/auth_dirs.inc | 9 src/app/config/config.c | 119 src/app/config/fallback_dirs.inc | 991 src/app/config/include.am | 1 src/app/config/or_options_st.h | 32 src/app/config/resolve_addr.c | 11 src/app/config/testnet.inc | 1 src/app/config/tor_cmdline_mode.h | 1 src/app/main/main.c | 80 src/app/main/ntmain.c | 7 src/app/main/shutdown.c | 7 src/app/main/subsystem_list.c | 2 src/config/geoip |272152 ++++++++++++++++++++++++---- src/config/geoip6 |196187 ++++++++++++++++++-- src/config/include.am | 6 src/config/torrc.sample.in | 24 src/core/crypto/hs_ntor.c | 9 src/core/crypto/include.am | 16 src/core/crypto/onion_crypto.c | 316 src/core/crypto/onion_crypto.h | 16 src/core/crypto/onion_tap.c | 246 src/core/crypto/onion_tap.h | 40 src/core/crypto/relay_crypto.c | 448 src/core/crypto/relay_crypto.h | 45 src/core/crypto/relay_crypto_cgo.c | 583 src/core/crypto/relay_crypto_cgo.h | 206 src/core/crypto/relay_crypto_st.h | 40 src/core/crypto/relay_crypto_tor1.c | 313 src/core/crypto/relay_crypto_tor1.h | 33 src/core/crypto/tor1_crypt_st.h | 39 src/core/include.am | 1 src/core/mainloop/connection.c | 91 src/core/mainloop/connection.h | 1 src/core/mainloop/cpuworker.c | 74 src/core/mainloop/cpuworker.h | 7 src/core/mainloop/include.am | 6 src/core/mainloop/mainloop.c | 31 src/core/mainloop/mainloop.h | 2 src/core/or/channel.c | 58 src/core/or/channel.h | 1 src/core/or/channelpadding.c | 47 src/core/or/channelpadding.h | 4 src/core/or/channeltls.c | 114 src/core/or/circuit_st.h | 41 src/core/or/circuitbuild.c | 355 src/core/or/circuitbuild.h | 20 src/core/or/circuitlist.c | 106 src/core/or/circuitlist.h | 12 src/core/or/circuitpadding.c | 32 src/core/or/circuitpadding.h | 10 src/core/or/circuitstats.c | 14 src/core/or/circuituse.c | 158 src/core/or/circuituse.h | 10 src/core/or/command.c | 23 src/core/or/conflux.c | 1006 src/core/or/conflux.h | 87 src/core/or/conflux_cell.c | 358 src/core/or/conflux_cell.h | 48 src/core/or/conflux_params.c | 330 src/core/or/conflux_params.h | 31 src/core/or/conflux_pool.c | 2215 src/core/or/conflux_pool.h | 55 src/core/or/conflux_st.h | 148 src/core/or/conflux_sys.c | 37 src/core/or/conflux_sys.h | 23 src/core/or/conflux_util.c | 474 src/core/or/conflux_util.h | 62 src/core/or/congestion_control_common.c | 474 src/core/or/congestion_control_common.h | 30 src/core/or/congestion_control_flow.c | 143 src/core/or/congestion_control_flow.h | 9 src/core/or/congestion_control_nola.c | 139 src/core/or/congestion_control_nola.h | 33 src/core/or/congestion_control_st.h | 48 src/core/or/congestion_control_vegas.c | 31 src/core/or/congestion_control_vegas.h | 3 src/core/or/congestion_control_westwood.c | 241 src/core/or/congestion_control_westwood.h | 33 src/core/or/connection_edge.c | 466 src/core/or/connection_edge.h | 14 src/core/or/connection_or.c | 228 src/core/or/connection_or.h | 5 src/core/or/connection_st.h | 2 src/core/or/cpath_build_state_st.h | 2 src/core/or/crypt_path.c | 63 src/core/or/crypt_path.h | 22 src/core/or/crypt_path_st.h | 15 src/core/or/dos.c | 146 src/core/or/dos.h | 34 src/core/or/dos_options.inc | 13 src/core/or/edge_connection_st.h | 25 src/core/or/entry_connection_st.h | 4 src/core/or/extend_info_st.h | 9 src/core/or/extendinfo.c | 30 src/core/or/extendinfo.h | 2 src/core/or/half_edge_st.h | 4 src/core/or/include.am | 51 src/core/or/lttng_cc.inc | 8 src/core/or/onion.c | 158 src/core/or/onion.h | 7 src/core/or/or.h | 133 src/core/or/or_circuit_st.h | 25 src/core/or/or_connection_st.h | 2 src/core/or/orconn_event.h | 18 src/core/or/origin_circuit_st.h | 25 src/core/or/policies.c | 10 src/core/or/policies.h | 1 src/core/or/protover.c | 32 src/core/or/protover.h | 11 src/core/or/reasons.c | 38 src/core/or/relay.c | 974 src/core/or/relay.h | 45 src/core/or/relay_crypto_st.h | 38 src/core/or/relay_msg.c | 286 src/core/or/relay_msg.h | 88 src/core/or/relay_msg_st.h | 47 src/core/or/scheduler.h | 6 src/core/or/scheduler_kist.c | 28 src/core/or/sendme.c | 230 src/core/or/sendme.h | 11 src/core/or/status.c | 7 src/core/or/versions.c | 22 src/core/proto/include.am | 2 src/core/proto/proto_socks.c | 37 src/ext/compat_blake2.h | 47 src/ext/equix/hashx/include/hashx.h | 195 src/ext/equix/hashx/src/blake2.c | 462 src/ext/equix/hashx/src/blake2.h | 73 src/ext/equix/hashx/src/compiler.c | 19 src/ext/equix/hashx/src/compiler.h | 77 src/ext/equix/hashx/src/compiler_a64.c | 164 src/ext/equix/hashx/src/compiler_x86.c | 159 src/ext/equix/hashx/src/context.c | 67 src/ext/equix/hashx/src/context.h | 39 src/ext/equix/hashx/src/force_inline.h | 9 src/ext/equix/hashx/src/hashx.c | 172 src/ext/equix/hashx/src/hashx_endian.h | 103 src/ext/equix/hashx/src/instruction.h | 31 src/ext/equix/hashx/src/program.c | 777 src/ext/equix/hashx/src/program.h | 52 src/ext/equix/hashx/src/program_exec.c | 158 src/ext/equix/hashx/src/siphash.c | 66 src/ext/equix/hashx/src/siphash.h | 35 src/ext/equix/hashx/src/siphash_rng.c | 41 src/ext/equix/hashx/src/siphash_rng.h | 34 src/ext/equix/hashx/src/unreachable.h | 9 src/ext/equix/hashx/src/virtual_memory.c | 141 src/ext/equix/hashx/src/virtual_memory.h | 23 src/ext/equix/include/equix.h | 166 src/ext/equix/src/context.c | 66 src/ext/equix/src/context.h | 18 src/ext/equix/src/equix.c | 131 src/ext/equix/src/solver.c | 283 src/ext/equix/src/solver.h | 44 src/ext/equix/src/solver_heap.h | 108 src/ext/include.am | 88 src/ext/polyval/ctmul.c | 311 src/ext/polyval/ctmul64.c | 133 src/ext/polyval/pclmul.c | 253 src/ext/polyval/polyval.c | 561 src/ext/polyval/polyval.h | 185 src/feature/client/bridges.c | 41 src/feature/client/bridges.h | 1 src/feature/client/circpathbias.c | 75 src/feature/client/circpathbias.h | 6 src/feature/client/dnsserv.c | 3 src/feature/client/entrynodes.c | 124 src/feature/client/entrynodes.h | 14 src/feature/client/include.am | 2 src/feature/client/transports.c | 328 src/feature/client/transports.h | 18 src/feature/control/btrack_orconn_cevent.c | 4 src/feature/control/control.c | 4 src/feature/control/control_auth.c | 39 src/feature/control/control_auth.h | 4 src/feature/control/control_cmd.c | 47 src/feature/control/control_cmd.h | 3 src/feature/control/control_events.c | 17 src/feature/control/control_events.h | 5 src/feature/control/control_fmt.c | 36 src/feature/control/control_getinfo.c | 6 src/feature/control/getinfo_geoip.c | 5 src/feature/control/include.am | 6 src/feature/dirauth/bwauth.c | 10 src/feature/dirauth/dirauth_config.c | 55 src/feature/dirauth/dirauth_options.inc | 8 src/feature/dirauth/dirvote.c | 223 src/feature/dirauth/dirvote.h | 34 src/feature/dirauth/process_descs.c | 49 src/feature/dirauth/process_descs.h | 3 src/feature/dirauth/voteflags.c | 28 src/feature/dircache/dircache.c | 21 src/feature/dircache/dirserv.c | 17 src/feature/dirclient/dirclient.c | 44 src/feature/dircommon/dir_connection_st.h | 8 src/feature/dircommon/directory.c | 46 src/feature/dircommon/directory.h | 1 src/feature/dircommon/include.am | 2 src/feature/dirparse/microdesc_parse.c | 18 src/feature/dirparse/ns_parse.c | 5 src/feature/dirparse/parsecommon.c | 13 src/feature/dirparse/parsecommon.h | 4 src/feature/dirparse/routerparse.c | 258 src/feature/dirparse/routerparse.h | 10 src/feature/hibernate/hibernate.c | 9 src/feature/hibernate/hibernate.h | 1 src/feature/hibernate/include.am | 2 src/feature/hs/hs_cache.c | 187 src/feature/hs/hs_cache.h | 17 src/feature/hs/hs_cell.c | 224 src/feature/hs/hs_cell.h | 35 src/feature/hs/hs_circuit.c | 427 src/feature/hs/hs_circuit.h | 31 src/feature/hs/hs_client.c | 227 src/feature/hs/hs_client.h | 12 src/feature/hs/hs_common.c | 6 src/feature/hs/hs_common.h | 16 src/feature/hs/hs_config.c | 29 src/feature/hs/hs_config.h | 5 src/feature/hs/hs_descriptor.c | 153 src/feature/hs/hs_descriptor.h | 11 src/feature/hs/hs_dos.c | 5 src/feature/hs/hs_ident.c | 10 src/feature/hs/hs_ident.h | 2 src/feature/hs/hs_intropoint.c | 22 src/feature/hs/hs_metrics.c | 155 src/feature/hs/hs_metrics.h | 78 src/feature/hs/hs_metrics_entry.c | 97 src/feature/hs/hs_metrics_entry.h | 56 src/feature/hs/hs_options.inc | 3 src/feature/hs/hs_pow.c | 569 src/feature/hs/hs_pow.h | 228 src/feature/hs/hs_service.c | 345 src/feature/hs/hs_service.h | 23 src/feature/hs/include.am | 19 src/feature/hs_common/include.am | 2 src/feature/metrics/include.am | 4 src/feature/nodelist/fmt_routerstatus.c | 16 src/feature/nodelist/fmt_routerstatus.h | 3 src/feature/nodelist/include.am | 4 src/feature/nodelist/microdesc.c | 8 src/feature/nodelist/microdesc_st.h | 14 src/feature/nodelist/networkstatus.c | 22 src/feature/nodelist/node_select.h | 8 src/feature/nodelist/node_st.h | 3 src/feature/nodelist/nodelist.c | 164 src/feature/nodelist/nodelist.h | 10 src/feature/nodelist/routerinfo_st.h | 14 src/feature/nodelist/routerlist.c | 79 src/feature/nodelist/routerstatus_st.h | 1 src/feature/nodelist/torcert.h | 1 src/feature/nodelist/vote_routerstatus_st.h | 1 src/feature/relay/circuitbuild_relay.c | 31 src/feature/relay/circuitbuild_relay.h | 11 src/feature/relay/dns.c | 43 src/feature/relay/dns.h | 4 src/feature/relay/ext_orport.c | 3 src/feature/relay/include.am | 4 src/feature/relay/onion_queue.c | 92 src/feature/relay/relay_config.c | 45 src/feature/relay/relay_find_addr.c | 18 src/feature/relay/relay_handshake.c | 96 src/feature/relay/relay_handshake.h | 3 src/feature/relay/relay_metrics.c | 450 src/feature/relay/relay_metrics.h | 66 src/feature/relay/relay_periodic.c | 6 src/feature/relay/relay_stub.c | 25 src/feature/relay/router.c | 180 src/feature/relay/router.h | 4 src/feature/relay/routerkeys.c | 353 src/feature/relay/routerkeys.h | 25 src/feature/relay/selftest.c | 16 src/feature/relay/selftest.h | 2 src/feature/rend/include.am | 4 src/feature/rend/rendcommon.c | 9 src/feature/rend/rendmid.c | 13 src/feature/stats/geoip_stats.c | 9 src/feature/stats/geoip_stats.h | 9 src/feature/stats/include.am | 2 src/feature/stats/rephist.c | 37 src/feature/stats/rephist.h | 6 src/include.am | 1 src/lib/cc/compat_compiler.h | 6 src/lib/compress/compress.c | 17 src/lib/conf/include.am | 6 src/lib/confmgt/include.am | 8 src/lib/crypt_ops/aes.h | 18 src/lib/crypt_ops/aes_nss.c | 145 src/lib/crypt_ops/aes_openssl.c | 442 src/lib/crypt_ops/compat_openssl.h | 28 src/lib/crypt_ops/crypto_dh.c | 20 src/lib/crypt_ops/crypto_dh.h | 2 src/lib/crypt_ops/crypto_dh_nss.c | 6 src/lib/crypt_ops/crypto_dh_openssl.c | 58 src/lib/crypt_ops/crypto_hkdf.c | 5 src/lib/crypt_ops/crypto_init.c | 3 src/lib/crypt_ops/crypto_nss_mgt.c | 2 src/lib/crypt_ops/crypto_openssl_mgt.c | 119 src/lib/crypt_ops/crypto_openssl_mgt.h | 21 src/lib/crypt_ops/crypto_rsa_openssl.c | 37 src/lib/crypt_ops/include.am | 6 src/lib/ctime/include.am | 4 src/lib/defs/dh_sizes.h | 5 src/lib/defs/include.am | 6 src/lib/dispatch/dispatch_cfg.c | 2 src/lib/dispatch/dispatch_cfg_st.h | 4 src/lib/dispatch/include.am | 4 src/lib/err/backtrace.h | 8 src/lib/evloop/compat_libevent.c | 2 src/lib/evloop/compat_libevent.h | 3 src/lib/evloop/token_bucket.c | 113 src/lib/evloop/token_bucket.h | 12 src/lib/evloop/workqueue.c | 262 src/lib/evloop/workqueue.h | 5 src/lib/fdio/fdio.c | 28 src/lib/fdio/fdio.h | 1 src/lib/fdio/include.am | 2 src/lib/fs/conffile.c | 2 src/lib/fs/files.c | 10 src/lib/fs/files.h | 4 src/lib/fs/path.c | 3 src/lib/geoip/geoip.c | 4 src/lib/geoip/geoip.h | 6 src/lib/geoip/include.am | 2 src/lib/lock/include.am | 2 src/lib/log/log.c | 6 src/lib/log/log_sys.c | 29 src/lib/log/util_bug.c | 27 src/lib/log/util_bug.h | 29 src/lib/malloc/malloc.h | 4 src/lib/math/include.am | 6 src/lib/math/prob_distr.c | 2 src/lib/math/stats.h | 2 src/lib/metrics/include.am | 8 src/lib/metrics/metrics_common.c | 2 src/lib/metrics/metrics_common.h | 23 src/lib/metrics/metrics_store.c | 6 src/lib/metrics/metrics_store.h | 6 src/lib/metrics/metrics_store_entry.c | 177 src/lib/metrics/metrics_store_entry.h | 16 src/lib/metrics/prometheus.c | 70 src/lib/net/include.am | 4 src/lib/net/socket.c | 8 src/lib/osinfo/include.am | 4 src/lib/osinfo/libc.c | 19 src/lib/process/daemon.c | 3 src/lib/process/process_unix.c | 35 src/lib/process/process_win32.c | 2 src/lib/process/restrict.c | 4 src/lib/process/waitpid.c | 3 src/lib/sandbox/sandbox.c | 337 src/lib/sandbox/sandbox.h | 3 src/lib/smartlist_core/include.am | 6 src/lib/string/util_string.c | 2 src/lib/term/include.am | 2 src/lib/time/compat_time.c | 26 src/lib/time/compat_time.h | 20 src/lib/time/include.am | 2 src/lib/tls/ciphers.inc | 38 src/lib/tls/ciphers_v13.inc | 15 src/lib/tls/include.am | 1 src/lib/tls/tortls.c | 59 src/lib/tls/tortls.h | 20 src/lib/tls/tortls_internal.h | 20 src/lib/tls/tortls_nss.c | 121 src/lib/tls/tortls_openssl.c | 940 src/lib/tls/tortls_st.h | 10 src/lib/tls/x509_openssl.c | 11 src/test/bench.c | 262 src/test/cgo_vectors.inc | 651 src/test/compression_bomb.h | 864 src/test/fakecircs.c | 17 src/test/hs_test_helpers.c | 12 src/test/include.am | 56 src/test/test.c | 215 src/test/test.h | 6 src/test/test_bridges.c | 12 src/test/test_bwmgt.c | 24 src/test/test_cell_formats.c | 868 src/test/test_channel.c | 25 src/test/test_channelpadding.c | 2 src/test/test_circuitbuild.c | 36 src/test/test_circuitlist.c | 10 src/test/test_circuitpadding.c | 54 src/test/test_config.c | 12 src/test/test_conflux_cell.c | 65 src/test/test_conflux_pool.c | 1351 src/test/test_congestion_control.c | 390 src/test/test_connection.c | 21 src/test/test_crypto.c | 480 src/test/test_crypto_cgo.c | 647 src/test/test_crypto_ope.c | 4 src/test/test_crypto_openssl.c | 5 src/test/test_crypto_slow.c | 135 src/test/test_dir.c | 281 src/test/test_dir_common.c | 8 src/test/test_dir_handle_get.c | 2 src/test/test_dirvote.c | 25 src/test/test_dos.c | 56 src/test/test_entrynodes.c | 77 src/test/test_extorport.c | 2 src/test/test_geoip.c | 13 src/test/test_hs_cache.c | 61 src/test/test_hs_client.c | 27 src/test/test_hs_common.c | 75 src/test/test_hs_control.c | 19 src/test/test_hs_descriptor.c | 98 src/test/test_hs_dos.c | 18 src/test/test_hs_intropoint.c | 5 src/test/test_hs_metrics.c | 38 src/test/test_hs_pow.c | 500 src/test/test_hs_pow_slow.c | 273 src/test/test_hs_service.c | 129 src/test/test_include.sh | 2 src/test/test_link_handshake.c | 111 src/test/test_metrics.c | 146 src/test/test_microdesc.c | 112 src/test/test_nodelist.c | 28 src/test/test_ntor_v3.c | 10 src/test/test_options.c | 38 src/test/test_parsecommon.c | 45 src/test/test_parseconf.sh | 6 src/test/test_periodic_event.c | 2 src/test/test_process_descs.c | 18 src/test/test_proto_http.c | 27 src/test/test_protover.c | 10 src/test/test_pt.c | 133 src/test/test_rebind.sh | 3 src/test/test_relaycell.c | 231 src/test/test_relaycrypt.c | 21 src/test/test_router.c | 18 src/test/test_routerkeys.c | 84 src/test/test_sandbox.c | 76 src/test/test_scheduler.c | 10 src/test/test_sendme.c | 139 src/test/test_slow.c | 1 src/test/test_socks.c | 65 src/test/test_status.c | 13 src/test/test_tortls.c | 232 src/test/test_tortls.h | 1 src/test/test_tortls_openssl.c | 520 src/test/test_util.c | 38 src/test/test_util_format.c | 2 src/test/test_voting_flags.c | 4 src/test/testing_common.c | 4 src/tools/include.am | 10 src/tools/tor-resolve.c | 2 src/trunnel/conflux.c | 1158 src/trunnel/conflux.h | 422 src/trunnel/hs/cell_introduce1.c | 344 src/trunnel/hs/cell_introduce1.h | 146 src/trunnel/include.am | 44 src/trunnel/link_handshake.c | 1562 src/trunnel/link_handshake.h | 632 src/trunnel/sendme_cell.c | 84 src/trunnel/sendme_cell.h | 25 src/trunnel/subproto_request.c | 456 src/trunnel/subproto_request.h | 157 src/win32/include.am | 3 src/win32/orconfig.h | 242 504 files changed, 456333 insertions(+), 66685 deletions(-) dpkg-source: warning: cannot verify inline signature for /srv/release.debian.org/tmp/tmppazcloeb/tor_0.4.7.16-1.dsc: no acceptable signature found dpkg-source: warning: cannot verify inline signature for /srv/release.debian.org/tmp/tmppazcloeb/tor_0.4.9.6-0+deb12u1.dsc: no acceptable signature found diff -Nru tor-0.4.7.16/CODE_OF_CONDUCT tor-0.4.9.6/CODE_OF_CONDUCT --- tor-0.4.7.16/CODE_OF_CONDUCT 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/CODE_OF_CONDUCT 2026-03-25 14:30:34.000000000 +0000 @@ -3,5 +3,4 @@ participate. For the latest version of our Code of Conduct, please see -https://gitweb.torproject.org/community/policies.git/plain/code_of_conduct.txt - +https://community.torproject.org/policies/code_of_conduct/ diff -Nru tor-0.4.7.16/ChangeLog tor-0.4.9.6/ChangeLog --- tor-0.4.7.16/ChangeLog 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/ChangeLog 2026-03-25 14:30:34.000000000 +0000 @@ -1,6 +1,1219 @@ -Changes in version 0.4.7.16 - 2023-11-03 +Changes in version 0.4.9.6 - 2026-03-25 + This is a security release fixing major bugfixes that could possibly lead to + remote crashing relays. We strongly recommend upgrading as soon as possible. + + o Major bugfix (security): + - Fix a stack overflow of 11 bytes on malicious CREATED2. This lead + to a remote crash. TROVE-2026-003. Reported-by: Anas Cherni of + Calif.io. Fixes bug 41231; bugfix on 0.4.9.1-alpha. + + o Major bugfix (security, conflux): + - Fix a memory compare using the wrong length. This could lead to a + remote crash when using the conflux subsystem. TROVE-2026-004. + Fixes bug 41232; bugfix on 0.4.8.1-alpha. + + o Minor bugfixes (security): + - Fix a series of defense in depth security issues found across the + codebase. Fixes bug 41228; bugfix on 0.3.5.1-alpha. + + o Minor bugfixes (portability): + - (Hopefully) fix our polyval implementation on big-endian + platforms. Fixes bug 41215; bugfix on 0.4.9.3-alpha. + + o Minor features (fallbackdir): + - Regenerate fallback directories generated on March 25, 2026. + + o Minor features (geoip data): + - Update the geoip files to match the IPFire Location Database, as + retrieved on 2026/03/25. + + +Changes in version 0.4.9.5 - 2026-02-12 + This first stable release in the 0.4.9 series introduces a new + circuit-level encryption design for better client security, as well + as a more scalable way for large relay operators to annotate which + relays they run so clients can avoid using too many of them in a + single circuit. + + o Major features (cryptography): + - Clients and relays can now negotiate Counter Galois Onion (CGO) + relay cryptography, as designed by Jean Paul Degabriele, + Alessandro Melloni, Jean-Pierre Münch, and Martijn Stam. CGO + provides improved resistance to several kinds of tagging attacks, + better forward secrecy, and better forgery resistance. Closes + ticket 41047. Implements proposal 359. + + o Major features (path selection): + - Clients and relays now support "happy families", a system to + simplify relay family operation and improve directory performance. + With "happy families", relays in a family share a secret "family + key", which they use to prove their membership in the family. + Implements proposal 321; closes ticket 41009. Note that until + enough clients are upgraded, relay operators will still need to + configure MyFamily lists. But once clients no longer depend on + those lists, we will be able to remove them entirely, thereby + simplifying family operation, and making microdescriptor downloads + approximately 80% smaller. For more information, see + https://community.torproject.org/relay/setup/post-install/family-ids/ + + o Major bugfixes (conflux): + - Ensure conflux guards obey family and subnet restrictions. Fixes + bug 40976; bugfix on 0.4.8.1-alpha. + + o Major bugfixes (controller events): + - Fix spikes occurring in bandwidth cache events on control connection. + Fixes bug 31524; bugfix on 0.0.9pre5. + + o Major bugfixes (sandbox): + - Fix sandbox to work on architectures that use Linux's generic + syscall interface, extending support for AArch64 (ARM64) and + adding support for RISC-V, allowing test_include.sh and the + sandbox unit tests to pass on these systems even when building + with fragile hardening enabled. Fixes bugs 40465 and 40599; bugfix + on 0.2.5.1-alpha. + + o Minor features (client security, reliability): + - When KeepaliveIsolateSOCKSAuth is keeping a circuit alive, expire + the circuit based on when it was last in use for any stream, not + (as we did before) based on when a stream was last attached to it. + Closes ticket 41157. Implements a minimal version of Proposal 368. + + o Minor features (exit relays): + - Implement reevaluating new exit policy against existing + connections. This is controlled by new config option + ReevaluateExitPolicy, defaulting to 0. Closes ticket 40676. + - Implement a token-bucket based rate limiter for stream creation + and resolve request. It is configured by the DoSStream* family of + configuration options. Closes ticket 40736. + - Add Monero ports to the ReducedExitPolicy. Closes ticket 41168. + + o Minor features (bridges): + - Save complete bridge lines to 'datadir/bridgelines'. Closes + ticket 29128. + + o Minor features (client extensibility): + - Implement new HTTPTunnelPort features for interoperability with + Arti's HTTP CONNECT proxy. This work adds new headers to requests + to and replies from the HttpConnectPort, support for OPTIONS + requests, tightens the expected syntax for Proxy-Authorization, + and increases defense-in-depth against some kinds of cross-site + HTTP attacks. Closes ticket 41156. Implements proposal 365. + - Detect invalid SOCKS5 username/password combinations according to + new extended parameters syntax. (Currently, this rejects any + SOCKS5 username beginning with "", except for the username + "0". Such usernames are now reserved to communicate + additional parameters with other Tor implementations.) Implements + proposal 351. + + o Minor features (sandboxing): + - Allow the fstatat64 and statx syscalls on i386 architecture when + glibc >= 2.33. On i386, glibc uses fstatat64 instead of newfstatat + for stat operations, and statx for time64 support. Without this, + SIGHUP configuration reload fails when using sandbox mode with + %include directives on i386 with Debian Bookworm or newer. + - Allow the lstat64 syscall on i386 architecture. This syscall is + used by glob() in glibc 2.36+ when processing %include directives + with directory patterns. + + o Minor features (security): + - Increase the size of our finite-field Diffie Hellman TLS group + (which we should never actually use!) to 2048 bits. Part of + ticket 41067. + - Require TLS version 1.2 or later. (Version 1.3 support will be + required in the near future.) Part of ticket 41067. + - Update TLS 1.2 client cipher list to match current Firefox. Part + of ticket 41067. + - Verify needle is smaller than haystack before calling memmem. + Closes ticket 40854. + + o Minor features (onion services): + - Add 3 more keywords to the ADD_ONION control command: + PoWDefensesEnabled, PoWQueueRate and PoWQueueBurst which correspond + to HiddenServicePoWDefensesEnabled, HiddenServicePoWQueueRate and + HiddenServicePoWQueueBurst from torrc. + - Reduce the minimum value of hsdir_interval to match recent tor- + spec change. + + o Minor feature (directory authority): + - Introduce MinimalAcceptedServerVersion to allow configuring + the minimum accepted relay version without requiring a new tor + release. Closes ticket 40817. + + o Minor features (metrics port): + - New metrics on the MetricsPort for the number of BUG() calls that + occurred at runtime. Fixes bugs 40839 and 41104; bugfix on + 0.4.7.1-alpha. + - Handle rephist tracking of ntor and ntor_v3 handshakes + individually such that MetricsPort exposes the correct values. + Fixes bug 40638; bugfix on 0.4.7.11. + - Add new metrics for relays on the MetricsPort namely the count of + drop cell, destroy cell and the number of circuit protocol + violation seen that lead to a circuit close. Closes ticket 40816. + + o Minor features (forward-compatibility): + - We now correctly parse microdescriptors and router descriptors + that do not include TAP onion keys. (For backward compatibility, + authorities continue to require these keys.) Implements part of + proposal 350. + + o Minor features (portability, android): + - Use /data/local/tmp for data storage on Android by default. Closes + ticket 40487. Patch from Hans-Christoph Steiner. + + o Minor features (directory authority): + - Export unsigned consensus documents once we have seen a threshold + of signatures, as a step toward the consensus transparency + experiment. + + o Minor features (fallbackdir): + - Regenerate fallback directories generated on February 12, 2026. + + o Minor features (geoip data): + - Update the geoip files to match the IPFire Location Database, + as retrieved on 2026/02/12. + + o Minor features (windows): + - Various compilation fixes for our Windows CI. Closes ticket 41214. + + o Minor bugfixes (exit relays): + - Clip every returned DNS TTL to 60 (RESOLVED) in order to mitigate + an exit DNS cache oracle. Fixes bug 40979; bugfix on 0.3.5.1-alpha. + + o Minor bugfixes (spec conformance): + - Set the length field correctly on RELAY_COMMAND_CONFLUX_SWITCH + messages. Previously, it was always set to the maximum value. + Fixes bug 41056; bugfix on 0.4.8.1-alpha. + - Do not treat "15" as a recognized remote END reason code. + Formerly, we treated it as synonymous with a local ENTRYPOLICY, + which isn't a valid remote code at all. Fixes bug 41171; bugfix + on 0.2.0.8-alpha. + + o Minor bugfixes (tooling): + - Fix a false positive valgrind related to inspecting a bitfield + next to another uninitialized bitfield. Fixes bug 41182; bugfix + on 0.3.3.2-alpha. + - Fix minor warnings from newer versions of shellcheck and clang. + Fixes bug 41166; bugfix on 0.4.3.1-alpha and several + other versions. + - Fix a warning when compiling with GCC 14.2. Closes 41032. + + o Minor bugfixes (threads): + - Make thread control POSIX compliant. Fixes bug 41109; bugfix + on 0.4.8.17. + + o Minor bugfix (client DNS): + - Handle empty DNS reply without sending back an error and instead + send back NOERROR (RFC1035 error code 0x0). Fixes bug 40248; + bugfix on 0.3.5.1-alpha. + + o Minor bugfixes (directory authorities): + - After we added layer-two vanguards, directory authorities wouldn't + think any of their vanguards were suitable for circuits, leading + to a "Failed to find node for hop #2 of our path. Discarding this + circuit." log message once per second from startup until they made + a fresh consensus. Now they look to their existing consensus on + startup, letting them build circuits properly from the beginning. + Fixes bug 40802; bugfix on 0.4.7.1-alpha. + + o Minor bugfixes (tests): + - Fix a test failure with OpenSSL builds running at security level 1 + or greater, which does not permit SHA-1 certificates. Fixes bug + 41021; bugfix on 0.2.8.1-alpha. + + o Minor bugfixes (bridges): + - Don't warn when BridgeRelay is 1 and ExitRelay is explicitly set + to 0. Fixes bug 40884; bugfix on 0.4.8.3-rc. + + o Minor bugfixes (conflux, client): + - Avoid a non fatal assert caused by data coming in on a conflux set + that is being freed during shutdown. Fixes bug 40870; bugfix + on 0.4.8.1-alpha. + + o Minor bugfixes (testing network): + - Enabling TestingTorNetwork no longer forces fast hidden service + intro point rotation. This reduces noise and errors when using + hidden services with TestingTorNetwork enabled. Fixes bug 40922; + bugfix on 0.3.2.1-alpha. + + o Minor bugfixes (relay): + - Refuse to overwrite an existing *.secret_family_key when running + tor --keygen-family. Fixes bug 41184; bugfix on 0.4.9.1-alpha. + + o New system requirements: + - When built with LibreSSL, Tor now requires LibreSSL 3.7 or later. + Part of ticket 41059. + - When built with OpenSSL, Tor now requires OpenSSL 1.1.1 or later. + (We strongly recommend 3.0 or later, but still build with 1.1.1, + even though it is not supported by the OpenSSL team, due to its + presence in Debian oldstable.) Part of ticket 41059. + + o Removed features (relays): + - Relays no longer support clients that falsely advertise TLS + ciphers they don't really support. (Clients have not done this + since 0.2.3.17-beta). Part of ticket 41031. + - Relays no longer support clients that require obsolete v1 and v2 + link handshakes. (The v3 link handshake has been supported since + 0.2.3.6-alpha). Part of ticket 41031. + - Relays no longer support the obsolete TAP circuit extension + protocol. (For backward compatibility, however, relays still + continue to include TAP keys in their descriptors.) Implements + part of proposal 350. + - Relays no longer support the obsolete "RSA-SHA256-TLSSecret" + authentication method, which used a dangerously short RSA key, and + which required access TLS session internals. The current method + ("Ed25519-SHA256-RFC5705") has been supported since 0.3.0.1-alpha. + Closes ticket 41020. + + o Removed features (directory authorities): + - Directory authorities no longer support consensus methods before + method 32. Closes ticket 40835. + - We include a new consensus method that removes support for + computing "package" lines in consensus documents. This feature was + never used, and support for including it in our votes was removed + in 0.4.2.1-alpha. Finishes implementation of proposal 301. + + +Changes in version 0.4.9.4-rc - 2026-01-28 + Finally, the release candidate for the 0.4.9.x series. It consists of minor + features and several bugfixes. Nothing major has been added since the alpha. + If everything goes well, the next version will be the first stable. + + o Minor features (security, reliability): + - When KeepaliveIsolateSOCKSAuth is keeping a circuit alive, expire + the circuit based on when it was last in use for any stream, not + (as we did before) based on when a stream was last attached to it. + Closes ticket 41157. Implements a minimal version of Proposal 368. + + o Minor feature (Exit): + - Add Monero ports to the ReducedExitPolicy. Closes ticket 41168. + + o Minor features (HTTPTunnelPort): + - Implement new HTTPTunnelPort features for interoperability with + Arti's HTTP CONNECT proxy. This work adds new headers to requests + to and replies from the HttpConnectPort, support for OPTIONS + requests, tightens the expected syntax for Proxy-Authorization, + and increases defense-in-depth against some kinds of cross-site + HTTP attacks. Closes ticket 41156. Implements proposal 365. + + o Minor features (linux seccomp2 sandbox): + - Allow the fstatat64 and statx syscalls on i386 architecture when + glibc >= 2.33. On i386, glibc uses fstatat64 instead of newfstatat + for stat operations, and statx for time64 support. Without this, + SIGHUP configuration reload fails when using sandbox mode with + %include directives on i386 with Debian Bookworm or newer. + - Allow the lstat64 syscall on i386 architecture. This syscall is + used by glob() in glibc 2.36+ when processing %include directives + with directory patterns. + + o Minor bugfixes (DNS, exit): + - Clip every returned DNS TTL to 60 (RESOLVED) in order to mitigate + an exit DNS cache oracle. Fixes bug 40979; bugfix on 0.3.5.1-alpha. + + o Minor bugfixes (spec conformance): + - Do not treat "15" as a recognized remote END reason code. + Formerly, we treated it as synonymous with a local ENTRYPOLICY, + which isn't a valid remote code at all. Fixes bug 41171; bugfix + on 0.2.0.8-alpha. + + o Minor bugfixes (tooling): + - Fix a false positive valgrind related to inspecting a bitfield + next to another uninitialized bitfield. Fixes bug 41182; bugfix + on 0.3.3.2-alpha. + + o Minor bugfixes (warnings): + - Fix minor warnings from newer versions of shellcheck and clang. + Fixes bug 41166; bugfix on 0.4.3.1-alpha and several + other versions. + + +Changes in version 0.4.8.22 - 2026-01-28 + This is likely the very last release of the 0.4.8.x series. Three major + bugfixes detailed below including two affecting directory servers (basically + all relays). We strongly recommend upgrading as soon as possible. + + o Major bugfixes (security): + - Avoid an out-of-bounds read error that could occur with + V1-formatted EXTEND cells. Fixes bug 41180; bugfix on 0.4.8.1-alpha. + This is tracked as TROVE-2025-016. + + o Major bugfixes (directory servers): + - Allow old clients to fetch the consensus even if they use version + 0 of the SENDME protocol. In mid 2025 we changed the required + minimum version of the "FlowCtrl" protocol to 1, meaning directory + caches hang up on clients that send a version 0 SENDME cell. Since + old clients were no longer able to retrieve the consensus, they + couldn't learn about this required minimum version -- meaning + we've had many many old clients loading down directory servers for + the past months. Fixes bug 41191; bugfix on 0.4.1.1-alpha. + - Don't count networkstatus serves until they finish. When we + started serving a consensus document but the client didn't receive + all of it, we were still counting that as a success in our stats. + This mistake, which can be triggered for example by obsolete + clients or by DPI-based censorship, led to wildly inflated user + counts because we estimate total users in the world based on + successful consensus fetches. Fixes bug 41192; bugfix + on 0.2.1.1-alpha. + + o Minor feature (testing, CI): + - Bump the CI version of chutney to the current version as of + 2026-01-21 (3338f5c). + + o Minor features (debugging, compression): + - Do not check for compression bombs for buffers smaller than 5MB + (increased from 64 KB). Fixes ticket 40739; bugfix on 0.2.1.29. + + o Minor features (directory servers): + - Track how many times directory servers begin serving networkstatus + documents, so we can compare it to the number of times we finish + serving them. Motivated by the fixes in ticket 41192. + + o Minor features (fallbackdir): + - Regenerate fallback directories generated on January 28, 2026. + + o Minor features (geoip data): + - Update the geoip files to match the IPFire Location Database, as + retrieved on 2026/01/28. + + o Minor bugfixes (relay): + - Downgrade "Error relaying cell across rendezvous" log warn to info + as the error condition is possible under normal circumstances. Fixes + bug 40951; bugfix on 0.3.5.1-alpha. + + o Code simplification and refactoring: + - Simplify SOCKS4a parsing to avoid the (false) appearance of + integer underflows, and to make the logic more obvious. Fixes bug + 41190; bugfix on 0.3.5.1-alpha. + + +Changes in version 0.4.8.21 - 2025-11-17 + This release is a continuation of the previous one and addresses additional + Conflux-related issues identified through further testing and feedback from + relay operators. We strongly recommend upgrading as soon as possible. + + o Major bugfixes (conflux, exit): + - When dequeuing out-of-order conflux cells, the circuit could be + closed in between two dequeues, which could lead to mishandling + a NULL pointer. Fixes bug 41162; bugfix on 0.4.8.4. + + o Minor feature (compiler flag): + - Add -mbranch-protection=standard for arm64. + + o Minor features (fallbackdir): + - Regenerate fallback directories generated on November 17, 2025. + + o Minor features (geoip data): + - Update the geoip files to match the IPFire Location Database, as + retrieved on 2025/11/17. + + o Minor bugfixes (bridges, pluggable transport): + - Fix a bug causing the initial tor process to hang instead of + exiting with RunAsDaemon, when pluggable transports are used. + Fixes bug 41088; bugfix on 0.4.8.1-alpha. + + +Changes in version 0.4.8.20 - 2025-11-10 + This release fixes several bugs related to Conflux edge cases as well as + adding a new hardening compiler flag if supported. + + o Minor feature (compiler flag): + - Add -fcf-protection=full if supported by the compiler. + Implements ticket 41139. + + o Minor features (fallbackdir): + - Regenerate fallback directories generated on November 10, 2025. + + o Minor features (geoip data): + - Update the geoip files to match the IPFire Location Database, as + retrieved on 2025/11/10. + + o Minor bugfixes (conflux fragile asserts): + - Fix the root cause of some conflux fragile asserts when a control + port listener is attached. Fixes bug 41037; bugfix on 0.4.8.16. + + o Minor bugfixes (conflux, relay): + - Fix a series of conflux edge cases about sequence number + arithmetic and OOM handler kicking in under heavy memory pressure. + Fixes bug 41155; bugfix on 0.4.8.4. + + +Changes in version 0.4.8.19 - 2025-10-06 + This release provides major bugfixes for a LibreSSL issue and a flow control + C-tor specific problem (not protocol). We strongly recommend you upgrade as + soon as possible. + + o Major bugfixes (client, TLS): + - Fix some clients not being able to connect to LibreSSL relays. + Fixes bug 41134; bugfix on 0.4.8.17. + + o Minor bugfixes (stream flow control performance): + - Use a 5 ms grace period to allow an edge connection to flush its + stream data to the socket before sending an XOFF. This + significantly reduces the number of XON/XOFF messages sent when + (1) the application is reading stream data at a fast rate, and (2) + conflux is enabled. Fixes part of bug 41130; bugfix on 0.4.7.2-alpha. + + o Minor features (fallbackdir): + - Regenerate fallback directories generated on October 06, 2025. + + o Minor features (geoip data): + - Update the geoip files to match the IPFire Location Database, as + retrieved on 2025/10/06. + + o Minor bugfix (process): + - Avoid closing all possible FDs when spawning a process (PT). On + some systems, this could lead to 3+ minutes hang. Fixes bug 40990; + bugfix on 0.3.5.1-alpha. + + +Changes in version 0.4.9.3-alpha - 2025-09-16 + This is the third alpha release and likely the last before going stable. + This release contains the new CGO circuit encryption. See proposal 359 for + more details. Several TLS minor fixes which will strengthen the link + security. + + o New system requirements: + - When built with LibreSSL, Tor now requires LibreSSL 3.7 or later. + Part of ticket 41059. + - When built with OpenSSL, Tor now requires OpenSSL 1.1.1 or later. + (We strongly recommend 3.0 or later, but still build with 1.1.1, + even though it is not supported by the OpenSSL team, due to its + presence in Debian oldstable.) Part of ticket 41059. + + o Major features (cell format): + - Tor now has (unused) internal support to encode and decode relay + messages in the new format required by our newer CGO encryption + algorithm. Closes ticket 41051. Part of proposal 359. + + o Major features (cryptography): + - Clients and relays can now negotiate Counter Galois Onion (CGO) + relay cryptography, as designed by Jean Paul Degabriele, + Alessandro Melloni, Jean-Pierre Münch, and Martijn Stam. CGO + provides improved resistance to several kinds of tagging attacks, + better forward secrecy, and better forgery resistance. Closes + ticket 41047. Implements proposal 359. + + o Major bugfixes (onion service directory cache): + - Preserve the download counter of an onion service descriptor + across descriptor uploads, so that recently updated descriptors + don't get pruned if there is memory pressure soon after update. + Additionally, create a separate torrc option MaxHSDirCacheBytes + that defaults to the former 20% of MaxMemInQueues threshold, but + can be controlled by relay operators under DoS. Also enforce this + threshold during HSDir uploads. Fixes bug 41006; bugfix + on 0.4.8.14. + + o Minor features (security): + - Increase the size of our finite-field Diffie Hellman TLS group + (which we should never actually use!) to 2048 bits. Part of + ticket 41067. + - Require TLS version 1.2 or later. (Version 1.3 support will be + required in the near future.) Part of ticket 41067. + - Update TLS 1.2 client cipher list to match current Firefox. Part + of ticket 41067. + + o Minor features (security, TLS): + - When we are running with OpenSSL 3.5.0 or later, support using the + ML-KEM768 for post-quantum key agreement. Closes ticket 41041. + + o Minor feature (client, TLS): + - Set the TLS 1.3 cipher list instead of falling back on the + default value. + + o Minor feature (padding, logging): + - Reduce the amount of messages being logged related to channel + padding timeout when log level is "notice". + + o Minor features (bridges): + - Save complete bridge lines to 'datadir/bridgelines'. Closes + ticket 29128. + + o Minor features (fallbackdir): + - Regenerate fallback directories generated on September 16, 2025. + + o Minor features (geoip data): + - Update the geoip files to match the IPFire Location Database, as + retrieved on 2025/09/16. + + o Minor features (hidden services): + - Reduce the minimum value of hsdir_interval to match recent tor- + spec change. + + o Minor features (hsdesc POW): + - Tolerate multiple PoW schemes in onion service descriptors, for + future extensibility. Implements torspec ticket 272. + + o Minor features (performance TLS): + - When running with with OpenSSL 3.0.0 or later, support using + X25519 for TLS key agreement. (This should slightly improve + performance for TLS session establishment.) + + o Minor features (portability): + - Fix warnings when compiling with GCC 15. Closes ticket 41079. + + o Minor bugfix (conflux): + - Remove the pending nonce if we realize that the nonce of the + unlinked circuit is not tracked anymore. Should avoid the non + fatal assert triggered with a control port circuit event. Fixes + bug 41037; bugfix on 0.4.8.15. + + o Minor bugfixes (bridges, pluggable transport): + - Fix a bug causing the initial tor process to hang instead of + exiting with RunAsDaemon, when pluggable transports are used. + Fixes bug 41088; bugfix on 0.4.9.1-alpha. + + o Minor bugfixes (circuit handling): + - Prevent circuit_mark_for_close() from being called twice on the + same circuit. Fixes bug 40951; bugfix on 0.4.8.16-dev. + - Prevent circuit_mark_for_close() from being called twice on the + same circuit. Second fix attempt Fixes bug 41106; bugfix + on 0.4.8.17 + + o Minor bugfixes (compilation): + - Fix linking on systems without a working stdatomic.h. Fixes bug + 41076; bugfix on 0.4.9.1-alpha. + + o Minor bugfixes (compiler warnings): + - Make sure the two bitfields in the half-closed edge struct are + unsigned, as we're using them for boolean values and assign 1 to + them. Fixes bug 40911; bugfix on 0.4.7.2-alpha. + + o Minor bugfixes (logging, metrics port): + - Count BUG statements for the MetricsPort only if they are warnings + or errors. Fixes bug 41104; bugfix on 0.4.7.1-alpha. Patch + contributed by shadowcoder. + + o Minor bugfixes (protocol): + - Set the length field correctly on RELAY_COMMAND_CONFLUX_SWITCH + messages. Previously, it was always set to the maximum value. + Fixes bug 41056; bugfix on 0.4.8.1-alpha. + + o Minor bugfixes (relay): + - Fix a crash when FamilyKeyDir is a path that cannot be read. Fixes + bug 41043; bugfix on 0.4.9.2-alpha. + + o Minor bugfixes (threads): + - Make thread control POSIX compliant. Fixes bug 41109; bugfix + on 0.4.8.17-dev. + + o Removed features: + - Relays no longer support clients that falsely advertise TLS + ciphers they don't really support. (Clients have not done this + since 0.2.3.17-beta). Part of ticket 41031. + - Relays no longer support clients that require obsolete v1 and v2 + link handshakes. (The v3 link handshake has been supported since + 0.2.3.6-alpha). Part of ticket 41031. + + +Changes in version 0.4.8.18 - 2025-09-16 + This is a minor release with a major onion service directory cache (HSDir) + bug fix. A series of minor bugfixes as well. As always, we strongly recommend + to upgrade as soon as possible. + + o Major bugfixes (onion service directory cache): + - Preserve the download counter of an onion service descriptor + across descriptor uploads, so that recently updated descriptors + don't get pruned if there is memory pressure soon after update. + Additionally, create a separate torrc option MaxHSDirCacheBytes + that defaults to the former 20% of MaxMemInQueues threshold, but + can be controlled by relay operators under DoS. Also enforce this + threshold during HSDir uploads. Fixes bug 41006; bugfix + on 0.4.8.14. + + o Minor feature (padding, logging): + - Reduce the amount of messages being logged related to channel + padding timeout when log level is "notice". + + o Minor features (fallbackdir): + - Regenerate fallback directories generated on September 16, 2025. + + o Minor features (geoip data): + - Update the geoip files to match the IPFire Location Database, as + retrieved on 2025/09/16. + + o Minor bugfix (conflux): + - Remove the pending nonce if we realize that the nonce of the + unlinked circuit is not tracked anymore. Should avoid the non + fatal assert triggered with a control port circuit event. Fixes + bug 41037; bugfix on 0.4.8.15. + + o Minor bugfixes (circuit handling): + - Prevent circuit_mark_for_close() from being called twice on the + same circuit. Second fix attempt Fixes bug 41106; bugfix + on 0.4.8.17. + + +Changes in version 0.4.8.17 - 2025-06-30 + This is a minor providing a series of minor features especially in the realm + of TLS. It also brings a new set of recommended and required sub protocols. + And finally, few minor bugfixes, nothing major. As always, we strongly + recommend you upgrade as soon as possible. + + o Minor features (security, TLS): + - When we are running with OpenSSL 3.5.0 or later, support using the + ML-KEM768 for post-quantum key agreement. Closes ticket 41041. + + o Minor feature (client, TLS): + - Set the TLS 1.3 cipher list instead of falling back on the + default value. + + o Minor features (fallbackdir): + - Regenerate fallback directories generated on June 30, 2025. + + o Minor features (geoip data): + - Update the geoip files to match the IPFire Location Database, as + retrieved on 2025/06/30. + + o Minor features (hsdesc POW): + - Tolerate multiple PoW schemes in onion service descriptors, for + future extensibility. Implements torspec ticket 272. + + o Minor features (performance TLS): + - When running with with OpenSSL 3.0.0 or later, support using + X25519 for TLS key agreement. (This should slightly improve + performance for TLS session establishment.) + + o Minor features (portability): + - Fix warnings when compiling with GCC 15. Closes ticket 41079. + + o Minor features (recommended protocols): + - Directory authorities now vote to recommend that clients support + certain protocols beyond those that are required. These include + improved support for connecting to relays on IPv6, NtorV3, and + congestion control. Part of ticket 40836. + + o Minor features (required protocols): + - Directory authorities now vote to require clients to support the + authenticated SENDME feature, which was introduced in + 0.4.1.1-alpha. Part of ticket 40836. + - Directory authorities now vote to require relays to support + certain protocols, all of which have been implemented since + 0.4.7.4-alpha or earlier. These include improved support for + connecting to relays on IPv6, NtorV3, running as a rate-limited + introduction point, authenticated SENDMEs, and congestion control. + Part of ticket 40836. + + o Minor bugfix (conflux): + - Avoid a non fatal assert when describing a conflux circuit on the + control port after being prepped to be freed. Fixes bug 41037; + bugfix on 0.4.8.15. + + o Minor bugfixes (circuit handling): + - Prevent circuit_mark_for_close() from being called twice on the + same circuit. Fixes bug 40951; bugfix on 0.4.8.16-dev. + + o Minor bugfixes (compiler warnings): + - Make sure the two bitfields in the half-closed edge struct are + unsigned, as we're using them for boolean values and assign 1 to + them. Fixes bug 40911; bugfix on 0.4.7.2-alpha. + + o Minor bugfixes (threads, memory): + - Improvements in cleanup of resources used by threads. Fixes bug + 40991; bugfix on 0.4.8.13-dev. + - Rework start and exit of worker threads. + + +Changes in version 0.4.9.2-alpha - 2025-04-02 + This is the second alpha of the 0.4.9.x series. We have several new minor + features and a big one, the happy families that was long awaited by relay + operators. This release also fixes a number of bugs including major ones. + + o Major feature (happy families): + - Clients and relays now support "happy families", a system to + simplify relay family operation and improve directory performance. + With "happy families", relays in a family shares a secret "family + key", which they use to prove their membership in the family. + Implements proposal 321; closes ticket 41009. Note that until + enough clients are upgraded, relay operators will still need to + configure MyFamily lists. But once clients no longer depend on + those lists, we will be able to remove them entirely, thereby + simplifying family operation, and making microdescriptor downloads + approximately 80% smaller. For more information, see + https://community.torproject.org/relay/setup/post-install/family-ids/ + + o Major features (client): + - Clients now respect "happy families" per proposal 321. This + feature will eventually allow a much more compact representation + for relay families, for a significant savings in directory + download size. + + o Minor feature (onion service, control port): + - Add 3 more keywords to the ADD_ONION control command: + PoWDefensesEnabled, PoWQueueRate and PoWQueueBurst which correspond + to HiddenServicePoWDefensesEnabled, HiddenServicePoWQueueRate and + HiddenServicePoWQueueBurst from torrc. + + o Minor feature (testing, CI): + - Use a fixed version of chutney (be881a1e) instead of its current + HEAD. This version should also be preferred when testing locally. + + o Minor features (compilation): + - Fix a warning when compiling with GCC 14.2. Closes 41032. + + o Minor features (continuous integration): + - Upgrade CI runners to use Debian Bookworm instead of Bullseye. + Closes ticket 41029. + + o Minor features (fallbackdir): + - Regenerate fallback directories generated on February 05, 2025. + - Regenerate fallback directories generated on March 20, 2025. + + o Minor features (geoip data): + - Update the geoip files to match the IPFire Location Database, as + retrieved on 2025/02/05. + - Update the geoip files to match the IPFire Location Database, as + retrieved on 2025/03/20. + - Update the geoip files to match the IPFire Location Database, as + retrieved on 2025/03/24. + + o Minor features (recommended protocols): + - Directory authorities now vote to recommend that clients support + certain protocols beyond those that are required. These include + improved support for connecting to relays on IPv6, NtorV3, and + congestion control. Part of ticket 40836. + + o Minor features (required protocols): + - Directory authorities now vote to require clients to support the + authenticated SENDME feature, which was introduced in + 0.4.1.1-alpha. Part of ticket 40836. + - Directory authorities now vote to require relays to support + certain protocols, all of which have been implemented since + 0.4.7.4-alpha or earlier. These include improved support for + connecting to relays on IPv6, NtorV3, running as a rate-limited + introduction point, authenticated SENDMEs, and congestion control. + Part of ticket 40836. + + o Major bugfix (control-events, bw-cache): + - Fixes spikes occurring in bandwidth cache on control connection. + Fixes bug 31524; bugfix on 0.4.8.12-dev. + + o Major bugfixes (conflux): + - Ensure conflux guards obey family and subnet restrictions. Fixes + bug 40976; bugfix on 0.4.8.13. + + o Major bugfixes (onion service directory cache): + - When the OOM killer kicks in, cleanup the descriptor cache of an + HSDir by looking at the lowest downloaded count instead of time in + cache. Fixes bug 40996; bugfix on 0.3.5.1-alpha. + + o Minor bugfix (client DNS): + - Handle empty DNS reply without sending back an error and instead + send back NOERROR (RFC1035 error code 0x0). Fixes bug 40248; + bugfix on 0.3.5.1-alpha. + + o Minor bugfix (conflux): + - Avoid a non fatal assert when describing a conflux circuit on the + control port after being prepped to be freed. Fixes bug 41037; + bugfix on 0.4.8.15. + + o Minor bugfix (dirauth): + - Fix typo in flag assignment approved-routers file. Fixes bug + 41035; bugfix on 0.4.8.15 + + o Minor bugfixes (control port): + - Correctly report conflux pair information to controller fields + Fixes bug 40872; bugfix on 0.4.8.1-alpha + + o Minor bugfixes (directory authorities): + - After we added layer-two vanguards, directory authorities wouldn't + think any of their vanguards were suitable for circuits, leading + to a "Failed to find node for hop #2 of our path. Discarding this + circuit." log message once per second from startup until they made + a fresh consensus. Now they look to their existing consensus on + startup, letting them build circuits properly from the beginning. + Fixes bug 40802; bugfix on 0.4.7.1-alpha. + + o Minor bugfixes (relay flag usage): + - Fix client usage of the MiddleOnly flag so that MiddleOnly relays + are not used as HS IP or RP by clients or services. Additionally, + give dirauths the ability to remove specific flags, as an + alternative to MiddleOnly. Fixes bug 41023; bugfix on 0.4.7.2-alpha + + o Minor bugfixes (sandbox, bwauth): + - Fix sandbox to work for bandwidth authority. Fixes bug 40933; + bugfix on 0.2.2.1-alpha + + o Minor bugfixes (tests): + - Fix a test failure with OpenSSL builds running at security level 1 + or greater, which does not permit SHA-1 certificates. (Fixes bug + 41021; bugfix on 0.2.8.1-alpha.) + + o Minor bugfixes (threads, memory): + - Improvements in cleanup of resources used by threads. Fixes bug + 40991; bugfix on 0.4.8.13-dev. + - Rework start and exit of worker threads. + + o Removed features: + - Relays no longer support the obsolete "RSA-SHA256-TLSSecret" + authentication method, which used a dangerously short RSA key, and + which required access TLS session internals. The current method + ("Ed25519-SHA256-RFC5705") has been supported since 0.3.0.1-alpha. + Closes ticket 41020. + + +Changes in version 0.4.8.16 - 2025-03-24 + This is a quick second release since 0.4.8.15 due to a typo in a directory + authority rule file. This only affects directory authorities. + + o Minor features (geoip data): + - Update the geoip files to match the IPFire Location Database, as + retrieved on 2025/03/24. + + o Minor bugfix (dirauth): + - Fix typo in flag assignment approved-routers file. Fixes bug + 41035; bugfix on 0.4.8.15. + + +Changes in version 0.4.8.15 - 2025-03-20 + This is a minor release fixing a sandbox issue for bandwidth authority and a + conflux issue on the control port. It also has a client fix about relay flag + usage. + + o Minor feature (testing, CI): + - Use a fixed version of chutney (be881a1e) instead of its current + HEAD. This version should also be preferred when testing locally. + + o Minor features (continuous integration): + - Upgrade CI runners to use Debian Bookworm instead of Bullseye. + Closes ticket 41029. + + o Minor features (fallbackdir): + - Regenerate fallback directories generated on March 20, 2025. + + o Minor features (geoip data): + - Update the geoip files to match the IPFire Location Database, as + retrieved on 2025/03/20. + + o Minor bugfixes (control port): + - Correctly report conflux pair information to controller fields. + Fixes bug 40872; bugfix on 0.4.8.1-alpha. + + o Minor bugfixes (relay flag usage): + - Fix client usage of the MiddleOnly flag so that MiddleOnly relays + are not used as HS IP or RP by clients or services. Additionally, + give dirauths the ability to remove specific flags, as an + alternative to MiddleOnly. Fixes bug 41023; bugfix on 0.4.7.2-alpha. + + o Minor bugfixes (sandbox, bwauth): + - Fix sandbox to work for bandwidth authority. Fixes bug 40933; + bugfix on 0.2.2.1-alpha. + + +Changes in version 0.4.8.14 - 2025-02-05 + Minor release fixing a major bug affecting onion service directory cache, + also known as HSDir. Furthermore, the fallbackdir list had more than 25% of + its entries unreachable or gone from the consensus. As usual, we strongly + recommend to update to this version as soon as possible. + + o Major bugfixes (onion service directory cache): + - When the OOM killer kicks in, cleanup the descriptor cache of an + HSDir by looking at the lowest downloaded count instead of time in + cache. Fixes bug 40996; bugfix on 0.3.5.1-alpha. + + o Minor feature (testing): + - test-network now unconditionally includes IPv6 instead of trying + to detect IPv6 support. + + o Minor features (fallbackdir): + - Regenerate fallback directories generated on February 05, 2025. + + o Minor features (geoip data): + - Update the geoip files to match the IPFire Location Database, as + retrieved on 2025/02/05. + + o Minor bugfixes (memory): + - Fix a pointer free that wasn't set to NULL afterwards which could + be reused by calling back in the free all function. Fixes bug + 40989; bugfix on 0.4.8.13. + + +Changes in version 0.4.9.1-alpha - 2024-12-03 + This is the first alpha of the 0.4.9.x series. This release mostly consists + of bugfixes including some major ones. There are several minor features in + this release but no large new subsystem. + + o Major bugfixes (sandbox): + - Fix sandbox to work on architectures that use Linux's generic + syscall interface, extending support for AArch64 (ARM64) and + adding support for RISC-V, allowing test_include.sh and the + sandbox unit tests to pass on these systems even when building + with fragile hardening enabled. Fixes bugs 40465 and 40599; bugfix + on 0.2.5.1-alpha. + + o Minor feature (defense in depth): + - Verify needle is smaller than haystack before calling memmem. + Closes ticket 40854. + + o Minor feature (directory authority): + - Introduce MinimalAcceptedServerVersion to allow modification of + minimal accepted version for relays without requiring a new tor + release. Closes ticket 40817. + + o Minor feature (exit policies): + - Implement reevaluating new exit policy against existing + connections. This is controlled by new config option + ReevaluateExitPolicy, defaulting to 0. Closes ticket 40676. + + o Minor feature (exit relay, DoS resistance): + - Implement a token-bucket based rate limiter for stream creation + and resolve request. It is configured by the DoSStream* family of + configuration options. Closes ticket 40736. + + o Minor feature (metrics port): + - New metrics on the MetricsPort for the number of BUG() that + occurred at runtime. Closes MR 760. + + o Minor feature (metrics port, relay): + - Add new metrics for relays on the MetricsPort namely the count of + drop cell, destroy cell and the number of circuit protocol + violation seen that lead to a circuit close. Closes ticket 40816. + + o Minor feature (testing): + - test-network now unconditionally includes IPv6 instead of trying + to detect IPv6 support. + + o Minor feature (testing, CI): + - Use a fixed version of chutney (be881a1e) instead of its current + HEAD. This version should also be preferred when testing locally. + + o Minor features (forward-compatibility): + - We now correctly parse microdescriptors and router descriptors + that do not include TAP onion keys. (For backward compatibility, + authorities continue to require these keys.) Implements part of + proposal 350. + + o Minor features (portability, android): + - Use /data/local/tmp for data storage on Android by default. Closes + ticket 40487. Patch from Hans-Christoph Steiner. + + o Minor features (SOCKS): + - Detect invalid SOCKS5 username/password combinations according to + new extended parameters syntax. (Currently, this rejects any + SOCKS5 username beginning with "", except for the username + "0". Such usernames are now reserved to communicate + additional parameters with other Tor implementations.) Implements + proposal 351. + + o Minor bugfix (MetricsPort, relay): + - Handle rephist tracking of ntor and ntor_v3 handshakes + individually such that MetricsPort exposes the correct values. + Fixes bug 40638; bugfix on 0.4.7.11. + + o Minor bugfix (process): + - Avoid closing all possible FDs when spawning a process (PT). On + some systems, this could lead to 3+ minutes hang. Fixes bug 40990; + bugfix on 0.3.5.1-alpha. + + o Minor bugfix (relay, sandbox): + - Disable a sandbox unit test that is failing on Debian Sid breaking + our nightly packages. Fixes bug 40918; bugfix on 0.3.5.1-alpha. + + o Minor bugfixes (bridge): + - Don't warn when BridgeRelay is 1 and ExitRelay is explicitly set + to 0. Fixes bug 40884; bugfix on 0.4.8.3-rc. + + o Minor bugfixes (compiler warnings): + - Make sure the two bitfields in the half-closed edge struct are + unsigned, as we're using them for boolean values and assign 1 to + them. Fixes bug 40911; bugfix on 0.4.7.2-alpha. + + o Minor bugfixes (conflux, client): + - Avoid a non fatal assert caused by data coming in on a conflux set + that is being freed during shutdown. Fixes bug 40870; bugfix + on 0.4.8.1-alpha. + + o Minor bugfixes (memory): + - Fix a pointer free that wasn't set to NULL afterwards which could + be reused by calling back in the free all function. Fixes bug + 40989; bugfix on 0.4.8.13. + + o Minor bugfixes (sandbox, bwauth): + - Fix sandbox to work for bandwidth authority. Fixes bug 40933; + bugfix on 0.2.2.1-alpha + + o Minor bugfixes (testing): + - Enabling TestingTorNetwork no longer forces fast hidden service + intro point rotation. This reduces noise and errors when using + hidden services with TestingTorNetwork enabled. Fixes bug 40922; + bugfix on 0.3.2.1-alpha. + + o Minor bugfixes (tor-resolve): + - Create socket with correct family as given by sockshost, fixes + IPv6. Fixes bug 40982; bugfix on 0.4.9.0-alpha. + + o Removed features: + - Directory authorities no longer support consensus methods before + method 32. Closes ticket 40835. + + o Removed features (directory authority): + - We include a new consensus method that removes support for + computing "package" lines in consensus documents. This feature was + never used, and support for including it in our votes was removed + in 0.4.2.1-alpha. Finishes implementation of proposal 301. + + o Removed features (obsolete): + - Relays no longer support the obsolete TAP circuit extension + protocol. (For backward compatibility, however, relays still + continue to include TAP keys in their descriptors.) Implements + part of proposal 350. + - Removed some vestigial code for selecting the TAP circuit + extension protocol. + + +Changes in version 0.4.8.13 - 2024-10-24 + This minor release fixes an important client circuit building (conflux + related) bug which led to performance degradation and extra load on the + network. Some minor memory leaks fixes as well as an important minor feature + for pluggable transports. We strongly recommend to update as soon as possible + for clients in order to neutralize this conflux bug. + + o Major bugfixes (circuit building): + - Conflux circuit building was ignoring the "predicted ports" + feature, which aims to make Tor stop building circuits if there + have been no user requests lately. This bug led to every idle Tor + on the network building and discarding circuits every 30 seconds, + which added overall load to the network, used bandwidth and + battery from clients that weren't actively using their Tor, and + kept sockets open on guards which added connection padding + essentially forever. Fixes bug 40981; bugfix on 0.4.8.1-alpha. + + o Minor feature (bridges, pluggable transport): + - Add STATUS TYPE=version handler for Pluggable Transport. This + allows us to gather version statistics on Pluggable Transport + usage from bridge servers on our metrics portal. Closes + ticket 11101. + + o Minor features (fallbackdir): + - Regenerate fallback directories generated on October 24, 2024. + + o Minor features (geoip data): + - Update the geoip files to match the IPFire Location Database, as + retrieved on 2024/10/24. + + o Minor bugfixes (memleak, authority): + - Fix a small memleak when computing a new consensus. This only + affects directory authorities. Fixes bug 40966; bugfix + on 0.3.5.1-alpha. + + o Minor bugfixes (memory): + - Fix memory leaks of the CPU worker code during shutdown. Fixes bug + 833; bugfix on 0.3.5.1-alpha. + + +Changes in version 0.4.8.12 - 2024-06-06 + This is a minor release with couple bugfixes affecting conflux and logging. + We also have the return of faravahar directory authority with new keys and + address. + + o Minor feature (dirauth): + - Add back faravahar with a new address and new keys. Closes 40689. + + o Minor features (fallbackdir): + - Regenerate fallback directories generated on June 06, 2024. + + o Minor features (geoip data): + - Update the geoip files to match the IPFire Location Database, as + retrieved on 2024/06/06. + + o Minor bugfix (circuit): + - Remove a log_warn being triggered by a protocol violation that + already emits a protocol warning log. Fixes bug 40932; bugfix + on 0.4.8.1-alpha. + + o Minor bugfixes (conflux): + - Avoid a potential hard assert (crash) when sending a cell on a + Conflux set. Fixes bug 40921; bugfix on 0.4.8.1-alpha. + - Make sure we don't process a closed circuit when packaging data. + This lead to a non fatal BUG() spamming logs. Fixes bug 40908; + bugfix on 0.4.8.1-alpha. + + +Changes in version 0.4.8.11 - 2024-04-10 + This is a minor release mostly to upgrade the fallbackdir list. + Directory authorities running this version will now automatically + reject relays running the end of life 0.4.7.x version. + + o Minor features (directory authorities): + - Reject 0.4.7.x series at the authority level. Closes ticket 40896. + + o Minor feature (dirauth, tor26): + - New IP address and keys. + + o Minor feature (directory authority): + - Allow BandwidthFiles "node_id" KeyValue without the dollar sign at + the start of the hexdigit, in order to easier database queries + combining Tor documents in which the relays fingerprint does not + include it. Fixes bug 40891; bugfix on 0.4.7 (all supported + versions of Tor). + + o Minor features (fallbackdir): + - Regenerate fallback directories generated on April 10, 2024. + + o Minor features (geoip data): + - Update the geoip files to match the IPFire Location Database, as + retrieved on 2024/04/10. + + o Minor bugfixes (directory authorities): + - Add a warning when publishing a vote or signatures to another + directory authority fails. Fixes bug 40910; bugfix + on 0.2.0.3-alpha. + + +Changes in version 0.4.8.10 - 2023-12-08 + This is a security release fixing a high severity bug (TROVE-2023-007) + affecting Exit relays supporting Conflux. We strongly recommend to update as + soon as possible. + + o Major bugfixes (TROVE-2023-007, exit): + - Improper error propagation from a safety check in conflux leg + linking led to a desynchronization of which legs were part of a + conflux set, ultimately causing a UAF and NULL pointer dereference + crash on Exit relays. Fixes bug 40897; bugfix on 0.4.8.1-alpha. + + o Minor features (fallbackdir): + - Regenerate fallback directories generated on December 08, 2023. + + o Minor features (geoip data): + - Update the geoip files to match the IPFire Location Database, as + retrieved on 2023/12/08. + + o Minor bugfixes (bridges, statistics): + - Correctly report statistics for client count over pluggable + transports. Fixes bug 40871; bugfix on 0.4.8.4. + + +Changes in version 0.4.8.9 - 2023-11-09 + This is another security release fixing a high severity bug affecting onion + services which is tracked by TROVE-2023-006. We are also releasing a guard + major bugfix as well. If you are an onion service operator, we strongly + recommend to update as soon as possible. + + o Major bugfixes (guard usage): + - When Tor excluded a guard due to temporary circuit restrictions, + it considered *additional* primary guards for potential usage by + that circuit. This could result in more than the specified number + of guards (currently 2) being used, long-term, by the tor client. + This could happen when a Guard was also selected as an Exit node, + but it was exacerbated by the Conflux guard restrictions. Both + instances have been fixed. Fixes bug 40876; bugfix + on 0.3.0.1-alpha. + + o Major bugfixes (onion service, TROVE-2023-006): + - Fix a possible hard assert on a NULL pointer when recording a + failed rendezvous circuit on the service side for the MetricsPort. + Fixes bug 40883; bugfix on 0.4.8.1-alpha. + + o Minor features (fallbackdir): + - Regenerate fallback directories generated on November 09, 2023. + + o Minor features (geoip data): + - Update the geoip files to match the IPFire Location Database, as + retrieved on 2023/11/09. + + +Changes in version 0.4.8.8 - 2023-11-03 We are releasing today a fix for a high security issue, TROVE-2023-004, that - is affecting relays. Please upgrade as soon as posssible. + is affecting relays. Also a few minor bugfixes detailed below. Please upgrade + as soon as possible. o Major bugfixes (TROVE-2023-004, relay): - Mitigate an issue when Tor compiled with OpenSSL can crash during @@ -14,11 +1227,39 @@ - Update the geoip files to match the IPFire Location Database, as retrieved on 2023/11/03. + o Minor bugfixes (directory authority): + - Look at the network parameter "maxunmeasuredbw" with the correct + spelling. Fixes bug 40869; bugfix on 0.4.6.1-alpha. + + o Minor bugfixes (vanguards addon support): + - Count the conflux linked cell as valid when it is successfully + processed. This will quiet a spurious warn in the vanguards addon. + Fixes bug 40878; bugfix on 0.4.8.1-alpha. + + +Changes in version 0.4.8.7 - 2023-09-25 + This version fixes a single major bug in the Conflux subsystem on the client + side. See below for more information. The upcoming Tor Browser 13 stable will + pick this up. + + o Major bugfixes (conflux): + - Fix an issue that prevented us from pre-building more conflux sets + after existing sets had been used. Fixes bug 40862; bugfix + on 0.4.8.1-alpha. + + o Minor features (fallbackdir): + - Regenerate fallback directories generated on September 25, 2023. -Changes in version 0.4.7.15 - 2023-09-18 - This version contains an important fix for onion service regarding congestion - control and its reliability. Apart from that, very minor bugfixes. We - strongly recommend all onion service operators to update immediately. + o Minor features (geoip data): + - Update the geoip files to match the IPFire Location Database, as + retrieved on 2023/09/25. + + +Changes in version 0.4.8.6 - 2023-09-18 + This version contains an important fix for onion services regarding + congestion control and its reliability. Apart from that, unneeded BUG + warnings have been suppressed especially about a compression bomb seen + on relays. o Major bugfixes (onion service): - Fix a reliability issue where services were expiring their @@ -27,6 +1268,10 @@ intro points. Bug reported and fixed by gitlab user @hyunsoo.kim676. Fixes bug 40858; bugfix on 0.4.7.5-alpha. + o Minor features (debugging, compression): + - Log the input and output buffer sizes when we detect a potential + compression bomb. Diagnostic for ticket 40739. + o Minor features (fallbackdir): - Regenerate fallback directories generated on September 18, 2023. @@ -34,10 +1279,92 @@ - Update the geoip files to match the IPFire Location Database, as retrieved on 2023/09/18. + o Minor bugfix (defensive programming): + - Disable multiple BUG warnings of a missing relay identity key when + starting an instance of Tor compiled without relay support. Fixes + bug 40848; bugfix on 0.4.3.1-alpha. + + o Minor bugfixes (bridge authority): + - When reporting a pseudo-networkstatus as a bridge authority, or + answering "ns/purpose/*" controller requests, include accurate + published-on dates from our list of router descriptors. Fixes bug + 40855; bugfix on 0.4.8.1-alpha. + + o Minor bugfixes (compression, zstd): + - Use less frightening language and lower the log-level of our run- + time ABI compatibility check message in our Zstd compression + subsystem. Fixes bug 40815; bugfix on 0.4.3.1-alpha. + + +Changes in version 0.4.8.5 - 2023-08-30 + Quick second release after the first stable few days ago fixing minor + annoying bugfixes creating log BUG stacktrace. We also fix BSD compilation + failures and PoW unit test. + + o Minor features (fallbackdir): + - Regenerate fallback directories generated on August 30, 2023. + + o Minor features (geoip data): + - Update the geoip files to match the IPFire Location Database, as + retrieved on 2023/08/30. + + o Minor bugfix (NetBSD, compilation): + - Fix compilation issue on NetBSD by avoiding an unnecessary + dependency on "huge" page mappings in Equi-X. Fixes bug 40843; + bugfix on 0.4.8.1-alpha. + + o Minor bugfix (NetBSD, testing): + - Fix test failures in "crypto/hashx" and "slow/crypto/equix" on + x86_64 and aarch64 NetBSD hosts, by adding support for + PROT_MPROTECT() flags. Fixes bug 40844; bugfix on 0.4.8.1-alpha. + + o Minor bugfixes (conflux): + - Demote a relay-side warn about too many legs to ProtocolWarn, as + there are conditions that it can briefly happen during set + construction. Also add additional set logging details for all + error cases. Fixes bug 40841; bugfix on 0.4.8.1-alpha. + - Prevent non-fatal assert stacktrace caused by using conflux sets + during their teardown process. Fixes bug 40842; bugfix + on 0.4.8.1-alpha. + + +Changes in version 0.4.8.4 - 2023-08-23 + Finally, this is the very first stable release of the 0.4.8.x series making + Proof-of-Work (prop#327) and Conflux (prop#329) available to the entire + network. Some major bugfixes since the release candidate detailed below. + + o Major feature (denial of service): + - Extend DoS protection to partially opened channels and known + relays. Because re-entry is not allowed anymore, we can apply DoS + protections onto known IP namely relays. Fixes bug 40821; bugfix + on 0.3.5.1-alpha. + + o Major bugfixes (conflux): + - Fix a relay-side crash caused by side effects of the fix for bug + 40827. Reverts part of that fix that caused the crash and adds + additional log messages to help find the root cause. Fixes bug + 40834; bugfix on 0.4.8.3-rc. + + o Major bugfixes (proof of work, onion service, hashx): + - Fix a very rare buffer overflow in hashx, specific to the dynamic + compiler on aarch64 platforms. Fixes bug 40833; bugfix + on 0.4.8.2-alpha. + + o Minor features (fallbackdir): + - Regenerate fallback directories generated on August 23, 2023. + + o Minor features (geoip data): + - Update the geoip files to match the IPFire Location Database, as + retrieved on 2023/08/23. + o Minor features (testing): - - Enable Doxygen and Stem tests for 0.4.8 and clean-up some logic - for handling versions of Tor that are no longer supported. Closes - ticket 40859. + - All Rust code is now linted (cargo clippy) as part of GitLab CI, and + existing warnings have been fixed. - Any unit tests written in Rust now + run as part of GitLab CI. + + o Minor bugfix (FreeBSD, compilation): + - Fix compilation issue on FreeBSD by properly importing + sys/param.h. Fixes bug 40825; bugfix on 0.4.8.1-alpha. o Minor bugfixes (compression): - Right after compression/decompression work is done, check for @@ -46,16 +1373,48 @@ log warning. Fixes bug 40739; bugfix on 0.3.5.1-alpha. Patch by "cypherpunks". - o Minor bugfixes (compression, zstd): - - Use less frightening language and lower the log-level of our run- - time ABI compatibility check message in our Zstd compression - subsystem. Fixes bug 40815; bugfix on 0.4.3.1-alpha. +Changes in version 0.4.8.3-rc - 2023-08-04 + This is the first release candidate (and likely the only) of the 0.4.8.x + series. We fixed a major conflux bugfix which was a fatal asserts on the + relay Exit side. See below for more details. Couple minor bugfixes. Until + stable, name of the game here is stabilization. + + o Major bugfixes (conflux): + - Fix a relay-side assert crash caused by attempts to use a conflux + circuit between circuit close and free, such that no legs were on + the conflux set. Fixed by nulling out the stream's circuit back- + pointer when the last leg is removed. Additional checks and log + messages have been added to detect other cases. Fixes bug 40827; + bugfix on 0.4.8.1-alpha. -Changes in version 0.4.7.14 - 2023-07-26 - This version contains several minor fixes and one major bugfix affecting - vanguards (onion service). As usual, we recommend upgrading to this version - as soon as possible. + o Minor features (fallbackdir): + - Regenerate fallback directories generated on August 04, 2023. + - Regenerate fallback directories generated on July 26, 2023. + + o Minor features (geoip data): + - Update the geoip files to match the IPFire Location Database, as + retrieved on 2023/07/26. + - Update the geoip files to match the IPFire Location Database, as + retrieved on 2023/08/04. + + o Minor features (bridge): + - warn when a bridge is also configure to be an exit relay. + Closes ticket 40819. + + o Minor bugfixes (compilation): + - Fix all -Werror=enum-int-mismatch warnings. No behavior change. + Fixes bug 40824; bugfix on 0.3.5.1-alpha. + + o Minor bugfixes (protocol warn): + - Wrap a handful of cases where ProtocolWarning logs could emit IP + addresses. Fixes bug 40828; bugfix on 0.3.5.1-alpha. + + +Changes in version 0.4.8.2-alpha - 2023-07-12 + This is our second alpha containing some minor bugfixes and one major bugfix + about L2 vanguard rotation. We believe this will be the last alpha before the + rc in a couple of weeks. o Major bugfixes (vanguards): - Rotate to a new L2 vanguard whenever an existing one loses the @@ -65,40 +1424,229 @@ to choose from so we would fail to make onion-related circuits. Fixes bug 40805; bugfix on 0.4.7.1-alpha. + o Minor feature (hs): + - Fix compiler warnings in equix and hashx when building with clang. + Closes ticket 40800. + + o Minor features (fallbackdir): + - Regenerate fallback directories generated on July 12, 2023. + + o Minor features (geoip data): + - Update the geoip files to match the IPFire Location Database, as + retrieved on 2023/07/12. + + o Minor bugfix (congestion control): + - Reduce the accepted range of a circuit's negotiated 'cc_sendme_inc' + to be +/- 1 from the consensus parameter value. Fixes bug 40569; + bugfix on 0.4.7.4-alpha. + - Remove unused congestion control algorithms and BDP calculation + code, now that we have settled on and fully tuned Vegas. Fixes bug + 40566; bugfix on 0.4.7.4-alpha. + - Update default congestion control parameters to match consensus. + Fixes bug 40709; bugfix on 0.4.7.4-alpha. + + o Minor bugfixes (compilation): + - Fix "initializer is not a constant" compilation error that + manifests itself on gcc versions < 8.1 and MSVC. Fixes bug 40773; + bugfix on 0.4.8.1-alpha + + o Minor bugfixes (conflux): + - Count leg launch attempts prior to attempting to launch them. This + avoids infinite launch attempts due to internal circuit building + failures. Additionally, double-check that we have enough exits in + our consensus overall, before attempting to launch conflux sets. + Fixes bug 40811; bugfix on 0.4.8.1-alpha. + - Fix a case where we were resuming reading on edge connections that + were already marked for close. Fixes bug 40801; bugfix + on 0.4.8.1-alpha. + - Fix stream attachment order when creating conflux circuits, so + that stream attachment happens after finishing the full link + handshake, rather than upon set finalization. Fixes bug 40801; + bugfix on 0.4.8.1-alpha. + - Handle legs being closed or destroyed before computing an RTT + (resulting in warns about too many legs). Fixes bug 40810; bugfix + on 0.4.8.1-alpha. + - Remove a "BUG" warning from conflux_pick_first_leg that can be + triggered by broken or malicious clients. Fixes bug 40801; bugfix + on 0.4.8.1-alpha. + + o Minor bugfixes (KIST): + - Prevent KISTSchedRunInterval from having values of 0 or 1, neither + of which work properly. Additionally, make a separate + KISTSchedRunIntervalClient parameter, so that the client and relay + KIST values can be set separately. Set the default of both to 2ms. + Fixes bug 40808; bugfix on 0.3.2.1-alpha. + + +Changes in version 0.4.8.1-alpha - 2023-06-01 + This is the first alpha of the 0.4.8.x series. Two major features in this + version which are Conflux and onion service Proof-of-Work (PoW). There are + also many small features in particular, worth noting, the MetricsPort is now + exporting more relay and onion service metrics. Finally, there are + also numerous minor bugfixes included in this version. + + o Major features (onion service, proof-of-work): + - Implement proposal 327 (Proof-Of-Work). This is aimed at thwarting + introduction flooding DoS attacks by introducing a dynamic Proof-Of-Work + protocol that occurs over introduction circuits. This introduces several + torrc options prefixed with "HiddenServicePoW" in order to control this + feature. By default, this is disabled. Closes ticket 40634. + + o Major features (conflux): + - Implement Proposal 329 (conflux traffic splitting). Conflux splits + traffic across two circuits to Exits that support the protocol. + These circuits are pre-built only, which means that if the pre- + built conflux pool runs out, regular circuits will then be used. + When using conflux circuit pairs, clients choose the lower-latency + circuit to send data to the Exit. When the Exit sends data to the + client, it maximizes throughput, by fully utilizing both circuits + in a multiplexed fashion. Alternatively, clients can request that + the Exit optimize for latency when transmitting to them, by + setting the torrc option 'ConfluxClientUX latency'. Onion services + are not currently supported, but will be in arti. Many other + future optimizations will also be possible using this protocol. + Closes ticket 40593. + + o Major features (dirauth): + - Directory authorities and relays now interact properly with + directory authorities if they change addresses. In the past, they + would continue to upload votes, signatures, descriptors, etc to + the hard-coded address in the configuration. Now, if the directory + authority is listed in the consensus at a different address, they + will direct queries to this new address. Implements ticket 40705. + o Minor feature (CI): - Update CI to use Debian Bullseye for runners. + o Minor feature (client, IPv6): + - Make client able to pick IPv6 relays by default now meaning + ClientUseIPv6 option now defaults to 1. Closes ticket 40785. + + o Minor feature (compilation): + - Fix returning something other than "Unknown N/A" as libc version + if we build tor on an O.S. like DragonFlyBSD, FreeBSD, OpenBSD + or NetBSD. + + o Minor feature (cpuworker): + - Always use the number of threads for our CPU worker pool to the + number of core available but cap it to a minimum of 2 in case of a + single core. Fixes bug 40713; bugfix on 0.3.5.1-alpha. + o Minor feature (lzma): - Fix compiler warnings for liblzma >= 5.3.1. Closes ticket 40741. + o Minor feature (MetricsPort, relay): + - Expose time until online keys expires on the MetricsPort. Closes + ticket 40546. + + o Minor feature (MetricsPort, relay, onion service): + - Add metrics for the relay side onion service interactions counting + seen cells. Closes ticket 40797. Patch by "friendly73". + o Minor features (directory authorities): - Directory authorities now include their AuthDirMaxServersPerAddr config option in the consensus parameter section of their vote. Now external tools can better predict how they will behave. Implements ticket 40753. + o Minor features (directory authority): + - Add a new consensus method in which the "published" times on + router entries in a microdesc consensus are all set to a + meaningless fixed date. Doing this will make the download size for + compressed microdesc consensus diffs much smaller. Part of ticket + 40130; implements proposal 275. + + o Minor features (network documents): + - Clients and relays no longer track the "published on" time + declared for relays in any consensus documents. When reporting + this time on the control port, they instead report a fixed date in + the future. Part of ticket 40130. + o Minor features (fallbackdir): - - Regenerate fallback directories generated on July 26, 2023. + - Regenerate fallback directories generated on June 01, 2023. o Minor features (geoip data): - Update the geoip files to match the IPFire Location Database, as - retrieved on 2023/07/26. + retrieved on 2023/06/01. + + o Minor features (hs, metrics): + - Add tor_hs_rend_circ_build_time and tor_hs_intro_circ_build_time + histograms to measure hidden service rend/intro circuit build time + durations. Part of ticket 40757. + + o Minor features (metrics): + - Add a `reason` label to the HS error metrics. Closes ticket 40758. + - Add service side metrics for REND and introduction request + failures. Closes ticket 40755. + - Add support for histograms. Part of ticket 40757. + + o Minor features (pluggable transports): + - Automatically restart managed Pluggable Transport processes when + their process terminate. Resolves ticket 33669. + + o Minor features (portability, compilation): + - Use OpenSSL 1.1 APIs for LibreSSL, fixing LibreSSL 3.5 + compatibility. Fixes issue 40630; patch by Alex Xu (Hello71). + + o Minor features (relay): + - Do not warn about configuration options that may expose a non- + anonymous onion service. Closes ticket 40691. + + o Minor features (relays): + - Trigger OOS when bind fails with EADDRINUSE. This improves + fairness when a large number of exit connections are requested, + and properly signals exhaustion to the network. Fixes issue 40597; + patch by Alex Xu (Hello71). + + o Minor features (tests): + - Avoid needless key reinitialization with OpenSSL during unit + tests, saving significant time. Patch from Alex Xu. o Minor bugfix (relay, logging): - The wrong max queue cell size was used in a protocol warning logging statement. Fixes bug 40745; bugfix on 0.4.7.1-alpha. - o Minor bugfixes (compilation): - - Fix all -Werror=enum-int-mismatch warnings. No behavior change. - Fixes bug 40824; bugfix on 0.3.5.1-alpha. + o Minor bugfixes (logging): + - Avoid ""double-quoting"" strings in several log messages. Fixes + bug 22723; bugfix on 0.1.2.2-alpha. + - Correct a log message when cleaning microdescriptors. Fixes bug + 40619; bugfix on 0.2.5.4-alpha. o Minor bugfixes (metrics): - Decrement hs_intro_established_count on introduction circuit close. Fixes bug 40751; bugfix on 0.4.7.12. + o Minor bugfixes (pluggable transports, windows): + - Remove a warning `BUG()` that could occur when attempting to + execute a non-existing pluggable transport on Windows. Fixes bug + 40596; bugfix on 0.4.0.1-alpha. + + o Minor bugfixes (relay): + - Remove a "BUG" warning for an acceptable race between a circuit + close and considering that circuit active. Fixes bug 40647; bugfix + on 0.3.5.1-alpha. + - Remove a harmless "Bug" log message that can happen in + relay_addr_learn_from_dirauth() on relays during startup. Finishes + fixing bug 40231. Fixes bug 40523; bugfix on 0.4.5.4-rc. + o Minor bugfixes (sandbox): - Allow membarrier for the sandbox. And allow rt_sigprocmask when compiled with LTTng. Fixes bug 40799; bugfix on 0.3.5.1-alpha. + - Fix sandbox support on AArch64 systems. More "*at" variants of + syscalls are now supported. Signed 32 bit syscall parameters are + checked more precisely, which should lead to lower likelihood of + breakages with future compiler and libc releases. Fixes bug 40599; + bugfix on 0.4.4.3-alpha. + + o Minor bugfixes (state file): + - Avoid a segfault if the state file doesn't contains TotalBuildTimes + along CircuitBuildAbandonedCount being above 0. Fixes bug 40437; + bugfix on 0.3.5.1-alpha. + + o Removed features: + - Remove the RendPostPeriod option. This was primarily used in + Version 2 Onion Services and after its deprecation isn't needed + anymore. Closes ticket 40431. Patch by Neel Chauhan. Changes in version 0.4.7.13 - 2023-01-12 @@ -110,7 +1658,7 @@ o Major bugfixes (congestion control): - Avoid incrementing the congestion window when the window is not - fully in use. Thia prevents overshoot in cases where long periods + fully in use. This prevents overshoot in cases where long periods of low activity would allow our congestion window to grow, and then get followed by a burst, which would cause queue overload. Also improve the increment checks for RFC3742. Fixes bug 40732; @@ -163,6 +1711,35 @@ on tor-0.4.6.1-alpha. +Changes in version 0.4.5.16 - 2023-01-12 + This version has one major bugfix for relay and a security fix, + TROVE-2022-002, affecting clients. We strongly recommend to upgrade to our + 0.4.7.x stable series. As a reminder, this series is EOL on February 15th, + 2023. + + o Major bugfixes (relay): + - When opening a channel because of a circuit request that did not + include an Ed25519 identity, record the Ed25519 identity that we + actually received, so that we can use the channel for other + circuit requests that _do_ list an Ed25519 identity. (Previously + we had code to record this identity, but a logic bug caused it to + be disabled.) Fixes bug 40563; bugfix on 0.3.0.1-alpha. Patch + from "cypherpunks". + + o Major bugfixes (TROVE-2022-002, client): + - The SafeSocks option had its logic inverted for SOCKS4 and + SOCKS4a. It would let the unsafe SOCKS4 pass but not the safe + SOCKS4a one. This is TROVE-2022-002 which was reported on + Hackerone by "cojabo". Fixes bug 40730; bugfix on 0.3.5.1-alpha. + + o Minor features (fallbackdir): + - Regenerate fallback directories generated on January 12, 2023. + + o Minor features (geoip data): + - Update the geoip files to match the IPFire Location Database, as + retrieved on 2023/01/12. + + Changes in version 0.4.7.12 - 2022-12-06 This version contains a major change that is a new key for moria1. Also, new metrics are exported on the MetricsPort for the congestion control @@ -190,6 +1767,43 @@ used by our thread pool. Fixes bug 40719; bugfix on 0.3.5.1-alpha. +Changes in version 0.4.5.15 - 2022-12-06 + This version has several major changes for directory authorities. And a + major bugfix on OSX. Again, we strongly recommend to upgrade to our 0.4.7.x + series latest stable. This series is EOL on February 15th, 2023. + + o Directory authority changes (dizum): + - Change dizum IP address. Closes ticket 40687. + + o Directory authority changes (Faravahar): + - Remove Faravahar until its operator, Sina, set it back up online + outside of Team Cymru network. Closes ticket 40688. + + o Directory authority changes (moria1): + - Rotate the relay identity key and v3 identity key for moria1. They + have been online for more than a decade and refreshing keys + periodically is good practice. Advertise new ports too, to avoid + confusion. Closes ticket 40722. + + o Major bugfixes (OSX): + - Fix coarse-time computation on Apple platforms (like Mac M1) where + the Mach absolute time ticks do not correspond directly to + nanoseconds. Previously, we computed our shift value wrong, which + led us to give incorrect timing results. Fixes bug 40684; bugfix + on 0.3.3.1-alpha. + + o Major bugfixes (relay): + - Improve security of our DNS cache by randomly clipping the TTL + value. TROVE-2021-009. Fixes bug 40674; bugfix on 0.3.5.1-alpha. + + o Minor features (fallbackdir): + - Regenerate fallback directories generated on December 06, 2022. + + o Minor features (geoip data): + - Update the geoip files to match the IPFire Location Database, as + retrieved on 2022/12/06. + + Changes in version 0.4.7.11 - 2022-11-10 This version contains several major fixes aimed at helping defend against network denial of service. It is also extending drastically the MetricsPort @@ -327,6 +1941,32 @@ Fixes bug 40658; bugfix on 0.4.7.9. +Changes in version 0.4.6.12 - 2022-08-12 + This version updates the geoip cache that we generate from IPFire location + database to use the August 9th, 2022 one. Everyone MUST update to this + latest release else circuit path selection and relay metrics are badly + affected. + + o Major bugfixes (geoip data): + - IPFire informed us on August 12th that databases generated after + (including) August 10th did not have proper ARIN network allocations. We + are updating the database to use the one generated on August 9th, 2022. + Fixes bug 40658; bugfix on 0.4.6.11. + + +Changes in version 0.4.5.14 - 2022-08-12 + This version updates the geoip cache that we generate from IPFire location + database to use the August 9th, 2022 one. Everyone MUST update to this + latest release else circuit path selection and relay metrics are badly + affected. + + o Major bugfixes (geoip data): + - IPFire informed us on August 12th that databases generated after + (including) August 10th did not have proper ARIN network allocations. We + are updating the database to use the one generated on August 9th, 2022. + Fixes bug 40658; bugfix on 0.4.5.13. + + Changes in version 0.4.7.9 - 2022-08-11 This version contains several major fixes aimed at reducing memory pressure on relays and possible side-channel. It also contains a major bugfix related to @@ -398,6 +2038,143 @@ o Minor bugfixes (relay): - Do not propagate either forward or backward a DESTROY remote reason when + closing a circuit in order to avoid a possible side channel. Fixes bug + 40649; bugfix on 0.1.2.4-alpha. + + +Changes in version 0.4.6.11 - 2022-08-11 + This version contains two major fixes aimed at reducing memory pressure on + relays and possible side-channel. The rest of the fixes were backported for + stability or safety purposes. + + This is the very LAST version of this series. As of August 1st 2022, it is + end-of-life (EOL). We thus strongly recommend to upgrade to the latest + stable of the 0.4.7.x series. + + o Major bugfixes (relay): + - Remove OR connections btrack subsystem entries when the connections + close normally. Before this, we would only remove the entry on error and + thus leaking memory for each normal OR connections. Fixes bug 40604; + bugfix on 0.4.0.1-alpha. + - Stop sending TRUNCATED cell and instead close the circuit from which we + received a DESTROY cell. This makes every relay in the circuit path to + stop queuing cells. Fixes bug 40623; bugfix on 0.1.0.2-rc. + + o Minor features (fallbackdir): + - Regenerate fallback directories generated on August 11, 2022. + + o Minor features (geoip data): + - Update the geoip files to match the IPFire Location Database, as + retrieved on 2022/08/11. + + o Minor features (linux seccomp2 sandbox): + - Permit the clone3 syscall, which is apparently used in glibc-2.34 + and later. Closes ticket 40590. + + o Minor bugfixes (controller, path bias): + - When a circuit's path is specified, in full or in part, from the + controller API, do not count that circuit towards our path-bias + calculations. (Doing so was incorrect, since we cannot tell + whether the controller is selecting relays randomly.) Resolves a + "Bug" warning. Fixes bug 40515; bugfix on 0.2.4.10-alpha. + + o Minor bugfixes (defense in depth): + - Change a test in the netflow padding code to make it more + _obviously_ safe against remotely triggered crashes. (It was safe + against these before, but not obviously so.) Fixes bug 40645; + bugfix on 0.3.1.1-alpha. + + o Minor bugfixes (linux seccomp2 sandbox): + - Allow the rseq system call in the sandbox. This solves a crash + issue with glibc 2.35 on Linux. Patch from pmu-ipf. Fixes bug + 40601; bugfix on 0.3.5.11. + + o Minor bugfixes (metrics port, onion service): + - The MetricsPort line for an onion service with multiple ports are now + unique that is one line per port. Before this, all ports of an onion + service would be on the same line which violates the Prometheus rules of + unique labels. Fixes bug 40581; bugfix on 0.4.5.1-alpha. + + o Minor bugfixes (onion service, client): + - Fix a fatal assert due to a guard subsystem recursion triggered by + the onion service client. Fixes bug 40579; bugfix on 0.3.5.1-alpha. + + o Minor bugfixes (performance, DoS): + - Fix one case of a not-especially viable denial-of-service attack + found by OSS-Fuzz in our consensus-diff parsing code. This attack + causes a lot small of memory allocations and then immediately + frees them: this is only slow when running with all the sanitizers + enabled. Fixes one case of bug 40472; bugfix on 0.3.1.1-alpha. + + o Minor bugfixes (relay): + - Do not propagate either forward or backward a DESTROY remote reason when + closing a circuit in order to avoid a possible side channel. Fixes bug + 40649; bugfix on 0.1.2.4-alpha. + + +Changes in version 0.4.5.13 - 2022-08-11 + This version contains two major fixes aimed at reducing memory pressure on + relays and possible side-channel. The rest of the fixes were backported for + stability or safety purposes. We strongly recommend to upgrade your relay to + this version or, ideally, to the latest stable of the 0.4.7.x series. + + o Major bugfixes (relay): + - Remove OR connections btrack subsystem entries when the connections + close normally. Before this, we would only remove the entry on error and + thus leaking memory for each normal OR connections. Fixes bug 40604; + bugfix on 0.4.0.1-alpha. + - Stop sending TRUNCATED cell and instead close the circuit from which we + received a DESTROY cell. This makes every relay in the circuit path to + stop queuing cells. Fixes bug 40623; bugfix on 0.1.0.2-rc. + + o Minor features (fallbackdir): + - Regenerate fallback directories generated on August 11, 2022. + + o Minor features (geoip data): + - Update the geoip files to match the IPFire Location Database, as + retrieved on 2022/08/11. + + o Minor features (linux seccomp2 sandbox): + - Permit the clone3 syscall, which is apparently used in glibc-2.34 + and later. Closes ticket 40590. + + o Minor bugfixes (controller, path bias): + - When a circuit's path is specified, in full or in part, from the + controller API, do not count that circuit towards our path-bias + calculations. (Doing so was incorrect, since we cannot tell + whether the controller is selecting relays randomly.) Resolves a + "Bug" warning. Fixes bug 40515; bugfix on 0.2.4.10-alpha. + + o Minor bugfixes (defense in depth): + - Change a test in the netflow padding code to make it more + _obviously_ safe against remotely triggered crashes. (It was safe + against these before, but not obviously so.) Fixes bug 40645; + bugfix on 0.3.1.1-alpha. + + o Minor bugfixes (linux seccomp2 sandbox): + - Allow the rseq system call in the sandbox. This solves a crash + issue with glibc 2.35 on Linux. Patch from pmu-ipf. Fixes bug + 40601; bugfix on 0.3.5.11. + + o Minor bugfixes (metrics port, onion service): + - The MetricsPort line for an onion service with multiple ports are now + unique that is one line per port. Before this, all ports of an onion + service would be on the same line which violates the Prometheus rules of + unique labels. Fixes bug 40581; bugfix on 0.4.5.1-alpha. + + o Minor bugfixes (onion service, client): + - Fix a fatal assert due to a guard subsystem recursion triggered by + the onion service client. Fixes bug 40579; bugfix on 0.3.5.1-alpha. + + o Minor bugfixes (performance, DoS): + - Fix one case of a not-especially viable denial-of-service attack + found by OSS-Fuzz in our consensus-diff parsing code. This attack + causes a lot small of memory allocations and then immediately + frees them: this is only slow when running with all the sanitizers + enabled. Fixes one case of bug 40472; bugfix on 0.3.1.1-alpha. + + o Minor bugfixes (relay): + - Do not propagate either forward or backward a DESTROY remote reason when closing a circuit in order to avoid a possible side channel. Fixes bug 40649; bugfix on 0.1.2.4-alpha. diff -Nru tor-0.4.7.16/LICENSE tor-0.4.9.6/LICENSE --- tor-0.4.7.16/LICENSE 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/LICENSE 2026-03-25 14:30:34.000000000 +0000 @@ -383,6 +383,33 @@ or promote products derived from this Software. =============================================================================== +Parts of src/ext/polyval are based on Thomas Pornin's GHASH implementation in +BearSSL, and distributed under the following license: + + Copyright (c) 2016 Thomas Pornin + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + + +=============================================================================== If you got Tor as a static binary with OpenSSL included, then you should know: "This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit (http://www.openssl.org/)" diff -Nru tor-0.4.7.16/Makefile.am tor-0.4.9.6/Makefile.am --- tor-0.4.7.16/Makefile.am 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/Makefile.am 2026-03-25 14:30:34.000000000 +0000 @@ -50,12 +50,12 @@ src/lib/libtor-sandbox.a \ src/lib/libtor-container.a \ src/lib/libtor-net.a \ - src/lib/libtor-thread.a \ src/lib/libtor-memarea.a \ src/lib/libtor-math.a \ src/lib/libtor-meminfo.a \ src/lib/libtor-osinfo.a \ src/lib/libtor-log.a \ + src/lib/libtor-thread.a \ src/lib/libtor-lock.a \ src/lib/libtor-fdio.a \ src/lib/libtor-string.a \ @@ -86,13 +86,13 @@ src/lib/libtor-sandbox-testing.a \ src/lib/libtor-container-testing.a \ src/lib/libtor-net-testing.a \ - src/lib/libtor-thread-testing.a \ src/lib/libtor-memarea-testing.a \ src/lib/libtor-math-testing.a \ src/lib/libtor-meminfo-testing.a \ src/lib/libtor-osinfo-testing.a \ src/lib/libtor-term-testing.a \ src/lib/libtor-log-testing.a \ + src/lib/libtor-thread-testing.a \ src/lib/libtor-lock-testing.a \ src/lib/libtor-fdio-testing.a \ src/lib/libtor-string-testing.a \ @@ -112,7 +112,12 @@ src/lib/libtor-tls.a \ src/lib/libtor-crypt-ops.a \ $(LIBKECCAK_TINY) \ - $(LIBDONNA) + $(LIBDONNA) \ + $(LIBPOLYVAL) + +if BUILD_MODULE_POW +TOR_CRYPTO_LIBS += $(EQUIX_LIBS) +endif # Variants of the above for linking the testing variant of tor (for coverage # and tests) @@ -121,7 +126,9 @@ src/lib/libtor-tls-testing.a \ src/lib/libtor-crypt-ops-testing.a \ $(LIBKECCAK_TINY) \ - $(LIBDONNA) + $(LIBDONNA) \ + $(LIBPOLYVAL) \ + $(EQUIX_LIBS) endif # All static libraries used to link tor. @@ -185,7 +192,6 @@ CODE_OF_CONDUCT \ INSTALL \ LICENSE \ - Makefile.nmake \ README.md \ ReleaseNotes \ scripts/build/combine_libs \ @@ -376,10 +382,9 @@ # # Run the IPv4 tests in $(ipv4_flavors), unconditionally # - tor relays and directory authorities require IPv4. -# Run the IPv6 tests in $(ipv6_flavors), if IPv6 is available -# - 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 +# Run the IPv6 tests in $(ipv6_flavors), unconditionally +# - clients don't technically require IPv6, but it's not worth +# supporting running this test suite on such systems. # - some IPv6 tests may fail without an IPv6 DNS server # (see #16971 and #17011) # Run the mixed tests in $(mixed_flavors), if a tor-stable binary is available @@ -396,25 +401,9 @@ echo "Running IPv4 flavors: $(ipv4_flavors)."; \ flavors="$$flavors $(ipv4_flavors)"; \ fi; \ - test_network_ipv6=false; \ - if test -n "$(ipv6_flavors)" || \ - test -n "$(ipv6_mixed_flavors)"; then \ - if ping6 -q -c 1 -o ::1 >/dev/null 2>&1 || \ - ping6 -q -c 1 -W 1 ::1 >/dev/null 2>&1 || \ - ping -6 -c 1 -W 1 ::1 >/dev/null 2>&1; then \ - test_network_ipv6=true; \ - fi; \ - fi; \ if test -n "$(ipv6_flavors)"; then \ - if test "$$test_network_ipv6" = "true"; then \ - echo "ping6 ::1 or ping ::1 succeeded, running IPv6" \ - "flavors: $(ipv6_flavors)."; \ - flavors="$$flavors $(ipv6_flavors)"; \ - else \ - echo "ping6 ::1 and ping ::1 failed, skipping IPv6" \ - "flavors: $(ipv6_flavors)."; \ - skip_flavors="$$skip_flavors $(ipv6_flavors)"; \ - fi; \ + echo "Running IPv6 flavors: $(ipv6_flavors)."; \ + flavors="$$flavors $(ipv6_flavors)"; \ fi; \ test_network_mixed=false; \ if test -n "$(mixed_flavors)" || \ @@ -435,8 +424,7 @@ fi; \ fi; \ if test -n "$(ipv6_mixed_flavors)"; then \ - if test "$$test_network_ipv6" = "true" && \ - test "$$test_network_mixed" = "true"; then \ + if test "$$test_network_mixed" = "true"; then \ echo "Running IPv6 mixed flavors:" \ "$(ipv6_mixed_flavors)."; \ flavors="$$flavors $(ipv6_mixed_flavors)"; \ diff -Nru tor-0.4.7.16/Makefile.in tor-0.4.9.6/Makefile.in --- tor-0.4.7.16/Makefile.in 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/Makefile.in 2026-03-25 14:30:34.000000000 +0000 @@ -125,122 +125,125 @@ src/test/test-hs-ntor-cl$(EXEEXT) $(am__EXEEXT_4) \ $(am__EXEEXT_5) $(am__EXEEXT_6) $(am__EXEEXT_7) \ $(am__EXEEXT_8) -@UNITTESTS_ENABLED_TRUE@am__append_1 = src/test/libtor-testing.a -@USE_NSS_TRUE@am__append_2 = @NSS_CFLAGS@ -@USE_NSS_TRUE@am__append_3 = @NSS_LIBS@ -@BUILD_KECCAK_TINY_TRUE@am__append_4 = $(LIBKECCAK_TINY_HDRS) -@BUILD_KECCAK_TINY_TRUE@am__append_5 = $(LIBKECCAK_TINY) -@UNITTESTS_ENABLED_TRUE@am__append_6 = src/lib/libtor-buf-testing.a -@UNITTESTS_ENABLED_TRUE@am__append_7 = src/lib/libtor-err-testing.a -@UNITTESTS_ENABLED_TRUE@am__append_8 = src/lib/libtor-ctime-testing.a -@UNITTESTS_ENABLED_TRUE@am__append_9 = src/lib/libtor-compress-testing.a -@UNITTESTS_ENABLED_TRUE@am__append_10 = src/lib/libtor-confmgt-testing.a -@UNITTESTS_ENABLED_TRUE@am__append_11 = src/lib/libtor-container-testing.a -@UNITTESTS_ENABLED_TRUE@am__append_12 = src/lib/libtor-crypt-ops-testing.a -@USE_NSS_TRUE@am__append_13 = \ +@BUILD_MODULE_POW_TRUE@am__append_1 = $(EQUIX_LIBS) +@UNITTESTS_ENABLED_TRUE@am__append_2 = src/test/libtor-testing.a +@USE_NSS_TRUE@am__append_3 = @NSS_CFLAGS@ +@USE_NSS_TRUE@am__append_4 = @NSS_LIBS@ +@BUILD_KECCAK_TINY_TRUE@am__append_5 = $(LIBKECCAK_TINY_HDRS) +@BUILD_KECCAK_TINY_TRUE@am__append_6 = $(LIBKECCAK_TINY) +@UNITTESTS_ENABLED_TRUE@am__append_7 = src/lib/libtor-buf-testing.a +@UNITTESTS_ENABLED_TRUE@am__append_8 = src/lib/libtor-err-testing.a +@UNITTESTS_ENABLED_TRUE@am__append_9 = src/lib/libtor-ctime-testing.a +@UNITTESTS_ENABLED_TRUE@am__append_10 = src/lib/libtor-compress-testing.a +@UNITTESTS_ENABLED_TRUE@am__append_11 = src/lib/libtor-confmgt-testing.a +@UNITTESTS_ENABLED_TRUE@am__append_12 = src/lib/libtor-container-testing.a +@UNITTESTS_ENABLED_TRUE@am__append_13 = src/lib/libtor-crypt-ops-testing.a +@USE_NSS_TRUE@am__append_14 = \ @USE_NSS_TRUE@ src/lib/crypt_ops/aes_nss.c \ @USE_NSS_TRUE@ src/lib/crypt_ops/crypto_digest_nss.c \ @USE_NSS_TRUE@ src/lib/crypt_ops/crypto_dh_nss.c \ @USE_NSS_TRUE@ src/lib/crypt_ops/crypto_nss_mgt.c \ @USE_NSS_TRUE@ src/lib/crypt_ops/crypto_rsa_nss.c -@USE_NSS_FALSE@am__append_14 = \ +@USE_NSS_FALSE@am__append_15 = \ @USE_NSS_FALSE@ src/lib/crypt_ops/aes_openssl.c \ @USE_NSS_FALSE@ src/lib/crypt_ops/crypto_digest_openssl.c \ @USE_NSS_FALSE@ src/lib/crypt_ops/crypto_rsa_openssl.c -@USE_OPENSSL_TRUE@am__append_15 = \ +@USE_OPENSSL_TRUE@am__append_16 = \ @USE_OPENSSL_TRUE@ src/lib/crypt_ops/crypto_dh_openssl.c \ @USE_OPENSSL_TRUE@ src/lib/crypt_ops/crypto_openssl_mgt.c -@UNITTESTS_ENABLED_TRUE@am__append_16 = src/lib/libtor-dispatch-testing.a -@UNITTESTS_ENABLED_TRUE@am__append_17 = src/lib/libtor-encoding-testing.a -@UNITTESTS_ENABLED_TRUE@am__append_18 = src/lib/libtor-evloop-testing.a -@UNITTESTS_ENABLED_TRUE@am__append_19 = src/lib/libtor-fdio-testing.a -@UNITTESTS_ENABLED_TRUE@am__append_20 = src/lib/libtor-fs-testing.a -@WIN32_TRUE@am__append_21 = src/lib/fs/winlib.c -@UNITTESTS_ENABLED_TRUE@am__append_22 = src/lib/libtor-geoip-testing.a +@UNITTESTS_ENABLED_TRUE@am__append_17 = src/lib/libtor-dispatch-testing.a +@UNITTESTS_ENABLED_TRUE@am__append_18 = src/lib/libtor-encoding-testing.a +@UNITTESTS_ENABLED_TRUE@am__append_19 = src/lib/libtor-evloop-testing.a +@UNITTESTS_ENABLED_TRUE@am__append_20 = src/lib/libtor-fdio-testing.a +@UNITTESTS_ENABLED_TRUE@am__append_21 = src/lib/libtor-fs-testing.a +@WIN32_TRUE@am__append_22 = src/lib/fs/winlib.c +@UNITTESTS_ENABLED_TRUE@am__append_23 = src/lib/libtor-geoip-testing.a # See bug 13538 -- this code is known to have signed overflow issues. -@BUILD_CURVE25519_DONNA_TRUE@am__append_23 = \ +@BUILD_CURVE25519_DONNA_TRUE@am__append_24 = \ @BUILD_CURVE25519_DONNA_TRUE@ @F_OMIT_FRAME_POINTER@ @CFLAGS_CONSTTIME@ -@BUILD_CURVE25519_DONNA_TRUE@am__append_24 = src/lib/libcurve25519_donna.a -@BUILD_CURVE25519_DONNA_C64_TRUE@@BUILD_CURVE25519_DONNA_FALSE@am__append_25 = @CFLAGS_CONSTTIME@ -@BUILD_CURVE25519_DONNA_C64_TRUE@@BUILD_CURVE25519_DONNA_FALSE@am__append_26 = src/lib/libcurve25519_donna.a -@UNITTESTS_ENABLED_TRUE@am__append_27 = src/lib/libtor-intmath-testing.a -@UNITTESTS_ENABLED_TRUE@am__append_28 = src/lib/libtor-llharden-testing.a -@UNITTESTS_ENABLED_TRUE@am__append_29 = src/lib/libtor-lock-testing.a -@THREADS_PTHREADS_TRUE@am__append_30 = src/lib/lock/compat_mutex_pthreads.c -@THREADS_WIN32_TRUE@am__append_31 = src/lib/lock/compat_mutex_winthreads.c -@UNITTESTS_ENABLED_TRUE@am__append_32 = src/lib/libtor-log-testing.a -@WIN32_TRUE@am__append_33 = src/lib/log/win32err.c -@UNITTESTS_ENABLED_TRUE@am__append_34 = src/lib/libtor-malloc-testing.a -@USE_OPENBSD_MALLOC_TRUE@am__append_35 = src/ext/OpenBSD_malloc_Linux.c -@UNITTESTS_ENABLED_TRUE@am__append_36 = src/lib/libtor-math-testing.a -@UNITTESTS_ENABLED_TRUE@am__append_37 = src/lib/libtor-memarea-testing.a -@UNITTESTS_ENABLED_TRUE@am__append_38 = src/lib/libtor-meminfo-testing.a -@UNITTESTS_ENABLED_TRUE@am__append_39 = src/lib/libtor-metrics-testing.a -@UNITTESTS_ENABLED_TRUE@am__append_40 = src/lib/libtor-net-testing.a -@UNITTESTS_ENABLED_TRUE@am__append_41 = src/lib/libtor-osinfo-testing.a -@UNITTESTS_ENABLED_TRUE@am__append_42 = src/lib/libtor-process-testing.a -@UNITTESTS_ENABLED_TRUE@am__append_43 = src/lib/libtor-pubsub-testing.a -@UNITTESTS_ENABLED_TRUE@am__append_44 = src/lib/libtor-sandbox-testing.a -@UNITTESTS_ENABLED_TRUE@am__append_45 = src/lib/libtor-string-testing.a -@UNITTESTS_ENABLED_TRUE@am__append_46 = src/lib/libtor-smartlist-core-testing.a -@UNITTESTS_ENABLED_TRUE@am__append_47 = src/lib/libtor-term-testing.a -@UNITTESTS_ENABLED_TRUE@am__append_48 = src/lib/libtor-thread-testing.a -@UNITTESTS_ENABLED_TRUE@am__append_49 = src/lib/libtor-time-testing.a -@UNITTESTS_ENABLED_TRUE@am__append_50 = src/lib/libtor-tls-testing.a -@USE_NSS_TRUE@am__append_51 = \ +@BUILD_CURVE25519_DONNA_TRUE@am__append_25 = src/lib/libcurve25519_donna.a +@BUILD_CURVE25519_DONNA_C64_TRUE@@BUILD_CURVE25519_DONNA_FALSE@am__append_26 = @CFLAGS_CONSTTIME@ +@BUILD_CURVE25519_DONNA_C64_TRUE@@BUILD_CURVE25519_DONNA_FALSE@am__append_27 = src/lib/libcurve25519_donna.a +@UNITTESTS_ENABLED_TRUE@am__append_28 = src/lib/libtor-intmath-testing.a +@UNITTESTS_ENABLED_TRUE@am__append_29 = src/lib/libtor-llharden-testing.a +@UNITTESTS_ENABLED_TRUE@am__append_30 = src/lib/libtor-lock-testing.a +@THREADS_PTHREADS_TRUE@am__append_31 = src/lib/lock/compat_mutex_pthreads.c +@THREADS_WIN32_TRUE@am__append_32 = src/lib/lock/compat_mutex_winthreads.c +@UNITTESTS_ENABLED_TRUE@am__append_33 = src/lib/libtor-log-testing.a +@WIN32_TRUE@am__append_34 = src/lib/log/win32err.c +@UNITTESTS_ENABLED_TRUE@am__append_35 = src/lib/libtor-malloc-testing.a +@USE_OPENBSD_MALLOC_TRUE@am__append_36 = src/ext/OpenBSD_malloc_Linux.c +@UNITTESTS_ENABLED_TRUE@am__append_37 = src/lib/libtor-math-testing.a +@UNITTESTS_ENABLED_TRUE@am__append_38 = src/lib/libtor-memarea-testing.a +@UNITTESTS_ENABLED_TRUE@am__append_39 = src/lib/libtor-meminfo-testing.a +@UNITTESTS_ENABLED_TRUE@am__append_40 = src/lib/libtor-metrics-testing.a +@UNITTESTS_ENABLED_TRUE@am__append_41 = src/lib/libtor-net-testing.a +@UNITTESTS_ENABLED_TRUE@am__append_42 = src/lib/libtor-osinfo-testing.a +@UNITTESTS_ENABLED_TRUE@am__append_43 = src/lib/libtor-process-testing.a +@UNITTESTS_ENABLED_TRUE@am__append_44 = src/lib/libtor-pubsub-testing.a +@UNITTESTS_ENABLED_TRUE@am__append_45 = src/lib/libtor-sandbox-testing.a +@UNITTESTS_ENABLED_TRUE@am__append_46 = src/lib/libtor-string-testing.a +@UNITTESTS_ENABLED_TRUE@am__append_47 = src/lib/libtor-smartlist-core-testing.a +@UNITTESTS_ENABLED_TRUE@am__append_48 = src/lib/libtor-term-testing.a +@UNITTESTS_ENABLED_TRUE@am__append_49 = src/lib/libtor-thread-testing.a +@UNITTESTS_ENABLED_TRUE@am__append_50 = src/lib/libtor-time-testing.a +@UNITTESTS_ENABLED_TRUE@am__append_51 = src/lib/libtor-tls-testing.a +@USE_NSS_TRUE@am__append_52 = \ @USE_NSS_TRUE@ src/lib/tls/nss_countbytes.c \ @USE_NSS_TRUE@ src/lib/tls/tortls_nss.c \ @USE_NSS_TRUE@ src/lib/tls/x509_nss.c -@USE_NSS_FALSE@am__append_52 = \ +@USE_NSS_FALSE@am__append_53 = \ @USE_NSS_FALSE@ src/lib/tls/tortls_openssl.c \ @USE_NSS_FALSE@ src/lib/tls/x509_openssl.c -@USE_TRACING_INSTRUMENTATION_LOG_DEBUG_TRUE@am__append_53 = \ +@USE_TRACING_INSTRUMENTATION_LOG_DEBUG_TRUE@am__append_54 = \ @USE_TRACING_INSTRUMENTATION_LOG_DEBUG_TRUE@ src/lib/trace/debug.h # ADD_C_FILE: INSERT HEADERS HERE. -@USE_TRACING_INSTRUMENTATION_USDT_TRUE@am__append_54 = \ +@USE_TRACING_INSTRUMENTATION_USDT_TRUE@am__append_55 = \ @USE_TRACING_INSTRUMENTATION_USDT_TRUE@ src/lib/trace/usdt/usdt.h # ADD_C_FILE: INSERT HEADERS HERE. -@USE_TRACING_INSTRUMENTATION_LTTNG_TRUE@am__append_55 = \ +@USE_TRACING_INSTRUMENTATION_LTTNG_TRUE@am__append_56 = \ @USE_TRACING_INSTRUMENTATION_LTTNG_TRUE@ src/lib/trace/lttng/lttng.h -@UNITTESTS_ENABLED_TRUE@am__append_56 = src/lib/libtor-version-testing.a -@UNITTESTS_ENABLED_TRUE@am__append_57 = src/lib/libtor-wallclock-testing.a -@UNITTESTS_ENABLED_TRUE@am__append_58 = \ +@UNITTESTS_ENABLED_TRUE@am__append_57 = src/lib/libtor-version-testing.a +@UNITTESTS_ENABLED_TRUE@am__append_58 = src/lib/libtor-wallclock-testing.a +@UNITTESTS_ENABLED_TRUE@am__append_59 = \ @UNITTESTS_ENABLED_TRUE@ src/trunnel/libor-trunnel-testing.a -@UNITTESTS_ENABLED_TRUE@am__append_59 = src/core/libtor-app-testing.a -@USE_TRACING_INSTRUMENTATION_LTTNG_TRUE@am__append_60 = \ -@USE_TRACING_INSTRUMENTATION_LTTNG_TRUE@ src/core/or/trace_probes_cc.c \ +@UNITTESTS_ENABLED_TRUE@am__append_60 = src/core/libtor-app-testing.a +@USE_TRACING_INSTRUMENTATION_LTTNG_TRUE@am__append_61 = \ +@USE_TRACING_INSTRUMENTATION_LTTNG_TRUE@ src/core/or/trace_probes_cc.c \ @USE_TRACING_INSTRUMENTATION_LTTNG_TRUE@ src/core/or/trace_probes_circuit.c -@USE_TRACING_INSTRUMENTATION_LTTNG_TRUE@am__append_61 = \ -@USE_TRACING_INSTRUMENTATION_LTTNG_TRUE@ src/core/or/trace_probes_cc.h \ +@USE_TRACING_INSTRUMENTATION_LTTNG_TRUE@am__append_62 = \ +@USE_TRACING_INSTRUMENTATION_LTTNG_TRUE@ src/core/or/trace_probes_cc.h \ @USE_TRACING_INSTRUMENTATION_LTTNG_TRUE@ src/core/or/trace_probes_circuit.h -@BUILD_MODULE_DIRAUTH_TRUE@am__append_62 = $(MODULE_DIRAUTH_SOURCES) -@BUILD_MODULE_DIRAUTH_FALSE@am__append_63 = src/feature/dirauth/dirauth_stub.c -@BUILD_MODULE_DIRCACHE_TRUE@am__append_64 = $(MODULE_DIRCACHE_SOURCES) -@BUILD_MODULE_DIRCACHE_FALSE@am__append_65 = src/feature/dircache/dircache_stub.c -@BUILD_MODULE_RELAY_TRUE@am__append_66 = $(MODULE_RELAY_SOURCES) -@BUILD_MODULE_RELAY_FALSE@am__append_67 = src/feature/relay/relay_stub.c -@BUILD_NT_SERVICES_TRUE@am__append_68 = src/app/main/ntmain.c +@BUILD_MODULE_DIRAUTH_TRUE@am__append_63 = $(MODULE_DIRAUTH_SOURCES) +@BUILD_MODULE_DIRAUTH_FALSE@am__append_64 = src/feature/dirauth/dirauth_stub.c +@BUILD_MODULE_DIRCACHE_TRUE@am__append_65 = $(MODULE_DIRCACHE_SOURCES) +@BUILD_MODULE_DIRCACHE_FALSE@am__append_66 = src/feature/dircache/dircache_stub.c +@BUILD_MODULE_POW_TRUE@am__append_67 = $(MODULE_POW_SOURCES) +@BUILD_MODULE_RELAY_TRUE@am__append_68 = $(MODULE_RELAY_SOURCES) +@BUILD_MODULE_RELAY_FALSE@am__append_69 = src/feature/relay/relay_stub.c +@BUILD_NT_SERVICES_TRUE@am__append_70 = src/app/main/ntmain.c # Add the sources of the modules that are needed for tests to work here. -@UNITTESTS_ENABLED_TRUE@am__append_69 = $(MODULE_RELAY_SOURCES) \ +@UNITTESTS_ENABLED_TRUE@am__append_71 = $(MODULE_RELAY_SOURCES) \ @UNITTESTS_ENABLED_TRUE@ $(MODULE_DIRCACHE_SOURCES) \ -@UNITTESTS_ENABLED_TRUE@ $(MODULE_DIRAUTH_SOURCES) -@COVERAGE_ENABLED_TRUE@am__append_70 = src/app/tor-cov -@USEPYTHON_TRUE@am__append_71 = \ +@UNITTESTS_ENABLED_TRUE@ $(MODULE_DIRAUTH_SOURCES) \ +@UNITTESTS_ENABLED_TRUE@ $(MODULE_POW_SOURCES) +@COVERAGE_ENABLED_TRUE@am__append_72 = src/app/tor-cov +@USEPYTHON_TRUE@am__append_73 = \ @USEPYTHON_TRUE@ src/test/test_ntor.sh \ @USEPYTHON_TRUE@ src/test/test_hs_ntor.sh \ @USEPYTHON_TRUE@ src/test/test_bt.sh \ @@ -251,12 +254,12 @@ # ... # Only do this when coverage is not on, since it invokes lots of code # in a kind of unpredictable way. -@COVERAGE_ENABLED_FALSE@@USEPYTHON_TRUE@am__append_72 = src/test/test_rebind.sh \ +@COVERAGE_ENABLED_FALSE@@USEPYTHON_TRUE@am__append_74 = src/test/test_rebind.sh \ @COVERAGE_ENABLED_FALSE@@USEPYTHON_TRUE@ src/test/test_include.sh -@USE_PERL_TRUE@am__append_73 = \ -@USE_PERL_TRUE@ scripts/maint/checkSpaceTest.sh +@USE_PERL_TRUE@am__append_75 = \ +@USE_PERL_TRUE@ scripts/maint/checkSpaceTest.sh -@UNITTESTS_ENABLED_TRUE@am__append_74 = \ +@UNITTESTS_ENABLED_TRUE@am__append_76 = \ @UNITTESTS_ENABLED_TRUE@ src/test/test \ @UNITTESTS_ENABLED_TRUE@ src/test/test-slow \ @UNITTESTS_ENABLED_TRUE@ src/test/test-memwipe \ @@ -268,7 +271,7 @@ # ADD_C_FILE: INSERT SOURCES HERE. -@UNITTESTS_ENABLED_TRUE@am__append_75 = \ +@UNITTESTS_ENABLED_TRUE@am__append_77 = \ @UNITTESTS_ENABLED_TRUE@ src/test/fakecircs.c \ @UNITTESTS_ENABLED_TRUE@ src/test/log_test_helpers.c \ @UNITTESTS_ENABLED_TRUE@ src/test/hs_test_helpers.c \ @@ -299,8 +302,11 @@ @UNITTESTS_ENABLED_TRUE@ src/test/test_circuitstats.c \ @UNITTESTS_ENABLED_TRUE@ src/test/test_compat_libevent.c \ @UNITTESTS_ENABLED_TRUE@ src/test/test_config.c \ +@UNITTESTS_ENABLED_TRUE@ src/test/test_conflux_cell.c \ +@UNITTESTS_ENABLED_TRUE@ src/test/test_conflux_pool.c \ @UNITTESTS_ENABLED_TRUE@ src/test/test_confmgr.c \ @UNITTESTS_ENABLED_TRUE@ src/test/test_confparse.c \ +@UNITTESTS_ENABLED_TRUE@ src/test/test_congestion_control.c \ @UNITTESTS_ENABLED_TRUE@ src/test/test_connection.c \ @UNITTESTS_ENABLED_TRUE@ src/test/test_conscache.c \ @UNITTESTS_ENABLED_TRUE@ src/test/test_consdiff.c \ @@ -311,6 +317,7 @@ @UNITTESTS_ENABLED_TRUE@ src/test/test_crypto.c \ @UNITTESTS_ENABLED_TRUE@ src/test/test_crypto_ope.c \ @UNITTESTS_ENABLED_TRUE@ src/test/test_crypto_rng.c \ +@UNITTESTS_ENABLED_TRUE@ src/test/test_crypto_cgo.c \ @UNITTESTS_ENABLED_TRUE@ src/test/test_data.c \ @UNITTESTS_ENABLED_TRUE@ src/test/test_dir.c \ @UNITTESTS_ENABLED_TRUE@ src/test/test_dirauth_ports.c \ @@ -338,6 +345,7 @@ @UNITTESTS_ENABLED_TRUE@ src/test/test_hs_descriptor.c \ @UNITTESTS_ENABLED_TRUE@ src/test/test_hs_dos.c \ @UNITTESTS_ENABLED_TRUE@ src/test/test_hs_metrics.c \ +@UNITTESTS_ENABLED_TRUE@ src/test/test_hs_pow.c \ @UNITTESTS_ENABLED_TRUE@ src/test/test_keypin.c \ @UNITTESTS_ENABLED_TRUE@ src/test/test_link_handshake.c \ @UNITTESTS_ENABLED_TRUE@ src/test/test_logging.c \ @@ -401,15 +409,16 @@ # ... -@UNITTESTS_ENABLED_TRUE@@USE_NSS_FALSE@am__append_76 = \ +@UNITTESTS_ENABLED_TRUE@@USE_NSS_FALSE@am__append_78 = \ @UNITTESTS_ENABLED_TRUE@@USE_NSS_FALSE@ src/test/test_crypto_openssl.c \ @UNITTESTS_ENABLED_TRUE@@USE_NSS_FALSE@ src/test/test_tortls_openssl.c -@UNITTESTS_ENABLED_TRUE@am__append_77 = \ +@UNITTESTS_ENABLED_TRUE@am__append_79 = \ @UNITTESTS_ENABLED_TRUE@ src/test/rng_test_helpers.c \ @UNITTESTS_ENABLED_TRUE@ src/test/test_slow.c \ @UNITTESTS_ENABLED_TRUE@ src/test/test_crypto_slow.c \ @UNITTESTS_ENABLED_TRUE@ src/test/test_process_slow.c \ +@UNITTESTS_ENABLED_TRUE@ src/test/test_hs_pow_slow.c \ @UNITTESTS_ENABLED_TRUE@ src/test/test_prob_distr.c \ @UNITTESTS_ENABLED_TRUE@ src/test/ptr_helpers.c \ @UNITTESTS_ENABLED_TRUE@ src/test/test_ptr_slow.c \ @@ -417,19 +426,20 @@ @UNITTESTS_ENABLED_TRUE@ src/test/testing_rsakeys.c \ @UNITTESTS_ENABLED_TRUE@ src/ext/tinytest.c -@UNITTESTS_ENABLED_TRUE@am__append_78 = src/test/test-bt-cl -@COVERAGE_ENABLED_TRUE@am__append_79 = src/tools/tor-cov-resolve +@UNITTESTS_ENABLED_TRUE@am__append_80 = src/test/test-bt-cl +@COVERAGE_ENABLED_TRUE@am__append_81 = src/tools/tor-cov-resolve # ... -@USE_NSS_FALSE@am__append_80 = src/tools/tor-gencert +@USE_NSS_FALSE@am__append_82 = src/tools/tor-gencert # ... -@COVERAGE_ENABLED_TRUE@@USE_NSS_FALSE@am__append_81 = src/tools/tor-cov-gencert -@BUILD_LIBTORRUNNER_TRUE@am__append_82 = src/tools/libtorrunner.a -@LIBFUZZER_ENABLED_TRUE@am__append_83 = -fsanitize=fuzzer-no-link +@COVERAGE_ENABLED_TRUE@@USE_NSS_FALSE@am__append_83 = src/tools/tor-cov-gencert +@BUILD_LIBTORRUNNER_TRUE@am__append_84 = src/tools/libtorrunner.a +@LIBFUZZER_ENABLED_TRUE@am__append_85 = -fsanitize=fuzzer-no-link subdir = . ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 -am__aclocal_m4_deps = $(top_srcdir)/m4/ax_check_sign.m4 \ +am__aclocal_m4_deps = $(top_srcdir)/m4/ax_check_compile_flag.m4 \ + $(top_srcdir)/m4/ax_check_sign.m4 \ $(top_srcdir)/m4/ax_compiler_vendor.m4 \ $(top_srcdir)/m4/ax_compiler_version.m4 \ $(top_srcdir)/m4/pc_from_ucontext.m4 $(top_srcdir)/m4/pkg.m4 \ @@ -510,9 +520,11 @@ am__src_core_libtor_app_testing_a_SOURCES_DIST = \ src/core/crypto/hs_ntor.c src/core/crypto/onion_crypto.c \ src/core/crypto/onion_fast.c src/core/crypto/onion_ntor.c \ - src/core/crypto/onion_ntor_v3.c src/core/crypto/onion_tap.c \ - src/core/crypto/relay_crypto.c src/core/mainloop/connection.c \ - src/core/mainloop/cpuworker.c src/core/mainloop/mainloop.c \ + src/core/crypto/onion_ntor_v3.c src/core/crypto/relay_crypto.c \ + src/core/crypto/relay_crypto_cgo.c \ + src/core/crypto/relay_crypto_tor1.c \ + 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 \ @@ -530,13 +542,15 @@ 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 src/core/or/reasons.c \ - src/core/or/relay.c 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/congestion_control_common.c \ + src/core/or/relay.c src/core/or/relay_msg.c \ + 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/congestion_control_common.c \ src/core/or/congestion_control_vegas.c \ - src/core/or/congestion_control_nola.c \ - src/core/or/congestion_control_westwood.c \ - src/core/or/congestion_control_flow.c src/core/or/status.c \ + src/core/or/congestion_control_flow.c src/core/or/conflux.c \ + src/core/or/conflux_cell.c src/core/or/conflux_params.c \ + src/core/or/conflux_pool.c src/core/or/conflux_sys.c \ + src/core/or/conflux_util.c src/core/or/status.c \ src/core/or/versions.c src/core/or/trace_probes_cc.c \ src/core/or/trace_probes_circuit.c src/core/proto/proto_cell.c \ src/core/proto/proto_control0.c src/core/proto/proto_ext_or.c \ @@ -606,7 +620,8 @@ src/feature/hs/hs_metrics.c src/feature/hs/hs_ob.c \ src/feature/hs/hs_service.c src/feature/hs/hs_stats.c \ src/feature/hs/hs_sys.c src/feature/hs/hs_metrics_entry.c \ - src/feature/keymgt/loadkey.c src/feature/metrics/metrics.c \ + src/feature/hs/hs_pow.c src/feature/keymgt/loadkey.c \ + src/feature/metrics/metrics.c \ src/feature/metrics/metrics_sys.c \ src/feature/nodelist/authcert.c \ src/feature/nodelist/describe.c src/feature/nodelist/dirlist.c \ @@ -667,7 +682,10 @@ src/feature/dircache/core_libtor_app_testing_a-dircache.$(OBJEXT) \ src/feature/dircache/core_libtor_app_testing_a-dirserv.$(OBJEXT) @BUILD_MODULE_DIRCACHE_TRUE@am__objects_5 = $(am__objects_4) -am__objects_6 = src/feature/relay/core_libtor_app_testing_a-circuitbuild_relay.$(OBJEXT) \ +am__objects_6 = \ + src/feature/hs/core_libtor_app_testing_a-hs_pow.$(OBJEXT) +@BUILD_MODULE_POW_TRUE@am__objects_7 = $(am__objects_6) +am__objects_8 = src/feature/relay/core_libtor_app_testing_a-circuitbuild_relay.$(OBJEXT) \ src/feature/relay/core_libtor_app_testing_a-dns.$(OBJEXT) \ src/feature/relay/core_libtor_app_testing_a-ext_orport.$(OBJEXT) \ src/feature/relay/core_libtor_app_testing_a-routermode.$(OBJEXT) \ @@ -679,16 +697,17 @@ src/feature/relay/core_libtor_app_testing_a-routerkeys.$(OBJEXT) \ src/feature/relay/core_libtor_app_testing_a-selftest.$(OBJEXT) \ src/feature/relay/core_libtor_app_testing_a-transport_config.$(OBJEXT) -@BUILD_MODULE_RELAY_TRUE@am__objects_7 = $(am__objects_6) -@BUILD_NT_SERVICES_TRUE@am__objects_8 = src/app/main/core_libtor_app_testing_a-ntmain.$(OBJEXT) -am__objects_9 = \ +@BUILD_MODULE_RELAY_TRUE@am__objects_9 = $(am__objects_8) +@BUILD_NT_SERVICES_TRUE@am__objects_10 = src/app/main/core_libtor_app_testing_a-ntmain.$(OBJEXT) +am__objects_11 = \ src/core/crypto/libtor_app_testing_a-hs_ntor.$(OBJEXT) \ src/core/crypto/libtor_app_testing_a-onion_crypto.$(OBJEXT) \ src/core/crypto/libtor_app_testing_a-onion_fast.$(OBJEXT) \ src/core/crypto/libtor_app_testing_a-onion_ntor.$(OBJEXT) \ src/core/crypto/libtor_app_testing_a-onion_ntor_v3.$(OBJEXT) \ - src/core/crypto/libtor_app_testing_a-onion_tap.$(OBJEXT) \ src/core/crypto/libtor_app_testing_a-relay_crypto.$(OBJEXT) \ + src/core/crypto/libtor_app_testing_a-relay_crypto_cgo.$(OBJEXT) \ + src/core/crypto/libtor_app_testing_a-relay_crypto_tor1.$(OBJEXT) \ src/core/mainloop/libtor_app_testing_a-connection.$(OBJEXT) \ src/core/mainloop/libtor_app_testing_a-cpuworker.$(OBJEXT) \ src/core/mainloop/libtor_app_testing_a-mainloop.$(OBJEXT) \ @@ -725,15 +744,20 @@ src/core/or/libtor_app_testing_a-protover.$(OBJEXT) \ src/core/or/libtor_app_testing_a-reasons.$(OBJEXT) \ src/core/or/libtor_app_testing_a-relay.$(OBJEXT) \ + src/core/or/libtor_app_testing_a-relay_msg.$(OBJEXT) \ src/core/or/libtor_app_testing_a-scheduler.$(OBJEXT) \ src/core/or/libtor_app_testing_a-scheduler_kist.$(OBJEXT) \ src/core/or/libtor_app_testing_a-scheduler_vanilla.$(OBJEXT) \ src/core/or/libtor_app_testing_a-sendme.$(OBJEXT) \ src/core/or/libtor_app_testing_a-congestion_control_common.$(OBJEXT) \ src/core/or/libtor_app_testing_a-congestion_control_vegas.$(OBJEXT) \ - src/core/or/libtor_app_testing_a-congestion_control_nola.$(OBJEXT) \ - src/core/or/libtor_app_testing_a-congestion_control_westwood.$(OBJEXT) \ src/core/or/libtor_app_testing_a-congestion_control_flow.$(OBJEXT) \ + src/core/or/libtor_app_testing_a-conflux.$(OBJEXT) \ + src/core/or/libtor_app_testing_a-conflux_cell.$(OBJEXT) \ + src/core/or/libtor_app_testing_a-conflux_params.$(OBJEXT) \ + src/core/or/libtor_app_testing_a-conflux_pool.$(OBJEXT) \ + src/core/or/libtor_app_testing_a-conflux_sys.$(OBJEXT) \ + src/core/or/libtor_app_testing_a-conflux_util.$(OBJEXT) \ src/core/or/libtor_app_testing_a-status.$(OBJEXT) \ src/core/or/libtor_app_testing_a-versions.$(OBJEXT) \ $(am__objects_1) \ @@ -803,6 +827,7 @@ src/feature/hs/core_libtor_app_testing_a-hs_stats.$(OBJEXT) \ src/feature/hs/core_libtor_app_testing_a-hs_sys.$(OBJEXT) \ src/feature/hs/core_libtor_app_testing_a-hs_metrics_entry.$(OBJEXT) \ + $(am__objects_7) \ src/feature/keymgt/core_libtor_app_testing_a-loadkey.$(OBJEXT) \ src/feature/metrics/core_libtor_app_testing_a-metrics.$(OBJEXT) \ src/feature/metrics/core_libtor_app_testing_a-metrics_sys.$(OBJEXT) \ @@ -823,7 +848,7 @@ src/feature/relay/core_libtor_app_testing_a-onion_queue.$(OBJEXT) \ src/feature/relay/core_libtor_app_testing_a-relay_find_addr.$(OBJEXT) \ src/feature/relay/core_libtor_app_testing_a-router.$(OBJEXT) \ - $(am__objects_7) \ + $(am__objects_9) \ src/feature/rend/core_libtor_app_testing_a-rendcommon.$(OBJEXT) \ src/feature/rend/core_libtor_app_testing_a-rendmid.$(OBJEXT) \ src/feature/stats/core_libtor_app_testing_a-bwhist.$(OBJEXT) \ @@ -840,12 +865,13 @@ src/app/main/core_libtor_app_testing_a-shutdown.$(OBJEXT) \ src/app/main/core_libtor_app_testing_a-subsystem_list.$(OBJEXT) \ src/app/main/core_libtor_app_testing_a-subsysmgr.$(OBJEXT) \ - $(am__objects_8) -@UNITTESTS_ENABLED_TRUE@am__objects_10 = $(am__objects_6) \ -@UNITTESTS_ENABLED_TRUE@ $(am__objects_4) $(am__objects_2) -am__objects_11 = $(am__objects_9) $(am__objects_10) + $(am__objects_10) +@UNITTESTS_ENABLED_TRUE@am__objects_12 = $(am__objects_8) \ +@UNITTESTS_ENABLED_TRUE@ $(am__objects_4) $(am__objects_2) \ +@UNITTESTS_ENABLED_TRUE@ $(am__objects_6) +am__objects_13 = $(am__objects_11) $(am__objects_12) @UNITTESTS_ENABLED_TRUE@am_src_core_libtor_app_testing_a_OBJECTS = \ -@UNITTESTS_ENABLED_TRUE@ $(am__objects_11) +@UNITTESTS_ENABLED_TRUE@ $(am__objects_13) src_core_libtor_app_testing_a_OBJECTS = \ $(am_src_core_libtor_app_testing_a_OBJECTS) src_core_libtor_app_a_AR = $(AR) $(ARFLAGS) @@ -853,7 +879,9 @@ am__src_core_libtor_app_a_SOURCES_DIST = src/core/crypto/hs_ntor.c \ src/core/crypto/onion_crypto.c src/core/crypto/onion_fast.c \ src/core/crypto/onion_ntor.c src/core/crypto/onion_ntor_v3.c \ - src/core/crypto/onion_tap.c src/core/crypto/relay_crypto.c \ + src/core/crypto/relay_crypto.c \ + src/core/crypto/relay_crypto_cgo.c \ + src/core/crypto/relay_crypto_tor1.c \ src/core/mainloop/connection.c src/core/mainloop/cpuworker.c \ src/core/mainloop/mainloop.c \ src/core/mainloop/mainloop_pubsub.c \ @@ -873,13 +901,15 @@ 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 src/core/or/reasons.c \ - src/core/or/relay.c 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/congestion_control_common.c \ + src/core/or/relay.c src/core/or/relay_msg.c \ + 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/congestion_control_common.c \ src/core/or/congestion_control_vegas.c \ - src/core/or/congestion_control_nola.c \ - src/core/or/congestion_control_westwood.c \ - src/core/or/congestion_control_flow.c src/core/or/status.c \ + src/core/or/congestion_control_flow.c src/core/or/conflux.c \ + src/core/or/conflux_cell.c src/core/or/conflux_params.c \ + src/core/or/conflux_pool.c src/core/or/conflux_sys.c \ + src/core/or/conflux_util.c src/core/or/status.c \ src/core/or/versions.c src/core/or/trace_probes_cc.c \ src/core/or/trace_probes_circuit.c src/core/proto/proto_cell.c \ src/core/proto/proto_control0.c src/core/proto/proto_ext_or.c \ @@ -949,7 +979,8 @@ src/feature/hs/hs_metrics.c src/feature/hs/hs_ob.c \ src/feature/hs/hs_service.c src/feature/hs/hs_stats.c \ src/feature/hs/hs_sys.c src/feature/hs/hs_metrics_entry.c \ - src/feature/keymgt/loadkey.c src/feature/metrics/metrics.c \ + src/feature/hs/hs_pow.c src/feature/keymgt/loadkey.c \ + src/feature/metrics/metrics.c \ src/feature/metrics/metrics_sys.c \ src/feature/nodelist/authcert.c \ src/feature/nodelist/describe.c src/feature/nodelist/dirlist.c \ @@ -985,9 +1016,9 @@ src/app/main/ntmain.c src/feature/dirauth/dirauth_stub.c \ src/feature/dircache/dircache_stub.c \ src/feature/relay/relay_stub.c -@USE_TRACING_INSTRUMENTATION_LTTNG_TRUE@am__objects_12 = src/core/or/trace_probes_cc.$(OBJEXT) \ +@USE_TRACING_INSTRUMENTATION_LTTNG_TRUE@am__objects_14 = src/core/or/trace_probes_cc.$(OBJEXT) \ @USE_TRACING_INSTRUMENTATION_LTTNG_TRUE@ src/core/or/trace_probes_circuit.$(OBJEXT) -am__objects_13 = src/feature/dirauth/authmode.$(OBJEXT) \ +am__objects_15 = src/feature/dirauth/authmode.$(OBJEXT) \ src/feature/dirauth/bridgeauth.$(OBJEXT) \ src/feature/dirauth/bwauth.$(OBJEXT) \ src/feature/dirauth/dirauth_config.$(OBJEXT) \ @@ -1005,13 +1036,15 @@ src/feature/dirauth/shared_random_state.$(OBJEXT) \ src/feature/dirauth/voteflags.$(OBJEXT) \ src/feature/dirauth/voting_schedule.$(OBJEXT) -@BUILD_MODULE_DIRAUTH_TRUE@am__objects_14 = $(am__objects_13) -am__objects_15 = src/feature/dircache/conscache.$(OBJEXT) \ +@BUILD_MODULE_DIRAUTH_TRUE@am__objects_16 = $(am__objects_15) +am__objects_17 = src/feature/dircache/conscache.$(OBJEXT) \ src/feature/dircache/consdiffmgr.$(OBJEXT) \ src/feature/dircache/dircache.$(OBJEXT) \ src/feature/dircache/dirserv.$(OBJEXT) -@BUILD_MODULE_DIRCACHE_TRUE@am__objects_16 = $(am__objects_15) -am__objects_17 = src/feature/relay/circuitbuild_relay.$(OBJEXT) \ +@BUILD_MODULE_DIRCACHE_TRUE@am__objects_18 = $(am__objects_17) +am__objects_19 = src/feature/hs/hs_pow.$(OBJEXT) +@BUILD_MODULE_POW_TRUE@am__objects_20 = $(am__objects_19) +am__objects_21 = src/feature/relay/circuitbuild_relay.$(OBJEXT) \ src/feature/relay/dns.$(OBJEXT) \ src/feature/relay/ext_orport.$(OBJEXT) \ src/feature/relay/routermode.$(OBJEXT) \ @@ -1023,16 +1056,17 @@ src/feature/relay/routerkeys.$(OBJEXT) \ src/feature/relay/selftest.$(OBJEXT) \ src/feature/relay/transport_config.$(OBJEXT) -@BUILD_MODULE_RELAY_TRUE@am__objects_18 = $(am__objects_17) -@BUILD_NT_SERVICES_TRUE@am__objects_19 = \ +@BUILD_MODULE_RELAY_TRUE@am__objects_22 = $(am__objects_21) +@BUILD_NT_SERVICES_TRUE@am__objects_23 = \ @BUILD_NT_SERVICES_TRUE@ src/app/main/ntmain.$(OBJEXT) -am__objects_20 = src/core/crypto/hs_ntor.$(OBJEXT) \ +am__objects_24 = src/core/crypto/hs_ntor.$(OBJEXT) \ src/core/crypto/onion_crypto.$(OBJEXT) \ src/core/crypto/onion_fast.$(OBJEXT) \ src/core/crypto/onion_ntor.$(OBJEXT) \ src/core/crypto/onion_ntor_v3.$(OBJEXT) \ - src/core/crypto/onion_tap.$(OBJEXT) \ src/core/crypto/relay_crypto.$(OBJEXT) \ + src/core/crypto/relay_crypto_cgo.$(OBJEXT) \ + src/core/crypto/relay_crypto_tor1.$(OBJEXT) \ src/core/mainloop/connection.$(OBJEXT) \ src/core/mainloop/cpuworker.$(OBJEXT) \ src/core/mainloop/mainloop.$(OBJEXT) \ @@ -1062,17 +1096,22 @@ src/core/or/orconn_event.$(OBJEXT) \ src/core/or/policies.$(OBJEXT) src/core/or/protover.$(OBJEXT) \ src/core/or/reasons.$(OBJEXT) src/core/or/relay.$(OBJEXT) \ + src/core/or/relay_msg.$(OBJEXT) \ src/core/or/scheduler.$(OBJEXT) \ src/core/or/scheduler_kist.$(OBJEXT) \ src/core/or/scheduler_vanilla.$(OBJEXT) \ src/core/or/sendme.$(OBJEXT) \ src/core/or/congestion_control_common.$(OBJEXT) \ src/core/or/congestion_control_vegas.$(OBJEXT) \ - src/core/or/congestion_control_nola.$(OBJEXT) \ - src/core/or/congestion_control_westwood.$(OBJEXT) \ src/core/or/congestion_control_flow.$(OBJEXT) \ + src/core/or/conflux.$(OBJEXT) \ + src/core/or/conflux_cell.$(OBJEXT) \ + src/core/or/conflux_params.$(OBJEXT) \ + src/core/or/conflux_pool.$(OBJEXT) \ + src/core/or/conflux_sys.$(OBJEXT) \ + src/core/or/conflux_util.$(OBJEXT) \ src/core/or/status.$(OBJEXT) src/core/or/versions.$(OBJEXT) \ - $(am__objects_12) src/core/proto/proto_cell.$(OBJEXT) \ + $(am__objects_14) src/core/proto/proto_cell.$(OBJEXT) \ src/core/proto/proto_control0.$(OBJEXT) \ src/core/proto/proto_ext_or.$(OBJEXT) \ src/core/proto/proto_haproxy.$(OBJEXT) \ @@ -1100,8 +1139,8 @@ src/feature/control/control_fmt.$(OBJEXT) \ src/feature/control/control_getinfo.$(OBJEXT) \ src/feature/control/control_proto.$(OBJEXT) \ - src/feature/control/getinfo_geoip.$(OBJEXT) $(am__objects_14) \ - $(am__objects_16) src/feature/dirclient/dirclient.$(OBJEXT) \ + src/feature/control/getinfo_geoip.$(OBJEXT) $(am__objects_16) \ + $(am__objects_18) src/feature/dirclient/dirclient.$(OBJEXT) \ src/feature/dirclient/dirclient_modes.$(OBJEXT) \ src/feature/dirclient/dlstatus.$(OBJEXT) \ src/feature/dircommon/consdiff.$(OBJEXT) \ @@ -1136,7 +1175,7 @@ src/feature/hs/hs_service.$(OBJEXT) \ src/feature/hs/hs_stats.$(OBJEXT) \ src/feature/hs/hs_sys.$(OBJEXT) \ - src/feature/hs/hs_metrics_entry.$(OBJEXT) \ + src/feature/hs/hs_metrics_entry.$(OBJEXT) $(am__objects_20) \ src/feature/keymgt/loadkey.$(OBJEXT) \ src/feature/metrics/metrics.$(OBJEXT) \ src/feature/metrics/metrics_sys.$(OBJEXT) \ @@ -1156,7 +1195,7 @@ src/feature/nodelist/torcert.$(OBJEXT) \ src/feature/relay/onion_queue.$(OBJEXT) \ src/feature/relay/relay_find_addr.$(OBJEXT) \ - src/feature/relay/router.$(OBJEXT) $(am__objects_18) \ + src/feature/relay/router.$(OBJEXT) $(am__objects_22) \ src/feature/rend/rendcommon.$(OBJEXT) \ src/feature/rend/rendmid.$(OBJEXT) \ src/feature/stats/bwhist.$(OBJEXT) \ @@ -1171,12 +1210,12 @@ src/app/main/risky_options.$(OBJEXT) \ src/app/main/shutdown.$(OBJEXT) \ src/app/main/subsystem_list.$(OBJEXT) \ - src/app/main/subsysmgr.$(OBJEXT) $(am__objects_19) -@BUILD_MODULE_DIRAUTH_FALSE@am__objects_21 = src/feature/dirauth/dirauth_stub.$(OBJEXT) -@BUILD_MODULE_DIRCACHE_FALSE@am__objects_22 = src/feature/dircache/dircache_stub.$(OBJEXT) -@BUILD_MODULE_RELAY_FALSE@am__objects_23 = src/feature/relay/relay_stub.$(OBJEXT) -am__objects_24 = $(am__objects_21) $(am__objects_22) $(am__objects_23) -am_src_core_libtor_app_a_OBJECTS = $(am__objects_20) $(am__objects_24) + src/app/main/subsysmgr.$(OBJEXT) $(am__objects_23) +@BUILD_MODULE_DIRAUTH_FALSE@am__objects_25 = src/feature/dirauth/dirauth_stub.$(OBJEXT) +@BUILD_MODULE_DIRCACHE_FALSE@am__objects_26 = src/feature/dircache/dircache_stub.$(OBJEXT) +@BUILD_MODULE_RELAY_FALSE@am__objects_27 = src/feature/relay/relay_stub.$(OBJEXT) +am__objects_28 = $(am__objects_25) $(am__objects_26) $(am__objects_27) +am_src_core_libtor_app_a_OBJECTS = $(am__objects_24) $(am__objects_28) src_core_libtor_app_a_OBJECTS = $(am_src_core_libtor_app_a_OBJECTS) src_ext_ed25519_donna_libed25519_donna_a_AR = $(AR) $(ARFLAGS) src_ext_ed25519_donna_libed25519_donna_a_LIBADD = @@ -1229,6 +1268,30 @@ src/ext/ed25519/ref10/libed25519_ref10_a-blinding.$(OBJEXT) src_ext_ed25519_ref10_libed25519_ref10_a_OBJECTS = \ $(am_src_ext_ed25519_ref10_libed25519_ref10_a_OBJECTS) +src_ext_equix_libequix_a_AR = $(AR) $(ARFLAGS) +src_ext_equix_libequix_a_LIBADD = +am_src_ext_equix_libequix_a_OBJECTS = \ + src/ext/equix/src/libequix_a-context.$(OBJEXT) \ + src/ext/equix/src/libequix_a-equix.$(OBJEXT) \ + src/ext/equix/src/libequix_a-solver.$(OBJEXT) +src_ext_equix_libequix_a_OBJECTS = \ + $(am_src_ext_equix_libequix_a_OBJECTS) +src_ext_equix_libhashx_a_AR = $(AR) $(ARFLAGS) +src_ext_equix_libhashx_a_LIBADD = +am_src_ext_equix_libhashx_a_OBJECTS = \ + src/ext/equix/hashx/src/libhashx_a-blake2.$(OBJEXT) \ + src/ext/equix/hashx/src/libhashx_a-compiler.$(OBJEXT) \ + src/ext/equix/hashx/src/libhashx_a-compiler_a64.$(OBJEXT) \ + src/ext/equix/hashx/src/libhashx_a-compiler_x86.$(OBJEXT) \ + src/ext/equix/hashx/src/libhashx_a-context.$(OBJEXT) \ + src/ext/equix/hashx/src/libhashx_a-hashx.$(OBJEXT) \ + src/ext/equix/hashx/src/libhashx_a-program.$(OBJEXT) \ + src/ext/equix/hashx/src/libhashx_a-program_exec.$(OBJEXT) \ + src/ext/equix/hashx/src/libhashx_a-siphash.$(OBJEXT) \ + src/ext/equix/hashx/src/libhashx_a-siphash_rng.$(OBJEXT) \ + src/ext/equix/hashx/src/libhashx_a-virtual_memory.$(OBJEXT) +src_ext_equix_libhashx_a_OBJECTS = \ + $(am_src_ext_equix_libhashx_a_OBJECTS) src_ext_keccak_tiny_libkeccak_tiny_a_AR = $(AR) $(ARFLAGS) src_ext_keccak_tiny_libkeccak_tiny_a_LIBADD = am__src_ext_keccak_tiny_libkeccak_tiny_a_SOURCES_DIST = \ @@ -1236,6 +1299,12 @@ @BUILD_KECCAK_TINY_TRUE@am_src_ext_keccak_tiny_libkeccak_tiny_a_OBJECTS = src/ext/keccak-tiny/libkeccak_tiny_a-keccak-tiny-unrolled.$(OBJEXT) src_ext_keccak_tiny_libkeccak_tiny_a_OBJECTS = \ $(am_src_ext_keccak_tiny_libkeccak_tiny_a_OBJECTS) +src_ext_polyval_libpolyval_a_AR = $(AR) $(ARFLAGS) +src_ext_polyval_libpolyval_a_LIBADD = +am_src_ext_polyval_libpolyval_a_OBJECTS = \ + src/ext/polyval/libpolyval_a-polyval.$(OBJEXT) +src_ext_polyval_libpolyval_a_OBJECTS = \ + $(am_src_ext_polyval_libpolyval_a_OBJECTS) src_lib_libcurve25519_donna_a_AR = $(AR) $(ARFLAGS) src_lib_libcurve25519_donna_a_LIBADD = am__src_lib_libcurve25519_donna_a_SOURCES_DIST = \ @@ -1247,8 +1316,8 @@ $(am_src_lib_libcurve25519_donna_a_OBJECTS) src_lib_libtor_buf_testing_a_AR = $(AR) $(ARFLAGS) src_lib_libtor_buf_testing_a_LIBADD = -am__objects_25 = src/lib/buf/libtor_buf_testing_a-buffers.$(OBJEXT) -am_src_lib_libtor_buf_testing_a_OBJECTS = $(am__objects_25) +am__objects_29 = src/lib/buf/libtor_buf_testing_a-buffers.$(OBJEXT) +am_src_lib_libtor_buf_testing_a_OBJECTS = $(am__objects_29) src_lib_libtor_buf_testing_a_OBJECTS = \ $(am_src_lib_libtor_buf_testing_a_OBJECTS) src_lib_libtor_buf_a_AR = $(AR) $(ARFLAGS) @@ -1257,14 +1326,14 @@ src_lib_libtor_buf_a_OBJECTS = $(am_src_lib_libtor_buf_a_OBJECTS) src_lib_libtor_compress_testing_a_AR = $(AR) $(ARFLAGS) src_lib_libtor_compress_testing_a_LIBADD = -am__objects_26 = \ +am__objects_30 = \ src/lib/compress/libtor_compress_testing_a-compress.$(OBJEXT) \ src/lib/compress/libtor_compress_testing_a-compress_buf.$(OBJEXT) \ src/lib/compress/libtor_compress_testing_a-compress_lzma.$(OBJEXT) \ src/lib/compress/libtor_compress_testing_a-compress_none.$(OBJEXT) \ src/lib/compress/libtor_compress_testing_a-compress_zlib.$(OBJEXT) \ src/lib/compress/libtor_compress_testing_a-compress_zstd.$(OBJEXT) -am_src_lib_libtor_compress_testing_a_OBJECTS = $(am__objects_26) +am_src_lib_libtor_compress_testing_a_OBJECTS = $(am__objects_30) src_lib_libtor_compress_testing_a_OBJECTS = \ $(am_src_lib_libtor_compress_testing_a_OBJECTS) src_lib_libtor_compress_a_AR = $(AR) $(ARFLAGS) @@ -1280,13 +1349,13 @@ $(am_src_lib_libtor_compress_a_OBJECTS) src_lib_libtor_confmgt_testing_a_AR = $(AR) $(ARFLAGS) src_lib_libtor_confmgt_testing_a_LIBADD = -am__objects_27 = \ +am__objects_31 = \ src/lib/confmgt/libtor_confmgt_testing_a-confmgt.$(OBJEXT) \ src/lib/confmgt/libtor_confmgt_testing_a-structvar.$(OBJEXT) \ src/lib/confmgt/libtor_confmgt_testing_a-type_defs.$(OBJEXT) \ src/lib/confmgt/libtor_confmgt_testing_a-typedvar.$(OBJEXT) \ src/lib/confmgt/libtor_confmgt_testing_a-unitparse.$(OBJEXT) -am_src_lib_libtor_confmgt_testing_a_OBJECTS = $(am__objects_27) +am_src_lib_libtor_confmgt_testing_a_OBJECTS = $(am__objects_31) src_lib_libtor_confmgt_testing_a_OBJECTS = \ $(am_src_lib_libtor_confmgt_testing_a_OBJECTS) src_lib_libtor_confmgt_a_AR = $(AR) $(ARFLAGS) @@ -1301,12 +1370,12 @@ $(am_src_lib_libtor_confmgt_a_OBJECTS) src_lib_libtor_container_testing_a_AR = $(AR) $(ARFLAGS) src_lib_libtor_container_testing_a_LIBADD = -am__objects_28 = src/lib/container/libtor_container_testing_a-bloomfilt.$(OBJEXT) \ +am__objects_32 = src/lib/container/libtor_container_testing_a-bloomfilt.$(OBJEXT) \ src/lib/container/libtor_container_testing_a-map.$(OBJEXT) \ src/lib/container/libtor_container_testing_a-namemap.$(OBJEXT) \ src/lib/container/libtor_container_testing_a-order.$(OBJEXT) \ src/lib/container/libtor_container_testing_a-smartlist.$(OBJEXT) -am_src_lib_libtor_container_testing_a_OBJECTS = $(am__objects_28) +am_src_lib_libtor_container_testing_a_OBJECTS = $(am__objects_32) src_lib_libtor_container_testing_a_OBJECTS = \ $(am_src_lib_libtor_container_testing_a_OBJECTS) src_lib_libtor_container_a_AR = $(AR) $(ARFLAGS) @@ -1346,17 +1415,17 @@ src/lib/crypt_ops/crypto_rsa_openssl.c \ src/lib/crypt_ops/crypto_dh_openssl.c \ src/lib/crypt_ops/crypto_openssl_mgt.c -@USE_NSS_TRUE@am__objects_29 = src/lib/crypt_ops/libtor_crypt_ops_testing_a-aes_nss.$(OBJEXT) \ +@USE_NSS_TRUE@am__objects_33 = src/lib/crypt_ops/libtor_crypt_ops_testing_a-aes_nss.$(OBJEXT) \ @USE_NSS_TRUE@ src/lib/crypt_ops/libtor_crypt_ops_testing_a-crypto_digest_nss.$(OBJEXT) \ @USE_NSS_TRUE@ src/lib/crypt_ops/libtor_crypt_ops_testing_a-crypto_dh_nss.$(OBJEXT) \ @USE_NSS_TRUE@ src/lib/crypt_ops/libtor_crypt_ops_testing_a-crypto_nss_mgt.$(OBJEXT) \ @USE_NSS_TRUE@ src/lib/crypt_ops/libtor_crypt_ops_testing_a-crypto_rsa_nss.$(OBJEXT) -@USE_NSS_FALSE@am__objects_30 = src/lib/crypt_ops/libtor_crypt_ops_testing_a-aes_openssl.$(OBJEXT) \ +@USE_NSS_FALSE@am__objects_34 = src/lib/crypt_ops/libtor_crypt_ops_testing_a-aes_openssl.$(OBJEXT) \ @USE_NSS_FALSE@ src/lib/crypt_ops/libtor_crypt_ops_testing_a-crypto_digest_openssl.$(OBJEXT) \ @USE_NSS_FALSE@ src/lib/crypt_ops/libtor_crypt_ops_testing_a-crypto_rsa_openssl.$(OBJEXT) -@USE_OPENSSL_TRUE@am__objects_31 = src/lib/crypt_ops/libtor_crypt_ops_testing_a-crypto_dh_openssl.$(OBJEXT) \ +@USE_OPENSSL_TRUE@am__objects_35 = src/lib/crypt_ops/libtor_crypt_ops_testing_a-crypto_dh_openssl.$(OBJEXT) \ @USE_OPENSSL_TRUE@ src/lib/crypt_ops/libtor_crypt_ops_testing_a-crypto_openssl_mgt.$(OBJEXT) -am__objects_32 = src/lib/crypt_ops/libtor_crypt_ops_testing_a-crypto_cipher.$(OBJEXT) \ +am__objects_36 = src/lib/crypt_ops/libtor_crypt_ops_testing_a-crypto_cipher.$(OBJEXT) \ src/lib/crypt_ops/libtor_crypt_ops_testing_a-crypto_curve25519.$(OBJEXT) \ src/lib/crypt_ops/libtor_crypt_ops_testing_a-crypto_dh.$(OBJEXT) \ src/lib/crypt_ops/libtor_crypt_ops_testing_a-crypto_digest.$(OBJEXT) \ @@ -1373,8 +1442,8 @@ src/lib/crypt_ops/libtor_crypt_ops_testing_a-crypto_s2k.$(OBJEXT) \ src/lib/crypt_ops/libtor_crypt_ops_testing_a-crypto_util.$(OBJEXT) \ src/lib/crypt_ops/libtor_crypt_ops_testing_a-digestset.$(OBJEXT) \ - $(am__objects_29) $(am__objects_30) $(am__objects_31) -am_src_lib_libtor_crypt_ops_testing_a_OBJECTS = $(am__objects_32) + $(am__objects_33) $(am__objects_34) $(am__objects_35) +am_src_lib_libtor_crypt_ops_testing_a_OBJECTS = $(am__objects_36) src_lib_libtor_crypt_ops_testing_a_OBJECTS = \ $(am_src_lib_libtor_crypt_ops_testing_a_OBJECTS) src_lib_libtor_crypt_ops_a_AR = $(AR) $(ARFLAGS) @@ -1404,15 +1473,15 @@ src/lib/crypt_ops/crypto_rsa_openssl.c \ src/lib/crypt_ops/crypto_dh_openssl.c \ src/lib/crypt_ops/crypto_openssl_mgt.c -@USE_NSS_TRUE@am__objects_33 = src/lib/crypt_ops/libtor_crypt_ops_a-aes_nss.$(OBJEXT) \ +@USE_NSS_TRUE@am__objects_37 = src/lib/crypt_ops/libtor_crypt_ops_a-aes_nss.$(OBJEXT) \ @USE_NSS_TRUE@ src/lib/crypt_ops/libtor_crypt_ops_a-crypto_digest_nss.$(OBJEXT) \ @USE_NSS_TRUE@ src/lib/crypt_ops/libtor_crypt_ops_a-crypto_dh_nss.$(OBJEXT) \ @USE_NSS_TRUE@ src/lib/crypt_ops/libtor_crypt_ops_a-crypto_nss_mgt.$(OBJEXT) \ @USE_NSS_TRUE@ src/lib/crypt_ops/libtor_crypt_ops_a-crypto_rsa_nss.$(OBJEXT) -@USE_NSS_FALSE@am__objects_34 = src/lib/crypt_ops/libtor_crypt_ops_a-aes_openssl.$(OBJEXT) \ +@USE_NSS_FALSE@am__objects_38 = src/lib/crypt_ops/libtor_crypt_ops_a-aes_openssl.$(OBJEXT) \ @USE_NSS_FALSE@ src/lib/crypt_ops/libtor_crypt_ops_a-crypto_digest_openssl.$(OBJEXT) \ @USE_NSS_FALSE@ src/lib/crypt_ops/libtor_crypt_ops_a-crypto_rsa_openssl.$(OBJEXT) -@USE_OPENSSL_TRUE@am__objects_35 = src/lib/crypt_ops/libtor_crypt_ops_a-crypto_dh_openssl.$(OBJEXT) \ +@USE_OPENSSL_TRUE@am__objects_39 = src/lib/crypt_ops/libtor_crypt_ops_a-crypto_dh_openssl.$(OBJEXT) \ @USE_OPENSSL_TRUE@ src/lib/crypt_ops/libtor_crypt_ops_a-crypto_openssl_mgt.$(OBJEXT) am_src_lib_libtor_crypt_ops_a_OBJECTS = \ src/lib/crypt_ops/libtor_crypt_ops_a-crypto_cipher.$(OBJEXT) \ @@ -1432,7 +1501,7 @@ src/lib/crypt_ops/libtor_crypt_ops_a-crypto_s2k.$(OBJEXT) \ src/lib/crypt_ops/libtor_crypt_ops_a-crypto_util.$(OBJEXT) \ src/lib/crypt_ops/libtor_crypt_ops_a-digestset.$(OBJEXT) \ - $(am__objects_33) $(am__objects_34) $(am__objects_35) + $(am__objects_37) $(am__objects_38) $(am__objects_39) src_lib_libtor_crypt_ops_a_OBJECTS = \ $(am_src_lib_libtor_crypt_ops_a_OBJECTS) src_lib_libtor_ctime_testing_a_AR = $(AR) $(ARFLAGS) @@ -1440,29 +1509,29 @@ am__src_lib_libtor_ctime_testing_a_SOURCES_DIST = \ src/ext/mulodi/mulodi4.c src/ext/csiphash.c \ src/lib/ctime/di_ops.c -@ADD_MULODI4_TRUE@am__objects_36 = src/ext/mulodi/lib_libtor_ctime_testing_a-mulodi4.$(OBJEXT) -am__objects_37 = $(am__objects_36) \ +@ADD_MULODI4_TRUE@am__objects_40 = src/ext/mulodi/lib_libtor_ctime_testing_a-mulodi4.$(OBJEXT) +am__objects_41 = $(am__objects_40) \ src/ext/lib_libtor_ctime_testing_a-csiphash.$(OBJEXT) \ src/lib/ctime/libtor_ctime_testing_a-di_ops.$(OBJEXT) -am_src_lib_libtor_ctime_testing_a_OBJECTS = $(am__objects_37) +am_src_lib_libtor_ctime_testing_a_OBJECTS = $(am__objects_41) src_lib_libtor_ctime_testing_a_OBJECTS = \ $(am_src_lib_libtor_ctime_testing_a_OBJECTS) src_lib_libtor_ctime_a_AR = $(AR) $(ARFLAGS) src_lib_libtor_ctime_a_LIBADD = am__src_lib_libtor_ctime_a_SOURCES_DIST = src/ext/mulodi/mulodi4.c \ src/ext/csiphash.c src/lib/ctime/di_ops.c -@ADD_MULODI4_TRUE@am__objects_38 = src/ext/mulodi/lib_libtor_ctime_a-mulodi4.$(OBJEXT) -am_src_lib_libtor_ctime_a_OBJECTS = $(am__objects_38) \ +@ADD_MULODI4_TRUE@am__objects_42 = src/ext/mulodi/lib_libtor_ctime_a-mulodi4.$(OBJEXT) +am_src_lib_libtor_ctime_a_OBJECTS = $(am__objects_42) \ src/ext/lib_libtor_ctime_a-csiphash.$(OBJEXT) \ src/lib/ctime/libtor_ctime_a-di_ops.$(OBJEXT) src_lib_libtor_ctime_a_OBJECTS = $(am_src_lib_libtor_ctime_a_OBJECTS) src_lib_libtor_dispatch_testing_a_AR = $(AR) $(ARFLAGS) src_lib_libtor_dispatch_testing_a_LIBADD = -am__objects_39 = src/lib/dispatch/libtor_dispatch_testing_a-dispatch_cfg.$(OBJEXT) \ +am__objects_43 = src/lib/dispatch/libtor_dispatch_testing_a-dispatch_cfg.$(OBJEXT) \ src/lib/dispatch/libtor_dispatch_testing_a-dispatch_core.$(OBJEXT) \ src/lib/dispatch/libtor_dispatch_testing_a-dispatch_naming.$(OBJEXT) \ src/lib/dispatch/libtor_dispatch_testing_a-dispatch_new.$(OBJEXT) -am_src_lib_libtor_dispatch_testing_a_OBJECTS = $(am__objects_39) +am_src_lib_libtor_dispatch_testing_a_OBJECTS = $(am__objects_43) src_lib_libtor_dispatch_testing_a_OBJECTS = \ $(am_src_lib_libtor_dispatch_testing_a_OBJECTS) src_lib_libtor_dispatch_a_AR = $(AR) $(ARFLAGS) @@ -1476,7 +1545,7 @@ $(am_src_lib_libtor_dispatch_a_OBJECTS) src_lib_libtor_encoding_testing_a_AR = $(AR) $(ARFLAGS) src_lib_libtor_encoding_testing_a_LIBADD = -am__objects_40 = \ +am__objects_44 = \ src/lib/encoding/libtor_encoding_testing_a-binascii.$(OBJEXT) \ src/lib/encoding/libtor_encoding_testing_a-confline.$(OBJEXT) \ src/lib/encoding/libtor_encoding_testing_a-cstring.$(OBJEXT) \ @@ -1485,7 +1554,7 @@ src/lib/encoding/libtor_encoding_testing_a-pem.$(OBJEXT) \ src/lib/encoding/libtor_encoding_testing_a-qstring.$(OBJEXT) \ src/lib/encoding/libtor_encoding_testing_a-time_fmt.$(OBJEXT) -am_src_lib_libtor_encoding_testing_a_OBJECTS = $(am__objects_40) +am_src_lib_libtor_encoding_testing_a_OBJECTS = $(am__objects_44) src_lib_libtor_encoding_testing_a_OBJECTS = \ $(am_src_lib_libtor_encoding_testing_a_OBJECTS) src_lib_libtor_encoding_a_AR = $(AR) $(ARFLAGS) @@ -1503,10 +1572,10 @@ $(am_src_lib_libtor_encoding_a_OBJECTS) src_lib_libtor_err_testing_a_AR = $(AR) $(ARFLAGS) src_lib_libtor_err_testing_a_LIBADD = -am__objects_41 = src/lib/err/libtor_err_testing_a-backtrace.$(OBJEXT) \ +am__objects_45 = src/lib/err/libtor_err_testing_a-backtrace.$(OBJEXT) \ src/lib/err/libtor_err_testing_a-torerr.$(OBJEXT) \ src/lib/err/libtor_err_testing_a-torerr_sys.$(OBJEXT) -am_src_lib_libtor_err_testing_a_OBJECTS = $(am__objects_41) +am_src_lib_libtor_err_testing_a_OBJECTS = $(am__objects_45) src_lib_libtor_err_testing_a_OBJECTS = \ $(am_src_lib_libtor_err_testing_a_OBJECTS) src_lib_libtor_err_a_AR = $(AR) $(ARFLAGS) @@ -1516,13 +1585,13 @@ src_lib_libtor_err_a_OBJECTS = $(am_src_lib_libtor_err_a_OBJECTS) src_lib_libtor_evloop_testing_a_AR = $(AR) $(ARFLAGS) src_lib_libtor_evloop_testing_a_LIBADD = -am__objects_42 = src/lib/evloop/libtor_evloop_testing_a-compat_libevent.$(OBJEXT) \ +am__objects_46 = src/lib/evloop/libtor_evloop_testing_a-compat_libevent.$(OBJEXT) \ src/lib/evloop/libtor_evloop_testing_a-evloop_sys.$(OBJEXT) \ src/lib/evloop/libtor_evloop_testing_a-procmon.$(OBJEXT) \ src/lib/evloop/libtor_evloop_testing_a-timers.$(OBJEXT) \ src/lib/evloop/libtor_evloop_testing_a-token_bucket.$(OBJEXT) \ src/lib/evloop/libtor_evloop_testing_a-workqueue.$(OBJEXT) -am_src_lib_libtor_evloop_testing_a_OBJECTS = $(am__objects_42) +am_src_lib_libtor_evloop_testing_a_OBJECTS = $(am__objects_46) src_lib_libtor_evloop_testing_a_OBJECTS = \ $(am_src_lib_libtor_evloop_testing_a_OBJECTS) src_lib_libtor_evloop_a_AR = $(AR) $(ARFLAGS) @@ -1538,8 +1607,8 @@ $(am_src_lib_libtor_evloop_a_OBJECTS) src_lib_libtor_fdio_testing_a_AR = $(AR) $(ARFLAGS) src_lib_libtor_fdio_testing_a_LIBADD = -am__objects_43 = src/lib/fdio/libtor_fdio_testing_a-fdio.$(OBJEXT) -am_src_lib_libtor_fdio_testing_a_OBJECTS = $(am__objects_43) +am__objects_47 = src/lib/fdio/libtor_fdio_testing_a-fdio.$(OBJEXT) +am_src_lib_libtor_fdio_testing_a_OBJECTS = $(am__objects_47) src_lib_libtor_fdio_testing_a_OBJECTS = \ $(am_src_lib_libtor_fdio_testing_a_OBJECTS) src_lib_libtor_fdio_a_AR = $(AR) $(ARFLAGS) @@ -1553,9 +1622,9 @@ src/lib/fs/lockfile.c src/lib/fs/mmap.c src/lib/fs/path.c \ src/lib/fs/storagedir.c src/lib/fs/userdb.c \ src/lib/fs/winlib.c -@WIN32_TRUE@am__objects_44 = \ +@WIN32_TRUE@am__objects_48 = \ @WIN32_TRUE@ src/lib/fs/libtor_fs_testing_a-winlib.$(OBJEXT) -am__objects_45 = src/lib/fs/libtor_fs_testing_a-conffile.$(OBJEXT) \ +am__objects_49 = src/lib/fs/libtor_fs_testing_a-conffile.$(OBJEXT) \ src/lib/fs/libtor_fs_testing_a-dir.$(OBJEXT) \ src/lib/fs/libtor_fs_testing_a-files.$(OBJEXT) \ src/lib/fs/libtor_fs_testing_a-freespace.$(OBJEXT) \ @@ -1564,8 +1633,8 @@ src/lib/fs/libtor_fs_testing_a-path.$(OBJEXT) \ src/lib/fs/libtor_fs_testing_a-storagedir.$(OBJEXT) \ src/lib/fs/libtor_fs_testing_a-userdb.$(OBJEXT) \ - $(am__objects_44) -am_src_lib_libtor_fs_testing_a_OBJECTS = $(am__objects_45) + $(am__objects_48) +am_src_lib_libtor_fs_testing_a_OBJECTS = $(am__objects_49) src_lib_libtor_fs_testing_a_OBJECTS = \ $(am_src_lib_libtor_fs_testing_a_OBJECTS) src_lib_libtor_fs_a_AR = $(AR) $(ARFLAGS) @@ -1575,18 +1644,18 @@ src/lib/fs/lockfile.c src/lib/fs/mmap.c src/lib/fs/path.c \ src/lib/fs/storagedir.c src/lib/fs/userdb.c \ src/lib/fs/winlib.c -@WIN32_TRUE@am__objects_46 = src/lib/fs/winlib.$(OBJEXT) +@WIN32_TRUE@am__objects_50 = src/lib/fs/winlib.$(OBJEXT) am_src_lib_libtor_fs_a_OBJECTS = src/lib/fs/conffile.$(OBJEXT) \ src/lib/fs/dir.$(OBJEXT) src/lib/fs/files.$(OBJEXT) \ src/lib/fs/freespace.$(OBJEXT) src/lib/fs/lockfile.$(OBJEXT) \ src/lib/fs/mmap.$(OBJEXT) src/lib/fs/path.$(OBJEXT) \ src/lib/fs/storagedir.$(OBJEXT) src/lib/fs/userdb.$(OBJEXT) \ - $(am__objects_46) + $(am__objects_50) src_lib_libtor_fs_a_OBJECTS = $(am_src_lib_libtor_fs_a_OBJECTS) src_lib_libtor_geoip_testing_a_AR = $(AR) $(ARFLAGS) src_lib_libtor_geoip_testing_a_LIBADD = -am__objects_47 = src/lib/geoip/libtor_geoip_testing_a-geoip.$(OBJEXT) -am_src_lib_libtor_geoip_testing_a_OBJECTS = $(am__objects_47) +am__objects_51 = src/lib/geoip/libtor_geoip_testing_a-geoip.$(OBJEXT) +am_src_lib_libtor_geoip_testing_a_OBJECTS = $(am__objects_51) src_lib_libtor_geoip_testing_a_OBJECTS = \ $(am_src_lib_libtor_geoip_testing_a_OBJECTS) src_lib_libtor_geoip_a_AR = $(AR) $(ARFLAGS) @@ -1595,12 +1664,12 @@ src_lib_libtor_geoip_a_OBJECTS = $(am_src_lib_libtor_geoip_a_OBJECTS) src_lib_libtor_intmath_testing_a_AR = $(AR) $(ARFLAGS) src_lib_libtor_intmath_testing_a_LIBADD = -am__objects_48 = \ +am__objects_52 = \ src/lib/intmath/libtor_intmath_testing_a-addsub.$(OBJEXT) \ src/lib/intmath/libtor_intmath_testing_a-bits.$(OBJEXT) \ src/lib/intmath/libtor_intmath_testing_a-muldiv.$(OBJEXT) \ src/lib/intmath/libtor_intmath_testing_a-weakrng.$(OBJEXT) -am_src_lib_libtor_intmath_testing_a_OBJECTS = $(am__objects_48) +am_src_lib_libtor_intmath_testing_a_OBJECTS = $(am__objects_52) src_lib_libtor_intmath_testing_a_OBJECTS = \ $(am_src_lib_libtor_intmath_testing_a_OBJECTS) src_lib_libtor_intmath_a_AR = $(AR) $(ARFLAGS) @@ -1614,8 +1683,8 @@ $(am_src_lib_libtor_intmath_a_OBJECTS) src_lib_libtor_llharden_testing_a_AR = $(AR) $(ARFLAGS) src_lib_libtor_llharden_testing_a_LIBADD = -am__objects_49 = src/lib/llharden/libtor_llharden_testing_a-winprocess_sys.$(OBJEXT) -am_src_lib_libtor_llharden_testing_a_OBJECTS = $(am__objects_49) +am__objects_53 = src/lib/llharden/libtor_llharden_testing_a-winprocess_sys.$(OBJEXT) +am_src_lib_libtor_llharden_testing_a_OBJECTS = $(am__objects_53) src_lib_libtor_llharden_testing_a_OBJECTS = \ $(am_src_lib_libtor_llharden_testing_a_OBJECTS) src_lib_libtor_llharden_a_AR = $(AR) $(ARFLAGS) @@ -1630,12 +1699,12 @@ src/lib/lock/compat_mutex.c \ src/lib/lock/compat_mutex_pthreads.c \ src/lib/lock/compat_mutex_winthreads.c -@THREADS_PTHREADS_TRUE@am__objects_50 = src/lib/lock/libtor_lock_testing_a-compat_mutex_pthreads.$(OBJEXT) -@THREADS_WIN32_TRUE@am__objects_51 = src/lib/lock/libtor_lock_testing_a-compat_mutex_winthreads.$(OBJEXT) -am__objects_52 = \ +@THREADS_PTHREADS_TRUE@am__objects_54 = src/lib/lock/libtor_lock_testing_a-compat_mutex_pthreads.$(OBJEXT) +@THREADS_WIN32_TRUE@am__objects_55 = src/lib/lock/libtor_lock_testing_a-compat_mutex_winthreads.$(OBJEXT) +am__objects_56 = \ src/lib/lock/libtor_lock_testing_a-compat_mutex.$(OBJEXT) \ - $(am__objects_50) $(am__objects_51) -am_src_lib_libtor_lock_testing_a_OBJECTS = $(am__objects_52) + $(am__objects_54) $(am__objects_55) +am_src_lib_libtor_lock_testing_a_OBJECTS = $(am__objects_56) src_lib_libtor_lock_testing_a_OBJECTS = \ $(am_src_lib_libtor_lock_testing_a_OBJECTS) src_lib_libtor_lock_a_AR = $(AR) $(ARFLAGS) @@ -1643,25 +1712,25 @@ am__src_lib_libtor_lock_a_SOURCES_DIST = src/lib/lock/compat_mutex.c \ src/lib/lock/compat_mutex_pthreads.c \ src/lib/lock/compat_mutex_winthreads.c -@THREADS_PTHREADS_TRUE@am__objects_53 = src/lib/lock/compat_mutex_pthreads.$(OBJEXT) -@THREADS_WIN32_TRUE@am__objects_54 = src/lib/lock/compat_mutex_winthreads.$(OBJEXT) +@THREADS_PTHREADS_TRUE@am__objects_57 = src/lib/lock/compat_mutex_pthreads.$(OBJEXT) +@THREADS_WIN32_TRUE@am__objects_58 = src/lib/lock/compat_mutex_winthreads.$(OBJEXT) am_src_lib_libtor_lock_a_OBJECTS = \ - src/lib/lock/compat_mutex.$(OBJEXT) $(am__objects_53) \ - $(am__objects_54) + src/lib/lock/compat_mutex.$(OBJEXT) $(am__objects_57) \ + $(am__objects_58) src_lib_libtor_lock_a_OBJECTS = $(am_src_lib_libtor_lock_a_OBJECTS) src_lib_libtor_log_testing_a_AR = $(AR) $(ARFLAGS) src_lib_libtor_log_testing_a_LIBADD = am__src_lib_libtor_log_testing_a_SOURCES_DIST = src/lib/log/escape.c \ src/lib/log/ratelim.c src/lib/log/log.c src/lib/log/log_sys.c \ src/lib/log/util_bug.c src/lib/log/win32err.c -@WIN32_TRUE@am__objects_55 = src/lib/log/libtor_log_testing_a-win32err.$(OBJEXT) -am__objects_56 = src/lib/log/libtor_log_testing_a-escape.$(OBJEXT) \ +@WIN32_TRUE@am__objects_59 = src/lib/log/libtor_log_testing_a-win32err.$(OBJEXT) +am__objects_60 = src/lib/log/libtor_log_testing_a-escape.$(OBJEXT) \ src/lib/log/libtor_log_testing_a-ratelim.$(OBJEXT) \ src/lib/log/libtor_log_testing_a-log.$(OBJEXT) \ src/lib/log/libtor_log_testing_a-log_sys.$(OBJEXT) \ src/lib/log/libtor_log_testing_a-util_bug.$(OBJEXT) \ - $(am__objects_55) -am_src_lib_libtor_log_testing_a_OBJECTS = $(am__objects_56) + $(am__objects_59) +am_src_lib_libtor_log_testing_a_OBJECTS = $(am__objects_60) src_lib_libtor_log_testing_a_OBJECTS = \ $(am_src_lib_libtor_log_testing_a_OBJECTS) src_lib_libtor_log_a_AR = $(AR) $(ARFLAGS) @@ -1669,40 +1738,40 @@ am__src_lib_libtor_log_a_SOURCES_DIST = src/lib/log/escape.c \ src/lib/log/ratelim.c src/lib/log/log.c src/lib/log/log_sys.c \ src/lib/log/util_bug.c src/lib/log/win32err.c -@WIN32_TRUE@am__objects_57 = src/lib/log/win32err.$(OBJEXT) +@WIN32_TRUE@am__objects_61 = src/lib/log/win32err.$(OBJEXT) am_src_lib_libtor_log_a_OBJECTS = src/lib/log/escape.$(OBJEXT) \ src/lib/log/ratelim.$(OBJEXT) src/lib/log/log.$(OBJEXT) \ src/lib/log/log_sys.$(OBJEXT) src/lib/log/util_bug.$(OBJEXT) \ - $(am__objects_57) + $(am__objects_61) src_lib_libtor_log_a_OBJECTS = $(am_src_lib_libtor_log_a_OBJECTS) src_lib_libtor_malloc_testing_a_AR = $(AR) $(ARFLAGS) src_lib_libtor_malloc_testing_a_LIBADD = am__src_lib_libtor_malloc_testing_a_SOURCES_DIST = \ src/lib/malloc/malloc.c src/lib/malloc/map_anon.c \ src/ext/OpenBSD_malloc_Linux.c -@USE_OPENBSD_MALLOC_TRUE@am__objects_58 = src/ext/lib_libtor_malloc_testing_a-OpenBSD_malloc_Linux.$(OBJEXT) -am__objects_59 = \ +@USE_OPENBSD_MALLOC_TRUE@am__objects_62 = src/ext/lib_libtor_malloc_testing_a-OpenBSD_malloc_Linux.$(OBJEXT) +am__objects_63 = \ src/lib/malloc/libtor_malloc_testing_a-malloc.$(OBJEXT) \ src/lib/malloc/libtor_malloc_testing_a-map_anon.$(OBJEXT) \ - $(am__objects_58) -am_src_lib_libtor_malloc_testing_a_OBJECTS = $(am__objects_59) + $(am__objects_62) +am_src_lib_libtor_malloc_testing_a_OBJECTS = $(am__objects_63) src_lib_libtor_malloc_testing_a_OBJECTS = \ $(am_src_lib_libtor_malloc_testing_a_OBJECTS) src_lib_libtor_malloc_a_AR = $(AR) $(ARFLAGS) src_lib_libtor_malloc_a_LIBADD = am__src_lib_libtor_malloc_a_SOURCES_DIST = src/lib/malloc/malloc.c \ src/lib/malloc/map_anon.c src/ext/OpenBSD_malloc_Linux.c -@USE_OPENBSD_MALLOC_TRUE@am__objects_60 = src/ext/OpenBSD_malloc_Linux.$(OBJEXT) +@USE_OPENBSD_MALLOC_TRUE@am__objects_64 = src/ext/OpenBSD_malloc_Linux.$(OBJEXT) am_src_lib_libtor_malloc_a_OBJECTS = src/lib/malloc/malloc.$(OBJEXT) \ - src/lib/malloc/map_anon.$(OBJEXT) $(am__objects_60) + src/lib/malloc/map_anon.$(OBJEXT) $(am__objects_64) src_lib_libtor_malloc_a_OBJECTS = \ $(am_src_lib_libtor_malloc_a_OBJECTS) src_lib_libtor_math_testing_a_AR = $(AR) $(ARFLAGS) src_lib_libtor_math_testing_a_LIBADD = -am__objects_61 = src/lib/math/libtor_math_testing_a-fp.$(OBJEXT) \ +am__objects_65 = src/lib/math/libtor_math_testing_a-fp.$(OBJEXT) \ src/lib/math/libtor_math_testing_a-laplace.$(OBJEXT) \ src/lib/math/libtor_math_testing_a-prob_distr.$(OBJEXT) -am_src_lib_libtor_math_testing_a_OBJECTS = $(am__objects_61) +am_src_lib_libtor_math_testing_a_OBJECTS = $(am__objects_65) src_lib_libtor_math_testing_a_OBJECTS = \ $(am_src_lib_libtor_math_testing_a_OBJECTS) src_lib_libtor_math_a_AR = $(AR) $(ARFLAGS) @@ -1713,9 +1782,9 @@ src_lib_libtor_math_a_OBJECTS = $(am_src_lib_libtor_math_a_OBJECTS) src_lib_libtor_memarea_testing_a_AR = $(AR) $(ARFLAGS) src_lib_libtor_memarea_testing_a_LIBADD = -am__objects_62 = \ +am__objects_66 = \ src/lib/memarea/libtor_memarea_testing_a-memarea.$(OBJEXT) -am_src_lib_libtor_memarea_testing_a_OBJECTS = $(am__objects_62) +am_src_lib_libtor_memarea_testing_a_OBJECTS = $(am__objects_66) src_lib_libtor_memarea_testing_a_OBJECTS = \ $(am_src_lib_libtor_memarea_testing_a_OBJECTS) src_lib_libtor_memarea_a_AR = $(AR) $(ARFLAGS) @@ -1726,9 +1795,9 @@ $(am_src_lib_libtor_memarea_a_OBJECTS) src_lib_libtor_meminfo_testing_a_AR = $(AR) $(ARFLAGS) src_lib_libtor_meminfo_testing_a_LIBADD = -am__objects_63 = \ +am__objects_67 = \ src/lib/meminfo/libtor_meminfo_testing_a-meminfo.$(OBJEXT) -am_src_lib_libtor_meminfo_testing_a_OBJECTS = $(am__objects_63) +am_src_lib_libtor_meminfo_testing_a_OBJECTS = $(am__objects_67) src_lib_libtor_meminfo_testing_a_OBJECTS = \ $(am_src_lib_libtor_meminfo_testing_a_OBJECTS) src_lib_libtor_meminfo_a_AR = $(AR) $(ARFLAGS) @@ -1739,11 +1808,11 @@ $(am_src_lib_libtor_meminfo_a_OBJECTS) src_lib_libtor_metrics_testing_a_AR = $(AR) $(ARFLAGS) src_lib_libtor_metrics_testing_a_LIBADD = -am__objects_64 = src/lib/metrics/libtor_metrics_testing_a-metrics_store.$(OBJEXT) \ +am__objects_68 = src/lib/metrics/libtor_metrics_testing_a-metrics_store.$(OBJEXT) \ src/lib/metrics/libtor_metrics_testing_a-metrics_store_entry.$(OBJEXT) \ src/lib/metrics/libtor_metrics_testing_a-metrics_common.$(OBJEXT) \ src/lib/metrics/libtor_metrics_testing_a-prometheus.$(OBJEXT) -am_src_lib_libtor_metrics_testing_a_OBJECTS = $(am__objects_64) +am_src_lib_libtor_metrics_testing_a_OBJECTS = $(am__objects_68) src_lib_libtor_metrics_testing_a_OBJECTS = \ $(am_src_lib_libtor_metrics_testing_a_OBJECTS) src_lib_libtor_metrics_a_AR = $(AR) $(ARFLAGS) @@ -1757,7 +1826,7 @@ $(am_src_lib_libtor_metrics_a_OBJECTS) src_lib_libtor_net_testing_a_AR = $(AR) $(ARFLAGS) src_lib_libtor_net_testing_a_LIBADD = -am__objects_65 = src/lib/net/libtor_net_testing_a-address.$(OBJEXT) \ +am__objects_69 = src/lib/net/libtor_net_testing_a-address.$(OBJEXT) \ src/lib/net/libtor_net_testing_a-alertsock.$(OBJEXT) \ src/lib/net/libtor_net_testing_a-buffers_net.$(OBJEXT) \ src/lib/net/libtor_net_testing_a-gethostname.$(OBJEXT) \ @@ -1766,7 +1835,7 @@ src/lib/net/libtor_net_testing_a-resolve.$(OBJEXT) \ src/lib/net/libtor_net_testing_a-socket.$(OBJEXT) \ src/lib/net/libtor_net_testing_a-socketpair.$(OBJEXT) -am_src_lib_libtor_net_testing_a_OBJECTS = $(am__objects_65) +am_src_lib_libtor_net_testing_a_OBJECTS = $(am__objects_69) src_lib_libtor_net_testing_a_OBJECTS = \ $(am_src_lib_libtor_net_testing_a_OBJECTS) src_lib_libtor_net_a_AR = $(AR) $(ARFLAGS) @@ -1781,10 +1850,10 @@ src_lib_libtor_net_a_OBJECTS = $(am_src_lib_libtor_net_a_OBJECTS) src_lib_libtor_osinfo_testing_a_AR = $(AR) $(ARFLAGS) src_lib_libtor_osinfo_testing_a_LIBADD = -am__objects_66 = \ +am__objects_70 = \ src/lib/osinfo/libtor_osinfo_testing_a-uname.$(OBJEXT) \ src/lib/osinfo/libtor_osinfo_testing_a-libc.$(OBJEXT) -am_src_lib_libtor_osinfo_testing_a_OBJECTS = $(am__objects_66) +am_src_lib_libtor_osinfo_testing_a_OBJECTS = $(am__objects_70) src_lib_libtor_osinfo_testing_a_OBJECTS = \ $(am_src_lib_libtor_osinfo_testing_a_OBJECTS) src_lib_libtor_osinfo_a_AR = $(AR) $(ARFLAGS) @@ -1795,7 +1864,7 @@ $(am_src_lib_libtor_osinfo_a_OBJECTS) src_lib_libtor_process_testing_a_AR = $(AR) $(ARFLAGS) src_lib_libtor_process_testing_a_LIBADD = -am__objects_67 = \ +am__objects_71 = \ src/lib/process/libtor_process_testing_a-daemon.$(OBJEXT) \ src/lib/process/libtor_process_testing_a-env.$(OBJEXT) \ src/lib/process/libtor_process_testing_a-pidfile.$(OBJEXT) \ @@ -1806,7 +1875,7 @@ src/lib/process/libtor_process_testing_a-restrict.$(OBJEXT) \ src/lib/process/libtor_process_testing_a-setuid.$(OBJEXT) \ src/lib/process/libtor_process_testing_a-waitpid.$(OBJEXT) -am_src_lib_libtor_process_testing_a_OBJECTS = $(am__objects_67) +am_src_lib_libtor_process_testing_a_OBJECTS = $(am__objects_71) src_lib_libtor_process_testing_a_OBJECTS = \ $(am_src_lib_libtor_process_testing_a_OBJECTS) src_lib_libtor_process_a_AR = $(AR) $(ARFLAGS) @@ -1825,11 +1894,11 @@ $(am_src_lib_libtor_process_a_OBJECTS) src_lib_libtor_pubsub_testing_a_AR = $(AR) $(ARFLAGS) src_lib_libtor_pubsub_testing_a_LIBADD = -am__objects_68 = \ +am__objects_72 = \ src/lib/pubsub/libtor_pubsub_testing_a-pubsub_build.$(OBJEXT) \ src/lib/pubsub/libtor_pubsub_testing_a-pubsub_check.$(OBJEXT) \ src/lib/pubsub/libtor_pubsub_testing_a-pubsub_publish.$(OBJEXT) -am_src_lib_libtor_pubsub_testing_a_OBJECTS = $(am__objects_68) +am_src_lib_libtor_pubsub_testing_a_OBJECTS = $(am__objects_72) src_lib_libtor_pubsub_testing_a_OBJECTS = \ $(am_src_lib_libtor_pubsub_testing_a_OBJECTS) src_lib_libtor_pubsub_a_AR = $(AR) $(ARFLAGS) @@ -1842,9 +1911,9 @@ $(am_src_lib_libtor_pubsub_a_OBJECTS) src_lib_libtor_sandbox_testing_a_AR = $(AR) $(ARFLAGS) src_lib_libtor_sandbox_testing_a_LIBADD = -am__objects_69 = \ +am__objects_73 = \ src/lib/sandbox/libtor_sandbox_testing_a-sandbox.$(OBJEXT) -am_src_lib_libtor_sandbox_testing_a_OBJECTS = $(am__objects_69) +am_src_lib_libtor_sandbox_testing_a_OBJECTS = $(am__objects_73) src_lib_libtor_sandbox_testing_a_OBJECTS = \ $(am_src_lib_libtor_sandbox_testing_a_OBJECTS) src_lib_libtor_sandbox_a_AR = $(AR) $(ARFLAGS) @@ -1855,10 +1924,10 @@ $(am_src_lib_libtor_sandbox_a_OBJECTS) src_lib_libtor_smartlist_core_testing_a_AR = $(AR) $(ARFLAGS) src_lib_libtor_smartlist_core_testing_a_LIBADD = -am__objects_70 = src/lib/smartlist_core/libtor_smartlist_core_testing_a-smartlist_core.$(OBJEXT) \ +am__objects_74 = src/lib/smartlist_core/libtor_smartlist_core_testing_a-smartlist_core.$(OBJEXT) \ src/lib/smartlist_core/libtor_smartlist_core_testing_a-smartlist_split.$(OBJEXT) am_src_lib_libtor_smartlist_core_testing_a_OBJECTS = \ - $(am__objects_70) + $(am__objects_74) src_lib_libtor_smartlist_core_testing_a_OBJECTS = \ $(am_src_lib_libtor_smartlist_core_testing_a_OBJECTS) src_lib_libtor_smartlist_core_a_AR = $(AR) $(ARFLAGS) @@ -1870,14 +1939,14 @@ $(am_src_lib_libtor_smartlist_core_a_OBJECTS) src_lib_libtor_string_testing_a_AR = $(AR) $(ARFLAGS) src_lib_libtor_string_testing_a_LIBADD = -am__objects_71 = \ +am__objects_75 = \ src/lib/string/libtor_string_testing_a-compat_ctype.$(OBJEXT) \ src/lib/string/libtor_string_testing_a-compat_string.$(OBJEXT) \ src/lib/string/libtor_string_testing_a-util_string.$(OBJEXT) \ src/lib/string/libtor_string_testing_a-parse_int.$(OBJEXT) \ src/lib/string/libtor_string_testing_a-printf.$(OBJEXT) \ src/lib/string/libtor_string_testing_a-scanf.$(OBJEXT) -am_src_lib_libtor_string_testing_a_OBJECTS = $(am__objects_71) +am_src_lib_libtor_string_testing_a_OBJECTS = $(am__objects_75) src_lib_libtor_string_testing_a_OBJECTS = \ $(am_src_lib_libtor_string_testing_a_OBJECTS) src_lib_libtor_string_a_AR = $(AR) $(ARFLAGS) @@ -1894,20 +1963,20 @@ src_lib_libtor_term_testing_a_LIBADD = am__src_lib_libtor_term_testing_a_SOURCES_DIST = \ src/lib/term/getpass.c src/ext/readpassphrase.c -@BUILD_READPASSPHRASE_C_TRUE@am__objects_72 = src/ext/lib_libtor_term_testing_a-readpassphrase.$(OBJEXT) -am__objects_73 = src/lib/term/libtor_term_testing_a-getpass.$(OBJEXT) \ - $(am__objects_72) -am_src_lib_libtor_term_testing_a_OBJECTS = $(am__objects_73) +@BUILD_READPASSPHRASE_C_TRUE@am__objects_76 = src/ext/lib_libtor_term_testing_a-readpassphrase.$(OBJEXT) +am__objects_77 = src/lib/term/libtor_term_testing_a-getpass.$(OBJEXT) \ + $(am__objects_76) +am_src_lib_libtor_term_testing_a_OBJECTS = $(am__objects_77) src_lib_libtor_term_testing_a_OBJECTS = \ $(am_src_lib_libtor_term_testing_a_OBJECTS) src_lib_libtor_term_a_AR = $(AR) $(ARFLAGS) src_lib_libtor_term_a_LIBADD = am__src_lib_libtor_term_a_SOURCES_DIST = src/lib/term/getpass.c \ src/ext/readpassphrase.c -@BUILD_READPASSPHRASE_C_TRUE@am__objects_74 = \ +@BUILD_READPASSPHRASE_C_TRUE@am__objects_78 = \ @BUILD_READPASSPHRASE_C_TRUE@ src/ext/readpassphrase.$(OBJEXT) am_src_lib_libtor_term_a_OBJECTS = src/lib/term/getpass.$(OBJEXT) \ - $(am__objects_74) + $(am__objects_78) src_lib_libtor_term_a_OBJECTS = $(am_src_lib_libtor_term_a_OBJECTS) src_lib_libtor_thread_testing_a_AR = $(AR) $(ARFLAGS) src_lib_libtor_thread_testing_a_LIBADD = @@ -1915,12 +1984,12 @@ src/lib/thread/compat_threads.c src/lib/thread/numcpus.c \ src/lib/thread/compat_pthreads.c \ src/lib/thread/compat_winthreads.c -@THREADS_PTHREADS_FALSE@@THREADS_WIN32_TRUE@am__objects_75 = src/lib/thread/libtor_thread_testing_a-compat_winthreads.$(OBJEXT) -@THREADS_PTHREADS_TRUE@am__objects_75 = src/lib/thread/libtor_thread_testing_a-compat_pthreads.$(OBJEXT) -am__objects_76 = src/lib/thread/libtor_thread_testing_a-compat_threads.$(OBJEXT) \ +@THREADS_PTHREADS_FALSE@@THREADS_WIN32_TRUE@am__objects_79 = src/lib/thread/libtor_thread_testing_a-compat_winthreads.$(OBJEXT) +@THREADS_PTHREADS_TRUE@am__objects_79 = src/lib/thread/libtor_thread_testing_a-compat_pthreads.$(OBJEXT) +am__objects_80 = src/lib/thread/libtor_thread_testing_a-compat_threads.$(OBJEXT) \ src/lib/thread/libtor_thread_testing_a-numcpus.$(OBJEXT) \ - $(am__objects_75) -am_src_lib_libtor_thread_testing_a_OBJECTS = $(am__objects_76) + $(am__objects_79) +am_src_lib_libtor_thread_testing_a_OBJECTS = $(am__objects_80) src_lib_libtor_thread_testing_a_OBJECTS = \ $(am_src_lib_libtor_thread_testing_a_OBJECTS) src_lib_libtor_thread_a_AR = $(AR) $(ARFLAGS) @@ -1929,20 +1998,20 @@ src/lib/thread/compat_threads.c src/lib/thread/numcpus.c \ src/lib/thread/compat_pthreads.c \ src/lib/thread/compat_winthreads.c -@THREADS_PTHREADS_FALSE@@THREADS_WIN32_TRUE@am__objects_77 = src/lib/thread/compat_winthreads.$(OBJEXT) -@THREADS_PTHREADS_TRUE@am__objects_77 = src/lib/thread/compat_pthreads.$(OBJEXT) +@THREADS_PTHREADS_FALSE@@THREADS_WIN32_TRUE@am__objects_81 = src/lib/thread/compat_winthreads.$(OBJEXT) +@THREADS_PTHREADS_TRUE@am__objects_81 = src/lib/thread/compat_pthreads.$(OBJEXT) am_src_lib_libtor_thread_a_OBJECTS = \ src/lib/thread/compat_threads.$(OBJEXT) \ - src/lib/thread/numcpus.$(OBJEXT) $(am__objects_77) + src/lib/thread/numcpus.$(OBJEXT) $(am__objects_81) src_lib_libtor_thread_a_OBJECTS = \ $(am_src_lib_libtor_thread_a_OBJECTS) src_lib_libtor_time_testing_a_AR = $(AR) $(ARFLAGS) src_lib_libtor_time_testing_a_LIBADD = -am__objects_78 = \ +am__objects_82 = \ src/lib/time/libtor_time_testing_a-compat_time.$(OBJEXT) \ src/lib/time/libtor_time_testing_a-time_sys.$(OBJEXT) \ src/lib/time/libtor_time_testing_a-tvdiff.$(OBJEXT) -am_src_lib_libtor_time_testing_a_OBJECTS = $(am__objects_78) +am_src_lib_libtor_time_testing_a_OBJECTS = $(am__objects_82) src_lib_libtor_time_testing_a_OBJECTS = \ $(am_src_lib_libtor_time_testing_a_OBJECTS) src_lib_libtor_time_a_AR = $(AR) $(ARFLAGS) @@ -1957,17 +2026,17 @@ src/lib/tls/x509.c src/lib/tls/nss_countbytes.c \ src/lib/tls/tortls_nss.c src/lib/tls/x509_nss.c \ src/lib/tls/tortls_openssl.c src/lib/tls/x509_openssl.c -@USE_NSS_TRUE@am__objects_79 = src/lib/tls/libtor_tls_testing_a-nss_countbytes.$(OBJEXT) \ +@USE_NSS_TRUE@am__objects_83 = src/lib/tls/libtor_tls_testing_a-nss_countbytes.$(OBJEXT) \ @USE_NSS_TRUE@ src/lib/tls/libtor_tls_testing_a-tortls_nss.$(OBJEXT) \ @USE_NSS_TRUE@ src/lib/tls/libtor_tls_testing_a-x509_nss.$(OBJEXT) -@USE_NSS_FALSE@am__objects_80 = src/lib/tls/libtor_tls_testing_a-tortls_openssl.$(OBJEXT) \ +@USE_NSS_FALSE@am__objects_84 = src/lib/tls/libtor_tls_testing_a-tortls_openssl.$(OBJEXT) \ @USE_NSS_FALSE@ src/lib/tls/libtor_tls_testing_a-x509_openssl.$(OBJEXT) -am__objects_81 = \ +am__objects_85 = \ src/lib/tls/libtor_tls_testing_a-buffers_tls.$(OBJEXT) \ src/lib/tls/libtor_tls_testing_a-tortls.$(OBJEXT) \ src/lib/tls/libtor_tls_testing_a-x509.$(OBJEXT) \ - $(am__objects_79) $(am__objects_80) -am_src_lib_libtor_tls_testing_a_OBJECTS = $(am__objects_81) + $(am__objects_83) $(am__objects_84) +am_src_lib_libtor_tls_testing_a_OBJECTS = $(am__objects_85) src_lib_libtor_tls_testing_a_OBJECTS = \ $(am_src_lib_libtor_tls_testing_a_OBJECTS) src_lib_libtor_tls_a_AR = $(AR) $(ARFLAGS) @@ -1977,33 +2046,33 @@ src/lib/tls/nss_countbytes.c src/lib/tls/tortls_nss.c \ src/lib/tls/x509_nss.c src/lib/tls/tortls_openssl.c \ src/lib/tls/x509_openssl.c -@USE_NSS_TRUE@am__objects_82 = src/lib/tls/libtor_tls_a-nss_countbytes.$(OBJEXT) \ +@USE_NSS_TRUE@am__objects_86 = src/lib/tls/libtor_tls_a-nss_countbytes.$(OBJEXT) \ @USE_NSS_TRUE@ src/lib/tls/libtor_tls_a-tortls_nss.$(OBJEXT) \ @USE_NSS_TRUE@ src/lib/tls/libtor_tls_a-x509_nss.$(OBJEXT) -@USE_NSS_FALSE@am__objects_83 = src/lib/tls/libtor_tls_a-tortls_openssl.$(OBJEXT) \ +@USE_NSS_FALSE@am__objects_87 = src/lib/tls/libtor_tls_a-tortls_openssl.$(OBJEXT) \ @USE_NSS_FALSE@ src/lib/tls/libtor_tls_a-x509_openssl.$(OBJEXT) am_src_lib_libtor_tls_a_OBJECTS = \ src/lib/tls/libtor_tls_a-buffers_tls.$(OBJEXT) \ src/lib/tls/libtor_tls_a-tortls.$(OBJEXT) \ - src/lib/tls/libtor_tls_a-x509.$(OBJEXT) $(am__objects_82) \ - $(am__objects_83) + src/lib/tls/libtor_tls_a-x509.$(OBJEXT) $(am__objects_86) \ + $(am__objects_87) src_lib_libtor_tls_a_OBJECTS = $(am_src_lib_libtor_tls_a_OBJECTS) src_lib_libtor_trace_a_AR = $(AR) $(ARFLAGS) src_lib_libtor_trace_a_LIBADD = am__src_lib_libtor_trace_a_SOURCES_DIST = src/lib/trace/trace_stub.c \ src/lib/trace/trace.c src/lib/trace/trace_sys.c -am__objects_84 = src/lib/trace/trace.$(OBJEXT) \ +am__objects_88 = src/lib/trace/trace.$(OBJEXT) \ src/lib/trace/trace_sys.$(OBJEXT) @USE_TRACING_FALSE@am_src_lib_libtor_trace_a_OBJECTS = \ @USE_TRACING_FALSE@ src/lib/trace/trace_stub.$(OBJEXT) @USE_TRACING_TRUE@am_src_lib_libtor_trace_a_OBJECTS = \ -@USE_TRACING_TRUE@ $(am__objects_84) +@USE_TRACING_TRUE@ $(am__objects_88) src_lib_libtor_trace_a_OBJECTS = $(am_src_lib_libtor_trace_a_OBJECTS) src_lib_libtor_version_testing_a_AR = $(AR) $(ARFLAGS) src_lib_libtor_version_testing_a_LIBADD = -am__objects_85 = src/lib/version/libtor_version_testing_a-git_revision.$(OBJEXT) \ +am__objects_89 = src/lib/version/libtor_version_testing_a-git_revision.$(OBJEXT) \ src/lib/version/libtor_version_testing_a-version.$(OBJEXT) -am_src_lib_libtor_version_testing_a_OBJECTS = $(am__objects_85) +am_src_lib_libtor_version_testing_a_OBJECTS = $(am__objects_89) src_lib_libtor_version_testing_a_OBJECTS = \ $(am_src_lib_libtor_version_testing_a_OBJECTS) src_lib_libtor_version_a_AR = $(AR) $(ARFLAGS) @@ -2015,10 +2084,10 @@ $(am_src_lib_libtor_version_a_OBJECTS) src_lib_libtor_wallclock_testing_a_AR = $(AR) $(ARFLAGS) src_lib_libtor_wallclock_testing_a_LIBADD = -am__objects_86 = src/lib/wallclock/libtor_wallclock_testing_a-approx_time.$(OBJEXT) \ +am__objects_90 = src/lib/wallclock/libtor_wallclock_testing_a-approx_time.$(OBJEXT) \ src/lib/wallclock/libtor_wallclock_testing_a-time_to_tm.$(OBJEXT) \ src/lib/wallclock/libtor_wallclock_testing_a-tor_gettimeofday.$(OBJEXT) -am_src_lib_libtor_wallclock_testing_a_OBJECTS = $(am__objects_86) +am_src_lib_libtor_wallclock_testing_a_OBJECTS = $(am__objects_90) src_lib_libtor_wallclock_testing_a_OBJECTS = \ $(am_src_lib_libtor_wallclock_testing_a_OBJECTS) src_lib_libtor_wallclock_a_AR = $(AR) $(ARFLAGS) @@ -2033,63 +2102,63 @@ src_test_fuzz_liboss_fuzz_address_a_LIBADD = am__src_test_fuzz_liboss_fuzz_address_a_SOURCES_DIST = \ src/test/fuzz/fuzzing_common.c src/test/fuzz/fuzz_address.c -@UNITTESTS_ENABLED_TRUE@am__objects_87 = src/test/fuzz/liboss_fuzz_address_a-fuzzing_common.$(OBJEXT) \ +@UNITTESTS_ENABLED_TRUE@am__objects_91 = src/test/fuzz/liboss_fuzz_address_a-fuzzing_common.$(OBJEXT) \ @UNITTESTS_ENABLED_TRUE@ src/test/fuzz/liboss_fuzz_address_a-fuzz_address.$(OBJEXT) -@OSS_FUZZ_ENABLED_TRUE@@UNITTESTS_ENABLED_TRUE@am_src_test_fuzz_liboss_fuzz_address_a_OBJECTS = $(am__objects_87) +@OSS_FUZZ_ENABLED_TRUE@@UNITTESTS_ENABLED_TRUE@am_src_test_fuzz_liboss_fuzz_address_a_OBJECTS = $(am__objects_91) src_test_fuzz_liboss_fuzz_address_a_OBJECTS = \ $(am_src_test_fuzz_liboss_fuzz_address_a_OBJECTS) src_test_fuzz_liboss_fuzz_addressPTR_a_AR = $(AR) $(ARFLAGS) src_test_fuzz_liboss_fuzz_addressPTR_a_LIBADD = am__src_test_fuzz_liboss_fuzz_addressPTR_a_SOURCES_DIST = \ src/test/fuzz/fuzzing_common.c src/test/fuzz/fuzz_addressPTR.c -@UNITTESTS_ENABLED_TRUE@am__objects_88 = src/test/fuzz/liboss_fuzz_addressPTR_a-fuzzing_common.$(OBJEXT) \ +@UNITTESTS_ENABLED_TRUE@am__objects_92 = src/test/fuzz/liboss_fuzz_addressPTR_a-fuzzing_common.$(OBJEXT) \ @UNITTESTS_ENABLED_TRUE@ src/test/fuzz/liboss_fuzz_addressPTR_a-fuzz_addressPTR.$(OBJEXT) -@OSS_FUZZ_ENABLED_TRUE@@UNITTESTS_ENABLED_TRUE@am_src_test_fuzz_liboss_fuzz_addressPTR_a_OBJECTS = $(am__objects_88) +@OSS_FUZZ_ENABLED_TRUE@@UNITTESTS_ENABLED_TRUE@am_src_test_fuzz_liboss_fuzz_addressPTR_a_OBJECTS = $(am__objects_92) src_test_fuzz_liboss_fuzz_addressPTR_a_OBJECTS = \ $(am_src_test_fuzz_liboss_fuzz_addressPTR_a_OBJECTS) src_test_fuzz_liboss_fuzz_consensus_a_AR = $(AR) $(ARFLAGS) src_test_fuzz_liboss_fuzz_consensus_a_LIBADD = am__src_test_fuzz_liboss_fuzz_consensus_a_SOURCES_DIST = \ src/test/fuzz/fuzzing_common.c src/test/fuzz/fuzz_consensus.c -@UNITTESTS_ENABLED_TRUE@am__objects_89 = src/test/fuzz/liboss_fuzz_consensus_a-fuzzing_common.$(OBJEXT) \ +@UNITTESTS_ENABLED_TRUE@am__objects_93 = src/test/fuzz/liboss_fuzz_consensus_a-fuzzing_common.$(OBJEXT) \ @UNITTESTS_ENABLED_TRUE@ src/test/fuzz/liboss_fuzz_consensus_a-fuzz_consensus.$(OBJEXT) -@OSS_FUZZ_ENABLED_TRUE@@UNITTESTS_ENABLED_TRUE@am_src_test_fuzz_liboss_fuzz_consensus_a_OBJECTS = $(am__objects_89) +@OSS_FUZZ_ENABLED_TRUE@@UNITTESTS_ENABLED_TRUE@am_src_test_fuzz_liboss_fuzz_consensus_a_OBJECTS = $(am__objects_93) src_test_fuzz_liboss_fuzz_consensus_a_OBJECTS = \ $(am_src_test_fuzz_liboss_fuzz_consensus_a_OBJECTS) src_test_fuzz_liboss_fuzz_descriptor_a_AR = $(AR) $(ARFLAGS) src_test_fuzz_liboss_fuzz_descriptor_a_LIBADD = am__src_test_fuzz_liboss_fuzz_descriptor_a_SOURCES_DIST = \ src/test/fuzz/fuzzing_common.c src/test/fuzz/fuzz_descriptor.c -@UNITTESTS_ENABLED_TRUE@am__objects_90 = src/test/fuzz/liboss_fuzz_descriptor_a-fuzzing_common.$(OBJEXT) \ +@UNITTESTS_ENABLED_TRUE@am__objects_94 = src/test/fuzz/liboss_fuzz_descriptor_a-fuzzing_common.$(OBJEXT) \ @UNITTESTS_ENABLED_TRUE@ src/test/fuzz/liboss_fuzz_descriptor_a-fuzz_descriptor.$(OBJEXT) -@OSS_FUZZ_ENABLED_TRUE@@UNITTESTS_ENABLED_TRUE@am_src_test_fuzz_liboss_fuzz_descriptor_a_OBJECTS = $(am__objects_90) +@OSS_FUZZ_ENABLED_TRUE@@UNITTESTS_ENABLED_TRUE@am_src_test_fuzz_liboss_fuzz_descriptor_a_OBJECTS = $(am__objects_94) src_test_fuzz_liboss_fuzz_descriptor_a_OBJECTS = \ $(am_src_test_fuzz_liboss_fuzz_descriptor_a_OBJECTS) src_test_fuzz_liboss_fuzz_diff_apply_a_AR = $(AR) $(ARFLAGS) src_test_fuzz_liboss_fuzz_diff_apply_a_LIBADD = am__src_test_fuzz_liboss_fuzz_diff_apply_a_SOURCES_DIST = \ src/test/fuzz/fuzzing_common.c src/test/fuzz/fuzz_diff_apply.c -@UNITTESTS_ENABLED_TRUE@am__objects_91 = src/test/fuzz/liboss_fuzz_diff_apply_a-fuzzing_common.$(OBJEXT) \ +@UNITTESTS_ENABLED_TRUE@am__objects_95 = src/test/fuzz/liboss_fuzz_diff_apply_a-fuzzing_common.$(OBJEXT) \ @UNITTESTS_ENABLED_TRUE@ src/test/fuzz/liboss_fuzz_diff_apply_a-fuzz_diff_apply.$(OBJEXT) -@OSS_FUZZ_ENABLED_TRUE@@UNITTESTS_ENABLED_TRUE@am_src_test_fuzz_liboss_fuzz_diff_apply_a_OBJECTS = $(am__objects_91) +@OSS_FUZZ_ENABLED_TRUE@@UNITTESTS_ENABLED_TRUE@am_src_test_fuzz_liboss_fuzz_diff_apply_a_OBJECTS = $(am__objects_95) src_test_fuzz_liboss_fuzz_diff_apply_a_OBJECTS = \ $(am_src_test_fuzz_liboss_fuzz_diff_apply_a_OBJECTS) src_test_fuzz_liboss_fuzz_diff_a_AR = $(AR) $(ARFLAGS) src_test_fuzz_liboss_fuzz_diff_a_LIBADD = am__src_test_fuzz_liboss_fuzz_diff_a_SOURCES_DIST = \ src/test/fuzz/fuzzing_common.c src/test/fuzz/fuzz_diff.c -@UNITTESTS_ENABLED_TRUE@am__objects_92 = src/test/fuzz/liboss_fuzz_diff_a-fuzzing_common.$(OBJEXT) \ +@UNITTESTS_ENABLED_TRUE@am__objects_96 = src/test/fuzz/liboss_fuzz_diff_a-fuzzing_common.$(OBJEXT) \ @UNITTESTS_ENABLED_TRUE@ src/test/fuzz/liboss_fuzz_diff_a-fuzz_diff.$(OBJEXT) -@OSS_FUZZ_ENABLED_TRUE@@UNITTESTS_ENABLED_TRUE@am_src_test_fuzz_liboss_fuzz_diff_a_OBJECTS = $(am__objects_92) +@OSS_FUZZ_ENABLED_TRUE@@UNITTESTS_ENABLED_TRUE@am_src_test_fuzz_liboss_fuzz_diff_a_OBJECTS = $(am__objects_96) src_test_fuzz_liboss_fuzz_diff_a_OBJECTS = \ $(am_src_test_fuzz_liboss_fuzz_diff_a_OBJECTS) src_test_fuzz_liboss_fuzz_extrainfo_a_AR = $(AR) $(ARFLAGS) src_test_fuzz_liboss_fuzz_extrainfo_a_LIBADD = am__src_test_fuzz_liboss_fuzz_extrainfo_a_SOURCES_DIST = \ src/test/fuzz/fuzzing_common.c src/test/fuzz/fuzz_extrainfo.c -@UNITTESTS_ENABLED_TRUE@am__objects_93 = src/test/fuzz/liboss_fuzz_extrainfo_a-fuzzing_common.$(OBJEXT) \ +@UNITTESTS_ENABLED_TRUE@am__objects_97 = src/test/fuzz/liboss_fuzz_extrainfo_a-fuzzing_common.$(OBJEXT) \ @UNITTESTS_ENABLED_TRUE@ src/test/fuzz/liboss_fuzz_extrainfo_a-fuzz_extrainfo.$(OBJEXT) -@OSS_FUZZ_ENABLED_TRUE@@UNITTESTS_ENABLED_TRUE@am_src_test_fuzz_liboss_fuzz_extrainfo_a_OBJECTS = $(am__objects_93) +@OSS_FUZZ_ENABLED_TRUE@@UNITTESTS_ENABLED_TRUE@am_src_test_fuzz_liboss_fuzz_extrainfo_a_OBJECTS = $(am__objects_97) src_test_fuzz_liboss_fuzz_extrainfo_a_OBJECTS = \ $(am_src_test_fuzz_liboss_fuzz_extrainfo_a_OBJECTS) src_test_fuzz_liboss_fuzz_hsdescv3_inner_a_AR = $(AR) $(ARFLAGS) @@ -2097,9 +2166,9 @@ am__src_test_fuzz_liboss_fuzz_hsdescv3_inner_a_SOURCES_DIST = \ src/test/fuzz/fuzzing_common.c \ src/test/fuzz/fuzz_hsdescv3_inner.c -@UNITTESTS_ENABLED_TRUE@am__objects_94 = src/test/fuzz/liboss_fuzz_hsdescv3_inner_a-fuzzing_common.$(OBJEXT) \ +@UNITTESTS_ENABLED_TRUE@am__objects_98 = src/test/fuzz/liboss_fuzz_hsdescv3_inner_a-fuzzing_common.$(OBJEXT) \ @UNITTESTS_ENABLED_TRUE@ src/test/fuzz/liboss_fuzz_hsdescv3_inner_a-fuzz_hsdescv3_inner.$(OBJEXT) -@OSS_FUZZ_ENABLED_TRUE@@UNITTESTS_ENABLED_TRUE@am_src_test_fuzz_liboss_fuzz_hsdescv3_inner_a_OBJECTS = $(am__objects_94) +@OSS_FUZZ_ENABLED_TRUE@@UNITTESTS_ENABLED_TRUE@am_src_test_fuzz_liboss_fuzz_hsdescv3_inner_a_OBJECTS = $(am__objects_98) src_test_fuzz_liboss_fuzz_hsdescv3_inner_a_OBJECTS = \ $(am_src_test_fuzz_liboss_fuzz_hsdescv3_inner_a_OBJECTS) src_test_fuzz_liboss_fuzz_hsdescv3_middle_a_AR = $(AR) $(ARFLAGS) @@ -2107,18 +2176,18 @@ am__src_test_fuzz_liboss_fuzz_hsdescv3_middle_a_SOURCES_DIST = \ src/test/fuzz/fuzzing_common.c \ src/test/fuzz/fuzz_hsdescv3_middle.c -@UNITTESTS_ENABLED_TRUE@am__objects_95 = src/test/fuzz/liboss_fuzz_hsdescv3_middle_a-fuzzing_common.$(OBJEXT) \ +@UNITTESTS_ENABLED_TRUE@am__objects_99 = src/test/fuzz/liboss_fuzz_hsdescv3_middle_a-fuzzing_common.$(OBJEXT) \ @UNITTESTS_ENABLED_TRUE@ src/test/fuzz/liboss_fuzz_hsdescv3_middle_a-fuzz_hsdescv3_middle.$(OBJEXT) -@OSS_FUZZ_ENABLED_TRUE@@UNITTESTS_ENABLED_TRUE@am_src_test_fuzz_liboss_fuzz_hsdescv3_middle_a_OBJECTS = $(am__objects_95) +@OSS_FUZZ_ENABLED_TRUE@@UNITTESTS_ENABLED_TRUE@am_src_test_fuzz_liboss_fuzz_hsdescv3_middle_a_OBJECTS = $(am__objects_99) src_test_fuzz_liboss_fuzz_hsdescv3_middle_a_OBJECTS = \ $(am_src_test_fuzz_liboss_fuzz_hsdescv3_middle_a_OBJECTS) src_test_fuzz_liboss_fuzz_hsdescv3_a_AR = $(AR) $(ARFLAGS) src_test_fuzz_liboss_fuzz_hsdescv3_a_LIBADD = am__src_test_fuzz_liboss_fuzz_hsdescv3_a_SOURCES_DIST = \ src/test/fuzz/fuzzing_common.c src/test/fuzz/fuzz_hsdescv3.c -@UNITTESTS_ENABLED_TRUE@am__objects_96 = src/test/fuzz/liboss_fuzz_hsdescv3_a-fuzzing_common.$(OBJEXT) \ +@UNITTESTS_ENABLED_TRUE@am__objects_100 = src/test/fuzz/liboss_fuzz_hsdescv3_a-fuzzing_common.$(OBJEXT) \ @UNITTESTS_ENABLED_TRUE@ src/test/fuzz/liboss_fuzz_hsdescv3_a-fuzz_hsdescv3.$(OBJEXT) -@OSS_FUZZ_ENABLED_TRUE@@UNITTESTS_ENABLED_TRUE@am_src_test_fuzz_liboss_fuzz_hsdescv3_a_OBJECTS = $(am__objects_96) +@OSS_FUZZ_ENABLED_TRUE@@UNITTESTS_ENABLED_TRUE@am_src_test_fuzz_liboss_fuzz_hsdescv3_a_OBJECTS = $(am__objects_100) src_test_fuzz_liboss_fuzz_hsdescv3_a_OBJECTS = \ $(am_src_test_fuzz_liboss_fuzz_hsdescv3_a_OBJECTS) src_test_fuzz_liboss_fuzz_http_connect_a_AR = $(AR) $(ARFLAGS) @@ -2126,54 +2195,54 @@ am__src_test_fuzz_liboss_fuzz_http_connect_a_SOURCES_DIST = \ src/test/fuzz/fuzzing_common.c \ src/test/fuzz/fuzz_http_connect.c -@UNITTESTS_ENABLED_TRUE@am__objects_97 = src/test/fuzz/liboss_fuzz_http_connect_a-fuzzing_common.$(OBJEXT) \ +@UNITTESTS_ENABLED_TRUE@am__objects_101 = src/test/fuzz/liboss_fuzz_http_connect_a-fuzzing_common.$(OBJEXT) \ @UNITTESTS_ENABLED_TRUE@ src/test/fuzz/liboss_fuzz_http_connect_a-fuzz_http_connect.$(OBJEXT) -@OSS_FUZZ_ENABLED_TRUE@@UNITTESTS_ENABLED_TRUE@am_src_test_fuzz_liboss_fuzz_http_connect_a_OBJECTS = $(am__objects_97) +@OSS_FUZZ_ENABLED_TRUE@@UNITTESTS_ENABLED_TRUE@am_src_test_fuzz_liboss_fuzz_http_connect_a_OBJECTS = $(am__objects_101) src_test_fuzz_liboss_fuzz_http_connect_a_OBJECTS = \ $(am_src_test_fuzz_liboss_fuzz_http_connect_a_OBJECTS) src_test_fuzz_liboss_fuzz_http_a_AR = $(AR) $(ARFLAGS) src_test_fuzz_liboss_fuzz_http_a_LIBADD = am__src_test_fuzz_liboss_fuzz_http_a_SOURCES_DIST = \ src/test/fuzz/fuzzing_common.c src/test/fuzz/fuzz_http.c -@UNITTESTS_ENABLED_TRUE@am__objects_98 = src/test/fuzz/liboss_fuzz_http_a-fuzzing_common.$(OBJEXT) \ +@UNITTESTS_ENABLED_TRUE@am__objects_102 = src/test/fuzz/liboss_fuzz_http_a-fuzzing_common.$(OBJEXT) \ @UNITTESTS_ENABLED_TRUE@ src/test/fuzz/liboss_fuzz_http_a-fuzz_http.$(OBJEXT) -@OSS_FUZZ_ENABLED_TRUE@@UNITTESTS_ENABLED_TRUE@am_src_test_fuzz_liboss_fuzz_http_a_OBJECTS = $(am__objects_98) +@OSS_FUZZ_ENABLED_TRUE@@UNITTESTS_ENABLED_TRUE@am_src_test_fuzz_liboss_fuzz_http_a_OBJECTS = $(am__objects_102) src_test_fuzz_liboss_fuzz_http_a_OBJECTS = \ $(am_src_test_fuzz_liboss_fuzz_http_a_OBJECTS) src_test_fuzz_liboss_fuzz_microdesc_a_AR = $(AR) $(ARFLAGS) src_test_fuzz_liboss_fuzz_microdesc_a_LIBADD = am__src_test_fuzz_liboss_fuzz_microdesc_a_SOURCES_DIST = \ src/test/fuzz/fuzzing_common.c src/test/fuzz/fuzz_microdesc.c -@UNITTESTS_ENABLED_TRUE@am__objects_99 = src/test/fuzz/liboss_fuzz_microdesc_a-fuzzing_common.$(OBJEXT) \ +@UNITTESTS_ENABLED_TRUE@am__objects_103 = src/test/fuzz/liboss_fuzz_microdesc_a-fuzzing_common.$(OBJEXT) \ @UNITTESTS_ENABLED_TRUE@ src/test/fuzz/liboss_fuzz_microdesc_a-fuzz_microdesc.$(OBJEXT) -@OSS_FUZZ_ENABLED_TRUE@@UNITTESTS_ENABLED_TRUE@am_src_test_fuzz_liboss_fuzz_microdesc_a_OBJECTS = $(am__objects_99) +@OSS_FUZZ_ENABLED_TRUE@@UNITTESTS_ENABLED_TRUE@am_src_test_fuzz_liboss_fuzz_microdesc_a_OBJECTS = $(am__objects_103) src_test_fuzz_liboss_fuzz_microdesc_a_OBJECTS = \ $(am_src_test_fuzz_liboss_fuzz_microdesc_a_OBJECTS) src_test_fuzz_liboss_fuzz_socks_a_AR = $(AR) $(ARFLAGS) src_test_fuzz_liboss_fuzz_socks_a_LIBADD = am__src_test_fuzz_liboss_fuzz_socks_a_SOURCES_DIST = \ src/test/fuzz/fuzzing_common.c src/test/fuzz/fuzz_socks.c -@UNITTESTS_ENABLED_TRUE@am__objects_100 = src/test/fuzz/liboss_fuzz_socks_a-fuzzing_common.$(OBJEXT) \ +@UNITTESTS_ENABLED_TRUE@am__objects_104 = src/test/fuzz/liboss_fuzz_socks_a-fuzzing_common.$(OBJEXT) \ @UNITTESTS_ENABLED_TRUE@ src/test/fuzz/liboss_fuzz_socks_a-fuzz_socks.$(OBJEXT) -@OSS_FUZZ_ENABLED_TRUE@@UNITTESTS_ENABLED_TRUE@am_src_test_fuzz_liboss_fuzz_socks_a_OBJECTS = $(am__objects_100) +@OSS_FUZZ_ENABLED_TRUE@@UNITTESTS_ENABLED_TRUE@am_src_test_fuzz_liboss_fuzz_socks_a_OBJECTS = $(am__objects_104) src_test_fuzz_liboss_fuzz_socks_a_OBJECTS = \ $(am_src_test_fuzz_liboss_fuzz_socks_a_OBJECTS) src_test_fuzz_liboss_fuzz_strops_a_AR = $(AR) $(ARFLAGS) src_test_fuzz_liboss_fuzz_strops_a_LIBADD = am__src_test_fuzz_liboss_fuzz_strops_a_SOURCES_DIST = \ src/test/fuzz/fuzzing_common.c src/test/fuzz/fuzz_strops.c -@UNITTESTS_ENABLED_TRUE@am__objects_101 = src/test/fuzz/liboss_fuzz_strops_a-fuzzing_common.$(OBJEXT) \ +@UNITTESTS_ENABLED_TRUE@am__objects_105 = src/test/fuzz/liboss_fuzz_strops_a-fuzzing_common.$(OBJEXT) \ @UNITTESTS_ENABLED_TRUE@ src/test/fuzz/liboss_fuzz_strops_a-fuzz_strops.$(OBJEXT) -@OSS_FUZZ_ENABLED_TRUE@@UNITTESTS_ENABLED_TRUE@am_src_test_fuzz_liboss_fuzz_strops_a_OBJECTS = $(am__objects_101) +@OSS_FUZZ_ENABLED_TRUE@@UNITTESTS_ENABLED_TRUE@am_src_test_fuzz_liboss_fuzz_strops_a_OBJECTS = $(am__objects_105) src_test_fuzz_liboss_fuzz_strops_a_OBJECTS = \ $(am_src_test_fuzz_liboss_fuzz_strops_a_OBJECTS) src_test_fuzz_liboss_fuzz_vrs_a_AR = $(AR) $(ARFLAGS) src_test_fuzz_liboss_fuzz_vrs_a_LIBADD = am__src_test_fuzz_liboss_fuzz_vrs_a_SOURCES_DIST = \ src/test/fuzz/fuzzing_common.c src/test/fuzz/fuzz_vrs.c -@UNITTESTS_ENABLED_TRUE@am__objects_102 = src/test/fuzz/liboss_fuzz_vrs_a-fuzzing_common.$(OBJEXT) \ +@UNITTESTS_ENABLED_TRUE@am__objects_106 = src/test/fuzz/liboss_fuzz_vrs_a-fuzzing_common.$(OBJEXT) \ @UNITTESTS_ENABLED_TRUE@ src/test/fuzz/liboss_fuzz_vrs_a-fuzz_vrs.$(OBJEXT) -@OSS_FUZZ_ENABLED_TRUE@@UNITTESTS_ENABLED_TRUE@am_src_test_fuzz_liboss_fuzz_vrs_a_OBJECTS = $(am__objects_102) +@OSS_FUZZ_ENABLED_TRUE@@UNITTESTS_ENABLED_TRUE@am_src_test_fuzz_liboss_fuzz_vrs_a_OBJECTS = $(am__objects_106) src_test_fuzz_liboss_fuzz_vrs_a_OBJECTS = \ $(am_src_test_fuzz_liboss_fuzz_vrs_a_OBJECTS) src_tools_libtorrunner_a_AR = $(AR) $(ARFLAGS) @@ -2196,8 +2265,9 @@ src/trunnel/channelpadding_negotiation.c \ src/trunnel/sendme_cell.c src/trunnel/flow_control_cells.c \ src/trunnel/congestion_control.c src/trunnel/socks5.c \ - src/trunnel/netinfo.c src/trunnel/circpad_negotiation.c -am__objects_103 = src/ext/trunnel/trunnel_libor_trunnel_testing_a-trunnel.$(OBJEXT) \ + src/trunnel/netinfo.c src/trunnel/circpad_negotiation.c \ + src/trunnel/conflux.c src/trunnel/subproto_request.c +am__objects_107 = src/ext/trunnel/trunnel_libor_trunnel_testing_a-trunnel.$(OBJEXT) \ src/trunnel/libor_trunnel_testing_a-ed25519_cert.$(OBJEXT) \ src/trunnel/libor_trunnel_testing_a-extension.$(OBJEXT) \ src/trunnel/libor_trunnel_testing_a-link_handshake.$(OBJEXT) \ @@ -2211,14 +2281,16 @@ src/trunnel/libor_trunnel_testing_a-congestion_control.$(OBJEXT) \ src/trunnel/libor_trunnel_testing_a-socks5.$(OBJEXT) \ src/trunnel/libor_trunnel_testing_a-netinfo.$(OBJEXT) \ - src/trunnel/libor_trunnel_testing_a-circpad_negotiation.$(OBJEXT) + src/trunnel/libor_trunnel_testing_a-circpad_negotiation.$(OBJEXT) \ + src/trunnel/libor_trunnel_testing_a-conflux.$(OBJEXT) \ + src/trunnel/libor_trunnel_testing_a-subproto_request.$(OBJEXT) @UNITTESTS_ENABLED_TRUE@am_src_trunnel_libor_trunnel_testing_a_OBJECTS = \ -@UNITTESTS_ENABLED_TRUE@ $(am__objects_103) +@UNITTESTS_ENABLED_TRUE@ $(am__objects_107) src_trunnel_libor_trunnel_testing_a_OBJECTS = \ $(am_src_trunnel_libor_trunnel_testing_a_OBJECTS) src_trunnel_libor_trunnel_a_AR = $(AR) $(ARFLAGS) src_trunnel_libor_trunnel_a_LIBADD = -am__objects_104 = \ +am__objects_108 = \ src/ext/trunnel/trunnel_libor_trunnel_a-trunnel.$(OBJEXT) \ src/trunnel/libor_trunnel_a-ed25519_cert.$(OBJEXT) \ src/trunnel/libor_trunnel_a-extension.$(OBJEXT) \ @@ -2233,8 +2305,10 @@ src/trunnel/libor_trunnel_a-congestion_control.$(OBJEXT) \ src/trunnel/libor_trunnel_a-socks5.$(OBJEXT) \ src/trunnel/libor_trunnel_a-netinfo.$(OBJEXT) \ - src/trunnel/libor_trunnel_a-circpad_negotiation.$(OBJEXT) -am_src_trunnel_libor_trunnel_a_OBJECTS = $(am__objects_104) + src/trunnel/libor_trunnel_a-circpad_negotiation.$(OBJEXT) \ + src/trunnel/libor_trunnel_a-conflux.$(OBJEXT) \ + src/trunnel/libor_trunnel_a-subproto_request.$(OBJEXT) +am_src_trunnel_libor_trunnel_a_OBJECTS = $(am__objects_108) src_trunnel_libor_trunnel_a_OBJECTS = \ $(am_src_trunnel_libor_trunnel_a_OBJECTS) am_src_app_tor_OBJECTS = src/app/main/tor_main.$(OBJEXT) @@ -2245,9 +2319,9 @@ src_app_tor_LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(src_app_tor_LDFLAGS) $(LDFLAGS) -o $@ am__src_app_tor_cov_SOURCES_DIST = src/app/main/tor_main.c -am__objects_105 = src/app/main/tor_cov-tor_main.$(OBJEXT) +am__objects_109 = src/app/main/tor_cov-tor_main.$(OBJEXT) @COVERAGE_ENABLED_TRUE@am_src_app_tor_cov_OBJECTS = \ -@COVERAGE_ENABLED_TRUE@ $(am__objects_105) +@COVERAGE_ENABLED_TRUE@ $(am__objects_109) src_app_tor_cov_OBJECTS = $(am_src_app_tor_cov_OBJECTS) @COVERAGE_ENABLED_TRUE@src_app_tor_cov_DEPENDENCIES = \ @COVERAGE_ENABLED_TRUE@ src/test/libtor-testing.a \ @@ -2439,9 +2513,9 @@ $(CFLAGS) $(src_test_fuzz_fuzz_vrs_LDFLAGS) $(LDFLAGS) -o $@ am__src_test_fuzz_lf_fuzz_address_SOURCES_DIST = \ src/test/fuzz/fuzzing_common.c src/test/fuzz/fuzz_address.c -@UNITTESTS_ENABLED_TRUE@am__objects_106 = src/test/fuzz/lf_fuzz_address-fuzzing_common.$(OBJEXT) \ +@UNITTESTS_ENABLED_TRUE@am__objects_110 = src/test/fuzz/lf_fuzz_address-fuzzing_common.$(OBJEXT) \ @UNITTESTS_ENABLED_TRUE@ src/test/fuzz/lf_fuzz_address-fuzz_address.$(OBJEXT) -@LIBFUZZER_ENABLED_TRUE@@UNITTESTS_ENABLED_TRUE@am_src_test_fuzz_lf_fuzz_address_OBJECTS = $(am__objects_106) +@LIBFUZZER_ENABLED_TRUE@@UNITTESTS_ENABLED_TRUE@am_src_test_fuzz_lf_fuzz_address_OBJECTS = $(am__objects_110) src_test_fuzz_lf_fuzz_address_OBJECTS = \ $(am_src_test_fuzz_lf_fuzz_address_OBJECTS) am__DEPENDENCIES_4 = $(am__DEPENDENCIES_3) @@ -2451,9 +2525,9 @@ $(src_test_fuzz_lf_fuzz_address_LDFLAGS) $(LDFLAGS) -o $@ am__src_test_fuzz_lf_fuzz_addressPTR_SOURCES_DIST = \ src/test/fuzz/fuzzing_common.c src/test/fuzz/fuzz_addressPTR.c -@UNITTESTS_ENABLED_TRUE@am__objects_107 = src/test/fuzz/lf_fuzz_addressPTR-fuzzing_common.$(OBJEXT) \ +@UNITTESTS_ENABLED_TRUE@am__objects_111 = src/test/fuzz/lf_fuzz_addressPTR-fuzzing_common.$(OBJEXT) \ @UNITTESTS_ENABLED_TRUE@ src/test/fuzz/lf_fuzz_addressPTR-fuzz_addressPTR.$(OBJEXT) -@LIBFUZZER_ENABLED_TRUE@@UNITTESTS_ENABLED_TRUE@am_src_test_fuzz_lf_fuzz_addressPTR_OBJECTS = $(am__objects_107) +@LIBFUZZER_ENABLED_TRUE@@UNITTESTS_ENABLED_TRUE@am_src_test_fuzz_lf_fuzz_addressPTR_OBJECTS = $(am__objects_111) src_test_fuzz_lf_fuzz_addressPTR_OBJECTS = \ $(am_src_test_fuzz_lf_fuzz_addressPTR_OBJECTS) @LIBFUZZER_ENABLED_TRUE@@UNITTESTS_ENABLED_TRUE@src_test_fuzz_lf_fuzz_addressPTR_DEPENDENCIES = $(am__DEPENDENCIES_4) @@ -2462,9 +2536,9 @@ $(src_test_fuzz_lf_fuzz_addressPTR_LDFLAGS) $(LDFLAGS) -o $@ am__src_test_fuzz_lf_fuzz_consensus_SOURCES_DIST = \ src/test/fuzz/fuzzing_common.c src/test/fuzz/fuzz_consensus.c -@UNITTESTS_ENABLED_TRUE@am__objects_108 = src/test/fuzz/lf_fuzz_consensus-fuzzing_common.$(OBJEXT) \ +@UNITTESTS_ENABLED_TRUE@am__objects_112 = src/test/fuzz/lf_fuzz_consensus-fuzzing_common.$(OBJEXT) \ @UNITTESTS_ENABLED_TRUE@ src/test/fuzz/lf_fuzz_consensus-fuzz_consensus.$(OBJEXT) -@LIBFUZZER_ENABLED_TRUE@@UNITTESTS_ENABLED_TRUE@am_src_test_fuzz_lf_fuzz_consensus_OBJECTS = $(am__objects_108) +@LIBFUZZER_ENABLED_TRUE@@UNITTESTS_ENABLED_TRUE@am_src_test_fuzz_lf_fuzz_consensus_OBJECTS = $(am__objects_112) src_test_fuzz_lf_fuzz_consensus_OBJECTS = \ $(am_src_test_fuzz_lf_fuzz_consensus_OBJECTS) @LIBFUZZER_ENABLED_TRUE@@UNITTESTS_ENABLED_TRUE@src_test_fuzz_lf_fuzz_consensus_DEPENDENCIES = $(am__DEPENDENCIES_4) @@ -2473,9 +2547,9 @@ $(src_test_fuzz_lf_fuzz_consensus_LDFLAGS) $(LDFLAGS) -o $@ am__src_test_fuzz_lf_fuzz_descriptor_SOURCES_DIST = \ src/test/fuzz/fuzzing_common.c src/test/fuzz/fuzz_descriptor.c -@UNITTESTS_ENABLED_TRUE@am__objects_109 = src/test/fuzz/lf_fuzz_descriptor-fuzzing_common.$(OBJEXT) \ +@UNITTESTS_ENABLED_TRUE@am__objects_113 = src/test/fuzz/lf_fuzz_descriptor-fuzzing_common.$(OBJEXT) \ @UNITTESTS_ENABLED_TRUE@ src/test/fuzz/lf_fuzz_descriptor-fuzz_descriptor.$(OBJEXT) -@LIBFUZZER_ENABLED_TRUE@@UNITTESTS_ENABLED_TRUE@am_src_test_fuzz_lf_fuzz_descriptor_OBJECTS = $(am__objects_109) +@LIBFUZZER_ENABLED_TRUE@@UNITTESTS_ENABLED_TRUE@am_src_test_fuzz_lf_fuzz_descriptor_OBJECTS = $(am__objects_113) src_test_fuzz_lf_fuzz_descriptor_OBJECTS = \ $(am_src_test_fuzz_lf_fuzz_descriptor_OBJECTS) @LIBFUZZER_ENABLED_TRUE@@UNITTESTS_ENABLED_TRUE@src_test_fuzz_lf_fuzz_descriptor_DEPENDENCIES = $(am__DEPENDENCIES_4) @@ -2484,9 +2558,9 @@ $(src_test_fuzz_lf_fuzz_descriptor_LDFLAGS) $(LDFLAGS) -o $@ am__src_test_fuzz_lf_fuzz_diff_SOURCES_DIST = \ src/test/fuzz/fuzzing_common.c src/test/fuzz/fuzz_diff.c -@UNITTESTS_ENABLED_TRUE@am__objects_110 = src/test/fuzz/lf_fuzz_diff-fuzzing_common.$(OBJEXT) \ +@UNITTESTS_ENABLED_TRUE@am__objects_114 = src/test/fuzz/lf_fuzz_diff-fuzzing_common.$(OBJEXT) \ @UNITTESTS_ENABLED_TRUE@ src/test/fuzz/lf_fuzz_diff-fuzz_diff.$(OBJEXT) -@LIBFUZZER_ENABLED_TRUE@@UNITTESTS_ENABLED_TRUE@am_src_test_fuzz_lf_fuzz_diff_OBJECTS = $(am__objects_110) +@LIBFUZZER_ENABLED_TRUE@@UNITTESTS_ENABLED_TRUE@am_src_test_fuzz_lf_fuzz_diff_OBJECTS = $(am__objects_114) src_test_fuzz_lf_fuzz_diff_OBJECTS = \ $(am_src_test_fuzz_lf_fuzz_diff_OBJECTS) @LIBFUZZER_ENABLED_TRUE@@UNITTESTS_ENABLED_TRUE@src_test_fuzz_lf_fuzz_diff_DEPENDENCIES = $(am__DEPENDENCIES_4) @@ -2495,9 +2569,9 @@ $(src_test_fuzz_lf_fuzz_diff_LDFLAGS) $(LDFLAGS) -o $@ am__src_test_fuzz_lf_fuzz_diff_apply_SOURCES_DIST = \ src/test/fuzz/fuzzing_common.c src/test/fuzz/fuzz_diff_apply.c -@UNITTESTS_ENABLED_TRUE@am__objects_111 = src/test/fuzz/lf_fuzz_diff_apply-fuzzing_common.$(OBJEXT) \ +@UNITTESTS_ENABLED_TRUE@am__objects_115 = src/test/fuzz/lf_fuzz_diff_apply-fuzzing_common.$(OBJEXT) \ @UNITTESTS_ENABLED_TRUE@ src/test/fuzz/lf_fuzz_diff_apply-fuzz_diff_apply.$(OBJEXT) -@LIBFUZZER_ENABLED_TRUE@@UNITTESTS_ENABLED_TRUE@am_src_test_fuzz_lf_fuzz_diff_apply_OBJECTS = $(am__objects_111) +@LIBFUZZER_ENABLED_TRUE@@UNITTESTS_ENABLED_TRUE@am_src_test_fuzz_lf_fuzz_diff_apply_OBJECTS = $(am__objects_115) src_test_fuzz_lf_fuzz_diff_apply_OBJECTS = \ $(am_src_test_fuzz_lf_fuzz_diff_apply_OBJECTS) @LIBFUZZER_ENABLED_TRUE@@UNITTESTS_ENABLED_TRUE@src_test_fuzz_lf_fuzz_diff_apply_DEPENDENCIES = $(am__DEPENDENCIES_4) @@ -2506,9 +2580,9 @@ $(src_test_fuzz_lf_fuzz_diff_apply_LDFLAGS) $(LDFLAGS) -o $@ am__src_test_fuzz_lf_fuzz_extrainfo_SOURCES_DIST = \ src/test/fuzz/fuzzing_common.c src/test/fuzz/fuzz_extrainfo.c -@UNITTESTS_ENABLED_TRUE@am__objects_112 = src/test/fuzz/lf_fuzz_extrainfo-fuzzing_common.$(OBJEXT) \ +@UNITTESTS_ENABLED_TRUE@am__objects_116 = src/test/fuzz/lf_fuzz_extrainfo-fuzzing_common.$(OBJEXT) \ @UNITTESTS_ENABLED_TRUE@ src/test/fuzz/lf_fuzz_extrainfo-fuzz_extrainfo.$(OBJEXT) -@LIBFUZZER_ENABLED_TRUE@@UNITTESTS_ENABLED_TRUE@am_src_test_fuzz_lf_fuzz_extrainfo_OBJECTS = $(am__objects_112) +@LIBFUZZER_ENABLED_TRUE@@UNITTESTS_ENABLED_TRUE@am_src_test_fuzz_lf_fuzz_extrainfo_OBJECTS = $(am__objects_116) src_test_fuzz_lf_fuzz_extrainfo_OBJECTS = \ $(am_src_test_fuzz_lf_fuzz_extrainfo_OBJECTS) @LIBFUZZER_ENABLED_TRUE@@UNITTESTS_ENABLED_TRUE@src_test_fuzz_lf_fuzz_extrainfo_DEPENDENCIES = $(am__DEPENDENCIES_4) @@ -2517,9 +2591,9 @@ $(src_test_fuzz_lf_fuzz_extrainfo_LDFLAGS) $(LDFLAGS) -o $@ am__src_test_fuzz_lf_fuzz_hsdescv3_SOURCES_DIST = \ src/test/fuzz/fuzzing_common.c src/test/fuzz/fuzz_hsdescv3.c -@UNITTESTS_ENABLED_TRUE@am__objects_113 = src/test/fuzz/lf_fuzz_hsdescv3-fuzzing_common.$(OBJEXT) \ +@UNITTESTS_ENABLED_TRUE@am__objects_117 = src/test/fuzz/lf_fuzz_hsdescv3-fuzzing_common.$(OBJEXT) \ @UNITTESTS_ENABLED_TRUE@ src/test/fuzz/lf_fuzz_hsdescv3-fuzz_hsdescv3.$(OBJEXT) -@LIBFUZZER_ENABLED_TRUE@@UNITTESTS_ENABLED_TRUE@am_src_test_fuzz_lf_fuzz_hsdescv3_OBJECTS = $(am__objects_113) +@LIBFUZZER_ENABLED_TRUE@@UNITTESTS_ENABLED_TRUE@am_src_test_fuzz_lf_fuzz_hsdescv3_OBJECTS = $(am__objects_117) src_test_fuzz_lf_fuzz_hsdescv3_OBJECTS = \ $(am_src_test_fuzz_lf_fuzz_hsdescv3_OBJECTS) @LIBFUZZER_ENABLED_TRUE@@UNITTESTS_ENABLED_TRUE@src_test_fuzz_lf_fuzz_hsdescv3_DEPENDENCIES = $(am__DEPENDENCIES_4) @@ -2529,9 +2603,9 @@ am__src_test_fuzz_lf_fuzz_hsdescv3_inner_SOURCES_DIST = \ src/test/fuzz/fuzzing_common.c \ src/test/fuzz/fuzz_hsdescv3_inner.c -@UNITTESTS_ENABLED_TRUE@am__objects_114 = src/test/fuzz/lf_fuzz_hsdescv3_inner-fuzzing_common.$(OBJEXT) \ +@UNITTESTS_ENABLED_TRUE@am__objects_118 = src/test/fuzz/lf_fuzz_hsdescv3_inner-fuzzing_common.$(OBJEXT) \ @UNITTESTS_ENABLED_TRUE@ src/test/fuzz/lf_fuzz_hsdescv3_inner-fuzz_hsdescv3_inner.$(OBJEXT) -@LIBFUZZER_ENABLED_TRUE@@UNITTESTS_ENABLED_TRUE@am_src_test_fuzz_lf_fuzz_hsdescv3_inner_OBJECTS = $(am__objects_114) +@LIBFUZZER_ENABLED_TRUE@@UNITTESTS_ENABLED_TRUE@am_src_test_fuzz_lf_fuzz_hsdescv3_inner_OBJECTS = $(am__objects_118) src_test_fuzz_lf_fuzz_hsdescv3_inner_OBJECTS = \ $(am_src_test_fuzz_lf_fuzz_hsdescv3_inner_OBJECTS) @LIBFUZZER_ENABLED_TRUE@@UNITTESTS_ENABLED_TRUE@src_test_fuzz_lf_fuzz_hsdescv3_inner_DEPENDENCIES = $(am__DEPENDENCIES_4) @@ -2542,9 +2616,9 @@ am__src_test_fuzz_lf_fuzz_hsdescv3_middle_SOURCES_DIST = \ src/test/fuzz/fuzzing_common.c \ src/test/fuzz/fuzz_hsdescv3_middle.c -@UNITTESTS_ENABLED_TRUE@am__objects_115 = src/test/fuzz/lf_fuzz_hsdescv3_middle-fuzzing_common.$(OBJEXT) \ +@UNITTESTS_ENABLED_TRUE@am__objects_119 = src/test/fuzz/lf_fuzz_hsdescv3_middle-fuzzing_common.$(OBJEXT) \ @UNITTESTS_ENABLED_TRUE@ src/test/fuzz/lf_fuzz_hsdescv3_middle-fuzz_hsdescv3_middle.$(OBJEXT) -@LIBFUZZER_ENABLED_TRUE@@UNITTESTS_ENABLED_TRUE@am_src_test_fuzz_lf_fuzz_hsdescv3_middle_OBJECTS = $(am__objects_115) +@LIBFUZZER_ENABLED_TRUE@@UNITTESTS_ENABLED_TRUE@am_src_test_fuzz_lf_fuzz_hsdescv3_middle_OBJECTS = $(am__objects_119) src_test_fuzz_lf_fuzz_hsdescv3_middle_OBJECTS = \ $(am_src_test_fuzz_lf_fuzz_hsdescv3_middle_OBJECTS) @LIBFUZZER_ENABLED_TRUE@@UNITTESTS_ENABLED_TRUE@src_test_fuzz_lf_fuzz_hsdescv3_middle_DEPENDENCIES = $(am__DEPENDENCIES_4) @@ -2554,9 +2628,9 @@ $@ am__src_test_fuzz_lf_fuzz_http_SOURCES_DIST = \ src/test/fuzz/fuzzing_common.c src/test/fuzz/fuzz_http.c -@UNITTESTS_ENABLED_TRUE@am__objects_116 = src/test/fuzz/lf_fuzz_http-fuzzing_common.$(OBJEXT) \ +@UNITTESTS_ENABLED_TRUE@am__objects_120 = src/test/fuzz/lf_fuzz_http-fuzzing_common.$(OBJEXT) \ @UNITTESTS_ENABLED_TRUE@ src/test/fuzz/lf_fuzz_http-fuzz_http.$(OBJEXT) -@LIBFUZZER_ENABLED_TRUE@@UNITTESTS_ENABLED_TRUE@am_src_test_fuzz_lf_fuzz_http_OBJECTS = $(am__objects_116) +@LIBFUZZER_ENABLED_TRUE@@UNITTESTS_ENABLED_TRUE@am_src_test_fuzz_lf_fuzz_http_OBJECTS = $(am__objects_120) src_test_fuzz_lf_fuzz_http_OBJECTS = \ $(am_src_test_fuzz_lf_fuzz_http_OBJECTS) @LIBFUZZER_ENABLED_TRUE@@UNITTESTS_ENABLED_TRUE@src_test_fuzz_lf_fuzz_http_DEPENDENCIES = $(am__DEPENDENCIES_4) @@ -2566,9 +2640,9 @@ am__src_test_fuzz_lf_fuzz_http_connect_SOURCES_DIST = \ src/test/fuzz/fuzzing_common.c \ src/test/fuzz/fuzz_http_connect.c -@UNITTESTS_ENABLED_TRUE@am__objects_117 = src/test/fuzz/lf_fuzz_http_connect-fuzzing_common.$(OBJEXT) \ +@UNITTESTS_ENABLED_TRUE@am__objects_121 = src/test/fuzz/lf_fuzz_http_connect-fuzzing_common.$(OBJEXT) \ @UNITTESTS_ENABLED_TRUE@ src/test/fuzz/lf_fuzz_http_connect-fuzz_http_connect.$(OBJEXT) -@LIBFUZZER_ENABLED_TRUE@@UNITTESTS_ENABLED_TRUE@am_src_test_fuzz_lf_fuzz_http_connect_OBJECTS = $(am__objects_117) +@LIBFUZZER_ENABLED_TRUE@@UNITTESTS_ENABLED_TRUE@am_src_test_fuzz_lf_fuzz_http_connect_OBJECTS = $(am__objects_121) src_test_fuzz_lf_fuzz_http_connect_OBJECTS = \ $(am_src_test_fuzz_lf_fuzz_http_connect_OBJECTS) @LIBFUZZER_ENABLED_TRUE@@UNITTESTS_ENABLED_TRUE@src_test_fuzz_lf_fuzz_http_connect_DEPENDENCIES = $(am__DEPENDENCIES_4) @@ -2577,9 +2651,9 @@ $(src_test_fuzz_lf_fuzz_http_connect_LDFLAGS) $(LDFLAGS) -o $@ am__src_test_fuzz_lf_fuzz_microdesc_SOURCES_DIST = \ src/test/fuzz/fuzzing_common.c src/test/fuzz/fuzz_microdesc.c -@UNITTESTS_ENABLED_TRUE@am__objects_118 = src/test/fuzz/lf_fuzz_microdesc-fuzzing_common.$(OBJEXT) \ +@UNITTESTS_ENABLED_TRUE@am__objects_122 = src/test/fuzz/lf_fuzz_microdesc-fuzzing_common.$(OBJEXT) \ @UNITTESTS_ENABLED_TRUE@ src/test/fuzz/lf_fuzz_microdesc-fuzz_microdesc.$(OBJEXT) -@LIBFUZZER_ENABLED_TRUE@@UNITTESTS_ENABLED_TRUE@am_src_test_fuzz_lf_fuzz_microdesc_OBJECTS = $(am__objects_118) +@LIBFUZZER_ENABLED_TRUE@@UNITTESTS_ENABLED_TRUE@am_src_test_fuzz_lf_fuzz_microdesc_OBJECTS = $(am__objects_122) src_test_fuzz_lf_fuzz_microdesc_OBJECTS = \ $(am_src_test_fuzz_lf_fuzz_microdesc_OBJECTS) @LIBFUZZER_ENABLED_TRUE@@UNITTESTS_ENABLED_TRUE@src_test_fuzz_lf_fuzz_microdesc_DEPENDENCIES = $(am__DEPENDENCIES_4) @@ -2588,9 +2662,9 @@ $(src_test_fuzz_lf_fuzz_microdesc_LDFLAGS) $(LDFLAGS) -o $@ am__src_test_fuzz_lf_fuzz_socks_SOURCES_DIST = \ src/test/fuzz/fuzzing_common.c src/test/fuzz/fuzz_socks.c -@UNITTESTS_ENABLED_TRUE@am__objects_119 = src/test/fuzz/lf_fuzz_socks-fuzzing_common.$(OBJEXT) \ +@UNITTESTS_ENABLED_TRUE@am__objects_123 = src/test/fuzz/lf_fuzz_socks-fuzzing_common.$(OBJEXT) \ @UNITTESTS_ENABLED_TRUE@ src/test/fuzz/lf_fuzz_socks-fuzz_socks.$(OBJEXT) -@LIBFUZZER_ENABLED_TRUE@@UNITTESTS_ENABLED_TRUE@am_src_test_fuzz_lf_fuzz_socks_OBJECTS = $(am__objects_119) +@LIBFUZZER_ENABLED_TRUE@@UNITTESTS_ENABLED_TRUE@am_src_test_fuzz_lf_fuzz_socks_OBJECTS = $(am__objects_123) src_test_fuzz_lf_fuzz_socks_OBJECTS = \ $(am_src_test_fuzz_lf_fuzz_socks_OBJECTS) @LIBFUZZER_ENABLED_TRUE@@UNITTESTS_ENABLED_TRUE@src_test_fuzz_lf_fuzz_socks_DEPENDENCIES = $(am__DEPENDENCIES_4) @@ -2599,9 +2673,9 @@ $(src_test_fuzz_lf_fuzz_socks_LDFLAGS) $(LDFLAGS) -o $@ am__src_test_fuzz_lf_fuzz_strops_SOURCES_DIST = \ src/test/fuzz/fuzzing_common.c src/test/fuzz/fuzz_strops.c -@UNITTESTS_ENABLED_TRUE@am__objects_120 = src/test/fuzz/lf_fuzz_strops-fuzzing_common.$(OBJEXT) \ +@UNITTESTS_ENABLED_TRUE@am__objects_124 = src/test/fuzz/lf_fuzz_strops-fuzzing_common.$(OBJEXT) \ @UNITTESTS_ENABLED_TRUE@ src/test/fuzz/lf_fuzz_strops-fuzz_strops.$(OBJEXT) -@LIBFUZZER_ENABLED_TRUE@@UNITTESTS_ENABLED_TRUE@am_src_test_fuzz_lf_fuzz_strops_OBJECTS = $(am__objects_120) +@LIBFUZZER_ENABLED_TRUE@@UNITTESTS_ENABLED_TRUE@am_src_test_fuzz_lf_fuzz_strops_OBJECTS = $(am__objects_124) src_test_fuzz_lf_fuzz_strops_OBJECTS = \ $(am_src_test_fuzz_lf_fuzz_strops_OBJECTS) @LIBFUZZER_ENABLED_TRUE@@UNITTESTS_ENABLED_TRUE@src_test_fuzz_lf_fuzz_strops_DEPENDENCIES = $(am__DEPENDENCIES_4) @@ -2610,9 +2684,9 @@ $(src_test_fuzz_lf_fuzz_strops_LDFLAGS) $(LDFLAGS) -o $@ am__src_test_fuzz_lf_fuzz_vrs_SOURCES_DIST = \ src/test/fuzz/fuzzing_common.c src/test/fuzz/fuzz_vrs.c -@UNITTESTS_ENABLED_TRUE@am__objects_121 = src/test/fuzz/lf_fuzz_vrs-fuzzing_common.$(OBJEXT) \ +@UNITTESTS_ENABLED_TRUE@am__objects_125 = src/test/fuzz/lf_fuzz_vrs-fuzzing_common.$(OBJEXT) \ @UNITTESTS_ENABLED_TRUE@ src/test/fuzz/lf_fuzz_vrs-fuzz_vrs.$(OBJEXT) -@LIBFUZZER_ENABLED_TRUE@@UNITTESTS_ENABLED_TRUE@am_src_test_fuzz_lf_fuzz_vrs_OBJECTS = $(am__objects_121) +@LIBFUZZER_ENABLED_TRUE@@UNITTESTS_ENABLED_TRUE@am_src_test_fuzz_lf_fuzz_vrs_OBJECTS = $(am__objects_125) src_test_fuzz_lf_fuzz_vrs_OBJECTS = \ $(am_src_test_fuzz_lf_fuzz_vrs_OBJECTS) @LIBFUZZER_ENABLED_TRUE@@UNITTESTS_ENABLED_TRUE@src_test_fuzz_lf_fuzz_vrs_DEPENDENCIES = $(am__DEPENDENCIES_4) @@ -2634,13 +2708,15 @@ src/test/test_circuitmux.c src/test/test_circuitmux_ewma.c \ src/test/test_circuitbuild.c src/test/test_circuituse.c \ src/test/test_circuitstats.c src/test/test_compat_libevent.c \ - src/test/test_config.c src/test/test_confmgr.c \ - src/test/test_confparse.c src/test/test_connection.c \ - src/test/test_conscache.c src/test/test_consdiff.c \ - src/test/test_consdiffmgr.c src/test/test_containers.c \ - src/test/test_controller.c src/test/test_controller_events.c \ - src/test/test_crypto.c src/test/test_crypto_ope.c \ - src/test/test_crypto_rng.c src/test/test_data.c \ + src/test/test_config.c src/test/test_conflux_cell.c \ + src/test/test_conflux_pool.c src/test/test_confmgr.c \ + src/test/test_confparse.c src/test/test_congestion_control.c \ + src/test/test_connection.c src/test/test_conscache.c \ + src/test/test_consdiff.c src/test/test_consdiffmgr.c \ + src/test/test_containers.c src/test/test_controller.c \ + src/test/test_controller_events.c src/test/test_crypto.c \ + src/test/test_crypto_ope.c src/test/test_crypto_rng.c \ + src/test/test_crypto_cgo.c src/test/test_data.c \ src/test/test_dir.c src/test/test_dirauth_ports.c \ src/test/test_dirvote.c src/test/test_dir_common.c \ src/test/test_dir_handle_get.c src/test/test_dispatch.c \ @@ -2654,38 +2730,39 @@ src/test/test_hs_ob.c src/test/test_handles.c \ src/test/test_hs_cache.c src/test/test_hs_descriptor.c \ src/test/test_hs_dos.c src/test/test_hs_metrics.c \ - src/test/test_keypin.c src/test/test_link_handshake.c \ - src/test/test_logging.c src/test/test_mainloop.c \ - src/test/test_metrics.c src/test/test_microdesc.c \ - src/test/test_namemap.c src/test/test_netinfo.c \ - src/test/test_nodelist.c src/test/test_ntor_v3.c \ - src/test/test_oom.c src/test/test_oos.c \ - src/test/test_options.c src/test/test_options_act.c \ - src/test/test_pem.c src/test/test_periodic_event.c \ - src/test/test_policy.c src/test/test_process.c \ - src/test/test_process_descs.c src/test/test_prob_distr.c \ - src/test/test_procmon.c src/test/test_proto_haproxy.c \ - src/test/test_proto_http.c 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 src/test/test_replay.c \ - src/test/test_router.c src/test/test_routerkeys.c \ - src/test/test_routerlist.c src/test/test_routerset.c \ - src/test/test_sandbox.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_statefile.c \ - src/test/test_stats.c 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 \ - src/test/test_util_process.c src/test/test_voting_flags.c \ - src/test/test_voting_schedule.c src/test/test_x509.c \ - src/test/test_helpers.c src/test/test_dns.c \ - src/test/test_parsecommon.c src/test/testing_common.c \ - src/test/testing_rsakeys.c src/ext/tinytest.c \ - src/test/test_crypto_openssl.c src/test/test_tortls_openssl.c -@UNITTESTS_ENABLED_TRUE@am__objects_122 = \ + src/test/test_hs_pow.c src/test/test_keypin.c \ + src/test/test_link_handshake.c src/test/test_logging.c \ + src/test/test_mainloop.c src/test/test_metrics.c \ + src/test/test_microdesc.c src/test/test_namemap.c \ + src/test/test_netinfo.c src/test/test_nodelist.c \ + src/test/test_ntor_v3.c src/test/test_oom.c \ + src/test/test_oos.c src/test/test_options.c \ + src/test/test_options_act.c src/test/test_pem.c \ + src/test/test_periodic_event.c src/test/test_policy.c \ + src/test/test_process.c src/test/test_process_descs.c \ + src/test/test_prob_distr.c src/test/test_procmon.c \ + src/test/test_proto_haproxy.c src/test/test_proto_http.c \ + 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 \ + src/test/test_replay.c src/test/test_router.c \ + src/test/test_routerkeys.c src/test/test_routerlist.c \ + src/test/test_routerset.c src/test/test_sandbox.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_statefile.c src/test/test_stats.c \ + 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 src/test/test_util_process.c \ + src/test/test_voting_flags.c src/test/test_voting_schedule.c \ + src/test/test_x509.c src/test/test_helpers.c \ + src/test/test_dns.c src/test/test_parsecommon.c \ + src/test/testing_common.c src/test/testing_rsakeys.c \ + src/ext/tinytest.c src/test/test_crypto_openssl.c \ + src/test/test_tortls_openssl.c +@UNITTESTS_ENABLED_TRUE@am__objects_126 = \ @UNITTESTS_ENABLED_TRUE@ src/test/test-fakecircs.$(OBJEXT) \ @UNITTESTS_ENABLED_TRUE@ src/test/test-log_test_helpers.$(OBJEXT) \ @UNITTESTS_ENABLED_TRUE@ src/test/test-hs_test_helpers.$(OBJEXT) \ @@ -2716,8 +2793,11 @@ @UNITTESTS_ENABLED_TRUE@ src/test/test-test_circuitstats.$(OBJEXT) \ @UNITTESTS_ENABLED_TRUE@ src/test/test-test_compat_libevent.$(OBJEXT) \ @UNITTESTS_ENABLED_TRUE@ src/test/test-test_config.$(OBJEXT) \ +@UNITTESTS_ENABLED_TRUE@ src/test/test-test_conflux_cell.$(OBJEXT) \ +@UNITTESTS_ENABLED_TRUE@ src/test/test-test_conflux_pool.$(OBJEXT) \ @UNITTESTS_ENABLED_TRUE@ src/test/test-test_confmgr.$(OBJEXT) \ @UNITTESTS_ENABLED_TRUE@ src/test/test-test_confparse.$(OBJEXT) \ +@UNITTESTS_ENABLED_TRUE@ src/test/test-test_congestion_control.$(OBJEXT) \ @UNITTESTS_ENABLED_TRUE@ src/test/test-test_connection.$(OBJEXT) \ @UNITTESTS_ENABLED_TRUE@ src/test/test-test_conscache.$(OBJEXT) \ @UNITTESTS_ENABLED_TRUE@ src/test/test-test_consdiff.$(OBJEXT) \ @@ -2728,6 +2808,7 @@ @UNITTESTS_ENABLED_TRUE@ src/test/test-test_crypto.$(OBJEXT) \ @UNITTESTS_ENABLED_TRUE@ src/test/test-test_crypto_ope.$(OBJEXT) \ @UNITTESTS_ENABLED_TRUE@ src/test/test-test_crypto_rng.$(OBJEXT) \ +@UNITTESTS_ENABLED_TRUE@ src/test/test-test_crypto_cgo.$(OBJEXT) \ @UNITTESTS_ENABLED_TRUE@ src/test/test-test_data.$(OBJEXT) \ @UNITTESTS_ENABLED_TRUE@ src/test/test-test_dir.$(OBJEXT) \ @UNITTESTS_ENABLED_TRUE@ src/test/test-test_dirauth_ports.$(OBJEXT) \ @@ -2755,6 +2836,7 @@ @UNITTESTS_ENABLED_TRUE@ src/test/test-test_hs_descriptor.$(OBJEXT) \ @UNITTESTS_ENABLED_TRUE@ src/test/test-test_hs_dos.$(OBJEXT) \ @UNITTESTS_ENABLED_TRUE@ src/test/test-test_hs_metrics.$(OBJEXT) \ +@UNITTESTS_ENABLED_TRUE@ src/test/test-test_hs_pow.$(OBJEXT) \ @UNITTESTS_ENABLED_TRUE@ src/test/test-test_keypin.$(OBJEXT) \ @UNITTESTS_ENABLED_TRUE@ src/test/test-test_link_handshake.$(OBJEXT) \ @UNITTESTS_ENABLED_TRUE@ src/test/test-test_logging.$(OBJEXT) \ @@ -2815,9 +2897,9 @@ @UNITTESTS_ENABLED_TRUE@ src/test/test-testing_common.$(OBJEXT) \ @UNITTESTS_ENABLED_TRUE@ src/test/test-testing_rsakeys.$(OBJEXT) \ @UNITTESTS_ENABLED_TRUE@ src/ext/test_test-tinytest.$(OBJEXT) -@UNITTESTS_ENABLED_TRUE@@USE_NSS_FALSE@am__objects_123 = src/test/test-test_crypto_openssl.$(OBJEXT) \ +@UNITTESTS_ENABLED_TRUE@@USE_NSS_FALSE@am__objects_127 = src/test/test-test_crypto_openssl.$(OBJEXT) \ @UNITTESTS_ENABLED_TRUE@@USE_NSS_FALSE@ src/test/test-test_tortls_openssl.$(OBJEXT) -am_src_test_test_OBJECTS = $(am__objects_122) $(am__objects_123) +am_src_test_test_OBJECTS = $(am__objects_126) $(am__objects_127) src_test_test_OBJECTS = $(am_src_test_test_OBJECTS) src_test_test_DEPENDENCIES = src/test/libtor-testing.a \ $(am__DEPENDENCIES_2) @@ -2858,21 +2940,22 @@ $(src_test_test_rng_LDFLAGS) $(LDFLAGS) -o $@ am__src_test_test_slow_SOURCES_DIST = 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 -@UNITTESTS_ENABLED_TRUE@am__objects_124 = src/test/test_slow-rng_test_helpers.$(OBJEXT) \ + src/test/test_process_slow.c src/test/test_hs_pow_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 +@UNITTESTS_ENABLED_TRUE@am__objects_128 = src/test/test_slow-rng_test_helpers.$(OBJEXT) \ @UNITTESTS_ENABLED_TRUE@ src/test/test_slow-test_slow.$(OBJEXT) \ @UNITTESTS_ENABLED_TRUE@ src/test/test_slow-test_crypto_slow.$(OBJEXT) \ @UNITTESTS_ENABLED_TRUE@ src/test/test_slow-test_process_slow.$(OBJEXT) \ +@UNITTESTS_ENABLED_TRUE@ src/test/test_slow-test_hs_pow_slow.$(OBJEXT) \ @UNITTESTS_ENABLED_TRUE@ src/test/test_slow-test_prob_distr.$(OBJEXT) \ @UNITTESTS_ENABLED_TRUE@ src/test/test_slow-ptr_helpers.$(OBJEXT) \ @UNITTESTS_ENABLED_TRUE@ src/test/test_slow-test_ptr_slow.$(OBJEXT) \ @UNITTESTS_ENABLED_TRUE@ src/test/test_slow-testing_common.$(OBJEXT) \ @UNITTESTS_ENABLED_TRUE@ src/test/test_slow-testing_rsakeys.$(OBJEXT) \ @UNITTESTS_ENABLED_TRUE@ src/ext/test_test_slow-tinytest.$(OBJEXT) -am_src_test_test_slow_OBJECTS = $(am__objects_124) +am_src_test_test_slow_OBJECTS = $(am__objects_128) src_test_test_slow_OBJECTS = $(am_src_test_test_slow_OBJECTS) src_test_test_slow_DEPENDENCIES = $(am__DEPENDENCIES_3) src_test_test_slow_LINK = $(CCLD) $(src_test_test_slow_CFLAGS) \ @@ -3020,14 +3103,16 @@ src/core/crypto/$(DEPDIR)/libtor_app_testing_a-onion_fast.Po \ src/core/crypto/$(DEPDIR)/libtor_app_testing_a-onion_ntor.Po \ src/core/crypto/$(DEPDIR)/libtor_app_testing_a-onion_ntor_v3.Po \ - src/core/crypto/$(DEPDIR)/libtor_app_testing_a-onion_tap.Po \ src/core/crypto/$(DEPDIR)/libtor_app_testing_a-relay_crypto.Po \ + src/core/crypto/$(DEPDIR)/libtor_app_testing_a-relay_crypto_cgo.Po \ + src/core/crypto/$(DEPDIR)/libtor_app_testing_a-relay_crypto_tor1.Po \ src/core/crypto/$(DEPDIR)/onion_crypto.Po \ src/core/crypto/$(DEPDIR)/onion_fast.Po \ src/core/crypto/$(DEPDIR)/onion_ntor.Po \ src/core/crypto/$(DEPDIR)/onion_ntor_v3.Po \ - src/core/crypto/$(DEPDIR)/onion_tap.Po \ src/core/crypto/$(DEPDIR)/relay_crypto.Po \ + src/core/crypto/$(DEPDIR)/relay_crypto_cgo.Po \ + src/core/crypto/$(DEPDIR)/relay_crypto_tor1.Po \ src/core/mainloop/$(DEPDIR)/connection.Po \ src/core/mainloop/$(DEPDIR)/cpuworker.Po \ src/core/mainloop/$(DEPDIR)/libtor_app_testing_a-connection.Po \ @@ -3055,11 +3140,15 @@ src/core/or/$(DEPDIR)/circuitstats.Po \ src/core/or/$(DEPDIR)/circuituse.Po \ src/core/or/$(DEPDIR)/command.Po \ + src/core/or/$(DEPDIR)/conflux.Po \ + src/core/or/$(DEPDIR)/conflux_cell.Po \ + src/core/or/$(DEPDIR)/conflux_params.Po \ + src/core/or/$(DEPDIR)/conflux_pool.Po \ + src/core/or/$(DEPDIR)/conflux_sys.Po \ + src/core/or/$(DEPDIR)/conflux_util.Po \ src/core/or/$(DEPDIR)/congestion_control_common.Po \ src/core/or/$(DEPDIR)/congestion_control_flow.Po \ - src/core/or/$(DEPDIR)/congestion_control_nola.Po \ src/core/or/$(DEPDIR)/congestion_control_vegas.Po \ - src/core/or/$(DEPDIR)/congestion_control_westwood.Po \ src/core/or/$(DEPDIR)/connection_edge.Po \ src/core/or/$(DEPDIR)/connection_or.Po \ src/core/or/$(DEPDIR)/crypt_path.Po \ @@ -3080,11 +3169,15 @@ src/core/or/$(DEPDIR)/libtor_app_testing_a-circuitstats.Po \ src/core/or/$(DEPDIR)/libtor_app_testing_a-circuituse.Po \ src/core/or/$(DEPDIR)/libtor_app_testing_a-command.Po \ + src/core/or/$(DEPDIR)/libtor_app_testing_a-conflux.Po \ + src/core/or/$(DEPDIR)/libtor_app_testing_a-conflux_cell.Po \ + src/core/or/$(DEPDIR)/libtor_app_testing_a-conflux_params.Po \ + src/core/or/$(DEPDIR)/libtor_app_testing_a-conflux_pool.Po \ + src/core/or/$(DEPDIR)/libtor_app_testing_a-conflux_sys.Po \ + src/core/or/$(DEPDIR)/libtor_app_testing_a-conflux_util.Po \ src/core/or/$(DEPDIR)/libtor_app_testing_a-congestion_control_common.Po \ src/core/or/$(DEPDIR)/libtor_app_testing_a-congestion_control_flow.Po \ - src/core/or/$(DEPDIR)/libtor_app_testing_a-congestion_control_nola.Po \ src/core/or/$(DEPDIR)/libtor_app_testing_a-congestion_control_vegas.Po \ - src/core/or/$(DEPDIR)/libtor_app_testing_a-congestion_control_westwood.Po \ src/core/or/$(DEPDIR)/libtor_app_testing_a-connection_edge.Po \ src/core/or/$(DEPDIR)/libtor_app_testing_a-connection_or.Po \ src/core/or/$(DEPDIR)/libtor_app_testing_a-crypt_path.Po \ @@ -3101,6 +3194,7 @@ src/core/or/$(DEPDIR)/libtor_app_testing_a-protover.Po \ src/core/or/$(DEPDIR)/libtor_app_testing_a-reasons.Po \ src/core/or/$(DEPDIR)/libtor_app_testing_a-relay.Po \ + src/core/or/$(DEPDIR)/libtor_app_testing_a-relay_msg.Po \ src/core/or/$(DEPDIR)/libtor_app_testing_a-scheduler.Po \ src/core/or/$(DEPDIR)/libtor_app_testing_a-scheduler_kist.Po \ src/core/or/$(DEPDIR)/libtor_app_testing_a-scheduler_vanilla.Po \ @@ -3118,6 +3212,7 @@ src/core/or/$(DEPDIR)/protover.Po \ src/core/or/$(DEPDIR)/reasons.Po \ src/core/or/$(DEPDIR)/relay.Po \ + src/core/or/$(DEPDIR)/relay_msg.Po \ src/core/or/$(DEPDIR)/scheduler.Po \ src/core/or/$(DEPDIR)/scheduler_kist.Po \ src/core/or/$(DEPDIR)/scheduler_vanilla.Po \ @@ -3190,9 +3285,24 @@ src/ext/ed25519/ref10/$(DEPDIR)/libed25519_ref10_a-sc_muladd.Po \ src/ext/ed25519/ref10/$(DEPDIR)/libed25519_ref10_a-sc_reduce.Po \ src/ext/ed25519/ref10/$(DEPDIR)/libed25519_ref10_a-sign.Po \ + src/ext/equix/hashx/src/$(DEPDIR)/libhashx_a-blake2.Po \ + src/ext/equix/hashx/src/$(DEPDIR)/libhashx_a-compiler.Po \ + src/ext/equix/hashx/src/$(DEPDIR)/libhashx_a-compiler_a64.Po \ + src/ext/equix/hashx/src/$(DEPDIR)/libhashx_a-compiler_x86.Po \ + src/ext/equix/hashx/src/$(DEPDIR)/libhashx_a-context.Po \ + src/ext/equix/hashx/src/$(DEPDIR)/libhashx_a-hashx.Po \ + src/ext/equix/hashx/src/$(DEPDIR)/libhashx_a-program.Po \ + src/ext/equix/hashx/src/$(DEPDIR)/libhashx_a-program_exec.Po \ + src/ext/equix/hashx/src/$(DEPDIR)/libhashx_a-siphash.Po \ + src/ext/equix/hashx/src/$(DEPDIR)/libhashx_a-siphash_rng.Po \ + src/ext/equix/hashx/src/$(DEPDIR)/libhashx_a-virtual_memory.Po \ + src/ext/equix/src/$(DEPDIR)/libequix_a-context.Po \ + src/ext/equix/src/$(DEPDIR)/libequix_a-equix.Po \ + src/ext/equix/src/$(DEPDIR)/libequix_a-solver.Po \ src/ext/keccak-tiny/$(DEPDIR)/libkeccak_tiny_a-keccak-tiny-unrolled.Po \ src/ext/mulodi/$(DEPDIR)/lib_libtor_ctime_a-mulodi4.Po \ src/ext/mulodi/$(DEPDIR)/lib_libtor_ctime_testing_a-mulodi4.Po \ + src/ext/polyval/$(DEPDIR)/libpolyval_a-polyval.Po \ src/ext/trunnel/$(DEPDIR)/trunnel_libor_trunnel_a-trunnel.Po \ src/ext/trunnel/$(DEPDIR)/trunnel_libor_trunnel_testing_a-trunnel.Po \ src/feature/api/$(DEPDIR)/core_libtor_app_testing_a-tor_api.Po \ @@ -3334,6 +3444,7 @@ src/feature/hs/$(DEPDIR)/core_libtor_app_testing_a-hs_metrics.Po \ src/feature/hs/$(DEPDIR)/core_libtor_app_testing_a-hs_metrics_entry.Po \ src/feature/hs/$(DEPDIR)/core_libtor_app_testing_a-hs_ob.Po \ + src/feature/hs/$(DEPDIR)/core_libtor_app_testing_a-hs_pow.Po \ src/feature/hs/$(DEPDIR)/core_libtor_app_testing_a-hs_service.Po \ src/feature/hs/$(DEPDIR)/core_libtor_app_testing_a-hs_stats.Po \ src/feature/hs/$(DEPDIR)/core_libtor_app_testing_a-hs_sys.Po \ @@ -3352,6 +3463,7 @@ src/feature/hs/$(DEPDIR)/hs_metrics.Po \ src/feature/hs/$(DEPDIR)/hs_metrics_entry.Po \ src/feature/hs/$(DEPDIR)/hs_ob.Po \ + src/feature/hs/$(DEPDIR)/hs_pow.Po \ src/feature/hs/$(DEPDIR)/hs_service.Po \ src/feature/hs/$(DEPDIR)/hs_stats.Po \ src/feature/hs/$(DEPDIR)/hs_sys.Po \ @@ -3782,8 +3894,11 @@ src/test/$(DEPDIR)/test-test_circuituse.Po \ src/test/$(DEPDIR)/test-test_compat_libevent.Po \ src/test/$(DEPDIR)/test-test_config.Po \ + src/test/$(DEPDIR)/test-test_conflux_cell.Po \ + src/test/$(DEPDIR)/test-test_conflux_pool.Po \ src/test/$(DEPDIR)/test-test_confmgr.Po \ src/test/$(DEPDIR)/test-test_confparse.Po \ + src/test/$(DEPDIR)/test-test_congestion_control.Po \ src/test/$(DEPDIR)/test-test_connection.Po \ src/test/$(DEPDIR)/test-test_conscache.Po \ src/test/$(DEPDIR)/test-test_consdiff.Po \ @@ -3792,6 +3907,7 @@ src/test/$(DEPDIR)/test-test_controller.Po \ src/test/$(DEPDIR)/test-test_controller_events.Po \ src/test/$(DEPDIR)/test-test_crypto.Po \ + src/test/$(DEPDIR)/test-test_crypto_cgo.Po \ src/test/$(DEPDIR)/test-test_crypto_ope.Po \ src/test/$(DEPDIR)/test-test_crypto_openssl.Po \ src/test/$(DEPDIR)/test-test_crypto_rng.Po \ @@ -3823,6 +3939,7 @@ src/test/$(DEPDIR)/test-test_hs_metrics.Po \ src/test/$(DEPDIR)/test-test_hs_ntor.Po \ src/test/$(DEPDIR)/test-test_hs_ob.Po \ + src/test/$(DEPDIR)/test-test_hs_pow.Po \ src/test/$(DEPDIR)/test-test_hs_service.Po \ src/test/$(DEPDIR)/test-test_keypin.Po \ src/test/$(DEPDIR)/test-test_link_handshake.Po \ @@ -3890,6 +4007,7 @@ src/test/$(DEPDIR)/test_slow-ptr_helpers.Po \ src/test/$(DEPDIR)/test_slow-rng_test_helpers.Po \ src/test/$(DEPDIR)/test_slow-test_crypto_slow.Po \ + src/test/$(DEPDIR)/test_slow-test_hs_pow_slow.Po \ src/test/$(DEPDIR)/test_slow-test_prob_distr.Po \ src/test/$(DEPDIR)/test_slow-test_process_slow.Po \ src/test/$(DEPDIR)/test_slow-test_ptr_slow.Po \ @@ -4003,6 +4121,7 @@ src/tools/$(DEPDIR)/tor_runner.Po \ src/trunnel/$(DEPDIR)/libor_trunnel_a-channelpadding_negotiation.Po \ src/trunnel/$(DEPDIR)/libor_trunnel_a-circpad_negotiation.Po \ + src/trunnel/$(DEPDIR)/libor_trunnel_a-conflux.Po \ src/trunnel/$(DEPDIR)/libor_trunnel_a-congestion_control.Po \ src/trunnel/$(DEPDIR)/libor_trunnel_a-ed25519_cert.Po \ src/trunnel/$(DEPDIR)/libor_trunnel_a-extension.Po \ @@ -4012,8 +4131,10 @@ src/trunnel/$(DEPDIR)/libor_trunnel_a-pwbox.Po \ src/trunnel/$(DEPDIR)/libor_trunnel_a-sendme_cell.Po \ src/trunnel/$(DEPDIR)/libor_trunnel_a-socks5.Po \ + src/trunnel/$(DEPDIR)/libor_trunnel_a-subproto_request.Po \ src/trunnel/$(DEPDIR)/libor_trunnel_testing_a-channelpadding_negotiation.Po \ src/trunnel/$(DEPDIR)/libor_trunnel_testing_a-circpad_negotiation.Po \ + src/trunnel/$(DEPDIR)/libor_trunnel_testing_a-conflux.Po \ src/trunnel/$(DEPDIR)/libor_trunnel_testing_a-congestion_control.Po \ src/trunnel/$(DEPDIR)/libor_trunnel_testing_a-ed25519_cert.Po \ src/trunnel/$(DEPDIR)/libor_trunnel_testing_a-extension.Po \ @@ -4023,6 +4144,7 @@ src/trunnel/$(DEPDIR)/libor_trunnel_testing_a-pwbox.Po \ src/trunnel/$(DEPDIR)/libor_trunnel_testing_a-sendme_cell.Po \ src/trunnel/$(DEPDIR)/libor_trunnel_testing_a-socks5.Po \ + src/trunnel/$(DEPDIR)/libor_trunnel_testing_a-subproto_request.Po \ src/trunnel/hs/$(DEPDIR)/libor_trunnel_a-cell_establish_intro.Po \ src/trunnel/hs/$(DEPDIR)/libor_trunnel_a-cell_introduce1.Po \ src/trunnel/hs/$(DEPDIR)/libor_trunnel_a-cell_rendezvous.Po \ @@ -4050,7 +4172,10 @@ $(src_core_libtor_app_a_SOURCES) \ $(src_ext_ed25519_donna_libed25519_donna_a_SOURCES) \ $(src_ext_ed25519_ref10_libed25519_ref10_a_SOURCES) \ + $(src_ext_equix_libequix_a_SOURCES) \ + $(src_ext_equix_libhashx_a_SOURCES) \ $(src_ext_keccak_tiny_libkeccak_tiny_a_SOURCES) \ + $(src_ext_polyval_libpolyval_a_SOURCES) \ $(src_lib_libcurve25519_donna_a_SOURCES) \ $(src_lib_libtor_buf_testing_a_SOURCES) \ $(src_lib_libtor_buf_a_SOURCES) \ @@ -4192,7 +4317,10 @@ $(am__src_core_libtor_app_a_SOURCES_DIST) \ $(src_ext_ed25519_donna_libed25519_donna_a_SOURCES) \ $(src_ext_ed25519_ref10_libed25519_ref10_a_SOURCES) \ + $(src_ext_equix_libequix_a_SOURCES) \ + $(src_ext_equix_libhashx_a_SOURCES) \ $(am__src_ext_keccak_tiny_libkeccak_tiny_a_SOURCES_DIST) \ + $(src_ext_polyval_libpolyval_a_SOURCES) \ $(am__src_lib_libcurve25519_donna_a_SOURCES_DIST) \ $(src_lib_libtor_buf_testing_a_SOURCES) \ $(src_lib_libtor_buf_a_SOURCES) \ @@ -4345,8 +4473,8 @@ src/ext/tinytest.h src/ext/tor_readpassphrase.h \ src/ext/strlcat.c src/ext/strlcpy.c src/ext/getdelim.c \ src/ext/tinytest_macros.h src/ext/tor_queue.h \ - src/ext/siphash.h src/ext/timeouts/timeout.h \ - src/ext/timeouts/timeout-debug.h \ + src/ext/siphash.h src/ext/compat_blake2.h \ + src/ext/timeouts/timeout.h src/ext/timeouts/timeout-debug.h \ src/ext/timeouts/timeout-bitops.c src/ext/timeouts/timeout.c \ src/ext/ed25519/ref10/api.h src/ext/ed25519/ref10/base.h \ src/ext/ed25519/ref10/base2.h \ @@ -4396,7 +4524,23 @@ src/ext/ed25519/donna/regression.h \ src/ext/ed25519/donna/test-ticks.h \ src/ext/ed25519/donna/test-internals.c \ - src/ext/keccak-tiny/keccak-tiny.h src/lib/arch/bytes.h \ + src/ext/equix/hashx/include/hashx.h \ + src/ext/equix/hashx/src/blake2.h \ + src/ext/equix/hashx/src/compiler.h \ + src/ext/equix/hashx/src/context.h \ + src/ext/equix/hashx/src/force_inline.h \ + src/ext/equix/hashx/src/hashx_endian.h \ + src/ext/equix/hashx/src/instruction.h \ + src/ext/equix/hashx/src/program.h \ + src/ext/equix/hashx/src/siphash_rng.h \ + src/ext/equix/hashx/src/siphash.h \ + src/ext/equix/hashx/src/unreachable.h \ + src/ext/equix/hashx/src/virtual_memory.h \ + src/ext/equix/include/equix.h src/ext/equix/src/context.h \ + src/ext/equix/src/solver_heap.h src/ext/equix/src/solver.h \ + src/ext/keccak-tiny/keccak-tiny.h src/ext/polyval/polyval.h \ + src/ext/polyval/pclmul.c src/ext/polyval/ctmul64.c \ + src/ext/polyval/ctmul.c src/lib/arch/bytes.h \ src/lib/buf/buffers.h src/lib/err/backtrace.h \ src/lib/err/torerr.h src/lib/err/torerr_sys.h \ src/lib/cc/compat_compiler.h src/lib/cc/ctassert.h \ @@ -4495,16 +4639,17 @@ src/lib/thread/numcpus.h src/lib/thread/thread_sys.h \ src/lib/thread/threads.h src/lib/time/compat_time.h \ src/lib/time/time_sys.h src/lib/time/tvdiff.h \ - src/lib/tls/ciphers.inc src/lib/tls/buffers_tls.h \ - src/lib/tls/nss_countbytes.h src/lib/tls/tortls.h \ - src/lib/tls/tortls_internal.h src/lib/tls/tortls_st.h \ - src/lib/tls/tortls_sys.h src/lib/tls/x509.h \ - src/lib/tls/x509_internal.h src/lib/trace/trace.h \ - src/lib/trace/trace_sys.h src/lib/trace/events.h \ - src/lib/trace/debug.h src/lib/trace/usdt/usdt.h \ - src/lib/trace/lttng/lttng.h src/lib/version/git_revision.h \ - src/lib/version/torversion.h src/lib/wallclock/approx_time.h \ - src/lib/wallclock/timeval.h src/lib/wallclock/time_to_tm.h \ + src/lib/tls/ciphers.inc src/lib/tls/ciphers_v13.inc \ + src/lib/tls/buffers_tls.h src/lib/tls/nss_countbytes.h \ + src/lib/tls/tortls.h src/lib/tls/tortls_internal.h \ + src/lib/tls/tortls_st.h src/lib/tls/tortls_sys.h \ + src/lib/tls/x509.h src/lib/tls/x509_internal.h \ + src/lib/trace/trace.h src/lib/trace/trace_sys.h \ + src/lib/trace/events.h src/lib/trace/debug.h \ + src/lib/trace/usdt/usdt.h src/lib/trace/lttng/lttng.h \ + src/lib/version/git_revision.h src/lib/version/torversion.h \ + src/lib/wallclock/approx_time.h src/lib/wallclock/timeval.h \ + src/lib/wallclock/time_to_tm.h \ src/lib/wallclock/tor_gettimeofday.h \ src/lib/wallclock/wallclock_sys.h src/ext/trunnel/trunnel.h \ src/ext/trunnel/trunnel-impl.h src/trunnel/trunnel-local.h \ @@ -4517,10 +4662,14 @@ src/trunnel/sendme_cell.h src/trunnel/flow_control_cells.h \ src/trunnel/congestion_control.h src/trunnel/socks5.h \ src/trunnel/netinfo.h src/trunnel/circpad_negotiation.h \ + src/trunnel/conflux.h src/trunnel/subproto_request.h \ src/core/crypto/hs_ntor.h src/core/crypto/onion_crypto.h \ src/core/crypto/onion_fast.h src/core/crypto/onion_ntor.h \ - src/core/crypto/onion_ntor_v3.h src/core/crypto/onion_tap.h \ - src/core/crypto/relay_crypto.h src/core/mainloop/connection.h \ + src/core/crypto/onion_ntor_v3.h src/core/crypto/relay_crypto.h \ + src/core/crypto/relay_crypto_st.h \ + src/core/crypto/relay_crypto_cgo.h \ + src/core/crypto/relay_crypto_tor1.h \ + src/core/crypto/tor1_crypt_st.h 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_state.inc \ @@ -4557,12 +4706,14 @@ src/core/or/origin_circuit_st.h src/core/or/policies.h \ src/core/or/port_cfg_st.h src/core/or/protover.h \ src/core/or/reasons.h 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/congestion_control_flow.h \ + src/core/or/relay_msg.h src/core/or/relay_msg_st.h \ + src/core/or/scheduler.h src/core/or/sendme.h \ + src/core/or/congestion_control_flow.h \ src/core/or/congestion_control_common.h \ - src/core/or/congestion_control_vegas.h \ - src/core/or/congestion_control_nola.h \ - src/core/or/congestion_control_westwood.h \ + src/core/or/congestion_control_vegas.h src/core/or/conflux.h \ + src/core/or/conflux_cell.h src/core/or/conflux_params.h \ + src/core/or/conflux_pool.h src/core/or/conflux_st.h \ + src/core/or/conflux_sys.h src/core/or/conflux_util.h \ src/core/or/server_port_cfg_st.h \ src/core/or/socks_request_st.h src/core/or/status.h \ src/core/or/tor_version_st.h src/core/or/var_cell_st.h \ @@ -4646,10 +4797,10 @@ src/feature/hs/hs_ident.h src/feature/hs/hs_intropoint.h \ src/feature/hs/hs_metrics.h src/feature/hs/hs_ob.h \ src/feature/hs/hs_opts_st.h src/feature/hs/hs_options.inc \ - src/feature/hs/hs_service.h src/feature/hs/hs_stats.h \ - src/feature/hs/hsdir_index_st.h src/feature/hs/hs_sys.h \ - src/feature/hs/hs_metrics_entry.h src/feature/keymgt/loadkey.h \ - src/feature/metrics/metrics.h \ + src/feature/hs/hs_pow.h src/feature/hs/hs_service.h \ + src/feature/hs/hs_stats.h src/feature/hs/hsdir_index_st.h \ + src/feature/hs/hs_sys.h src/feature/hs/hs_metrics_entry.h \ + src/feature/keymgt/loadkey.h src/feature/metrics/metrics.h \ src/feature/metrics/metrics_sys.h \ src/feature/nodelist/authcert.h \ src/feature/nodelist/authority_cert_st.h \ @@ -4702,17 +4853,18 @@ src/app/config/fallback_dirs.inc src/app/config/testnet.inc \ src/app/main/main.h src/app/main/ntmain.h \ src/app/main/risky_options.h src/app/main/shutdown.h \ - src/app/main/subsysmgr.h src/test/fakechans.h \ - src/test/fakecircs.h src/test/hs_test_helpers.h \ - src/test/log_test_helpers.h src/test/opts_test_helpers.h \ - src/test/resolve_test_helpers.h src/test/rng_test_helpers.h \ - src/test/test.h src/test/ptr_helpers.h src/test/test_helpers.h \ + src/app/main/subsysmgr.h src/test/compression_bomb.h \ + src/test/fakechans.h src/test/fakecircs.h \ + src/test/hs_test_helpers.h src/test/log_test_helpers.h \ + src/test/opts_test_helpers.h src/test/resolve_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 \ src/test/test_tortls.h src/test/test_descriptors.inc \ src/test/example_extrainfo.inc \ src/test/failing_routerdescs.inc src/test/ed25519_vectors.inc \ - src/test/test_hs_descriptor.inc src/test/vote_descriptors.inc \ - src/test/fuzz/fuzzing.h + src/test/cgo_vectors.inc src/test/test_hs_descriptor.inc \ + src/test/vote_descriptors.inc src/test/fuzz/fuzzing.h HEADERS = $(noinst_HEADERS) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) \ $(LISP)orconfig.h.in @@ -4987,8 +5139,7 @@ $(srcdir)/src/lib/wallclock/include.am \ $(srcdir)/src/test/fuzz/include.am \ $(srcdir)/src/test/include.am $(srcdir)/src/tools/include.am \ - $(srcdir)/src/trunnel/include.am \ - $(srcdir)/src/win32/include.am $(srcdir)/warning_flags.in \ + $(srcdir)/src/trunnel/include.am $(srcdir)/warning_flags.in \ $(top_srcdir)/contrib/operator-tools/tor.logrotate.in \ $(top_srcdir)/scripts/maint/checkOptionDocs.pl.in \ $(top_srcdir)/src/config/torrc.minimal.in \ @@ -5045,6 +5196,7 @@ EXEEXT = @EXEEXT@ F_OMIT_FRAME_POINTER = @F_OMIT_FRAME_POINTER@ GREP = @GREP@ +HASHX_SIZE = @HASHX_SIZE@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ @@ -5175,38 +5327,39 @@ top_srcdir = @top_srcdir@ ACLOCAL_AMFLAGS = -I m4 noinst_LIBRARIES = $(LIBED25519_REF10) $(LIBED25519_DONNA) \ - $(am__append_5) src/lib/libtor-buf.a $(am__append_6) \ - src/lib/libtor-err.a $(am__append_7) src/lib/libtor-ctime.a \ - $(am__append_8) src/lib/libtor-compress.a $(am__append_9) \ - src/lib/libtor-confmgt.a $(am__append_10) \ - src/lib/libtor-container.a $(am__append_11) \ - src/lib/libtor-crypt-ops.a $(am__append_12) \ - src/lib/libtor-dispatch.a $(am__append_16) \ - src/lib/libtor-encoding.a $(am__append_17) \ - src/lib/libtor-evloop.a $(am__append_18) src/lib/libtor-fdio.a \ - $(am__append_19) src/lib/libtor-fs.a $(am__append_20) \ - src/lib/libtor-geoip.a $(am__append_22) $(am__append_24) \ - $(am__append_26) src/lib/libtor-intmath.a $(am__append_27) \ - src/lib/libtor-llharden.a $(am__append_28) \ - src/lib/libtor-lock.a $(am__append_29) src/lib/libtor-log.a \ - $(am__append_32) src/lib/libtor-malloc.a $(am__append_34) \ - src/lib/libtor-math.a $(am__append_36) \ - src/lib/libtor-memarea.a $(am__append_37) \ - src/lib/libtor-meminfo.a $(am__append_38) \ - src/lib/libtor-metrics.a $(am__append_39) src/lib/libtor-net.a \ - $(am__append_40) src/lib/libtor-osinfo.a $(am__append_41) \ - src/lib/libtor-process.a $(am__append_42) \ - src/lib/libtor-pubsub.a $(am__append_43) \ - src/lib/libtor-sandbox.a $(am__append_44) \ - src/lib/libtor-string.a $(am__append_45) \ - src/lib/libtor-smartlist-core.a $(am__append_46) \ - src/lib/libtor-term.a $(am__append_47) src/lib/libtor-thread.a \ - $(am__append_48) src/lib/libtor-time.a $(am__append_49) \ - src/lib/libtor-tls.a $(am__append_50) src/lib/libtor-trace.a \ - src/lib/libtor-version.a $(am__append_56) \ - src/lib/libtor-wallclock.a $(am__append_57) \ - src/trunnel/libor-trunnel.a $(am__append_58) \ - src/core/libtor-app.a $(am__append_59) $(am__append_82) \ + $(EQUIX_LIBS) $(am__append_6) $(LIBPOLYVAL) \ + src/lib/libtor-buf.a $(am__append_7) src/lib/libtor-err.a \ + $(am__append_8) src/lib/libtor-ctime.a $(am__append_9) \ + src/lib/libtor-compress.a $(am__append_10) \ + src/lib/libtor-confmgt.a $(am__append_11) \ + src/lib/libtor-container.a $(am__append_12) \ + src/lib/libtor-crypt-ops.a $(am__append_13) \ + src/lib/libtor-dispatch.a $(am__append_17) \ + src/lib/libtor-encoding.a $(am__append_18) \ + src/lib/libtor-evloop.a $(am__append_19) src/lib/libtor-fdio.a \ + $(am__append_20) src/lib/libtor-fs.a $(am__append_21) \ + src/lib/libtor-geoip.a $(am__append_23) $(am__append_25) \ + $(am__append_27) src/lib/libtor-intmath.a $(am__append_28) \ + src/lib/libtor-llharden.a $(am__append_29) \ + src/lib/libtor-lock.a $(am__append_30) src/lib/libtor-log.a \ + $(am__append_33) src/lib/libtor-malloc.a $(am__append_35) \ + src/lib/libtor-math.a $(am__append_37) \ + src/lib/libtor-memarea.a $(am__append_38) \ + src/lib/libtor-meminfo.a $(am__append_39) \ + src/lib/libtor-metrics.a $(am__append_40) src/lib/libtor-net.a \ + $(am__append_41) src/lib/libtor-osinfo.a $(am__append_42) \ + src/lib/libtor-process.a $(am__append_43) \ + src/lib/libtor-pubsub.a $(am__append_44) \ + src/lib/libtor-sandbox.a $(am__append_45) \ + src/lib/libtor-string.a $(am__append_46) \ + src/lib/libtor-smartlist-core.a $(am__append_47) \ + src/lib/libtor-term.a $(am__append_48) src/lib/libtor-thread.a \ + $(am__append_49) src/lib/libtor-time.a $(am__append_50) \ + src/lib/libtor-tls.a $(am__append_51) src/lib/libtor-trace.a \ + src/lib/libtor-version.a $(am__append_57) \ + src/lib/libtor-wallclock.a $(am__append_58) \ + src/trunnel/libor-trunnel.a $(am__append_59) \ + src/core/libtor-app.a $(am__append_60) $(am__append_84) \ $(OSS_FUZZ_FUZZERS) EXTRA_DIST = src/ext/ext.md src/ext/timeouts/bench/bench-add.lua \ src/ext/timeouts/bench/bench-aux.lua \ @@ -5241,24 +5394,25 @@ src/test/unittest_part2.sh src/test/unittest_part3.sh \ src/test/unittest_part4.sh src/test/unittest_part5.sh \ src/test/unittest_part6.sh src/test/unittest_part7.sh \ - src/test/unittest_part8.sh src/win32/orconfig.h \ - src/config/geoip src/config/geoip6 src/config/torrc.minimal.in \ - src/config/torrc.sample.in src/config/README \ - doc/asciidoc-helper.sh $(html_in) $(man_in) $(txt_in) \ - doc/state-contents.txt doc/torrc_format.txt \ + src/test/unittest_part8.sh src/config/geoip src/config/geoip6 \ + src/config/torrc.minimal.in src/config/torrc.sample.in \ + src/config/README doc/asciidoc-helper.sh $(html_in) $(man_in) \ + $(txt_in) doc/state-contents.txt doc/torrc_format.txt \ doc/tor-doxygen.css doc/TUNING doc/HACKING/README.1st.md \ doc/HACKING/CodingStandards.md doc/HACKING/Fuzzing.md \ doc/HACKING/GettingStarted.md doc/HACKING/HelpfulTools.md \ doc/HACKING/HowToReview.md doc/HACKING/Module.md \ doc/HACKING/ReleasingTor.md doc/HACKING/WritingTests.md \ - contrib/README contrib/client-tools/torify \ + doc/HACKING/tracing/EventsCircuit.md \ + doc/HACKING/tracing/README.md contrib/README \ + contrib/client-tools/torify \ contrib/operator-tools/tor-exit-notice.html \ contrib/or-tools/exitlist contrib/win32build/tor-mingw.nsi.in \ contrib/win32build/tor.ico contrib/win32build/tor.nsi.in \ ChangeLog CONTRIBUTING CODE_OF_CONDUCT INSTALL LICENSE \ - Makefile.nmake README.md ReleaseNotes \ - scripts/build/combine_libs scripts/maint/checkIncludes.py \ - scripts/maint/checkSpace.pl scripts/maint/checkSpaceTest.sh \ + README.md ReleaseNotes scripts/build/combine_libs \ + scripts/maint/checkIncludes.py scripts/maint/checkSpace.pl \ + scripts/maint/checkSpaceTest.sh \ scripts/maint/checkspace_tests/dubious.c \ scripts/maint/checkspace_tests/dubious.h \ scripts/maint/checkspace_tests/expected.txt \ @@ -5426,13 +5580,13 @@ # ADD_C_FILE: INSERT HEADERS HERE. noinst_HEADERS = $(EXTHEADERS) $(ED25519_REF10_HDRS) \ - $(ED25519_DONNA_HDRS) $(am__append_4) src/lib/arch/bytes.h \ - src/lib/buf/buffers.h src/lib/err/backtrace.h \ - src/lib/err/torerr.h src/lib/err/torerr_sys.h \ - src/lib/cc/compat_compiler.h src/lib/cc/ctassert.h \ - src/lib/cc/tokpaste.h src/lib/cc/torint.h \ - src/lib/ctime/di_ops.h src/lib/compress/compress.h \ - src/lib/compress/compress_lzma.h \ + $(ED25519_DONNA_HDRS) $(EQUIX_HDRS) $(am__append_5) \ + $(POLYVAL_HDRS) src/lib/arch/bytes.h src/lib/buf/buffers.h \ + src/lib/err/backtrace.h src/lib/err/torerr.h \ + src/lib/err/torerr_sys.h src/lib/cc/compat_compiler.h \ + src/lib/cc/ctassert.h src/lib/cc/tokpaste.h \ + src/lib/cc/torint.h src/lib/ctime/di_ops.h \ + src/lib/compress/compress.h src/lib/compress/compress_lzma.h \ src/lib/compress/compress_none.h \ src/lib/compress/compress_sys.h \ src/lib/compress/compress_zlib.h \ @@ -5525,11 +5679,11 @@ src/lib/thread/numcpus.h src/lib/thread/thread_sys.h \ src/lib/thread/threads.h src/lib/time/compat_time.h \ src/lib/time/time_sys.h src/lib/time/tvdiff.h \ - src/lib/tls/ciphers.inc src/lib/tls/buffers_tls.h \ - src/lib/tls/nss_countbytes.h src/lib/tls/tortls.h \ - src/lib/tls/tortls_internal.h src/lib/tls/tortls_st.h \ - src/lib/tls/tortls_sys.h src/lib/tls/x509.h \ - src/lib/tls/x509_internal.h $(TRACEHEADERS) \ + src/lib/tls/ciphers.inc src/lib/tls/ciphers_v13.inc \ + src/lib/tls/buffers_tls.h src/lib/tls/nss_countbytes.h \ + src/lib/tls/tortls.h src/lib/tls/tortls_internal.h \ + src/lib/tls/tortls_st.h src/lib/tls/tortls_sys.h \ + src/lib/tls/x509.h src/lib/tls/x509_internal.h $(TRACEHEADERS) \ src/lib/version/git_revision.h src/lib/version/torversion.h \ src/lib/wallclock/approx_time.h src/lib/wallclock/timeval.h \ src/lib/wallclock/time_to_tm.h \ @@ -5537,8 +5691,11 @@ src/lib/wallclock/wallclock_sys.h $(TRUNNELHEADERS) \ src/core/crypto/hs_ntor.h src/core/crypto/onion_crypto.h \ src/core/crypto/onion_fast.h src/core/crypto/onion_ntor.h \ - src/core/crypto/onion_ntor_v3.h src/core/crypto/onion_tap.h \ - src/core/crypto/relay_crypto.h src/core/mainloop/connection.h \ + src/core/crypto/onion_ntor_v3.h src/core/crypto/relay_crypto.h \ + src/core/crypto/relay_crypto_st.h \ + src/core/crypto/relay_crypto_cgo.h \ + src/core/crypto/relay_crypto_tor1.h \ + src/core/crypto/tor1_crypt_st.h 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_state.inc \ @@ -5575,16 +5732,18 @@ src/core/or/origin_circuit_st.h src/core/or/policies.h \ src/core/or/port_cfg_st.h src/core/or/protover.h \ src/core/or/reasons.h 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/congestion_control_flow.h \ + src/core/or/relay_msg.h src/core/or/relay_msg_st.h \ + src/core/or/scheduler.h src/core/or/sendme.h \ + src/core/or/congestion_control_flow.h \ src/core/or/congestion_control_common.h \ - src/core/or/congestion_control_vegas.h \ - src/core/or/congestion_control_nola.h \ - src/core/or/congestion_control_westwood.h \ + src/core/or/congestion_control_vegas.h src/core/or/conflux.h \ + src/core/or/conflux_cell.h src/core/or/conflux_params.h \ + src/core/or/conflux_pool.h src/core/or/conflux_st.h \ + src/core/or/conflux_sys.h src/core/or/conflux_util.h \ src/core/or/server_port_cfg_st.h \ src/core/or/socks_request_st.h src/core/or/status.h \ src/core/or/tor_version_st.h src/core/or/var_cell_st.h \ - src/core/or/versions.h $(am__append_61) \ + src/core/or/versions.h $(am__append_62) \ src/core/proto/proto_cell.h src/core/proto/proto_control0.h \ src/core/proto/proto_ext_or.h src/core/proto/proto_haproxy.h \ src/core/proto/proto_http.h src/core/proto/proto_socks.h \ @@ -5663,10 +5822,10 @@ src/feature/hs/hs_ident.h src/feature/hs/hs_intropoint.h \ src/feature/hs/hs_metrics.h src/feature/hs/hs_ob.h \ src/feature/hs/hs_opts_st.h src/feature/hs/hs_options.inc \ - src/feature/hs/hs_service.h src/feature/hs/hs_stats.h \ - src/feature/hs/hsdir_index_st.h src/feature/hs/hs_sys.h \ - src/feature/hs/hs_metrics_entry.h src/feature/keymgt/loadkey.h \ - src/feature/metrics/metrics.h \ + src/feature/hs/hs_pow.h src/feature/hs/hs_service.h \ + src/feature/hs/hs_stats.h src/feature/hs/hsdir_index_st.h \ + src/feature/hs/hs_sys.h src/feature/hs/hs_metrics_entry.h \ + src/feature/keymgt/loadkey.h src/feature/metrics/metrics.h \ src/feature/metrics/metrics_sys.h \ src/feature/nodelist/authcert.h \ src/feature/nodelist/authority_cert_st.h \ @@ -5720,24 +5879,26 @@ src/app/main/main.h src/app/main/ntmain.h \ src/app/main/risky_options.h src/app/main/shutdown.h \ src/app/main/subsysmgr.h src/app/main/ntmain.h \ - src/test/fakechans.h src/test/fakecircs.h \ - src/test/hs_test_helpers.h src/test/log_test_helpers.h \ - src/test/opts_test_helpers.h src/test/resolve_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/compression_bomb.h src/test/fakechans.h \ + src/test/fakecircs.h src/test/hs_test_helpers.h \ + src/test/log_test_helpers.h src/test/opts_test_helpers.h \ + src/test/resolve_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 \ src/test/test_tortls.h src/test/test_descriptors.inc \ src/test/example_extrainfo.inc \ src/test/failing_routerdescs.inc src/test/ed25519_vectors.inc \ - src/test/test_descriptors.inc src/test/test_hs_descriptor.inc \ - src/test/vote_descriptors.inc src/test/fuzz/fuzzing.h + src/test/cgo_vectors.inc src/test/test_descriptors.inc \ + src/test/test_hs_descriptor.inc src/test/vote_descriptors.inc \ + src/test/fuzz/fuzzing.h CLEANFILES = micro-revision.i micro-revision.tmp $(asciidoc_product) DISTCLEANFILES = $(html_in) $(man_in) -MOSTLYCLEANFILES = libtor.a $(am__append_1) +MOSTLYCLEANFILES = libtor.a $(am__append_2) bin_SCRIPTS = contrib/client-tools/torify AM_CPPFLAGS = -I$(top_srcdir)/src -I$(top_srcdir)/src/ext \ -I$(top_srcdir)/src/ext/trunnel -I$(top_srcdir)/src/trunnel \ - -I$(srcdir)/src/ext -Isrc/ext -DSHARE_DATADIR="\"$(datadir)\"" \ + -I$(srcdir)/src/ext/ -I$(srcdir)/src/ext/equix/hashx/include/ \ + -DSHARE_DATADIR="\"$(datadir)\"" \ -DLOCALSTATEDIR="\"$(localstatedir)\"" \ -DBINDIR="\"$(bindir)\"" AM_CFLAGS = \ @@ -5763,12 +5924,12 @@ src/lib/libtor-sandbox.a \ src/lib/libtor-container.a \ src/lib/libtor-net.a \ - src/lib/libtor-thread.a \ src/lib/libtor-memarea.a \ src/lib/libtor-math.a \ src/lib/libtor-meminfo.a \ src/lib/libtor-osinfo.a \ src/lib/libtor-log.a \ + src/lib/libtor-thread.a \ src/lib/libtor-lock.a \ src/lib/libtor-fdio.a \ src/lib/libtor-string.a \ @@ -5799,13 +5960,13 @@ @UNITTESTS_ENABLED_TRUE@ src/lib/libtor-sandbox-testing.a \ @UNITTESTS_ENABLED_TRUE@ src/lib/libtor-container-testing.a \ @UNITTESTS_ENABLED_TRUE@ src/lib/libtor-net-testing.a \ -@UNITTESTS_ENABLED_TRUE@ src/lib/libtor-thread-testing.a \ @UNITTESTS_ENABLED_TRUE@ src/lib/libtor-memarea-testing.a \ @UNITTESTS_ENABLED_TRUE@ src/lib/libtor-math-testing.a \ @UNITTESTS_ENABLED_TRUE@ src/lib/libtor-meminfo-testing.a \ @UNITTESTS_ENABLED_TRUE@ src/lib/libtor-osinfo-testing.a \ @UNITTESTS_ENABLED_TRUE@ src/lib/libtor-term-testing.a \ @UNITTESTS_ENABLED_TRUE@ src/lib/libtor-log-testing.a \ +@UNITTESTS_ENABLED_TRUE@ src/lib/libtor-thread-testing.a \ @UNITTESTS_ENABLED_TRUE@ src/lib/libtor-lock-testing.a \ @UNITTESTS_ENABLED_TRUE@ src/lib/libtor-fdio-testing.a \ @UNITTESTS_ENABLED_TRUE@ src/lib/libtor-string-testing.a \ @@ -5821,12 +5982,8 @@ # Internal crypto libraries used in Tor -TOR_CRYPTO_LIBS = \ - src/lib/libtor-tls.a \ - src/lib/libtor-crypt-ops.a \ - $(LIBKECCAK_TINY) \ - $(LIBDONNA) - +TOR_CRYPTO_LIBS = src/lib/libtor-tls.a src/lib/libtor-crypt-ops.a \ + $(LIBKECCAK_TINY) $(LIBDONNA) $(LIBPOLYVAL) $(am__append_1) # Variants of the above for linking the testing variant of tor (for coverage # and tests) @@ -5834,7 +5991,9 @@ @UNITTESTS_ENABLED_TRUE@ src/lib/libtor-tls-testing.a \ @UNITTESTS_ENABLED_TRUE@ src/lib/libtor-crypt-ops-testing.a \ @UNITTESTS_ENABLED_TRUE@ $(LIBKECCAK_TINY) \ -@UNITTESTS_ENABLED_TRUE@ $(LIBDONNA) +@UNITTESTS_ENABLED_TRUE@ $(LIBDONNA) \ +@UNITTESTS_ENABLED_TRUE@ $(LIBPOLYVAL) \ +@UNITTESTS_ENABLED_TRUE@ $(EQUIX_LIBS) # All static libraries used to link tor. @@ -5860,19 +6019,20 @@ @UNITTESTS_ENABLED_TRUE@ src/lib/libtor-trace.a TOR_LDFLAGS_CRYPTLIB = @TOR_LDFLAGS_openssl@ -TOR_LIBS_CRYPTLIB = @TOR_OPENSSL_LIBS@ $(am__append_3) -TOR_CFLAGS_CRYPTLIB = $(am__append_2) +TOR_LIBS_CRYPTLIB = @TOR_OPENSSL_LIBS@ $(am__append_4) +TOR_CFLAGS_CRYPTLIB = $(am__append_3) EXTHEADERS = \ - src/ext/ht.h \ - src/ext/byteorder.h \ - src/ext/tinytest.h \ + src/ext/ht.h \ + src/ext/byteorder.h \ + src/ext/tinytest.h \ src/ext/tor_readpassphrase.h \ - src/ext/strlcat.c \ - src/ext/strlcpy.c \ - src/ext/getdelim.c \ + src/ext/strlcat.c \ + src/ext/strlcpy.c \ + src/ext/getdelim.c \ src/ext/tinytest_macros.h \ - src/ext/tor_queue.h \ + src/ext/tor_queue.h \ src/ext/siphash.h \ + src/ext/compat_blake2.h \ src/ext/timeouts/timeout.h \ src/ext/timeouts/timeout-debug.h \ src/ext/timeouts/timeout-bitops.c \ @@ -5992,6 +6152,57 @@ src/ext/ed25519/donna/test-internals.c LIBED25519_DONNA = src/ext/ed25519/donna/libed25519_donna.a +src_ext_equix_libhashx_a_CPPFLAGS = \ + -I$(srcdir)/src/ext/equix/hashx/include/ \ + -I$(srcdir)/src/ext/equix/hashx/src/ \ + -DHASHX_SIZE=@HASHX_SIZE@ \ + -DEQUIX_STATIC=1 -DHASHX_STATIC=1 + +src_ext_equix_libhashx_a_SOURCES = \ + src/ext/equix/hashx/src/blake2.c \ + src/ext/equix/hashx/src/compiler.c \ + src/ext/equix/hashx/src/compiler_a64.c \ + src/ext/equix/hashx/src/compiler_x86.c \ + src/ext/equix/hashx/src/context.c \ + src/ext/equix/hashx/src/hashx.c \ + src/ext/equix/hashx/src/program.c \ + src/ext/equix/hashx/src/program_exec.c \ + src/ext/equix/hashx/src/siphash.c \ + src/ext/equix/hashx/src/siphash_rng.c \ + src/ext/equix/hashx/src/virtual_memory.c + +src_ext_equix_libequix_a_CPPFLAGS = \ + -I$(srcdir)/src/ext/equix/include/ \ + -I$(srcdir)/src/ext/equix/src/ \ + $(src_ext_equix_libhashx_a_CPPFLAGS) + +src_ext_equix_libequix_a_SOURCES = \ + src/ext/equix/src/context.c \ + src/ext/equix/src/equix.c \ + src/ext/equix/src/solver.c + +EQUIX_HDRS = \ + src/ext/equix/hashx/include/hashx.h \ + src/ext/equix/hashx/src/blake2.h \ + src/ext/equix/hashx/src/compiler.h \ + src/ext/equix/hashx/src/context.h \ + src/ext/equix/hashx/src/force_inline.h \ + src/ext/equix/hashx/src/hashx_endian.h \ + src/ext/equix/hashx/src/instruction.h \ + src/ext/equix/hashx/src/program.h \ + src/ext/equix/hashx/src/siphash_rng.h \ + src/ext/equix/hashx/src/siphash.h \ + src/ext/equix/hashx/src/unreachable.h \ + src/ext/equix/hashx/src/virtual_memory.h \ + src/ext/equix/include/equix.h \ + src/ext/equix/src/context.h \ + src/ext/equix/src/solver_heap.h \ + src/ext/equix/src/solver.h + +EQUIX_LIBS = \ + src/ext/equix/libhashx.a \ + src/ext/equix/libequix.a + @BUILD_KECCAK_TINY_TRUE@src_ext_keccak_tiny_libkeccak_tiny_a_CFLAGS = \ @BUILD_KECCAK_TINY_TRUE@ @CFLAGS_CONSTTIME@ @@ -6002,6 +6213,19 @@ @BUILD_KECCAK_TINY_TRUE@ src/ext/keccak-tiny/keccak-tiny.h @BUILD_KECCAK_TINY_TRUE@LIBKECCAK_TINY = src/ext/keccak-tiny/libkeccak-tiny.a +src_ext_polyval_libpolyval_a_CFLAGS = \ + @CFLAGS_CONSTTIME@ + +src_ext_polyval_libpolyval_a_SOURCES = \ + src/ext/polyval/polyval.c + +POLYVAL_HDRS = \ + src/ext/polyval/polyval.h \ + src/ext/polyval/pclmul.c \ + src/ext/polyval/ctmul64.c \ + src/ext/polyval/ctmul.c + +LIBPOLYVAL = src/ext/polyval/libpolyval.a # ADD_C_FILE: INSERT SOURCES HERE. src_lib_libtor_buf_a_SOURCES = \ @@ -6029,8 +6253,8 @@ # ADD_C_FILE: INSERT SOURCES HERE. src_lib_libtor_ctime_a_SOURCES = \ - $(mulodi4_source) \ - src/ext/csiphash.c \ + $(mulodi4_source) \ + src/ext/csiphash.c \ src/lib/ctime/di_ops.c src_lib_libtor_ctime_testing_a_SOURCES = \ @@ -6056,10 +6280,10 @@ # ADD_C_FILE: INSERT SOURCES HERE. src_lib_libtor_confmgt_a_SOURCES = \ - src/lib/confmgt/confmgt.c \ - src/lib/confmgt/structvar.c \ - src/lib/confmgt/type_defs.c \ - src/lib/confmgt/typedvar.c \ + src/lib/confmgt/confmgt.c \ + src/lib/confmgt/structvar.c \ + src/lib/confmgt/type_defs.c \ + src/lib/confmgt/typedvar.c \ src/lib/confmgt/unitparse.c src_lib_libtor_confmgt_testing_a_SOURCES = \ @@ -6098,7 +6322,7 @@ src/lib/crypt_ops/crypto_rand_numeric.c \ src/lib/crypt_ops/crypto_rsa.c src/lib/crypt_ops/crypto_s2k.c \ src/lib/crypt_ops/crypto_util.c src/lib/crypt_ops/digestset.c \ - $(am__append_13) $(am__append_14) $(am__append_15) + $(am__append_14) $(am__append_15) $(am__append_16) src_lib_libtor_crypt_ops_a_CFLAGS = $(AM_CFLAGS) $(TOR_CFLAGS_CRYPTLIB) src_lib_libtor_crypt_ops_testing_a_SOURCES = \ $(src_lib_libtor_crypt_ops_a_SOURCES) @@ -6167,7 +6391,7 @@ src_lib_libtor_fs_a_SOURCES = src/lib/fs/conffile.c src/lib/fs/dir.c \ src/lib/fs/files.c src/lib/fs/freespace.c \ src/lib/fs/lockfile.c src/lib/fs/mmap.c src/lib/fs/path.c \ - src/lib/fs/storagedir.c src/lib/fs/userdb.c $(am__append_21) + src/lib/fs/storagedir.c src/lib/fs/userdb.c $(am__append_22) src_lib_libtor_fs_testing_a_SOURCES = \ $(src_lib_libtor_fs_a_SOURCES) @@ -6184,7 +6408,7 @@ src_lib_libtor_geoip_testing_a_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS) src_lib_libtor_geoip_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS) src_lib_libcurve25519_donna_a_CFLAGS = $(TOR_CFLAGS_CRYPTO) \ - $(am__append_23) $(am__append_25) + $(am__append_24) $(am__append_26) @BUILD_CURVE25519_DONNA_C64_TRUE@@BUILD_CURVE25519_DONNA_FALSE@src_lib_libcurve25519_donna_a_SOURCES = \ @BUILD_CURVE25519_DONNA_C64_TRUE@@BUILD_CURVE25519_DONNA_FALSE@ src/ext/curve25519_donna/curve25519-donna-c64.c @@ -6225,7 +6449,7 @@ # ADD_C_FILE: INSERT SOURCES HERE. src_lib_libtor_lock_a_SOURCES = src/lib/lock/compat_mutex.c \ - $(am__append_30) $(am__append_31) + $(am__append_31) $(am__append_32) src_lib_libtor_lock_testing_a_SOURCES = \ $(src_lib_libtor_lock_a_SOURCES) @@ -6235,7 +6459,7 @@ # ADD_C_FILE: INSERT SOURCES HERE. src_lib_libtor_log_a_SOURCES = src/lib/log/escape.c \ src/lib/log/ratelim.c src/lib/log/log.c src/lib/log/log_sys.c \ - src/lib/log/util_bug.c $(am__append_33) + src/lib/log/util_bug.c $(am__append_34) src_lib_libtor_log_testing_a_SOURCES = \ $(src_lib_libtor_log_a_SOURCES) @@ -6244,7 +6468,7 @@ # ADD_C_FILE: INSERT SOURCES HERE. src_lib_libtor_malloc_a_SOURCES = src/lib/malloc/malloc.c \ - src/lib/malloc/map_anon.c $(am__append_35) + src/lib/malloc/map_anon.c $(am__append_36) src_lib_libtor_malloc_testing_a_SOURCES = \ $(src_lib_libtor_malloc_a_SOURCES) @@ -6253,7 +6477,7 @@ # ADD_C_FILE: INSERT SOURCES HERE. src_lib_libtor_math_a_SOURCES = \ - src/lib/math/fp.c \ + src/lib/math/fp.c \ src/lib/math/laplace.c \ src/lib/math/prob_distr.c @@ -6286,8 +6510,8 @@ # ADD_C_FILE: INSERT SOURCES HERE. src_lib_libtor_metrics_a_SOURCES = \ src/lib/metrics/metrics_store.c \ - src/lib/metrics/metrics_store_entry.c \ - src/lib/metrics/metrics_common.c \ + src/lib/metrics/metrics_store_entry.c \ + src/lib/metrics/metrics_common.c \ src/lib/metrics/prometheus.c src_lib_libtor_metrics_testing_a_SOURCES = \ @@ -6299,7 +6523,7 @@ # ADD_C_FILE: INSERT SOURCES HERE. src_lib_libtor_net_a_SOURCES = \ src/lib/net/address.c \ - src/lib/net/alertsock.c \ + src/lib/net/alertsock.c \ src/lib/net/buffers_net.c \ src/lib/net/gethostname.c \ src/lib/net/inaddr.c \ @@ -6383,7 +6607,7 @@ # 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_core.c \ src/lib/smartlist_core/smartlist_split.c src_lib_libtor_smartlist_core_testing_a_SOURCES = \ @@ -6435,8 +6659,8 @@ # ADD_C_FILE: INSERT SOURCES HERE. src_lib_libtor_tls_a_SOURCES = src/lib/tls/buffers_tls.c \ - src/lib/tls/tortls.c src/lib/tls/x509.c $(am__append_51) \ - $(am__append_52) + src/lib/tls/tortls.c src/lib/tls/x509.c $(am__append_52) \ + $(am__append_53) src_lib_libtor_tls_a_CFLAGS = $(AM_CFLAGS) $(TOR_CFLAGS_CRYPTLIB) src_lib_libtor_tls_testing_a_SOURCES = \ $(src_lib_libtor_tls_a_SOURCES) @@ -6454,8 +6678,8 @@ # ADD_C_FILE: INSERT HEADERS HERE. TRACEHEADERS = src/lib/trace/trace.h src/lib/trace/trace_sys.h \ - src/lib/trace/events.h $(am__append_53) $(am__append_54) \ - $(am__append_55) + src/lib/trace/events.h $(am__append_54) $(am__append_55) \ + $(am__append_56) @USE_TRACING_FALSE@src_lib_libtor_trace_a_SOURCES = src/lib/trace/trace_stub.c @USE_TRACING_TRUE@src_lib_libtor_trace_a_SOURCES = $(LIBTOR_TRACE_A_SOURCES) @@ -6491,43 +6715,49 @@ src/trunnel/flow_control_cells.trunnel \ src/trunnel/congestion_control.trunnel \ src/trunnel/socks5.trunnel \ - src/trunnel/circpad_negotiation.trunnel + src/trunnel/circpad_negotiation.trunnel \ + src/trunnel/conflux.trunnel \ + src/trunnel/subproto_request.trunnel TRUNNELSOURCES = \ src/ext/trunnel/trunnel.c \ src/trunnel/ed25519_cert.c \ src/trunnel/extension.c \ src/trunnel/link_handshake.c \ - src/trunnel/pwbox.c \ - src/trunnel/hs/cell_establish_intro.c \ + src/trunnel/pwbox.c \ + src/trunnel/hs/cell_establish_intro.c \ src/trunnel/hs/cell_introduce1.c \ src/trunnel/hs/cell_rendezvous.c \ src/trunnel/channelpadding_negotiation.c \ - src/trunnel/sendme_cell.c \ - src/trunnel/flow_control_cells.c \ - src/trunnel/congestion_control.c \ + src/trunnel/sendme_cell.c \ + src/trunnel/flow_control_cells.c \ + src/trunnel/congestion_control.c \ src/trunnel/socks5.c \ src/trunnel/netinfo.c \ - src/trunnel/circpad_negotiation.c + src/trunnel/circpad_negotiation.c \ + src/trunnel/conflux.c \ + src/trunnel/subproto_request.c TRUNNELHEADERS = \ - src/ext/trunnel/trunnel.h \ - src/ext/trunnel/trunnel-impl.h \ - src/trunnel/trunnel-local.h \ - src/trunnel/ed25519_cert.h \ + src/ext/trunnel/trunnel.h \ + src/ext/trunnel/trunnel-impl.h \ + src/trunnel/trunnel-local.h \ + src/trunnel/ed25519_cert.h \ src/trunnel/extension.h \ - src/trunnel/link_handshake.h \ - src/trunnel/pwbox.h \ - src/trunnel/hs/cell_establish_intro.h \ + src/trunnel/link_handshake.h \ + src/trunnel/pwbox.h \ + src/trunnel/hs/cell_establish_intro.h \ src/trunnel/hs/cell_introduce1.h \ src/trunnel/hs/cell_rendezvous.h \ src/trunnel/channelpadding_negotiation.h \ - src/trunnel/sendme_cell.h \ - src/trunnel/flow_control_cells.h \ - src/trunnel/congestion_control.h \ - src/trunnel/socks5.h \ + src/trunnel/sendme_cell.h \ + src/trunnel/flow_control_cells.h \ + src/trunnel/congestion_control.h \ + src/trunnel/socks5.h \ src/trunnel/netinfo.h \ - src/trunnel/circpad_negotiation.h + src/trunnel/circpad_negotiation.h \ + src/trunnel/conflux.h \ + src/trunnel/subproto_request.h src_trunnel_libor_trunnel_a_SOURCES = $(TRUNNELSOURCES) src_trunnel_libor_trunnel_a_CPPFLAGS = \ @@ -6582,7 +6812,9 @@ LIBTOR_APP_A_SOURCES = src/core/crypto/hs_ntor.c \ src/core/crypto/onion_crypto.c src/core/crypto/onion_fast.c \ src/core/crypto/onion_ntor.c src/core/crypto/onion_ntor_v3.c \ - src/core/crypto/onion_tap.c src/core/crypto/relay_crypto.c \ + src/core/crypto/relay_crypto.c \ + src/core/crypto/relay_crypto_cgo.c \ + src/core/crypto/relay_crypto_tor1.c \ src/core/mainloop/connection.c src/core/mainloop/cpuworker.c \ src/core/mainloop/mainloop.c \ src/core/mainloop/mainloop_pubsub.c \ @@ -6602,14 +6834,16 @@ 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 src/core/or/reasons.c \ - src/core/or/relay.c 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/congestion_control_common.c \ + src/core/or/relay.c src/core/or/relay_msg.c \ + 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/congestion_control_common.c \ src/core/or/congestion_control_vegas.c \ - src/core/or/congestion_control_nola.c \ - src/core/or/congestion_control_westwood.c \ - src/core/or/congestion_control_flow.c src/core/or/status.c \ - src/core/or/versions.c $(am__append_60) \ + src/core/or/congestion_control_flow.c src/core/or/conflux.c \ + src/core/or/conflux_cell.c src/core/or/conflux_params.c \ + src/core/or/conflux_pool.c src/core/or/conflux_sys.c \ + src/core/or/conflux_util.c src/core/or/status.c \ + src/core/or/versions.c $(am__append_61) \ src/core/proto/proto_cell.c src/core/proto/proto_control0.c \ src/core/proto/proto_ext_or.c src/core/proto/proto_haproxy.c \ src/core/proto/proto_http.c src/core/proto/proto_socks.c \ @@ -6631,8 +6865,8 @@ src/feature/control/control_fmt.c \ src/feature/control/control_getinfo.c \ src/feature/control/control_proto.c \ - src/feature/control/getinfo_geoip.c $(am__append_62) \ - $(am__append_64) src/feature/dirclient/dirclient.c \ + src/feature/control/getinfo_geoip.c $(am__append_63) \ + $(am__append_65) src/feature/dirclient/dirclient.c \ src/feature/dirclient/dirclient_modes.c \ src/feature/dirclient/dlstatus.c \ src/feature/dircommon/consdiff.c \ @@ -6659,7 +6893,8 @@ src/feature/hs/hs_metrics.c src/feature/hs/hs_ob.c \ src/feature/hs/hs_service.c src/feature/hs/hs_stats.c \ src/feature/hs/hs_sys.c src/feature/hs/hs_metrics_entry.c \ - src/feature/keymgt/loadkey.c src/feature/metrics/metrics.c \ + $(am__append_67) src/feature/keymgt/loadkey.c \ + src/feature/metrics/metrics.c \ src/feature/metrics/metrics_sys.c \ src/feature/nodelist/authcert.c \ src/feature/nodelist/describe.c src/feature/nodelist/dirlist.c \ @@ -6675,7 +6910,7 @@ src/feature/nodelist/fmt_routerstatus.c \ src/feature/nodelist/torcert.c src/feature/relay/onion_queue.c \ src/feature/relay/relay_find_addr.c src/feature/relay/router.c \ - $(am__append_66) src/feature/rend/rendcommon.c \ + $(am__append_68) src/feature/rend/rendcommon.c \ src/feature/rend/rendmid.c src/feature/stats/bwhist.c \ src/feature/stats/connstats.c src/feature/stats/geoip_stats.c \ src/feature/stats/rephist.c src/feature/stats/predict_ports.c \ @@ -6683,12 +6918,12 @@ src/app/config/resolve_addr.c src/app/config/statefile.c \ src/app/main/main.c src/app/main/risky_options.c \ src/app/main/shutdown.c src/app/main/subsystem_list.c \ - src/app/main/subsysmgr.c $(am__append_68) + src/app/main/subsysmgr.c $(am__append_70) # # Sources that we only add for the real libtor_a, and not for testing. # -LIBTOR_APP_A_STUB_SOURCES = $(am__append_63) $(am__append_65) \ - $(am__append_67) +LIBTOR_APP_A_STUB_SOURCES = $(am__append_64) $(am__append_66) \ + $(am__append_69) # ADD_C_FILE: INSERT SOURCES HERE. MODULE_DIRAUTH_SOURCES = \ @@ -6720,13 +6955,18 @@ src/feature/dircache/dirserv.c +# Proof of Work module +MODULE_POW_SOURCES = \ + src/feature/hs/hs_pow.c + + # The Relay module. # ADD_C_FILE: INSERT SOURCES HERE. MODULE_RELAY_SOURCES = \ src/feature/relay/circuitbuild_relay.c \ src/feature/relay/dns.c \ - src/feature/relay/ext_orport.c \ + src/feature/relay/ext_orport.c \ src/feature/relay/routermode.c \ src/feature/relay/relay_config.c \ src/feature/relay/relay_handshake.c \ @@ -6745,7 +6985,7 @@ # tests for everything. See the UNITTESTS_ENABLED branch below. # LIBTOR_APP_TESTING_A_SOURCES = $(LIBTOR_APP_A_SOURCES) \ - $(am__append_69) + $(am__append_71) src_core_libtor_app_a_SOURCES = \ $(LIBTOR_APP_A_SOURCES) \ $(LIBTOR_APP_A_STUB_SOURCES) @@ -6805,8 +7045,8 @@ src/test/unittest_part2.sh src/test/unittest_part3.sh \ src/test/unittest_part4.sh src/test/unittest_part5.sh \ src/test/unittest_part6.sh src/test/unittest_part7.sh \ - src/test/unittest_part8.sh $(am__append_71) $(am__append_72) \ - $(am__append_73) + src/test/unittest_part8.sh $(am__append_73) $(am__append_74) \ + $(am__append_75) # These flavors are run using automake's test-driver and test-network.sh @@ -6831,16 +7071,16 @@ TEST_CHUTNEY_FLAVORS_IPV6_MIXED = mixed+hs-v3-ipv6 src_test_AM_CPPFLAGS = -DSHARE_DATADIR="\"$(datadir)\"" \ -DLOCALSTATEDIR="\"$(localstatedir)\"" \ - -DBINDIR="\"$(bindir)\"" \ - -DTOR_UNIT_TESTS \ + -DBINDIR="\"$(bindir)\"" \ + -DTOR_UNIT_TESTS \ $(AM_CPPFLAGS) # -L flags need to go in LDFLAGS. -l flags need to go in LDADD. # This seems to matter nowhere but on Windows, but I assure you that it # matters a lot there, and is quite hard to debug if you forget to do it. -src_test_test_SOURCES = $(am__append_75) $(am__append_76) -src_test_test_slow_SOURCES = $(am__append_77) +src_test_test_SOURCES = $(am__append_77) $(am__append_78) +src_test_test_slow_SOURCES = $(am__append_79) src_test_test_memwipe_SOURCES = \ src/test/test-memwipe.c @@ -6899,7 +7139,7 @@ @TOR_LDFLAGS_libevent@ src_test_bench_LDADD = \ - libtor.a \ + libtor.a \ @TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ @TOR_LIBEVENT_LIBS@ \ $(TOR_LIBS_CRYPTLIB) @TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_SHLWAPI@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@ \ @CURVE25519_LIBS@ \ @@ -6944,7 +7184,7 @@ libtor.a \ @TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ \ $(TOR_LIBS_CRYPTLIB) @TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_SHLWAPI@ @TOR_LIB_GDI@ \ - @CURVE25519_LIBS@ @TOR_TRACE_LIBS@ + @CURVE25519_LIBS@ @TOR_TRACE_LIBS@ src_test_test_hs_ntor_cl_AM_CPPFLAGS = \ $(AM_CPPFLAGS) @@ -6954,7 +7194,7 @@ @UNITTESTS_ENABLED_TRUE@ $(TOR_UTIL_TESTING_LIBS) \ @UNITTESTS_ENABLED_TRUE@ @TOR_LIB_MATH@ \ @UNITTESTS_ENABLED_TRUE@ @TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_SHLWAPI@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@ \ -@UNITTESTS_ENABLED_TRUE@ @TOR_TRACE_LIBS@ +@UNITTESTS_ENABLED_TRUE@ @TOR_TRACE_LIBS@ @UNITTESTS_ENABLED_TRUE@src_test_test_bt_cl_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS) @UNITTESTS_ENABLED_TRUE@src_test_test_bt_cl_CPPFLAGS = $(src_test_AM_CPPFLAGS) $(TEST_CPPFLAGS) @@ -6963,7 +7203,7 @@ src_tools_tor_resolve_LDADD = \ src/trunnel/libor-trunnel.a \ $(TOR_UTIL_LIBS) \ - $(TOR_CRYPTO_LIBS) $(TOR_LIBS_CRYPTLIB)\ + $(TOR_CRYPTO_LIBS) $(TOR_LIBS_CRYPTLIB)\ @TOR_LIB_MATH@ @TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_SHLWAPI@ @TOR_LIB_USERENV@ @COVERAGE_ENABLED_TRUE@src_tools_tor_cov_resolve_SOURCES = src/tools/tor-resolve.c @@ -6988,8 +7228,8 @@ src_tools_tor_print_ed_signing_cert_LDFLAGS = @TOR_LDFLAGS_zlib@ @TOR_LDFLAGS_openssl@ src_tools_tor_print_ed_signing_cert_LDADD = \ src/trunnel/libor-trunnel.a \ - $(TOR_CRYPTO_LIBS) \ - $(TOR_UTIL_LIBS) \ + $(TOR_CRYPTO_LIBS) \ + $(TOR_UTIL_LIBS) \ @TOR_LIB_MATH@ $(TOR_LIBS_CRYPTLIB) \ @TOR_LIB_WS32@ @TOR_LIB_USERENV@ @TOR_LIB_SHLWAPI@ @TOR_LIB_GDI@ @@ -7004,8 +7244,8 @@ @COVERAGE_ENABLED_TRUE@@USE_NSS_FALSE@ @TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_SHLWAPI@ @TOR_LIB_GDI@ @CURVE25519_LIBS@ @BUILD_LIBTORRUNNER_TRUE@src_tools_libtorrunner_a_SOURCES = \ -@BUILD_LIBTORRUNNER_TRUE@ src/tools/tor_runner.c \ -@BUILD_LIBTORRUNNER_TRUE@ src/feature/api/tor_api.c +@BUILD_LIBTORRUNNER_TRUE@ src/tools/tor_runner.c \ +@BUILD_LIBTORRUNNER_TRUE@ src/feature/api/tor_api.c confdir = $(sysconfdir)/tor tordatadir = $(datadir)/tor @@ -7438,9 +7678,9 @@ @USE_ASCIIDOC_FALSE@man_in = asciidoc_product = $(nodist_man1_MANS) $(doc_DATA) AM_ETAGSFLAGS = --regex='{c}/MOCK_IMPL([^,]+,\W*\([a-zA-Z0-9_]+\)\W*,/\1/s' -@COVERAGE_ENABLED_FALSE@TEST_CFLAGS = $(am__append_83) +@COVERAGE_ENABLED_FALSE@TEST_CFLAGS = $(am__append_85) @COVERAGE_ENABLED_TRUE@TEST_CFLAGS = -fno-inline -fprofile-arcs \ -@COVERAGE_ENABLED_TRUE@ -ftest-coverage $(am__append_83) +@COVERAGE_ENABLED_TRUE@ -ftest-coverage $(am__append_85) @COVERAGE_ENABLED_FALSE@TEST_CPPFLAGS = -DTOR_UNIT_TESTS @TOR_MODULES_ALL_ENABLED@ @COVERAGE_ENABLED_TRUE@@DISABLE_ASSERTS_IN_UNIT_TESTS_FALSE@TEST_CPPFLAGS = -DTOR_UNIT_TESTS -DTOR_COVERAGE @TOR_MODULES_ALL_ENABLED@ @COVERAGE_ENABLED_TRUE@@DISABLE_ASSERTS_IN_UNIT_TESTS_TRUE@TEST_CPPFLAGS = -DTOR_UNIT_TESTS -DTOR_COVERAGE -DDISABLE_ASSERTS_IN_UNIT_TESTS @TOR_MODULES_ALL_ENABLED@ @@ -7473,7 +7713,7 @@ .SUFFIXES: .c .log .o .obj .test .test$(EXEEXT) .trs am--refresh: Makefile @: -$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(srcdir)/src/include.am $(srcdir)/src/ext/include.am $(srcdir)/src/lib/arch/include.am $(srcdir)/src/lib/buf/include.am $(srcdir)/src/lib/err/include.am $(srcdir)/src/lib/cc/include.am $(srcdir)/src/lib/ctime/include.am $(srcdir)/src/lib/compress/include.am $(srcdir)/src/lib/conf/include.am $(srcdir)/src/lib/confmgt/include.am $(srcdir)/src/lib/container/include.am $(srcdir)/src/lib/crypt_ops/include.am $(srcdir)/src/lib/defs/include.am $(srcdir)/src/lib/dispatch/include.am $(srcdir)/src/lib/encoding/include.am $(srcdir)/src/lib/evloop/include.am $(srcdir)/src/lib/fdio/include.am $(srcdir)/src/lib/fs/include.am $(srcdir)/src/lib/geoip/include.am $(srcdir)/src/lib/include.libdonna.am $(srcdir)/src/lib/intmath/include.am $(srcdir)/src/lib/llharden/include.am $(srcdir)/src/lib/lock/include.am $(srcdir)/src/lib/log/include.am $(srcdir)/src/lib/malloc/include.am $(srcdir)/src/lib/math/include.am $(srcdir)/src/lib/memarea/include.am $(srcdir)/src/lib/meminfo/include.am $(srcdir)/src/lib/metrics/include.am $(srcdir)/src/lib/net/include.am $(srcdir)/src/lib/osinfo/include.am $(srcdir)/src/lib/process/include.am $(srcdir)/src/lib/pubsub/include.am $(srcdir)/src/lib/sandbox/include.am $(srcdir)/src/lib/string/include.am $(srcdir)/src/lib/subsys/include.am $(srcdir)/src/lib/smartlist_core/include.am $(srcdir)/src/lib/term/include.am $(srcdir)/src/lib/testsupport/include.am $(srcdir)/src/lib/thread/include.am $(srcdir)/src/lib/time/include.am $(srcdir)/src/lib/tls/include.am $(srcdir)/src/lib/trace/include.am $(srcdir)/src/lib/trace/usdt/include.am $(srcdir)/src/lib/trace/lttng/include.am $(srcdir)/src/lib/version/include.am $(srcdir)/src/lib/wallclock/include.am $(srcdir)/src/trunnel/include.am $(srcdir)/src/core/crypto/include.am $(srcdir)/src/core/mainloop/include.am $(srcdir)/src/core/or/include.am $(srcdir)/src/core/proto/include.am $(srcdir)/src/feature/api/include.am $(srcdir)/src/feature/client/include.am $(srcdir)/src/feature/control/include.am $(srcdir)/src/feature/dirauth/include.am $(srcdir)/src/feature/dircache/include.am $(srcdir)/src/feature/dirclient/include.am $(srcdir)/src/feature/dircommon/include.am $(srcdir)/src/feature/dirparse/include.am $(srcdir)/src/feature/hibernate/include.am $(srcdir)/src/feature/hs_common/include.am $(srcdir)/src/feature/hs/include.am $(srcdir)/src/feature/keymgt/include.am $(srcdir)/src/feature/metrics/include.am $(srcdir)/src/feature/nodelist/include.am $(srcdir)/src/feature/relay/include.am $(srcdir)/src/feature/rend/include.am $(srcdir)/src/feature/stats/include.am $(srcdir)/src/app/config/include.am $(srcdir)/src/app/main/include.am $(srcdir)/src/core/include.am $(srcdir)/src/app/include.am $(srcdir)/src/test/include.am $(srcdir)/src/tools/include.am $(srcdir)/src/win32/include.am $(srcdir)/src/config/include.am $(srcdir)/src/test/fuzz/include.am $(srcdir)/doc/include.am $(srcdir)/contrib/include.am $(am__configure_deps) +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(srcdir)/src/include.am $(srcdir)/src/ext/include.am $(srcdir)/src/lib/arch/include.am $(srcdir)/src/lib/buf/include.am $(srcdir)/src/lib/err/include.am $(srcdir)/src/lib/cc/include.am $(srcdir)/src/lib/ctime/include.am $(srcdir)/src/lib/compress/include.am $(srcdir)/src/lib/conf/include.am $(srcdir)/src/lib/confmgt/include.am $(srcdir)/src/lib/container/include.am $(srcdir)/src/lib/crypt_ops/include.am $(srcdir)/src/lib/defs/include.am $(srcdir)/src/lib/dispatch/include.am $(srcdir)/src/lib/encoding/include.am $(srcdir)/src/lib/evloop/include.am $(srcdir)/src/lib/fdio/include.am $(srcdir)/src/lib/fs/include.am $(srcdir)/src/lib/geoip/include.am $(srcdir)/src/lib/include.libdonna.am $(srcdir)/src/lib/intmath/include.am $(srcdir)/src/lib/llharden/include.am $(srcdir)/src/lib/lock/include.am $(srcdir)/src/lib/log/include.am $(srcdir)/src/lib/malloc/include.am $(srcdir)/src/lib/math/include.am $(srcdir)/src/lib/memarea/include.am $(srcdir)/src/lib/meminfo/include.am $(srcdir)/src/lib/metrics/include.am $(srcdir)/src/lib/net/include.am $(srcdir)/src/lib/osinfo/include.am $(srcdir)/src/lib/process/include.am $(srcdir)/src/lib/pubsub/include.am $(srcdir)/src/lib/sandbox/include.am $(srcdir)/src/lib/string/include.am $(srcdir)/src/lib/subsys/include.am $(srcdir)/src/lib/smartlist_core/include.am $(srcdir)/src/lib/term/include.am $(srcdir)/src/lib/testsupport/include.am $(srcdir)/src/lib/thread/include.am $(srcdir)/src/lib/time/include.am $(srcdir)/src/lib/tls/include.am $(srcdir)/src/lib/trace/include.am $(srcdir)/src/lib/trace/usdt/include.am $(srcdir)/src/lib/trace/lttng/include.am $(srcdir)/src/lib/version/include.am $(srcdir)/src/lib/wallclock/include.am $(srcdir)/src/trunnel/include.am $(srcdir)/src/core/crypto/include.am $(srcdir)/src/core/mainloop/include.am $(srcdir)/src/core/or/include.am $(srcdir)/src/core/proto/include.am $(srcdir)/src/feature/api/include.am $(srcdir)/src/feature/client/include.am $(srcdir)/src/feature/control/include.am $(srcdir)/src/feature/dirauth/include.am $(srcdir)/src/feature/dircache/include.am $(srcdir)/src/feature/dirclient/include.am $(srcdir)/src/feature/dircommon/include.am $(srcdir)/src/feature/dirparse/include.am $(srcdir)/src/feature/hibernate/include.am $(srcdir)/src/feature/hs_common/include.am $(srcdir)/src/feature/hs/include.am $(srcdir)/src/feature/keymgt/include.am $(srcdir)/src/feature/metrics/include.am $(srcdir)/src/feature/nodelist/include.am $(srcdir)/src/feature/relay/include.am $(srcdir)/src/feature/rend/include.am $(srcdir)/src/feature/stats/include.am $(srcdir)/src/app/config/include.am $(srcdir)/src/app/main/include.am $(srcdir)/src/core/include.am $(srcdir)/src/app/include.am $(srcdir)/src/test/include.am $(srcdir)/src/tools/include.am $(srcdir)/src/config/include.am $(srcdir)/src/test/fuzz/include.am $(srcdir)/doc/include.am $(srcdir)/contrib/include.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ @@ -7495,7 +7735,7 @@ echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__maybe_remake_depfiles);; \ esac; -$(srcdir)/src/include.am $(srcdir)/src/ext/include.am $(srcdir)/src/lib/arch/include.am $(srcdir)/src/lib/buf/include.am $(srcdir)/src/lib/err/include.am $(srcdir)/src/lib/cc/include.am $(srcdir)/src/lib/ctime/include.am $(srcdir)/src/lib/compress/include.am $(srcdir)/src/lib/conf/include.am $(srcdir)/src/lib/confmgt/include.am $(srcdir)/src/lib/container/include.am $(srcdir)/src/lib/crypt_ops/include.am $(srcdir)/src/lib/defs/include.am $(srcdir)/src/lib/dispatch/include.am $(srcdir)/src/lib/encoding/include.am $(srcdir)/src/lib/evloop/include.am $(srcdir)/src/lib/fdio/include.am $(srcdir)/src/lib/fs/include.am $(srcdir)/src/lib/geoip/include.am $(srcdir)/src/lib/include.libdonna.am $(srcdir)/src/lib/intmath/include.am $(srcdir)/src/lib/llharden/include.am $(srcdir)/src/lib/lock/include.am $(srcdir)/src/lib/log/include.am $(srcdir)/src/lib/malloc/include.am $(srcdir)/src/lib/math/include.am $(srcdir)/src/lib/memarea/include.am $(srcdir)/src/lib/meminfo/include.am $(srcdir)/src/lib/metrics/include.am $(srcdir)/src/lib/net/include.am $(srcdir)/src/lib/osinfo/include.am $(srcdir)/src/lib/process/include.am $(srcdir)/src/lib/pubsub/include.am $(srcdir)/src/lib/sandbox/include.am $(srcdir)/src/lib/string/include.am $(srcdir)/src/lib/subsys/include.am $(srcdir)/src/lib/smartlist_core/include.am $(srcdir)/src/lib/term/include.am $(srcdir)/src/lib/testsupport/include.am $(srcdir)/src/lib/thread/include.am $(srcdir)/src/lib/time/include.am $(srcdir)/src/lib/tls/include.am $(srcdir)/src/lib/trace/include.am $(srcdir)/src/lib/trace/usdt/include.am $(srcdir)/src/lib/trace/lttng/include.am $(srcdir)/src/lib/version/include.am $(srcdir)/src/lib/wallclock/include.am $(srcdir)/src/trunnel/include.am $(srcdir)/src/core/crypto/include.am $(srcdir)/src/core/mainloop/include.am $(srcdir)/src/core/or/include.am $(srcdir)/src/core/proto/include.am $(srcdir)/src/feature/api/include.am $(srcdir)/src/feature/client/include.am $(srcdir)/src/feature/control/include.am $(srcdir)/src/feature/dirauth/include.am $(srcdir)/src/feature/dircache/include.am $(srcdir)/src/feature/dirclient/include.am $(srcdir)/src/feature/dircommon/include.am $(srcdir)/src/feature/dirparse/include.am $(srcdir)/src/feature/hibernate/include.am $(srcdir)/src/feature/hs_common/include.am $(srcdir)/src/feature/hs/include.am $(srcdir)/src/feature/keymgt/include.am $(srcdir)/src/feature/metrics/include.am $(srcdir)/src/feature/nodelist/include.am $(srcdir)/src/feature/relay/include.am $(srcdir)/src/feature/rend/include.am $(srcdir)/src/feature/stats/include.am $(srcdir)/src/app/config/include.am $(srcdir)/src/app/main/include.am $(srcdir)/src/core/include.am $(srcdir)/src/app/include.am $(srcdir)/src/test/include.am $(srcdir)/src/tools/include.am $(srcdir)/src/win32/include.am $(srcdir)/src/config/include.am $(srcdir)/src/test/fuzz/include.am $(srcdir)/doc/include.am $(srcdir)/contrib/include.am $(am__empty): +$(srcdir)/src/include.am $(srcdir)/src/ext/include.am $(srcdir)/src/lib/arch/include.am $(srcdir)/src/lib/buf/include.am $(srcdir)/src/lib/err/include.am $(srcdir)/src/lib/cc/include.am $(srcdir)/src/lib/ctime/include.am $(srcdir)/src/lib/compress/include.am $(srcdir)/src/lib/conf/include.am $(srcdir)/src/lib/confmgt/include.am $(srcdir)/src/lib/container/include.am $(srcdir)/src/lib/crypt_ops/include.am $(srcdir)/src/lib/defs/include.am $(srcdir)/src/lib/dispatch/include.am $(srcdir)/src/lib/encoding/include.am $(srcdir)/src/lib/evloop/include.am $(srcdir)/src/lib/fdio/include.am $(srcdir)/src/lib/fs/include.am $(srcdir)/src/lib/geoip/include.am $(srcdir)/src/lib/include.libdonna.am $(srcdir)/src/lib/intmath/include.am $(srcdir)/src/lib/llharden/include.am $(srcdir)/src/lib/lock/include.am $(srcdir)/src/lib/log/include.am $(srcdir)/src/lib/malloc/include.am $(srcdir)/src/lib/math/include.am $(srcdir)/src/lib/memarea/include.am $(srcdir)/src/lib/meminfo/include.am $(srcdir)/src/lib/metrics/include.am $(srcdir)/src/lib/net/include.am $(srcdir)/src/lib/osinfo/include.am $(srcdir)/src/lib/process/include.am $(srcdir)/src/lib/pubsub/include.am $(srcdir)/src/lib/sandbox/include.am $(srcdir)/src/lib/string/include.am $(srcdir)/src/lib/subsys/include.am $(srcdir)/src/lib/smartlist_core/include.am $(srcdir)/src/lib/term/include.am $(srcdir)/src/lib/testsupport/include.am $(srcdir)/src/lib/thread/include.am $(srcdir)/src/lib/time/include.am $(srcdir)/src/lib/tls/include.am $(srcdir)/src/lib/trace/include.am $(srcdir)/src/lib/trace/usdt/include.am $(srcdir)/src/lib/trace/lttng/include.am $(srcdir)/src/lib/version/include.am $(srcdir)/src/lib/wallclock/include.am $(srcdir)/src/trunnel/include.am $(srcdir)/src/core/crypto/include.am $(srcdir)/src/core/mainloop/include.am $(srcdir)/src/core/or/include.am $(srcdir)/src/core/proto/include.am $(srcdir)/src/feature/api/include.am $(srcdir)/src/feature/client/include.am $(srcdir)/src/feature/control/include.am $(srcdir)/src/feature/dirauth/include.am $(srcdir)/src/feature/dircache/include.am $(srcdir)/src/feature/dirclient/include.am $(srcdir)/src/feature/dircommon/include.am $(srcdir)/src/feature/dirparse/include.am $(srcdir)/src/feature/hibernate/include.am $(srcdir)/src/feature/hs_common/include.am $(srcdir)/src/feature/hs/include.am $(srcdir)/src/feature/keymgt/include.am $(srcdir)/src/feature/metrics/include.am $(srcdir)/src/feature/nodelist/include.am $(srcdir)/src/feature/relay/include.am $(srcdir)/src/feature/rend/include.am $(srcdir)/src/feature/stats/include.am $(srcdir)/src/app/config/include.am $(srcdir)/src/app/main/include.am $(srcdir)/src/core/include.am $(srcdir)/src/app/include.am $(srcdir)/src/test/include.am $(srcdir)/src/tools/include.am $(srcdir)/src/config/include.am $(srcdir)/src/test/fuzz/include.am $(srcdir)/doc/include.am $(srcdir)/contrib/include.am $(am__empty): $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) $(SHELL) ./config.status --recheck @@ -7601,10 +7841,13 @@ src/core/crypto/libtor_app_testing_a-onion_ntor_v3.$(OBJEXT): \ src/core/crypto/$(am__dirstamp) \ src/core/crypto/$(DEPDIR)/$(am__dirstamp) -src/core/crypto/libtor_app_testing_a-onion_tap.$(OBJEXT): \ +src/core/crypto/libtor_app_testing_a-relay_crypto.$(OBJEXT): \ src/core/crypto/$(am__dirstamp) \ src/core/crypto/$(DEPDIR)/$(am__dirstamp) -src/core/crypto/libtor_app_testing_a-relay_crypto.$(OBJEXT): \ +src/core/crypto/libtor_app_testing_a-relay_crypto_cgo.$(OBJEXT): \ + src/core/crypto/$(am__dirstamp) \ + src/core/crypto/$(DEPDIR)/$(am__dirstamp) +src/core/crypto/libtor_app_testing_a-relay_crypto_tor1.$(OBJEXT): \ src/core/crypto/$(am__dirstamp) \ src/core/crypto/$(DEPDIR)/$(am__dirstamp) src/core/mainloop/$(am__dirstamp): @@ -7727,6 +7970,9 @@ src/core/or/libtor_app_testing_a-relay.$(OBJEXT): \ src/core/or/$(am__dirstamp) \ src/core/or/$(DEPDIR)/$(am__dirstamp) +src/core/or/libtor_app_testing_a-relay_msg.$(OBJEXT): \ + src/core/or/$(am__dirstamp) \ + src/core/or/$(DEPDIR)/$(am__dirstamp) src/core/or/libtor_app_testing_a-scheduler.$(OBJEXT): \ src/core/or/$(am__dirstamp) \ src/core/or/$(DEPDIR)/$(am__dirstamp) @@ -7745,13 +7991,25 @@ src/core/or/libtor_app_testing_a-congestion_control_vegas.$(OBJEXT): \ src/core/or/$(am__dirstamp) \ src/core/or/$(DEPDIR)/$(am__dirstamp) -src/core/or/libtor_app_testing_a-congestion_control_nola.$(OBJEXT): \ +src/core/or/libtor_app_testing_a-congestion_control_flow.$(OBJEXT): \ + src/core/or/$(am__dirstamp) \ + src/core/or/$(DEPDIR)/$(am__dirstamp) +src/core/or/libtor_app_testing_a-conflux.$(OBJEXT): \ src/core/or/$(am__dirstamp) \ src/core/or/$(DEPDIR)/$(am__dirstamp) -src/core/or/libtor_app_testing_a-congestion_control_westwood.$(OBJEXT): \ +src/core/or/libtor_app_testing_a-conflux_cell.$(OBJEXT): \ src/core/or/$(am__dirstamp) \ src/core/or/$(DEPDIR)/$(am__dirstamp) -src/core/or/libtor_app_testing_a-congestion_control_flow.$(OBJEXT): \ +src/core/or/libtor_app_testing_a-conflux_params.$(OBJEXT): \ + src/core/or/$(am__dirstamp) \ + src/core/or/$(DEPDIR)/$(am__dirstamp) +src/core/or/libtor_app_testing_a-conflux_pool.$(OBJEXT): \ + src/core/or/$(am__dirstamp) \ + src/core/or/$(DEPDIR)/$(am__dirstamp) +src/core/or/libtor_app_testing_a-conflux_sys.$(OBJEXT): \ + src/core/or/$(am__dirstamp) \ + src/core/or/$(DEPDIR)/$(am__dirstamp) +src/core/or/libtor_app_testing_a-conflux_util.$(OBJEXT): \ src/core/or/$(am__dirstamp) \ src/core/or/$(DEPDIR)/$(am__dirstamp) src/core/or/libtor_app_testing_a-status.$(OBJEXT): \ @@ -8099,6 +8357,9 @@ src/feature/hs/core_libtor_app_testing_a-hs_metrics_entry.$(OBJEXT): \ src/feature/hs/$(am__dirstamp) \ src/feature/hs/$(DEPDIR)/$(am__dirstamp) +src/feature/hs/core_libtor_app_testing_a-hs_pow.$(OBJEXT): \ + src/feature/hs/$(am__dirstamp) \ + src/feature/hs/$(DEPDIR)/$(am__dirstamp) src/feature/keymgt/$(am__dirstamp): @$(MKDIR_P) src/feature/keymgt @: > src/feature/keymgt/$(am__dirstamp) @@ -8314,11 +8575,15 @@ src/core/crypto/onion_ntor_v3.$(OBJEXT): \ src/core/crypto/$(am__dirstamp) \ src/core/crypto/$(DEPDIR)/$(am__dirstamp) -src/core/crypto/onion_tap.$(OBJEXT): src/core/crypto/$(am__dirstamp) \ - src/core/crypto/$(DEPDIR)/$(am__dirstamp) src/core/crypto/relay_crypto.$(OBJEXT): \ src/core/crypto/$(am__dirstamp) \ src/core/crypto/$(DEPDIR)/$(am__dirstamp) +src/core/crypto/relay_crypto_cgo.$(OBJEXT): \ + src/core/crypto/$(am__dirstamp) \ + src/core/crypto/$(DEPDIR)/$(am__dirstamp) +src/core/crypto/relay_crypto_tor1.$(OBJEXT): \ + src/core/crypto/$(am__dirstamp) \ + src/core/crypto/$(DEPDIR)/$(am__dirstamp) src/core/mainloop/connection.$(OBJEXT): \ src/core/mainloop/$(am__dirstamp) \ src/core/mainloop/$(DEPDIR)/$(am__dirstamp) @@ -8399,6 +8664,8 @@ src/core/or/$(DEPDIR)/$(am__dirstamp) src/core/or/relay.$(OBJEXT): src/core/or/$(am__dirstamp) \ src/core/or/$(DEPDIR)/$(am__dirstamp) +src/core/or/relay_msg.$(OBJEXT): src/core/or/$(am__dirstamp) \ + src/core/or/$(DEPDIR)/$(am__dirstamp) src/core/or/scheduler.$(OBJEXT): src/core/or/$(am__dirstamp) \ src/core/or/$(DEPDIR)/$(am__dirstamp) src/core/or/scheduler_kist.$(OBJEXT): src/core/or/$(am__dirstamp) \ @@ -8413,14 +8680,20 @@ src/core/or/congestion_control_vegas.$(OBJEXT): \ src/core/or/$(am__dirstamp) \ src/core/or/$(DEPDIR)/$(am__dirstamp) -src/core/or/congestion_control_nola.$(OBJEXT): \ +src/core/or/congestion_control_flow.$(OBJEXT): \ src/core/or/$(am__dirstamp) \ src/core/or/$(DEPDIR)/$(am__dirstamp) -src/core/or/congestion_control_westwood.$(OBJEXT): \ - src/core/or/$(am__dirstamp) \ +src/core/or/conflux.$(OBJEXT): src/core/or/$(am__dirstamp) \ src/core/or/$(DEPDIR)/$(am__dirstamp) -src/core/or/congestion_control_flow.$(OBJEXT): \ - src/core/or/$(am__dirstamp) \ +src/core/or/conflux_cell.$(OBJEXT): src/core/or/$(am__dirstamp) \ + src/core/or/$(DEPDIR)/$(am__dirstamp) +src/core/or/conflux_params.$(OBJEXT): src/core/or/$(am__dirstamp) \ + src/core/or/$(DEPDIR)/$(am__dirstamp) +src/core/or/conflux_pool.$(OBJEXT): src/core/or/$(am__dirstamp) \ + src/core/or/$(DEPDIR)/$(am__dirstamp) +src/core/or/conflux_sys.$(OBJEXT): src/core/or/$(am__dirstamp) \ + src/core/or/$(DEPDIR)/$(am__dirstamp) +src/core/or/conflux_util.$(OBJEXT): src/core/or/$(am__dirstamp) \ src/core/or/$(DEPDIR)/$(am__dirstamp) src/core/or/status.$(OBJEXT): src/core/or/$(am__dirstamp) \ src/core/or/$(DEPDIR)/$(am__dirstamp) @@ -8673,6 +8946,8 @@ src/feature/hs/hs_metrics_entry.$(OBJEXT): \ src/feature/hs/$(am__dirstamp) \ src/feature/hs/$(DEPDIR)/$(am__dirstamp) +src/feature/hs/hs_pow.$(OBJEXT): src/feature/hs/$(am__dirstamp) \ + src/feature/hs/$(DEPDIR)/$(am__dirstamp) src/feature/keymgt/loadkey.$(OBJEXT): \ src/feature/keymgt/$(am__dirstamp) \ src/feature/keymgt/$(DEPDIR)/$(am__dirstamp) @@ -8968,6 +9243,73 @@ $(AM_V_at)-rm -f src/ext/ed25519/ref10/libed25519_ref10.a $(AM_V_AR)$(src_ext_ed25519_ref10_libed25519_ref10_a_AR) src/ext/ed25519/ref10/libed25519_ref10.a $(src_ext_ed25519_ref10_libed25519_ref10_a_OBJECTS) $(src_ext_ed25519_ref10_libed25519_ref10_a_LIBADD) $(AM_V_at)$(RANLIB) src/ext/ed25519/ref10/libed25519_ref10.a +src/ext/equix/src/$(am__dirstamp): + @$(MKDIR_P) src/ext/equix/src + @: > src/ext/equix/src/$(am__dirstamp) +src/ext/equix/src/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) src/ext/equix/src/$(DEPDIR) + @: > src/ext/equix/src/$(DEPDIR)/$(am__dirstamp) +src/ext/equix/src/libequix_a-context.$(OBJEXT): \ + src/ext/equix/src/$(am__dirstamp) \ + src/ext/equix/src/$(DEPDIR)/$(am__dirstamp) +src/ext/equix/src/libequix_a-equix.$(OBJEXT): \ + src/ext/equix/src/$(am__dirstamp) \ + src/ext/equix/src/$(DEPDIR)/$(am__dirstamp) +src/ext/equix/src/libequix_a-solver.$(OBJEXT): \ + src/ext/equix/src/$(am__dirstamp) \ + src/ext/equix/src/$(DEPDIR)/$(am__dirstamp) +src/ext/equix/$(am__dirstamp): + @$(MKDIR_P) src/ext/equix + @: > src/ext/equix/$(am__dirstamp) + +src/ext/equix/libequix.a: $(src_ext_equix_libequix_a_OBJECTS) $(src_ext_equix_libequix_a_DEPENDENCIES) $(EXTRA_src_ext_equix_libequix_a_DEPENDENCIES) src/ext/equix/$(am__dirstamp) + $(AM_V_at)-rm -f src/ext/equix/libequix.a + $(AM_V_AR)$(src_ext_equix_libequix_a_AR) src/ext/equix/libequix.a $(src_ext_equix_libequix_a_OBJECTS) $(src_ext_equix_libequix_a_LIBADD) + $(AM_V_at)$(RANLIB) src/ext/equix/libequix.a +src/ext/equix/hashx/src/$(am__dirstamp): + @$(MKDIR_P) src/ext/equix/hashx/src + @: > src/ext/equix/hashx/src/$(am__dirstamp) +src/ext/equix/hashx/src/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) src/ext/equix/hashx/src/$(DEPDIR) + @: > src/ext/equix/hashx/src/$(DEPDIR)/$(am__dirstamp) +src/ext/equix/hashx/src/libhashx_a-blake2.$(OBJEXT): \ + src/ext/equix/hashx/src/$(am__dirstamp) \ + src/ext/equix/hashx/src/$(DEPDIR)/$(am__dirstamp) +src/ext/equix/hashx/src/libhashx_a-compiler.$(OBJEXT): \ + src/ext/equix/hashx/src/$(am__dirstamp) \ + src/ext/equix/hashx/src/$(DEPDIR)/$(am__dirstamp) +src/ext/equix/hashx/src/libhashx_a-compiler_a64.$(OBJEXT): \ + src/ext/equix/hashx/src/$(am__dirstamp) \ + src/ext/equix/hashx/src/$(DEPDIR)/$(am__dirstamp) +src/ext/equix/hashx/src/libhashx_a-compiler_x86.$(OBJEXT): \ + src/ext/equix/hashx/src/$(am__dirstamp) \ + src/ext/equix/hashx/src/$(DEPDIR)/$(am__dirstamp) +src/ext/equix/hashx/src/libhashx_a-context.$(OBJEXT): \ + src/ext/equix/hashx/src/$(am__dirstamp) \ + src/ext/equix/hashx/src/$(DEPDIR)/$(am__dirstamp) +src/ext/equix/hashx/src/libhashx_a-hashx.$(OBJEXT): \ + src/ext/equix/hashx/src/$(am__dirstamp) \ + src/ext/equix/hashx/src/$(DEPDIR)/$(am__dirstamp) +src/ext/equix/hashx/src/libhashx_a-program.$(OBJEXT): \ + src/ext/equix/hashx/src/$(am__dirstamp) \ + src/ext/equix/hashx/src/$(DEPDIR)/$(am__dirstamp) +src/ext/equix/hashx/src/libhashx_a-program_exec.$(OBJEXT): \ + src/ext/equix/hashx/src/$(am__dirstamp) \ + src/ext/equix/hashx/src/$(DEPDIR)/$(am__dirstamp) +src/ext/equix/hashx/src/libhashx_a-siphash.$(OBJEXT): \ + src/ext/equix/hashx/src/$(am__dirstamp) \ + src/ext/equix/hashx/src/$(DEPDIR)/$(am__dirstamp) +src/ext/equix/hashx/src/libhashx_a-siphash_rng.$(OBJEXT): \ + src/ext/equix/hashx/src/$(am__dirstamp) \ + src/ext/equix/hashx/src/$(DEPDIR)/$(am__dirstamp) +src/ext/equix/hashx/src/libhashx_a-virtual_memory.$(OBJEXT): \ + src/ext/equix/hashx/src/$(am__dirstamp) \ + src/ext/equix/hashx/src/$(DEPDIR)/$(am__dirstamp) + +src/ext/equix/libhashx.a: $(src_ext_equix_libhashx_a_OBJECTS) $(src_ext_equix_libhashx_a_DEPENDENCIES) $(EXTRA_src_ext_equix_libhashx_a_DEPENDENCIES) src/ext/equix/$(am__dirstamp) + $(AM_V_at)-rm -f src/ext/equix/libhashx.a + $(AM_V_AR)$(src_ext_equix_libhashx_a_AR) src/ext/equix/libhashx.a $(src_ext_equix_libhashx_a_OBJECTS) $(src_ext_equix_libhashx_a_LIBADD) + $(AM_V_at)$(RANLIB) src/ext/equix/libhashx.a src/ext/keccak-tiny/$(am__dirstamp): @$(MKDIR_P) src/ext/keccak-tiny @: > src/ext/keccak-tiny/$(am__dirstamp) @@ -8982,6 +9324,20 @@ $(AM_V_at)-rm -f src/ext/keccak-tiny/libkeccak-tiny.a $(AM_V_AR)$(src_ext_keccak_tiny_libkeccak_tiny_a_AR) src/ext/keccak-tiny/libkeccak-tiny.a $(src_ext_keccak_tiny_libkeccak_tiny_a_OBJECTS) $(src_ext_keccak_tiny_libkeccak_tiny_a_LIBADD) $(AM_V_at)$(RANLIB) src/ext/keccak-tiny/libkeccak-tiny.a +src/ext/polyval/$(am__dirstamp): + @$(MKDIR_P) src/ext/polyval + @: > src/ext/polyval/$(am__dirstamp) +src/ext/polyval/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) src/ext/polyval/$(DEPDIR) + @: > src/ext/polyval/$(DEPDIR)/$(am__dirstamp) +src/ext/polyval/libpolyval_a-polyval.$(OBJEXT): \ + src/ext/polyval/$(am__dirstamp) \ + src/ext/polyval/$(DEPDIR)/$(am__dirstamp) + +src/ext/polyval/libpolyval.a: $(src_ext_polyval_libpolyval_a_OBJECTS) $(src_ext_polyval_libpolyval_a_DEPENDENCIES) $(EXTRA_src_ext_polyval_libpolyval_a_DEPENDENCIES) src/ext/polyval/$(am__dirstamp) + $(AM_V_at)-rm -f src/ext/polyval/libpolyval.a + $(AM_V_AR)$(src_ext_polyval_libpolyval_a_AR) src/ext/polyval/libpolyval.a $(src_ext_polyval_libpolyval_a_OBJECTS) $(src_ext_polyval_libpolyval_a_LIBADD) + $(AM_V_at)$(RANLIB) src/ext/polyval/libpolyval.a src/ext/curve25519_donna/$(am__dirstamp): @$(MKDIR_P) src/ext/curve25519_donna @: > src/ext/curve25519_donna/$(am__dirstamp) @@ -10720,6 +11076,12 @@ src/trunnel/libor_trunnel_testing_a-circpad_negotiation.$(OBJEXT): \ src/trunnel/$(am__dirstamp) \ src/trunnel/$(DEPDIR)/$(am__dirstamp) +src/trunnel/libor_trunnel_testing_a-conflux.$(OBJEXT): \ + src/trunnel/$(am__dirstamp) \ + src/trunnel/$(DEPDIR)/$(am__dirstamp) +src/trunnel/libor_trunnel_testing_a-subproto_request.$(OBJEXT): \ + src/trunnel/$(am__dirstamp) \ + src/trunnel/$(DEPDIR)/$(am__dirstamp) src/trunnel/libor-trunnel-testing.a: $(src_trunnel_libor_trunnel_testing_a_OBJECTS) $(src_trunnel_libor_trunnel_testing_a_DEPENDENCIES) $(EXTRA_src_trunnel_libor_trunnel_testing_a_DEPENDENCIES) src/trunnel/$(am__dirstamp) $(AM_V_at)-rm -f src/trunnel/libor-trunnel-testing.a @@ -10770,6 +11132,12 @@ src/trunnel/libor_trunnel_a-circpad_negotiation.$(OBJEXT): \ src/trunnel/$(am__dirstamp) \ src/trunnel/$(DEPDIR)/$(am__dirstamp) +src/trunnel/libor_trunnel_a-conflux.$(OBJEXT): \ + src/trunnel/$(am__dirstamp) \ + src/trunnel/$(DEPDIR)/$(am__dirstamp) +src/trunnel/libor_trunnel_a-subproto_request.$(OBJEXT): \ + src/trunnel/$(am__dirstamp) \ + src/trunnel/$(DEPDIR)/$(am__dirstamp) src/trunnel/libor-trunnel.a: $(src_trunnel_libor_trunnel_a_OBJECTS) $(src_trunnel_libor_trunnel_a_DEPENDENCIES) $(EXTRA_src_trunnel_libor_trunnel_a_DEPENDENCIES) src/trunnel/$(am__dirstamp) $(AM_V_at)-rm -f src/trunnel/libor-trunnel.a @@ -11182,10 +11550,16 @@ src/test/$(am__dirstamp) src/test/$(DEPDIR)/$(am__dirstamp) src/test/test-test_config.$(OBJEXT): src/test/$(am__dirstamp) \ src/test/$(DEPDIR)/$(am__dirstamp) +src/test/test-test_conflux_cell.$(OBJEXT): src/test/$(am__dirstamp) \ + src/test/$(DEPDIR)/$(am__dirstamp) +src/test/test-test_conflux_pool.$(OBJEXT): src/test/$(am__dirstamp) \ + src/test/$(DEPDIR)/$(am__dirstamp) src/test/test-test_confmgr.$(OBJEXT): src/test/$(am__dirstamp) \ src/test/$(DEPDIR)/$(am__dirstamp) src/test/test-test_confparse.$(OBJEXT): src/test/$(am__dirstamp) \ src/test/$(DEPDIR)/$(am__dirstamp) +src/test/test-test_congestion_control.$(OBJEXT): \ + src/test/$(am__dirstamp) src/test/$(DEPDIR)/$(am__dirstamp) src/test/test-test_connection.$(OBJEXT): src/test/$(am__dirstamp) \ src/test/$(DEPDIR)/$(am__dirstamp) src/test/test-test_conscache.$(OBJEXT): src/test/$(am__dirstamp) \ @@ -11206,6 +11580,8 @@ src/test/$(DEPDIR)/$(am__dirstamp) src/test/test-test_crypto_rng.$(OBJEXT): src/test/$(am__dirstamp) \ src/test/$(DEPDIR)/$(am__dirstamp) +src/test/test-test_crypto_cgo.$(OBJEXT): src/test/$(am__dirstamp) \ + src/test/$(DEPDIR)/$(am__dirstamp) src/test/test-test_data.$(OBJEXT): src/test/$(am__dirstamp) \ src/test/$(DEPDIR)/$(am__dirstamp) src/test/test-test_dir.$(OBJEXT): src/test/$(am__dirstamp) \ @@ -11260,6 +11636,8 @@ src/test/$(DEPDIR)/$(am__dirstamp) src/test/test-test_hs_metrics.$(OBJEXT): src/test/$(am__dirstamp) \ src/test/$(DEPDIR)/$(am__dirstamp) +src/test/test-test_hs_pow.$(OBJEXT): src/test/$(am__dirstamp) \ + src/test/$(DEPDIR)/$(am__dirstamp) src/test/test-test_keypin.$(OBJEXT): src/test/$(am__dirstamp) \ src/test/$(DEPDIR)/$(am__dirstamp) src/test/test-test_link_handshake.$(OBJEXT): src/test/$(am__dirstamp) \ @@ -11432,6 +11810,8 @@ src/test/$(am__dirstamp) src/test/$(DEPDIR)/$(am__dirstamp) src/test/test_slow-test_process_slow.$(OBJEXT): \ src/test/$(am__dirstamp) src/test/$(DEPDIR)/$(am__dirstamp) +src/test/test_slow-test_hs_pow_slow.$(OBJEXT): \ + src/test/$(am__dirstamp) src/test/$(DEPDIR)/$(am__dirstamp) src/test/test_slow-test_prob_distr.$(OBJEXT): \ src/test/$(am__dirstamp) src/test/$(DEPDIR)/$(am__dirstamp) src/test/test_slow-ptr_helpers.$(OBJEXT): src/test/$(am__dirstamp) \ @@ -11544,8 +11924,11 @@ -rm -f src/ext/curve25519_donna/*.$(OBJEXT) -rm -f src/ext/ed25519/donna/*.$(OBJEXT) -rm -f src/ext/ed25519/ref10/*.$(OBJEXT) + -rm -f src/ext/equix/hashx/src/*.$(OBJEXT) + -rm -f src/ext/equix/src/*.$(OBJEXT) -rm -f src/ext/keccak-tiny/*.$(OBJEXT) -rm -f src/ext/mulodi/*.$(OBJEXT) + -rm -f src/ext/polyval/*.$(OBJEXT) -rm -f src/ext/trunnel/*.$(OBJEXT) -rm -f src/feature/api/*.$(OBJEXT) -rm -f src/feature/client/*.$(OBJEXT) @@ -11637,14 +12020,16 @@ @AMDEP_TRUE@@am__include@ @am__quote@src/core/crypto/$(DEPDIR)/libtor_app_testing_a-onion_fast.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/core/crypto/$(DEPDIR)/libtor_app_testing_a-onion_ntor.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/core/crypto/$(DEPDIR)/libtor_app_testing_a-onion_ntor_v3.Po@am__quote@ # am--include-marker -@AMDEP_TRUE@@am__include@ @am__quote@src/core/crypto/$(DEPDIR)/libtor_app_testing_a-onion_tap.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/core/crypto/$(DEPDIR)/libtor_app_testing_a-relay_crypto.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/core/crypto/$(DEPDIR)/libtor_app_testing_a-relay_crypto_cgo.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/core/crypto/$(DEPDIR)/libtor_app_testing_a-relay_crypto_tor1.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/core/crypto/$(DEPDIR)/onion_crypto.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/core/crypto/$(DEPDIR)/onion_fast.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/core/crypto/$(DEPDIR)/onion_ntor.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/core/crypto/$(DEPDIR)/onion_ntor_v3.Po@am__quote@ # am--include-marker -@AMDEP_TRUE@@am__include@ @am__quote@src/core/crypto/$(DEPDIR)/onion_tap.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/core/crypto/$(DEPDIR)/relay_crypto.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/core/crypto/$(DEPDIR)/relay_crypto_cgo.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/core/crypto/$(DEPDIR)/relay_crypto_tor1.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/core/mainloop/$(DEPDIR)/connection.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/core/mainloop/$(DEPDIR)/cpuworker.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/core/mainloop/$(DEPDIR)/libtor_app_testing_a-connection.Po@am__quote@ # am--include-marker @@ -11672,11 +12057,15 @@ @AMDEP_TRUE@@am__include@ @am__quote@src/core/or/$(DEPDIR)/circuitstats.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/core/or/$(DEPDIR)/circuituse.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/core/or/$(DEPDIR)/command.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/core/or/$(DEPDIR)/conflux.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/core/or/$(DEPDIR)/conflux_cell.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/core/or/$(DEPDIR)/conflux_params.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/core/or/$(DEPDIR)/conflux_pool.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/core/or/$(DEPDIR)/conflux_sys.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/core/or/$(DEPDIR)/conflux_util.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/core/or/$(DEPDIR)/congestion_control_common.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/core/or/$(DEPDIR)/congestion_control_flow.Po@am__quote@ # am--include-marker -@AMDEP_TRUE@@am__include@ @am__quote@src/core/or/$(DEPDIR)/congestion_control_nola.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/core/or/$(DEPDIR)/congestion_control_vegas.Po@am__quote@ # am--include-marker -@AMDEP_TRUE@@am__include@ @am__quote@src/core/or/$(DEPDIR)/congestion_control_westwood.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/core/or/$(DEPDIR)/connection_edge.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/core/or/$(DEPDIR)/connection_or.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/core/or/$(DEPDIR)/crypt_path.Po@am__quote@ # am--include-marker @@ -11697,11 +12086,15 @@ @AMDEP_TRUE@@am__include@ @am__quote@src/core/or/$(DEPDIR)/libtor_app_testing_a-circuitstats.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/core/or/$(DEPDIR)/libtor_app_testing_a-circuituse.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/core/or/$(DEPDIR)/libtor_app_testing_a-command.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/core/or/$(DEPDIR)/libtor_app_testing_a-conflux.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/core/or/$(DEPDIR)/libtor_app_testing_a-conflux_cell.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/core/or/$(DEPDIR)/libtor_app_testing_a-conflux_params.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/core/or/$(DEPDIR)/libtor_app_testing_a-conflux_pool.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/core/or/$(DEPDIR)/libtor_app_testing_a-conflux_sys.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/core/or/$(DEPDIR)/libtor_app_testing_a-conflux_util.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/core/or/$(DEPDIR)/libtor_app_testing_a-congestion_control_common.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/core/or/$(DEPDIR)/libtor_app_testing_a-congestion_control_flow.Po@am__quote@ # am--include-marker -@AMDEP_TRUE@@am__include@ @am__quote@src/core/or/$(DEPDIR)/libtor_app_testing_a-congestion_control_nola.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/core/or/$(DEPDIR)/libtor_app_testing_a-congestion_control_vegas.Po@am__quote@ # am--include-marker -@AMDEP_TRUE@@am__include@ @am__quote@src/core/or/$(DEPDIR)/libtor_app_testing_a-congestion_control_westwood.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/core/or/$(DEPDIR)/libtor_app_testing_a-connection_edge.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/core/or/$(DEPDIR)/libtor_app_testing_a-connection_or.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/core/or/$(DEPDIR)/libtor_app_testing_a-crypt_path.Po@am__quote@ # am--include-marker @@ -11718,6 +12111,7 @@ @AMDEP_TRUE@@am__include@ @am__quote@src/core/or/$(DEPDIR)/libtor_app_testing_a-protover.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/core/or/$(DEPDIR)/libtor_app_testing_a-reasons.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/core/or/$(DEPDIR)/libtor_app_testing_a-relay.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/core/or/$(DEPDIR)/libtor_app_testing_a-relay_msg.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/core/or/$(DEPDIR)/libtor_app_testing_a-scheduler.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/core/or/$(DEPDIR)/libtor_app_testing_a-scheduler_kist.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/core/or/$(DEPDIR)/libtor_app_testing_a-scheduler_vanilla.Po@am__quote@ # am--include-marker @@ -11735,6 +12129,7 @@ @AMDEP_TRUE@@am__include@ @am__quote@src/core/or/$(DEPDIR)/protover.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/core/or/$(DEPDIR)/reasons.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/core/or/$(DEPDIR)/relay.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/core/or/$(DEPDIR)/relay_msg.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/core/or/$(DEPDIR)/scheduler.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/core/or/$(DEPDIR)/scheduler_kist.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/core/or/$(DEPDIR)/scheduler_vanilla.Po@am__quote@ # am--include-marker @@ -11807,9 +12202,24 @@ @AMDEP_TRUE@@am__include@ @am__quote@src/ext/ed25519/ref10/$(DEPDIR)/libed25519_ref10_a-sc_muladd.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/ext/ed25519/ref10/$(DEPDIR)/libed25519_ref10_a-sc_reduce.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/ext/ed25519/ref10/$(DEPDIR)/libed25519_ref10_a-sign.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/ext/equix/hashx/src/$(DEPDIR)/libhashx_a-blake2.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/ext/equix/hashx/src/$(DEPDIR)/libhashx_a-compiler.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/ext/equix/hashx/src/$(DEPDIR)/libhashx_a-compiler_a64.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/ext/equix/hashx/src/$(DEPDIR)/libhashx_a-compiler_x86.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/ext/equix/hashx/src/$(DEPDIR)/libhashx_a-context.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/ext/equix/hashx/src/$(DEPDIR)/libhashx_a-hashx.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/ext/equix/hashx/src/$(DEPDIR)/libhashx_a-program.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/ext/equix/hashx/src/$(DEPDIR)/libhashx_a-program_exec.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/ext/equix/hashx/src/$(DEPDIR)/libhashx_a-siphash.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/ext/equix/hashx/src/$(DEPDIR)/libhashx_a-siphash_rng.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/ext/equix/hashx/src/$(DEPDIR)/libhashx_a-virtual_memory.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/ext/equix/src/$(DEPDIR)/libequix_a-context.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/ext/equix/src/$(DEPDIR)/libequix_a-equix.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/ext/equix/src/$(DEPDIR)/libequix_a-solver.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/ext/keccak-tiny/$(DEPDIR)/libkeccak_tiny_a-keccak-tiny-unrolled.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/ext/mulodi/$(DEPDIR)/lib_libtor_ctime_a-mulodi4.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/ext/mulodi/$(DEPDIR)/lib_libtor_ctime_testing_a-mulodi4.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/ext/polyval/$(DEPDIR)/libpolyval_a-polyval.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/ext/trunnel/$(DEPDIR)/trunnel_libor_trunnel_a-trunnel.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/ext/trunnel/$(DEPDIR)/trunnel_libor_trunnel_testing_a-trunnel.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/feature/api/$(DEPDIR)/core_libtor_app_testing_a-tor_api.Po@am__quote@ # am--include-marker @@ -11951,6 +12361,7 @@ @AMDEP_TRUE@@am__include@ @am__quote@src/feature/hs/$(DEPDIR)/core_libtor_app_testing_a-hs_metrics.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/feature/hs/$(DEPDIR)/core_libtor_app_testing_a-hs_metrics_entry.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/feature/hs/$(DEPDIR)/core_libtor_app_testing_a-hs_ob.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/feature/hs/$(DEPDIR)/core_libtor_app_testing_a-hs_pow.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/feature/hs/$(DEPDIR)/core_libtor_app_testing_a-hs_service.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/feature/hs/$(DEPDIR)/core_libtor_app_testing_a-hs_stats.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/feature/hs/$(DEPDIR)/core_libtor_app_testing_a-hs_sys.Po@am__quote@ # am--include-marker @@ -11969,6 +12380,7 @@ @AMDEP_TRUE@@am__include@ @am__quote@src/feature/hs/$(DEPDIR)/hs_metrics.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/feature/hs/$(DEPDIR)/hs_metrics_entry.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/feature/hs/$(DEPDIR)/hs_ob.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/feature/hs/$(DEPDIR)/hs_pow.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/feature/hs/$(DEPDIR)/hs_service.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/feature/hs/$(DEPDIR)/hs_stats.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/feature/hs/$(DEPDIR)/hs_sys.Po@am__quote@ # am--include-marker @@ -12404,8 +12816,11 @@ @AMDEP_TRUE@@am__include@ @am__quote@src/test/$(DEPDIR)/test-test_circuituse.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/test/$(DEPDIR)/test-test_compat_libevent.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/test/$(DEPDIR)/test-test_config.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/test/$(DEPDIR)/test-test_conflux_cell.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/test/$(DEPDIR)/test-test_conflux_pool.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/test/$(DEPDIR)/test-test_confmgr.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/test/$(DEPDIR)/test-test_confparse.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/test/$(DEPDIR)/test-test_congestion_control.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/test/$(DEPDIR)/test-test_connection.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/test/$(DEPDIR)/test-test_conscache.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/test/$(DEPDIR)/test-test_consdiff.Po@am__quote@ # am--include-marker @@ -12414,6 +12829,7 @@ @AMDEP_TRUE@@am__include@ @am__quote@src/test/$(DEPDIR)/test-test_controller.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/test/$(DEPDIR)/test-test_controller_events.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/test/$(DEPDIR)/test-test_crypto.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/test/$(DEPDIR)/test-test_crypto_cgo.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/test/$(DEPDIR)/test-test_crypto_ope.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/test/$(DEPDIR)/test-test_crypto_openssl.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/test/$(DEPDIR)/test-test_crypto_rng.Po@am__quote@ # am--include-marker @@ -12445,6 +12861,7 @@ @AMDEP_TRUE@@am__include@ @am__quote@src/test/$(DEPDIR)/test-test_hs_metrics.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/test/$(DEPDIR)/test-test_hs_ntor.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/test/$(DEPDIR)/test-test_hs_ob.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/test/$(DEPDIR)/test-test_hs_pow.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/test/$(DEPDIR)/test-test_hs_service.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/test/$(DEPDIR)/test-test_keypin.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/test/$(DEPDIR)/test-test_link_handshake.Po@am__quote@ # am--include-marker @@ -12512,6 +12929,7 @@ @AMDEP_TRUE@@am__include@ @am__quote@src/test/$(DEPDIR)/test_slow-ptr_helpers.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/test/$(DEPDIR)/test_slow-rng_test_helpers.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/test/$(DEPDIR)/test_slow-test_crypto_slow.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/test/$(DEPDIR)/test_slow-test_hs_pow_slow.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/test/$(DEPDIR)/test_slow-test_prob_distr.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/test/$(DEPDIR)/test_slow-test_process_slow.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/test/$(DEPDIR)/test_slow-test_ptr_slow.Po@am__quote@ # am--include-marker @@ -12625,6 +13043,7 @@ @AMDEP_TRUE@@am__include@ @am__quote@src/tools/$(DEPDIR)/tor_runner.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/trunnel/$(DEPDIR)/libor_trunnel_a-channelpadding_negotiation.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/trunnel/$(DEPDIR)/libor_trunnel_a-circpad_negotiation.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/trunnel/$(DEPDIR)/libor_trunnel_a-conflux.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/trunnel/$(DEPDIR)/libor_trunnel_a-congestion_control.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/trunnel/$(DEPDIR)/libor_trunnel_a-ed25519_cert.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/trunnel/$(DEPDIR)/libor_trunnel_a-extension.Po@am__quote@ # am--include-marker @@ -12634,8 +13053,10 @@ @AMDEP_TRUE@@am__include@ @am__quote@src/trunnel/$(DEPDIR)/libor_trunnel_a-pwbox.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/trunnel/$(DEPDIR)/libor_trunnel_a-sendme_cell.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/trunnel/$(DEPDIR)/libor_trunnel_a-socks5.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/trunnel/$(DEPDIR)/libor_trunnel_a-subproto_request.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/trunnel/$(DEPDIR)/libor_trunnel_testing_a-channelpadding_negotiation.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/trunnel/$(DEPDIR)/libor_trunnel_testing_a-circpad_negotiation.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/trunnel/$(DEPDIR)/libor_trunnel_testing_a-conflux.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/trunnel/$(DEPDIR)/libor_trunnel_testing_a-congestion_control.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/trunnel/$(DEPDIR)/libor_trunnel_testing_a-ed25519_cert.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/trunnel/$(DEPDIR)/libor_trunnel_testing_a-extension.Po@am__quote@ # am--include-marker @@ -12645,6 +13066,7 @@ @AMDEP_TRUE@@am__include@ @am__quote@src/trunnel/$(DEPDIR)/libor_trunnel_testing_a-pwbox.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/trunnel/$(DEPDIR)/libor_trunnel_testing_a-sendme_cell.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/trunnel/$(DEPDIR)/libor_trunnel_testing_a-socks5.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/trunnel/$(DEPDIR)/libor_trunnel_testing_a-subproto_request.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/trunnel/hs/$(DEPDIR)/libor_trunnel_a-cell_establish_intro.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/trunnel/hs/$(DEPDIR)/libor_trunnel_a-cell_introduce1.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/trunnel/hs/$(DEPDIR)/libor_trunnel_a-cell_rendezvous.Po@am__quote@ # am--include-marker @@ -12744,20 +13166,6 @@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_core_libtor_app_testing_a_CPPFLAGS) $(CPPFLAGS) $(src_core_libtor_app_testing_a_CFLAGS) $(CFLAGS) -c -o src/core/crypto/libtor_app_testing_a-onion_ntor_v3.obj `if test -f 'src/core/crypto/onion_ntor_v3.c'; then $(CYGPATH_W) 'src/core/crypto/onion_ntor_v3.c'; else $(CYGPATH_W) '$(srcdir)/src/core/crypto/onion_ntor_v3.c'; fi` -src/core/crypto/libtor_app_testing_a-onion_tap.o: src/core/crypto/onion_tap.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_core_libtor_app_testing_a_CPPFLAGS) $(CPPFLAGS) $(src_core_libtor_app_testing_a_CFLAGS) $(CFLAGS) -MT src/core/crypto/libtor_app_testing_a-onion_tap.o -MD -MP -MF src/core/crypto/$(DEPDIR)/libtor_app_testing_a-onion_tap.Tpo -c -o src/core/crypto/libtor_app_testing_a-onion_tap.o `test -f 'src/core/crypto/onion_tap.c' || echo '$(srcdir)/'`src/core/crypto/onion_tap.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/core/crypto/$(DEPDIR)/libtor_app_testing_a-onion_tap.Tpo src/core/crypto/$(DEPDIR)/libtor_app_testing_a-onion_tap.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/core/crypto/onion_tap.c' object='src/core/crypto/libtor_app_testing_a-onion_tap.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_core_libtor_app_testing_a_CPPFLAGS) $(CPPFLAGS) $(src_core_libtor_app_testing_a_CFLAGS) $(CFLAGS) -c -o src/core/crypto/libtor_app_testing_a-onion_tap.o `test -f 'src/core/crypto/onion_tap.c' || echo '$(srcdir)/'`src/core/crypto/onion_tap.c - -src/core/crypto/libtor_app_testing_a-onion_tap.obj: src/core/crypto/onion_tap.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_core_libtor_app_testing_a_CPPFLAGS) $(CPPFLAGS) $(src_core_libtor_app_testing_a_CFLAGS) $(CFLAGS) -MT src/core/crypto/libtor_app_testing_a-onion_tap.obj -MD -MP -MF src/core/crypto/$(DEPDIR)/libtor_app_testing_a-onion_tap.Tpo -c -o src/core/crypto/libtor_app_testing_a-onion_tap.obj `if test -f 'src/core/crypto/onion_tap.c'; then $(CYGPATH_W) 'src/core/crypto/onion_tap.c'; else $(CYGPATH_W) '$(srcdir)/src/core/crypto/onion_tap.c'; fi` -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/core/crypto/$(DEPDIR)/libtor_app_testing_a-onion_tap.Tpo src/core/crypto/$(DEPDIR)/libtor_app_testing_a-onion_tap.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/core/crypto/onion_tap.c' object='src/core/crypto/libtor_app_testing_a-onion_tap.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_core_libtor_app_testing_a_CPPFLAGS) $(CPPFLAGS) $(src_core_libtor_app_testing_a_CFLAGS) $(CFLAGS) -c -o src/core/crypto/libtor_app_testing_a-onion_tap.obj `if test -f 'src/core/crypto/onion_tap.c'; then $(CYGPATH_W) 'src/core/crypto/onion_tap.c'; else $(CYGPATH_W) '$(srcdir)/src/core/crypto/onion_tap.c'; fi` - src/core/crypto/libtor_app_testing_a-relay_crypto.o: src/core/crypto/relay_crypto.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_core_libtor_app_testing_a_CPPFLAGS) $(CPPFLAGS) $(src_core_libtor_app_testing_a_CFLAGS) $(CFLAGS) -MT src/core/crypto/libtor_app_testing_a-relay_crypto.o -MD -MP -MF src/core/crypto/$(DEPDIR)/libtor_app_testing_a-relay_crypto.Tpo -c -o src/core/crypto/libtor_app_testing_a-relay_crypto.o `test -f 'src/core/crypto/relay_crypto.c' || echo '$(srcdir)/'`src/core/crypto/relay_crypto.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/core/crypto/$(DEPDIR)/libtor_app_testing_a-relay_crypto.Tpo src/core/crypto/$(DEPDIR)/libtor_app_testing_a-relay_crypto.Po @@ -12772,6 +13180,34 @@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_core_libtor_app_testing_a_CPPFLAGS) $(CPPFLAGS) $(src_core_libtor_app_testing_a_CFLAGS) $(CFLAGS) -c -o src/core/crypto/libtor_app_testing_a-relay_crypto.obj `if test -f 'src/core/crypto/relay_crypto.c'; then $(CYGPATH_W) 'src/core/crypto/relay_crypto.c'; else $(CYGPATH_W) '$(srcdir)/src/core/crypto/relay_crypto.c'; fi` +src/core/crypto/libtor_app_testing_a-relay_crypto_cgo.o: src/core/crypto/relay_crypto_cgo.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_core_libtor_app_testing_a_CPPFLAGS) $(CPPFLAGS) $(src_core_libtor_app_testing_a_CFLAGS) $(CFLAGS) -MT src/core/crypto/libtor_app_testing_a-relay_crypto_cgo.o -MD -MP -MF src/core/crypto/$(DEPDIR)/libtor_app_testing_a-relay_crypto_cgo.Tpo -c -o src/core/crypto/libtor_app_testing_a-relay_crypto_cgo.o `test -f 'src/core/crypto/relay_crypto_cgo.c' || echo '$(srcdir)/'`src/core/crypto/relay_crypto_cgo.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/core/crypto/$(DEPDIR)/libtor_app_testing_a-relay_crypto_cgo.Tpo src/core/crypto/$(DEPDIR)/libtor_app_testing_a-relay_crypto_cgo.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/core/crypto/relay_crypto_cgo.c' object='src/core/crypto/libtor_app_testing_a-relay_crypto_cgo.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_core_libtor_app_testing_a_CPPFLAGS) $(CPPFLAGS) $(src_core_libtor_app_testing_a_CFLAGS) $(CFLAGS) -c -o src/core/crypto/libtor_app_testing_a-relay_crypto_cgo.o `test -f 'src/core/crypto/relay_crypto_cgo.c' || echo '$(srcdir)/'`src/core/crypto/relay_crypto_cgo.c + +src/core/crypto/libtor_app_testing_a-relay_crypto_cgo.obj: src/core/crypto/relay_crypto_cgo.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_core_libtor_app_testing_a_CPPFLAGS) $(CPPFLAGS) $(src_core_libtor_app_testing_a_CFLAGS) $(CFLAGS) -MT src/core/crypto/libtor_app_testing_a-relay_crypto_cgo.obj -MD -MP -MF src/core/crypto/$(DEPDIR)/libtor_app_testing_a-relay_crypto_cgo.Tpo -c -o src/core/crypto/libtor_app_testing_a-relay_crypto_cgo.obj `if test -f 'src/core/crypto/relay_crypto_cgo.c'; then $(CYGPATH_W) 'src/core/crypto/relay_crypto_cgo.c'; else $(CYGPATH_W) '$(srcdir)/src/core/crypto/relay_crypto_cgo.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/core/crypto/$(DEPDIR)/libtor_app_testing_a-relay_crypto_cgo.Tpo src/core/crypto/$(DEPDIR)/libtor_app_testing_a-relay_crypto_cgo.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/core/crypto/relay_crypto_cgo.c' object='src/core/crypto/libtor_app_testing_a-relay_crypto_cgo.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_core_libtor_app_testing_a_CPPFLAGS) $(CPPFLAGS) $(src_core_libtor_app_testing_a_CFLAGS) $(CFLAGS) -c -o src/core/crypto/libtor_app_testing_a-relay_crypto_cgo.obj `if test -f 'src/core/crypto/relay_crypto_cgo.c'; then $(CYGPATH_W) 'src/core/crypto/relay_crypto_cgo.c'; else $(CYGPATH_W) '$(srcdir)/src/core/crypto/relay_crypto_cgo.c'; fi` + +src/core/crypto/libtor_app_testing_a-relay_crypto_tor1.o: src/core/crypto/relay_crypto_tor1.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_core_libtor_app_testing_a_CPPFLAGS) $(CPPFLAGS) $(src_core_libtor_app_testing_a_CFLAGS) $(CFLAGS) -MT src/core/crypto/libtor_app_testing_a-relay_crypto_tor1.o -MD -MP -MF src/core/crypto/$(DEPDIR)/libtor_app_testing_a-relay_crypto_tor1.Tpo -c -o src/core/crypto/libtor_app_testing_a-relay_crypto_tor1.o `test -f 'src/core/crypto/relay_crypto_tor1.c' || echo '$(srcdir)/'`src/core/crypto/relay_crypto_tor1.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/core/crypto/$(DEPDIR)/libtor_app_testing_a-relay_crypto_tor1.Tpo src/core/crypto/$(DEPDIR)/libtor_app_testing_a-relay_crypto_tor1.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/core/crypto/relay_crypto_tor1.c' object='src/core/crypto/libtor_app_testing_a-relay_crypto_tor1.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_core_libtor_app_testing_a_CPPFLAGS) $(CPPFLAGS) $(src_core_libtor_app_testing_a_CFLAGS) $(CFLAGS) -c -o src/core/crypto/libtor_app_testing_a-relay_crypto_tor1.o `test -f 'src/core/crypto/relay_crypto_tor1.c' || echo '$(srcdir)/'`src/core/crypto/relay_crypto_tor1.c + +src/core/crypto/libtor_app_testing_a-relay_crypto_tor1.obj: src/core/crypto/relay_crypto_tor1.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_core_libtor_app_testing_a_CPPFLAGS) $(CPPFLAGS) $(src_core_libtor_app_testing_a_CFLAGS) $(CFLAGS) -MT src/core/crypto/libtor_app_testing_a-relay_crypto_tor1.obj -MD -MP -MF src/core/crypto/$(DEPDIR)/libtor_app_testing_a-relay_crypto_tor1.Tpo -c -o src/core/crypto/libtor_app_testing_a-relay_crypto_tor1.obj `if test -f 'src/core/crypto/relay_crypto_tor1.c'; then $(CYGPATH_W) 'src/core/crypto/relay_crypto_tor1.c'; else $(CYGPATH_W) '$(srcdir)/src/core/crypto/relay_crypto_tor1.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/core/crypto/$(DEPDIR)/libtor_app_testing_a-relay_crypto_tor1.Tpo src/core/crypto/$(DEPDIR)/libtor_app_testing_a-relay_crypto_tor1.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/core/crypto/relay_crypto_tor1.c' object='src/core/crypto/libtor_app_testing_a-relay_crypto_tor1.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_core_libtor_app_testing_a_CPPFLAGS) $(CPPFLAGS) $(src_core_libtor_app_testing_a_CFLAGS) $(CFLAGS) -c -o src/core/crypto/libtor_app_testing_a-relay_crypto_tor1.obj `if test -f 'src/core/crypto/relay_crypto_tor1.c'; then $(CYGPATH_W) 'src/core/crypto/relay_crypto_tor1.c'; else $(CYGPATH_W) '$(srcdir)/src/core/crypto/relay_crypto_tor1.c'; fi` + src/core/mainloop/libtor_app_testing_a-connection.o: src/core/mainloop/connection.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_core_libtor_app_testing_a_CPPFLAGS) $(CPPFLAGS) $(src_core_libtor_app_testing_a_CFLAGS) $(CFLAGS) -MT src/core/mainloop/libtor_app_testing_a-connection.o -MD -MP -MF src/core/mainloop/$(DEPDIR)/libtor_app_testing_a-connection.Tpo -c -o src/core/mainloop/libtor_app_testing_a-connection.o `test -f 'src/core/mainloop/connection.c' || echo '$(srcdir)/'`src/core/mainloop/connection.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/core/mainloop/$(DEPDIR)/libtor_app_testing_a-connection.Tpo src/core/mainloop/$(DEPDIR)/libtor_app_testing_a-connection.Po @@ -13276,6 +13712,20 @@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_core_libtor_app_testing_a_CPPFLAGS) $(CPPFLAGS) $(src_core_libtor_app_testing_a_CFLAGS) $(CFLAGS) -c -o src/core/or/libtor_app_testing_a-relay.obj `if test -f 'src/core/or/relay.c'; then $(CYGPATH_W) 'src/core/or/relay.c'; else $(CYGPATH_W) '$(srcdir)/src/core/or/relay.c'; fi` +src/core/or/libtor_app_testing_a-relay_msg.o: src/core/or/relay_msg.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_core_libtor_app_testing_a_CPPFLAGS) $(CPPFLAGS) $(src_core_libtor_app_testing_a_CFLAGS) $(CFLAGS) -MT src/core/or/libtor_app_testing_a-relay_msg.o -MD -MP -MF src/core/or/$(DEPDIR)/libtor_app_testing_a-relay_msg.Tpo -c -o src/core/or/libtor_app_testing_a-relay_msg.o `test -f 'src/core/or/relay_msg.c' || echo '$(srcdir)/'`src/core/or/relay_msg.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/core/or/$(DEPDIR)/libtor_app_testing_a-relay_msg.Tpo src/core/or/$(DEPDIR)/libtor_app_testing_a-relay_msg.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/core/or/relay_msg.c' object='src/core/or/libtor_app_testing_a-relay_msg.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_core_libtor_app_testing_a_CPPFLAGS) $(CPPFLAGS) $(src_core_libtor_app_testing_a_CFLAGS) $(CFLAGS) -c -o src/core/or/libtor_app_testing_a-relay_msg.o `test -f 'src/core/or/relay_msg.c' || echo '$(srcdir)/'`src/core/or/relay_msg.c + +src/core/or/libtor_app_testing_a-relay_msg.obj: src/core/or/relay_msg.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_core_libtor_app_testing_a_CPPFLAGS) $(CPPFLAGS) $(src_core_libtor_app_testing_a_CFLAGS) $(CFLAGS) -MT src/core/or/libtor_app_testing_a-relay_msg.obj -MD -MP -MF src/core/or/$(DEPDIR)/libtor_app_testing_a-relay_msg.Tpo -c -o src/core/or/libtor_app_testing_a-relay_msg.obj `if test -f 'src/core/or/relay_msg.c'; then $(CYGPATH_W) 'src/core/or/relay_msg.c'; else $(CYGPATH_W) '$(srcdir)/src/core/or/relay_msg.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/core/or/$(DEPDIR)/libtor_app_testing_a-relay_msg.Tpo src/core/or/$(DEPDIR)/libtor_app_testing_a-relay_msg.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/core/or/relay_msg.c' object='src/core/or/libtor_app_testing_a-relay_msg.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_core_libtor_app_testing_a_CPPFLAGS) $(CPPFLAGS) $(src_core_libtor_app_testing_a_CFLAGS) $(CFLAGS) -c -o src/core/or/libtor_app_testing_a-relay_msg.obj `if test -f 'src/core/or/relay_msg.c'; then $(CYGPATH_W) 'src/core/or/relay_msg.c'; else $(CYGPATH_W) '$(srcdir)/src/core/or/relay_msg.c'; fi` + src/core/or/libtor_app_testing_a-scheduler.o: src/core/or/scheduler.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_core_libtor_app_testing_a_CPPFLAGS) $(CPPFLAGS) $(src_core_libtor_app_testing_a_CFLAGS) $(CFLAGS) -MT src/core/or/libtor_app_testing_a-scheduler.o -MD -MP -MF src/core/or/$(DEPDIR)/libtor_app_testing_a-scheduler.Tpo -c -o src/core/or/libtor_app_testing_a-scheduler.o `test -f 'src/core/or/scheduler.c' || echo '$(srcdir)/'`src/core/or/scheduler.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/core/or/$(DEPDIR)/libtor_app_testing_a-scheduler.Tpo src/core/or/$(DEPDIR)/libtor_app_testing_a-scheduler.Po @@ -13360,34 +13810,6 @@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_core_libtor_app_testing_a_CPPFLAGS) $(CPPFLAGS) $(src_core_libtor_app_testing_a_CFLAGS) $(CFLAGS) -c -o src/core/or/libtor_app_testing_a-congestion_control_vegas.obj `if test -f 'src/core/or/congestion_control_vegas.c'; then $(CYGPATH_W) 'src/core/or/congestion_control_vegas.c'; else $(CYGPATH_W) '$(srcdir)/src/core/or/congestion_control_vegas.c'; fi` -src/core/or/libtor_app_testing_a-congestion_control_nola.o: src/core/or/congestion_control_nola.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_core_libtor_app_testing_a_CPPFLAGS) $(CPPFLAGS) $(src_core_libtor_app_testing_a_CFLAGS) $(CFLAGS) -MT src/core/or/libtor_app_testing_a-congestion_control_nola.o -MD -MP -MF src/core/or/$(DEPDIR)/libtor_app_testing_a-congestion_control_nola.Tpo -c -o src/core/or/libtor_app_testing_a-congestion_control_nola.o `test -f 'src/core/or/congestion_control_nola.c' || echo '$(srcdir)/'`src/core/or/congestion_control_nola.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/core/or/$(DEPDIR)/libtor_app_testing_a-congestion_control_nola.Tpo src/core/or/$(DEPDIR)/libtor_app_testing_a-congestion_control_nola.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/core/or/congestion_control_nola.c' object='src/core/or/libtor_app_testing_a-congestion_control_nola.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_core_libtor_app_testing_a_CPPFLAGS) $(CPPFLAGS) $(src_core_libtor_app_testing_a_CFLAGS) $(CFLAGS) -c -o src/core/or/libtor_app_testing_a-congestion_control_nola.o `test -f 'src/core/or/congestion_control_nola.c' || echo '$(srcdir)/'`src/core/or/congestion_control_nola.c - -src/core/or/libtor_app_testing_a-congestion_control_nola.obj: src/core/or/congestion_control_nola.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_core_libtor_app_testing_a_CPPFLAGS) $(CPPFLAGS) $(src_core_libtor_app_testing_a_CFLAGS) $(CFLAGS) -MT src/core/or/libtor_app_testing_a-congestion_control_nola.obj -MD -MP -MF src/core/or/$(DEPDIR)/libtor_app_testing_a-congestion_control_nola.Tpo -c -o src/core/or/libtor_app_testing_a-congestion_control_nola.obj `if test -f 'src/core/or/congestion_control_nola.c'; then $(CYGPATH_W) 'src/core/or/congestion_control_nola.c'; else $(CYGPATH_W) '$(srcdir)/src/core/or/congestion_control_nola.c'; fi` -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/core/or/$(DEPDIR)/libtor_app_testing_a-congestion_control_nola.Tpo src/core/or/$(DEPDIR)/libtor_app_testing_a-congestion_control_nola.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/core/or/congestion_control_nola.c' object='src/core/or/libtor_app_testing_a-congestion_control_nola.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_core_libtor_app_testing_a_CPPFLAGS) $(CPPFLAGS) $(src_core_libtor_app_testing_a_CFLAGS) $(CFLAGS) -c -o src/core/or/libtor_app_testing_a-congestion_control_nola.obj `if test -f 'src/core/or/congestion_control_nola.c'; then $(CYGPATH_W) 'src/core/or/congestion_control_nola.c'; else $(CYGPATH_W) '$(srcdir)/src/core/or/congestion_control_nola.c'; fi` - -src/core/or/libtor_app_testing_a-congestion_control_westwood.o: src/core/or/congestion_control_westwood.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_core_libtor_app_testing_a_CPPFLAGS) $(CPPFLAGS) $(src_core_libtor_app_testing_a_CFLAGS) $(CFLAGS) -MT src/core/or/libtor_app_testing_a-congestion_control_westwood.o -MD -MP -MF src/core/or/$(DEPDIR)/libtor_app_testing_a-congestion_control_westwood.Tpo -c -o src/core/or/libtor_app_testing_a-congestion_control_westwood.o `test -f 'src/core/or/congestion_control_westwood.c' || echo '$(srcdir)/'`src/core/or/congestion_control_westwood.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/core/or/$(DEPDIR)/libtor_app_testing_a-congestion_control_westwood.Tpo src/core/or/$(DEPDIR)/libtor_app_testing_a-congestion_control_westwood.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/core/or/congestion_control_westwood.c' object='src/core/or/libtor_app_testing_a-congestion_control_westwood.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_core_libtor_app_testing_a_CPPFLAGS) $(CPPFLAGS) $(src_core_libtor_app_testing_a_CFLAGS) $(CFLAGS) -c -o src/core/or/libtor_app_testing_a-congestion_control_westwood.o `test -f 'src/core/or/congestion_control_westwood.c' || echo '$(srcdir)/'`src/core/or/congestion_control_westwood.c - -src/core/or/libtor_app_testing_a-congestion_control_westwood.obj: src/core/or/congestion_control_westwood.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_core_libtor_app_testing_a_CPPFLAGS) $(CPPFLAGS) $(src_core_libtor_app_testing_a_CFLAGS) $(CFLAGS) -MT src/core/or/libtor_app_testing_a-congestion_control_westwood.obj -MD -MP -MF src/core/or/$(DEPDIR)/libtor_app_testing_a-congestion_control_westwood.Tpo -c -o src/core/or/libtor_app_testing_a-congestion_control_westwood.obj `if test -f 'src/core/or/congestion_control_westwood.c'; then $(CYGPATH_W) 'src/core/or/congestion_control_westwood.c'; else $(CYGPATH_W) '$(srcdir)/src/core/or/congestion_control_westwood.c'; fi` -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/core/or/$(DEPDIR)/libtor_app_testing_a-congestion_control_westwood.Tpo src/core/or/$(DEPDIR)/libtor_app_testing_a-congestion_control_westwood.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/core/or/congestion_control_westwood.c' object='src/core/or/libtor_app_testing_a-congestion_control_westwood.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_core_libtor_app_testing_a_CPPFLAGS) $(CPPFLAGS) $(src_core_libtor_app_testing_a_CFLAGS) $(CFLAGS) -c -o src/core/or/libtor_app_testing_a-congestion_control_westwood.obj `if test -f 'src/core/or/congestion_control_westwood.c'; then $(CYGPATH_W) 'src/core/or/congestion_control_westwood.c'; else $(CYGPATH_W) '$(srcdir)/src/core/or/congestion_control_westwood.c'; fi` - src/core/or/libtor_app_testing_a-congestion_control_flow.o: src/core/or/congestion_control_flow.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_core_libtor_app_testing_a_CPPFLAGS) $(CPPFLAGS) $(src_core_libtor_app_testing_a_CFLAGS) $(CFLAGS) -MT src/core/or/libtor_app_testing_a-congestion_control_flow.o -MD -MP -MF src/core/or/$(DEPDIR)/libtor_app_testing_a-congestion_control_flow.Tpo -c -o src/core/or/libtor_app_testing_a-congestion_control_flow.o `test -f 'src/core/or/congestion_control_flow.c' || echo '$(srcdir)/'`src/core/or/congestion_control_flow.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/core/or/$(DEPDIR)/libtor_app_testing_a-congestion_control_flow.Tpo src/core/or/$(DEPDIR)/libtor_app_testing_a-congestion_control_flow.Po @@ -13402,6 +13824,90 @@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_core_libtor_app_testing_a_CPPFLAGS) $(CPPFLAGS) $(src_core_libtor_app_testing_a_CFLAGS) $(CFLAGS) -c -o src/core/or/libtor_app_testing_a-congestion_control_flow.obj `if test -f 'src/core/or/congestion_control_flow.c'; then $(CYGPATH_W) 'src/core/or/congestion_control_flow.c'; else $(CYGPATH_W) '$(srcdir)/src/core/or/congestion_control_flow.c'; fi` +src/core/or/libtor_app_testing_a-conflux.o: src/core/or/conflux.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_core_libtor_app_testing_a_CPPFLAGS) $(CPPFLAGS) $(src_core_libtor_app_testing_a_CFLAGS) $(CFLAGS) -MT src/core/or/libtor_app_testing_a-conflux.o -MD -MP -MF src/core/or/$(DEPDIR)/libtor_app_testing_a-conflux.Tpo -c -o src/core/or/libtor_app_testing_a-conflux.o `test -f 'src/core/or/conflux.c' || echo '$(srcdir)/'`src/core/or/conflux.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/core/or/$(DEPDIR)/libtor_app_testing_a-conflux.Tpo src/core/or/$(DEPDIR)/libtor_app_testing_a-conflux.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/core/or/conflux.c' object='src/core/or/libtor_app_testing_a-conflux.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_core_libtor_app_testing_a_CPPFLAGS) $(CPPFLAGS) $(src_core_libtor_app_testing_a_CFLAGS) $(CFLAGS) -c -o src/core/or/libtor_app_testing_a-conflux.o `test -f 'src/core/or/conflux.c' || echo '$(srcdir)/'`src/core/or/conflux.c + +src/core/or/libtor_app_testing_a-conflux.obj: src/core/or/conflux.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_core_libtor_app_testing_a_CPPFLAGS) $(CPPFLAGS) $(src_core_libtor_app_testing_a_CFLAGS) $(CFLAGS) -MT src/core/or/libtor_app_testing_a-conflux.obj -MD -MP -MF src/core/or/$(DEPDIR)/libtor_app_testing_a-conflux.Tpo -c -o src/core/or/libtor_app_testing_a-conflux.obj `if test -f 'src/core/or/conflux.c'; then $(CYGPATH_W) 'src/core/or/conflux.c'; else $(CYGPATH_W) '$(srcdir)/src/core/or/conflux.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/core/or/$(DEPDIR)/libtor_app_testing_a-conflux.Tpo src/core/or/$(DEPDIR)/libtor_app_testing_a-conflux.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/core/or/conflux.c' object='src/core/or/libtor_app_testing_a-conflux.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_core_libtor_app_testing_a_CPPFLAGS) $(CPPFLAGS) $(src_core_libtor_app_testing_a_CFLAGS) $(CFLAGS) -c -o src/core/or/libtor_app_testing_a-conflux.obj `if test -f 'src/core/or/conflux.c'; then $(CYGPATH_W) 'src/core/or/conflux.c'; else $(CYGPATH_W) '$(srcdir)/src/core/or/conflux.c'; fi` + +src/core/or/libtor_app_testing_a-conflux_cell.o: src/core/or/conflux_cell.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_core_libtor_app_testing_a_CPPFLAGS) $(CPPFLAGS) $(src_core_libtor_app_testing_a_CFLAGS) $(CFLAGS) -MT src/core/or/libtor_app_testing_a-conflux_cell.o -MD -MP -MF src/core/or/$(DEPDIR)/libtor_app_testing_a-conflux_cell.Tpo -c -o src/core/or/libtor_app_testing_a-conflux_cell.o `test -f 'src/core/or/conflux_cell.c' || echo '$(srcdir)/'`src/core/or/conflux_cell.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/core/or/$(DEPDIR)/libtor_app_testing_a-conflux_cell.Tpo src/core/or/$(DEPDIR)/libtor_app_testing_a-conflux_cell.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/core/or/conflux_cell.c' object='src/core/or/libtor_app_testing_a-conflux_cell.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_core_libtor_app_testing_a_CPPFLAGS) $(CPPFLAGS) $(src_core_libtor_app_testing_a_CFLAGS) $(CFLAGS) -c -o src/core/or/libtor_app_testing_a-conflux_cell.o `test -f 'src/core/or/conflux_cell.c' || echo '$(srcdir)/'`src/core/or/conflux_cell.c + +src/core/or/libtor_app_testing_a-conflux_cell.obj: src/core/or/conflux_cell.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_core_libtor_app_testing_a_CPPFLAGS) $(CPPFLAGS) $(src_core_libtor_app_testing_a_CFLAGS) $(CFLAGS) -MT src/core/or/libtor_app_testing_a-conflux_cell.obj -MD -MP -MF src/core/or/$(DEPDIR)/libtor_app_testing_a-conflux_cell.Tpo -c -o src/core/or/libtor_app_testing_a-conflux_cell.obj `if test -f 'src/core/or/conflux_cell.c'; then $(CYGPATH_W) 'src/core/or/conflux_cell.c'; else $(CYGPATH_W) '$(srcdir)/src/core/or/conflux_cell.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/core/or/$(DEPDIR)/libtor_app_testing_a-conflux_cell.Tpo src/core/or/$(DEPDIR)/libtor_app_testing_a-conflux_cell.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/core/or/conflux_cell.c' object='src/core/or/libtor_app_testing_a-conflux_cell.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_core_libtor_app_testing_a_CPPFLAGS) $(CPPFLAGS) $(src_core_libtor_app_testing_a_CFLAGS) $(CFLAGS) -c -o src/core/or/libtor_app_testing_a-conflux_cell.obj `if test -f 'src/core/or/conflux_cell.c'; then $(CYGPATH_W) 'src/core/or/conflux_cell.c'; else $(CYGPATH_W) '$(srcdir)/src/core/or/conflux_cell.c'; fi` + +src/core/or/libtor_app_testing_a-conflux_params.o: src/core/or/conflux_params.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_core_libtor_app_testing_a_CPPFLAGS) $(CPPFLAGS) $(src_core_libtor_app_testing_a_CFLAGS) $(CFLAGS) -MT src/core/or/libtor_app_testing_a-conflux_params.o -MD -MP -MF src/core/or/$(DEPDIR)/libtor_app_testing_a-conflux_params.Tpo -c -o src/core/or/libtor_app_testing_a-conflux_params.o `test -f 'src/core/or/conflux_params.c' || echo '$(srcdir)/'`src/core/or/conflux_params.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/core/or/$(DEPDIR)/libtor_app_testing_a-conflux_params.Tpo src/core/or/$(DEPDIR)/libtor_app_testing_a-conflux_params.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/core/or/conflux_params.c' object='src/core/or/libtor_app_testing_a-conflux_params.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_core_libtor_app_testing_a_CPPFLAGS) $(CPPFLAGS) $(src_core_libtor_app_testing_a_CFLAGS) $(CFLAGS) -c -o src/core/or/libtor_app_testing_a-conflux_params.o `test -f 'src/core/or/conflux_params.c' || echo '$(srcdir)/'`src/core/or/conflux_params.c + +src/core/or/libtor_app_testing_a-conflux_params.obj: src/core/or/conflux_params.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_core_libtor_app_testing_a_CPPFLAGS) $(CPPFLAGS) $(src_core_libtor_app_testing_a_CFLAGS) $(CFLAGS) -MT src/core/or/libtor_app_testing_a-conflux_params.obj -MD -MP -MF src/core/or/$(DEPDIR)/libtor_app_testing_a-conflux_params.Tpo -c -o src/core/or/libtor_app_testing_a-conflux_params.obj `if test -f 'src/core/or/conflux_params.c'; then $(CYGPATH_W) 'src/core/or/conflux_params.c'; else $(CYGPATH_W) '$(srcdir)/src/core/or/conflux_params.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/core/or/$(DEPDIR)/libtor_app_testing_a-conflux_params.Tpo src/core/or/$(DEPDIR)/libtor_app_testing_a-conflux_params.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/core/or/conflux_params.c' object='src/core/or/libtor_app_testing_a-conflux_params.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_core_libtor_app_testing_a_CPPFLAGS) $(CPPFLAGS) $(src_core_libtor_app_testing_a_CFLAGS) $(CFLAGS) -c -o src/core/or/libtor_app_testing_a-conflux_params.obj `if test -f 'src/core/or/conflux_params.c'; then $(CYGPATH_W) 'src/core/or/conflux_params.c'; else $(CYGPATH_W) '$(srcdir)/src/core/or/conflux_params.c'; fi` + +src/core/or/libtor_app_testing_a-conflux_pool.o: src/core/or/conflux_pool.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_core_libtor_app_testing_a_CPPFLAGS) $(CPPFLAGS) $(src_core_libtor_app_testing_a_CFLAGS) $(CFLAGS) -MT src/core/or/libtor_app_testing_a-conflux_pool.o -MD -MP -MF src/core/or/$(DEPDIR)/libtor_app_testing_a-conflux_pool.Tpo -c -o src/core/or/libtor_app_testing_a-conflux_pool.o `test -f 'src/core/or/conflux_pool.c' || echo '$(srcdir)/'`src/core/or/conflux_pool.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/core/or/$(DEPDIR)/libtor_app_testing_a-conflux_pool.Tpo src/core/or/$(DEPDIR)/libtor_app_testing_a-conflux_pool.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/core/or/conflux_pool.c' object='src/core/or/libtor_app_testing_a-conflux_pool.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_core_libtor_app_testing_a_CPPFLAGS) $(CPPFLAGS) $(src_core_libtor_app_testing_a_CFLAGS) $(CFLAGS) -c -o src/core/or/libtor_app_testing_a-conflux_pool.o `test -f 'src/core/or/conflux_pool.c' || echo '$(srcdir)/'`src/core/or/conflux_pool.c + +src/core/or/libtor_app_testing_a-conflux_pool.obj: src/core/or/conflux_pool.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_core_libtor_app_testing_a_CPPFLAGS) $(CPPFLAGS) $(src_core_libtor_app_testing_a_CFLAGS) $(CFLAGS) -MT src/core/or/libtor_app_testing_a-conflux_pool.obj -MD -MP -MF src/core/or/$(DEPDIR)/libtor_app_testing_a-conflux_pool.Tpo -c -o src/core/or/libtor_app_testing_a-conflux_pool.obj `if test -f 'src/core/or/conflux_pool.c'; then $(CYGPATH_W) 'src/core/or/conflux_pool.c'; else $(CYGPATH_W) '$(srcdir)/src/core/or/conflux_pool.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/core/or/$(DEPDIR)/libtor_app_testing_a-conflux_pool.Tpo src/core/or/$(DEPDIR)/libtor_app_testing_a-conflux_pool.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/core/or/conflux_pool.c' object='src/core/or/libtor_app_testing_a-conflux_pool.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_core_libtor_app_testing_a_CPPFLAGS) $(CPPFLAGS) $(src_core_libtor_app_testing_a_CFLAGS) $(CFLAGS) -c -o src/core/or/libtor_app_testing_a-conflux_pool.obj `if test -f 'src/core/or/conflux_pool.c'; then $(CYGPATH_W) 'src/core/or/conflux_pool.c'; else $(CYGPATH_W) '$(srcdir)/src/core/or/conflux_pool.c'; fi` + +src/core/or/libtor_app_testing_a-conflux_sys.o: src/core/or/conflux_sys.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_core_libtor_app_testing_a_CPPFLAGS) $(CPPFLAGS) $(src_core_libtor_app_testing_a_CFLAGS) $(CFLAGS) -MT src/core/or/libtor_app_testing_a-conflux_sys.o -MD -MP -MF src/core/or/$(DEPDIR)/libtor_app_testing_a-conflux_sys.Tpo -c -o src/core/or/libtor_app_testing_a-conflux_sys.o `test -f 'src/core/or/conflux_sys.c' || echo '$(srcdir)/'`src/core/or/conflux_sys.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/core/or/$(DEPDIR)/libtor_app_testing_a-conflux_sys.Tpo src/core/or/$(DEPDIR)/libtor_app_testing_a-conflux_sys.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/core/or/conflux_sys.c' object='src/core/or/libtor_app_testing_a-conflux_sys.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_core_libtor_app_testing_a_CPPFLAGS) $(CPPFLAGS) $(src_core_libtor_app_testing_a_CFLAGS) $(CFLAGS) -c -o src/core/or/libtor_app_testing_a-conflux_sys.o `test -f 'src/core/or/conflux_sys.c' || echo '$(srcdir)/'`src/core/or/conflux_sys.c + +src/core/or/libtor_app_testing_a-conflux_sys.obj: src/core/or/conflux_sys.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_core_libtor_app_testing_a_CPPFLAGS) $(CPPFLAGS) $(src_core_libtor_app_testing_a_CFLAGS) $(CFLAGS) -MT src/core/or/libtor_app_testing_a-conflux_sys.obj -MD -MP -MF src/core/or/$(DEPDIR)/libtor_app_testing_a-conflux_sys.Tpo -c -o src/core/or/libtor_app_testing_a-conflux_sys.obj `if test -f 'src/core/or/conflux_sys.c'; then $(CYGPATH_W) 'src/core/or/conflux_sys.c'; else $(CYGPATH_W) '$(srcdir)/src/core/or/conflux_sys.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/core/or/$(DEPDIR)/libtor_app_testing_a-conflux_sys.Tpo src/core/or/$(DEPDIR)/libtor_app_testing_a-conflux_sys.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/core/or/conflux_sys.c' object='src/core/or/libtor_app_testing_a-conflux_sys.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_core_libtor_app_testing_a_CPPFLAGS) $(CPPFLAGS) $(src_core_libtor_app_testing_a_CFLAGS) $(CFLAGS) -c -o src/core/or/libtor_app_testing_a-conflux_sys.obj `if test -f 'src/core/or/conflux_sys.c'; then $(CYGPATH_W) 'src/core/or/conflux_sys.c'; else $(CYGPATH_W) '$(srcdir)/src/core/or/conflux_sys.c'; fi` + +src/core/or/libtor_app_testing_a-conflux_util.o: src/core/or/conflux_util.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_core_libtor_app_testing_a_CPPFLAGS) $(CPPFLAGS) $(src_core_libtor_app_testing_a_CFLAGS) $(CFLAGS) -MT src/core/or/libtor_app_testing_a-conflux_util.o -MD -MP -MF src/core/or/$(DEPDIR)/libtor_app_testing_a-conflux_util.Tpo -c -o src/core/or/libtor_app_testing_a-conflux_util.o `test -f 'src/core/or/conflux_util.c' || echo '$(srcdir)/'`src/core/or/conflux_util.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/core/or/$(DEPDIR)/libtor_app_testing_a-conflux_util.Tpo src/core/or/$(DEPDIR)/libtor_app_testing_a-conflux_util.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/core/or/conflux_util.c' object='src/core/or/libtor_app_testing_a-conflux_util.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_core_libtor_app_testing_a_CPPFLAGS) $(CPPFLAGS) $(src_core_libtor_app_testing_a_CFLAGS) $(CFLAGS) -c -o src/core/or/libtor_app_testing_a-conflux_util.o `test -f 'src/core/or/conflux_util.c' || echo '$(srcdir)/'`src/core/or/conflux_util.c + +src/core/or/libtor_app_testing_a-conflux_util.obj: src/core/or/conflux_util.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_core_libtor_app_testing_a_CPPFLAGS) $(CPPFLAGS) $(src_core_libtor_app_testing_a_CFLAGS) $(CFLAGS) -MT src/core/or/libtor_app_testing_a-conflux_util.obj -MD -MP -MF src/core/or/$(DEPDIR)/libtor_app_testing_a-conflux_util.Tpo -c -o src/core/or/libtor_app_testing_a-conflux_util.obj `if test -f 'src/core/or/conflux_util.c'; then $(CYGPATH_W) 'src/core/or/conflux_util.c'; else $(CYGPATH_W) '$(srcdir)/src/core/or/conflux_util.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/core/or/$(DEPDIR)/libtor_app_testing_a-conflux_util.Tpo src/core/or/$(DEPDIR)/libtor_app_testing_a-conflux_util.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/core/or/conflux_util.c' object='src/core/or/libtor_app_testing_a-conflux_util.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_core_libtor_app_testing_a_CPPFLAGS) $(CPPFLAGS) $(src_core_libtor_app_testing_a_CFLAGS) $(CFLAGS) -c -o src/core/or/libtor_app_testing_a-conflux_util.obj `if test -f 'src/core/or/conflux_util.c'; then $(CYGPATH_W) 'src/core/or/conflux_util.c'; else $(CYGPATH_W) '$(srcdir)/src/core/or/conflux_util.c'; fi` + src/core/or/libtor_app_testing_a-status.o: src/core/or/status.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_core_libtor_app_testing_a_CPPFLAGS) $(CPPFLAGS) $(src_core_libtor_app_testing_a_CFLAGS) $(CFLAGS) -MT src/core/or/libtor_app_testing_a-status.o -MD -MP -MF src/core/or/$(DEPDIR)/libtor_app_testing_a-status.Tpo -c -o src/core/or/libtor_app_testing_a-status.o `test -f 'src/core/or/status.c' || echo '$(srcdir)/'`src/core/or/status.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/core/or/$(DEPDIR)/libtor_app_testing_a-status.Tpo src/core/or/$(DEPDIR)/libtor_app_testing_a-status.Po @@ -14676,6 +15182,20 @@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_core_libtor_app_testing_a_CPPFLAGS) $(CPPFLAGS) $(src_core_libtor_app_testing_a_CFLAGS) $(CFLAGS) -c -o src/feature/hs/core_libtor_app_testing_a-hs_metrics_entry.obj `if test -f 'src/feature/hs/hs_metrics_entry.c'; then $(CYGPATH_W) 'src/feature/hs/hs_metrics_entry.c'; else $(CYGPATH_W) '$(srcdir)/src/feature/hs/hs_metrics_entry.c'; fi` +src/feature/hs/core_libtor_app_testing_a-hs_pow.o: src/feature/hs/hs_pow.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_core_libtor_app_testing_a_CPPFLAGS) $(CPPFLAGS) $(src_core_libtor_app_testing_a_CFLAGS) $(CFLAGS) -MT src/feature/hs/core_libtor_app_testing_a-hs_pow.o -MD -MP -MF src/feature/hs/$(DEPDIR)/core_libtor_app_testing_a-hs_pow.Tpo -c -o src/feature/hs/core_libtor_app_testing_a-hs_pow.o `test -f 'src/feature/hs/hs_pow.c' || echo '$(srcdir)/'`src/feature/hs/hs_pow.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/feature/hs/$(DEPDIR)/core_libtor_app_testing_a-hs_pow.Tpo src/feature/hs/$(DEPDIR)/core_libtor_app_testing_a-hs_pow.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/feature/hs/hs_pow.c' object='src/feature/hs/core_libtor_app_testing_a-hs_pow.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_core_libtor_app_testing_a_CPPFLAGS) $(CPPFLAGS) $(src_core_libtor_app_testing_a_CFLAGS) $(CFLAGS) -c -o src/feature/hs/core_libtor_app_testing_a-hs_pow.o `test -f 'src/feature/hs/hs_pow.c' || echo '$(srcdir)/'`src/feature/hs/hs_pow.c + +src/feature/hs/core_libtor_app_testing_a-hs_pow.obj: src/feature/hs/hs_pow.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_core_libtor_app_testing_a_CPPFLAGS) $(CPPFLAGS) $(src_core_libtor_app_testing_a_CFLAGS) $(CFLAGS) -MT src/feature/hs/core_libtor_app_testing_a-hs_pow.obj -MD -MP -MF src/feature/hs/$(DEPDIR)/core_libtor_app_testing_a-hs_pow.Tpo -c -o src/feature/hs/core_libtor_app_testing_a-hs_pow.obj `if test -f 'src/feature/hs/hs_pow.c'; then $(CYGPATH_W) 'src/feature/hs/hs_pow.c'; else $(CYGPATH_W) '$(srcdir)/src/feature/hs/hs_pow.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/feature/hs/$(DEPDIR)/core_libtor_app_testing_a-hs_pow.Tpo src/feature/hs/$(DEPDIR)/core_libtor_app_testing_a-hs_pow.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/feature/hs/hs_pow.c' object='src/feature/hs/core_libtor_app_testing_a-hs_pow.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_core_libtor_app_testing_a_CPPFLAGS) $(CPPFLAGS) $(src_core_libtor_app_testing_a_CFLAGS) $(CFLAGS) -c -o src/feature/hs/core_libtor_app_testing_a-hs_pow.obj `if test -f 'src/feature/hs/hs_pow.c'; then $(CYGPATH_W) 'src/feature/hs/hs_pow.c'; else $(CYGPATH_W) '$(srcdir)/src/feature/hs/hs_pow.c'; fi` + src/feature/keymgt/core_libtor_app_testing_a-loadkey.o: src/feature/keymgt/loadkey.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_core_libtor_app_testing_a_CPPFLAGS) $(CPPFLAGS) $(src_core_libtor_app_testing_a_CFLAGS) $(CFLAGS) -MT src/feature/keymgt/core_libtor_app_testing_a-loadkey.o -MD -MP -MF src/feature/keymgt/$(DEPDIR)/core_libtor_app_testing_a-loadkey.Tpo -c -o src/feature/keymgt/core_libtor_app_testing_a-loadkey.o `test -f 'src/feature/keymgt/loadkey.c' || echo '$(srcdir)/'`src/feature/keymgt/loadkey.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/feature/keymgt/$(DEPDIR)/core_libtor_app_testing_a-loadkey.Tpo src/feature/keymgt/$(DEPDIR)/core_libtor_app_testing_a-loadkey.Po @@ -15950,6 +16470,202 @@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_ext_ed25519_ref10_libed25519_ref10_a_CFLAGS) $(CFLAGS) -c -o src/ext/ed25519/ref10/libed25519_ref10_a-blinding.obj `if test -f 'src/ext/ed25519/ref10/blinding.c'; then $(CYGPATH_W) 'src/ext/ed25519/ref10/blinding.c'; else $(CYGPATH_W) '$(srcdir)/src/ext/ed25519/ref10/blinding.c'; fi` +src/ext/equix/src/libequix_a-context.o: src/ext/equix/src/context.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_ext_equix_libequix_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT src/ext/equix/src/libequix_a-context.o -MD -MP -MF src/ext/equix/src/$(DEPDIR)/libequix_a-context.Tpo -c -o src/ext/equix/src/libequix_a-context.o `test -f 'src/ext/equix/src/context.c' || echo '$(srcdir)/'`src/ext/equix/src/context.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ext/equix/src/$(DEPDIR)/libequix_a-context.Tpo src/ext/equix/src/$(DEPDIR)/libequix_a-context.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ext/equix/src/context.c' object='src/ext/equix/src/libequix_a-context.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_ext_equix_libequix_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o src/ext/equix/src/libequix_a-context.o `test -f 'src/ext/equix/src/context.c' || echo '$(srcdir)/'`src/ext/equix/src/context.c + +src/ext/equix/src/libequix_a-context.obj: src/ext/equix/src/context.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_ext_equix_libequix_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT src/ext/equix/src/libequix_a-context.obj -MD -MP -MF src/ext/equix/src/$(DEPDIR)/libequix_a-context.Tpo -c -o src/ext/equix/src/libequix_a-context.obj `if test -f 'src/ext/equix/src/context.c'; then $(CYGPATH_W) 'src/ext/equix/src/context.c'; else $(CYGPATH_W) '$(srcdir)/src/ext/equix/src/context.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ext/equix/src/$(DEPDIR)/libequix_a-context.Tpo src/ext/equix/src/$(DEPDIR)/libequix_a-context.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ext/equix/src/context.c' object='src/ext/equix/src/libequix_a-context.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_ext_equix_libequix_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o src/ext/equix/src/libequix_a-context.obj `if test -f 'src/ext/equix/src/context.c'; then $(CYGPATH_W) 'src/ext/equix/src/context.c'; else $(CYGPATH_W) '$(srcdir)/src/ext/equix/src/context.c'; fi` + +src/ext/equix/src/libequix_a-equix.o: src/ext/equix/src/equix.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_ext_equix_libequix_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT src/ext/equix/src/libequix_a-equix.o -MD -MP -MF src/ext/equix/src/$(DEPDIR)/libequix_a-equix.Tpo -c -o src/ext/equix/src/libequix_a-equix.o `test -f 'src/ext/equix/src/equix.c' || echo '$(srcdir)/'`src/ext/equix/src/equix.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ext/equix/src/$(DEPDIR)/libequix_a-equix.Tpo src/ext/equix/src/$(DEPDIR)/libequix_a-equix.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ext/equix/src/equix.c' object='src/ext/equix/src/libequix_a-equix.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_ext_equix_libequix_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o src/ext/equix/src/libequix_a-equix.o `test -f 'src/ext/equix/src/equix.c' || echo '$(srcdir)/'`src/ext/equix/src/equix.c + +src/ext/equix/src/libequix_a-equix.obj: src/ext/equix/src/equix.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_ext_equix_libequix_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT src/ext/equix/src/libequix_a-equix.obj -MD -MP -MF src/ext/equix/src/$(DEPDIR)/libequix_a-equix.Tpo -c -o src/ext/equix/src/libequix_a-equix.obj `if test -f 'src/ext/equix/src/equix.c'; then $(CYGPATH_W) 'src/ext/equix/src/equix.c'; else $(CYGPATH_W) '$(srcdir)/src/ext/equix/src/equix.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ext/equix/src/$(DEPDIR)/libequix_a-equix.Tpo src/ext/equix/src/$(DEPDIR)/libequix_a-equix.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ext/equix/src/equix.c' object='src/ext/equix/src/libequix_a-equix.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_ext_equix_libequix_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o src/ext/equix/src/libequix_a-equix.obj `if test -f 'src/ext/equix/src/equix.c'; then $(CYGPATH_W) 'src/ext/equix/src/equix.c'; else $(CYGPATH_W) '$(srcdir)/src/ext/equix/src/equix.c'; fi` + +src/ext/equix/src/libequix_a-solver.o: src/ext/equix/src/solver.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_ext_equix_libequix_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT src/ext/equix/src/libequix_a-solver.o -MD -MP -MF src/ext/equix/src/$(DEPDIR)/libequix_a-solver.Tpo -c -o src/ext/equix/src/libequix_a-solver.o `test -f 'src/ext/equix/src/solver.c' || echo '$(srcdir)/'`src/ext/equix/src/solver.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ext/equix/src/$(DEPDIR)/libequix_a-solver.Tpo src/ext/equix/src/$(DEPDIR)/libequix_a-solver.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ext/equix/src/solver.c' object='src/ext/equix/src/libequix_a-solver.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_ext_equix_libequix_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o src/ext/equix/src/libequix_a-solver.o `test -f 'src/ext/equix/src/solver.c' || echo '$(srcdir)/'`src/ext/equix/src/solver.c + +src/ext/equix/src/libequix_a-solver.obj: src/ext/equix/src/solver.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_ext_equix_libequix_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT src/ext/equix/src/libequix_a-solver.obj -MD -MP -MF src/ext/equix/src/$(DEPDIR)/libequix_a-solver.Tpo -c -o src/ext/equix/src/libequix_a-solver.obj `if test -f 'src/ext/equix/src/solver.c'; then $(CYGPATH_W) 'src/ext/equix/src/solver.c'; else $(CYGPATH_W) '$(srcdir)/src/ext/equix/src/solver.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ext/equix/src/$(DEPDIR)/libequix_a-solver.Tpo src/ext/equix/src/$(DEPDIR)/libequix_a-solver.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ext/equix/src/solver.c' object='src/ext/equix/src/libequix_a-solver.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_ext_equix_libequix_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o src/ext/equix/src/libequix_a-solver.obj `if test -f 'src/ext/equix/src/solver.c'; then $(CYGPATH_W) 'src/ext/equix/src/solver.c'; else $(CYGPATH_W) '$(srcdir)/src/ext/equix/src/solver.c'; fi` + +src/ext/equix/hashx/src/libhashx_a-blake2.o: src/ext/equix/hashx/src/blake2.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_ext_equix_libhashx_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT src/ext/equix/hashx/src/libhashx_a-blake2.o -MD -MP -MF src/ext/equix/hashx/src/$(DEPDIR)/libhashx_a-blake2.Tpo -c -o src/ext/equix/hashx/src/libhashx_a-blake2.o `test -f 'src/ext/equix/hashx/src/blake2.c' || echo '$(srcdir)/'`src/ext/equix/hashx/src/blake2.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ext/equix/hashx/src/$(DEPDIR)/libhashx_a-blake2.Tpo src/ext/equix/hashx/src/$(DEPDIR)/libhashx_a-blake2.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ext/equix/hashx/src/blake2.c' object='src/ext/equix/hashx/src/libhashx_a-blake2.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_ext_equix_libhashx_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o src/ext/equix/hashx/src/libhashx_a-blake2.o `test -f 'src/ext/equix/hashx/src/blake2.c' || echo '$(srcdir)/'`src/ext/equix/hashx/src/blake2.c + +src/ext/equix/hashx/src/libhashx_a-blake2.obj: src/ext/equix/hashx/src/blake2.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_ext_equix_libhashx_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT src/ext/equix/hashx/src/libhashx_a-blake2.obj -MD -MP -MF src/ext/equix/hashx/src/$(DEPDIR)/libhashx_a-blake2.Tpo -c -o src/ext/equix/hashx/src/libhashx_a-blake2.obj `if test -f 'src/ext/equix/hashx/src/blake2.c'; then $(CYGPATH_W) 'src/ext/equix/hashx/src/blake2.c'; else $(CYGPATH_W) '$(srcdir)/src/ext/equix/hashx/src/blake2.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ext/equix/hashx/src/$(DEPDIR)/libhashx_a-blake2.Tpo src/ext/equix/hashx/src/$(DEPDIR)/libhashx_a-blake2.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ext/equix/hashx/src/blake2.c' object='src/ext/equix/hashx/src/libhashx_a-blake2.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_ext_equix_libhashx_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o src/ext/equix/hashx/src/libhashx_a-blake2.obj `if test -f 'src/ext/equix/hashx/src/blake2.c'; then $(CYGPATH_W) 'src/ext/equix/hashx/src/blake2.c'; else $(CYGPATH_W) '$(srcdir)/src/ext/equix/hashx/src/blake2.c'; fi` + +src/ext/equix/hashx/src/libhashx_a-compiler.o: src/ext/equix/hashx/src/compiler.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_ext_equix_libhashx_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT src/ext/equix/hashx/src/libhashx_a-compiler.o -MD -MP -MF src/ext/equix/hashx/src/$(DEPDIR)/libhashx_a-compiler.Tpo -c -o src/ext/equix/hashx/src/libhashx_a-compiler.o `test -f 'src/ext/equix/hashx/src/compiler.c' || echo '$(srcdir)/'`src/ext/equix/hashx/src/compiler.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ext/equix/hashx/src/$(DEPDIR)/libhashx_a-compiler.Tpo src/ext/equix/hashx/src/$(DEPDIR)/libhashx_a-compiler.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ext/equix/hashx/src/compiler.c' object='src/ext/equix/hashx/src/libhashx_a-compiler.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_ext_equix_libhashx_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o src/ext/equix/hashx/src/libhashx_a-compiler.o `test -f 'src/ext/equix/hashx/src/compiler.c' || echo '$(srcdir)/'`src/ext/equix/hashx/src/compiler.c + +src/ext/equix/hashx/src/libhashx_a-compiler.obj: src/ext/equix/hashx/src/compiler.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_ext_equix_libhashx_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT src/ext/equix/hashx/src/libhashx_a-compiler.obj -MD -MP -MF src/ext/equix/hashx/src/$(DEPDIR)/libhashx_a-compiler.Tpo -c -o src/ext/equix/hashx/src/libhashx_a-compiler.obj `if test -f 'src/ext/equix/hashx/src/compiler.c'; then $(CYGPATH_W) 'src/ext/equix/hashx/src/compiler.c'; else $(CYGPATH_W) '$(srcdir)/src/ext/equix/hashx/src/compiler.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ext/equix/hashx/src/$(DEPDIR)/libhashx_a-compiler.Tpo src/ext/equix/hashx/src/$(DEPDIR)/libhashx_a-compiler.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ext/equix/hashx/src/compiler.c' object='src/ext/equix/hashx/src/libhashx_a-compiler.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_ext_equix_libhashx_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o src/ext/equix/hashx/src/libhashx_a-compiler.obj `if test -f 'src/ext/equix/hashx/src/compiler.c'; then $(CYGPATH_W) 'src/ext/equix/hashx/src/compiler.c'; else $(CYGPATH_W) '$(srcdir)/src/ext/equix/hashx/src/compiler.c'; fi` + +src/ext/equix/hashx/src/libhashx_a-compiler_a64.o: src/ext/equix/hashx/src/compiler_a64.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_ext_equix_libhashx_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT src/ext/equix/hashx/src/libhashx_a-compiler_a64.o -MD -MP -MF src/ext/equix/hashx/src/$(DEPDIR)/libhashx_a-compiler_a64.Tpo -c -o src/ext/equix/hashx/src/libhashx_a-compiler_a64.o `test -f 'src/ext/equix/hashx/src/compiler_a64.c' || echo '$(srcdir)/'`src/ext/equix/hashx/src/compiler_a64.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ext/equix/hashx/src/$(DEPDIR)/libhashx_a-compiler_a64.Tpo src/ext/equix/hashx/src/$(DEPDIR)/libhashx_a-compiler_a64.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ext/equix/hashx/src/compiler_a64.c' object='src/ext/equix/hashx/src/libhashx_a-compiler_a64.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_ext_equix_libhashx_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o src/ext/equix/hashx/src/libhashx_a-compiler_a64.o `test -f 'src/ext/equix/hashx/src/compiler_a64.c' || echo '$(srcdir)/'`src/ext/equix/hashx/src/compiler_a64.c + +src/ext/equix/hashx/src/libhashx_a-compiler_a64.obj: src/ext/equix/hashx/src/compiler_a64.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_ext_equix_libhashx_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT src/ext/equix/hashx/src/libhashx_a-compiler_a64.obj -MD -MP -MF src/ext/equix/hashx/src/$(DEPDIR)/libhashx_a-compiler_a64.Tpo -c -o src/ext/equix/hashx/src/libhashx_a-compiler_a64.obj `if test -f 'src/ext/equix/hashx/src/compiler_a64.c'; then $(CYGPATH_W) 'src/ext/equix/hashx/src/compiler_a64.c'; else $(CYGPATH_W) '$(srcdir)/src/ext/equix/hashx/src/compiler_a64.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ext/equix/hashx/src/$(DEPDIR)/libhashx_a-compiler_a64.Tpo src/ext/equix/hashx/src/$(DEPDIR)/libhashx_a-compiler_a64.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ext/equix/hashx/src/compiler_a64.c' object='src/ext/equix/hashx/src/libhashx_a-compiler_a64.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_ext_equix_libhashx_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o src/ext/equix/hashx/src/libhashx_a-compiler_a64.obj `if test -f 'src/ext/equix/hashx/src/compiler_a64.c'; then $(CYGPATH_W) 'src/ext/equix/hashx/src/compiler_a64.c'; else $(CYGPATH_W) '$(srcdir)/src/ext/equix/hashx/src/compiler_a64.c'; fi` + +src/ext/equix/hashx/src/libhashx_a-compiler_x86.o: src/ext/equix/hashx/src/compiler_x86.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_ext_equix_libhashx_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT src/ext/equix/hashx/src/libhashx_a-compiler_x86.o -MD -MP -MF src/ext/equix/hashx/src/$(DEPDIR)/libhashx_a-compiler_x86.Tpo -c -o src/ext/equix/hashx/src/libhashx_a-compiler_x86.o `test -f 'src/ext/equix/hashx/src/compiler_x86.c' || echo '$(srcdir)/'`src/ext/equix/hashx/src/compiler_x86.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ext/equix/hashx/src/$(DEPDIR)/libhashx_a-compiler_x86.Tpo src/ext/equix/hashx/src/$(DEPDIR)/libhashx_a-compiler_x86.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ext/equix/hashx/src/compiler_x86.c' object='src/ext/equix/hashx/src/libhashx_a-compiler_x86.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_ext_equix_libhashx_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o src/ext/equix/hashx/src/libhashx_a-compiler_x86.o `test -f 'src/ext/equix/hashx/src/compiler_x86.c' || echo '$(srcdir)/'`src/ext/equix/hashx/src/compiler_x86.c + +src/ext/equix/hashx/src/libhashx_a-compiler_x86.obj: src/ext/equix/hashx/src/compiler_x86.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_ext_equix_libhashx_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT src/ext/equix/hashx/src/libhashx_a-compiler_x86.obj -MD -MP -MF src/ext/equix/hashx/src/$(DEPDIR)/libhashx_a-compiler_x86.Tpo -c -o src/ext/equix/hashx/src/libhashx_a-compiler_x86.obj `if test -f 'src/ext/equix/hashx/src/compiler_x86.c'; then $(CYGPATH_W) 'src/ext/equix/hashx/src/compiler_x86.c'; else $(CYGPATH_W) '$(srcdir)/src/ext/equix/hashx/src/compiler_x86.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ext/equix/hashx/src/$(DEPDIR)/libhashx_a-compiler_x86.Tpo src/ext/equix/hashx/src/$(DEPDIR)/libhashx_a-compiler_x86.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ext/equix/hashx/src/compiler_x86.c' object='src/ext/equix/hashx/src/libhashx_a-compiler_x86.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_ext_equix_libhashx_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o src/ext/equix/hashx/src/libhashx_a-compiler_x86.obj `if test -f 'src/ext/equix/hashx/src/compiler_x86.c'; then $(CYGPATH_W) 'src/ext/equix/hashx/src/compiler_x86.c'; else $(CYGPATH_W) '$(srcdir)/src/ext/equix/hashx/src/compiler_x86.c'; fi` + +src/ext/equix/hashx/src/libhashx_a-context.o: src/ext/equix/hashx/src/context.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_ext_equix_libhashx_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT src/ext/equix/hashx/src/libhashx_a-context.o -MD -MP -MF src/ext/equix/hashx/src/$(DEPDIR)/libhashx_a-context.Tpo -c -o src/ext/equix/hashx/src/libhashx_a-context.o `test -f 'src/ext/equix/hashx/src/context.c' || echo '$(srcdir)/'`src/ext/equix/hashx/src/context.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ext/equix/hashx/src/$(DEPDIR)/libhashx_a-context.Tpo src/ext/equix/hashx/src/$(DEPDIR)/libhashx_a-context.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ext/equix/hashx/src/context.c' object='src/ext/equix/hashx/src/libhashx_a-context.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_ext_equix_libhashx_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o src/ext/equix/hashx/src/libhashx_a-context.o `test -f 'src/ext/equix/hashx/src/context.c' || echo '$(srcdir)/'`src/ext/equix/hashx/src/context.c + +src/ext/equix/hashx/src/libhashx_a-context.obj: src/ext/equix/hashx/src/context.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_ext_equix_libhashx_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT src/ext/equix/hashx/src/libhashx_a-context.obj -MD -MP -MF src/ext/equix/hashx/src/$(DEPDIR)/libhashx_a-context.Tpo -c -o src/ext/equix/hashx/src/libhashx_a-context.obj `if test -f 'src/ext/equix/hashx/src/context.c'; then $(CYGPATH_W) 'src/ext/equix/hashx/src/context.c'; else $(CYGPATH_W) '$(srcdir)/src/ext/equix/hashx/src/context.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ext/equix/hashx/src/$(DEPDIR)/libhashx_a-context.Tpo src/ext/equix/hashx/src/$(DEPDIR)/libhashx_a-context.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ext/equix/hashx/src/context.c' object='src/ext/equix/hashx/src/libhashx_a-context.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_ext_equix_libhashx_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o src/ext/equix/hashx/src/libhashx_a-context.obj `if test -f 'src/ext/equix/hashx/src/context.c'; then $(CYGPATH_W) 'src/ext/equix/hashx/src/context.c'; else $(CYGPATH_W) '$(srcdir)/src/ext/equix/hashx/src/context.c'; fi` + +src/ext/equix/hashx/src/libhashx_a-hashx.o: src/ext/equix/hashx/src/hashx.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_ext_equix_libhashx_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT src/ext/equix/hashx/src/libhashx_a-hashx.o -MD -MP -MF src/ext/equix/hashx/src/$(DEPDIR)/libhashx_a-hashx.Tpo -c -o src/ext/equix/hashx/src/libhashx_a-hashx.o `test -f 'src/ext/equix/hashx/src/hashx.c' || echo '$(srcdir)/'`src/ext/equix/hashx/src/hashx.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ext/equix/hashx/src/$(DEPDIR)/libhashx_a-hashx.Tpo src/ext/equix/hashx/src/$(DEPDIR)/libhashx_a-hashx.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ext/equix/hashx/src/hashx.c' object='src/ext/equix/hashx/src/libhashx_a-hashx.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_ext_equix_libhashx_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o src/ext/equix/hashx/src/libhashx_a-hashx.o `test -f 'src/ext/equix/hashx/src/hashx.c' || echo '$(srcdir)/'`src/ext/equix/hashx/src/hashx.c + +src/ext/equix/hashx/src/libhashx_a-hashx.obj: src/ext/equix/hashx/src/hashx.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_ext_equix_libhashx_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT src/ext/equix/hashx/src/libhashx_a-hashx.obj -MD -MP -MF src/ext/equix/hashx/src/$(DEPDIR)/libhashx_a-hashx.Tpo -c -o src/ext/equix/hashx/src/libhashx_a-hashx.obj `if test -f 'src/ext/equix/hashx/src/hashx.c'; then $(CYGPATH_W) 'src/ext/equix/hashx/src/hashx.c'; else $(CYGPATH_W) '$(srcdir)/src/ext/equix/hashx/src/hashx.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ext/equix/hashx/src/$(DEPDIR)/libhashx_a-hashx.Tpo src/ext/equix/hashx/src/$(DEPDIR)/libhashx_a-hashx.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ext/equix/hashx/src/hashx.c' object='src/ext/equix/hashx/src/libhashx_a-hashx.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_ext_equix_libhashx_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o src/ext/equix/hashx/src/libhashx_a-hashx.obj `if test -f 'src/ext/equix/hashx/src/hashx.c'; then $(CYGPATH_W) 'src/ext/equix/hashx/src/hashx.c'; else $(CYGPATH_W) '$(srcdir)/src/ext/equix/hashx/src/hashx.c'; fi` + +src/ext/equix/hashx/src/libhashx_a-program.o: src/ext/equix/hashx/src/program.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_ext_equix_libhashx_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT src/ext/equix/hashx/src/libhashx_a-program.o -MD -MP -MF src/ext/equix/hashx/src/$(DEPDIR)/libhashx_a-program.Tpo -c -o src/ext/equix/hashx/src/libhashx_a-program.o `test -f 'src/ext/equix/hashx/src/program.c' || echo '$(srcdir)/'`src/ext/equix/hashx/src/program.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ext/equix/hashx/src/$(DEPDIR)/libhashx_a-program.Tpo src/ext/equix/hashx/src/$(DEPDIR)/libhashx_a-program.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ext/equix/hashx/src/program.c' object='src/ext/equix/hashx/src/libhashx_a-program.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_ext_equix_libhashx_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o src/ext/equix/hashx/src/libhashx_a-program.o `test -f 'src/ext/equix/hashx/src/program.c' || echo '$(srcdir)/'`src/ext/equix/hashx/src/program.c + +src/ext/equix/hashx/src/libhashx_a-program.obj: src/ext/equix/hashx/src/program.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_ext_equix_libhashx_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT src/ext/equix/hashx/src/libhashx_a-program.obj -MD -MP -MF src/ext/equix/hashx/src/$(DEPDIR)/libhashx_a-program.Tpo -c -o src/ext/equix/hashx/src/libhashx_a-program.obj `if test -f 'src/ext/equix/hashx/src/program.c'; then $(CYGPATH_W) 'src/ext/equix/hashx/src/program.c'; else $(CYGPATH_W) '$(srcdir)/src/ext/equix/hashx/src/program.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ext/equix/hashx/src/$(DEPDIR)/libhashx_a-program.Tpo src/ext/equix/hashx/src/$(DEPDIR)/libhashx_a-program.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ext/equix/hashx/src/program.c' object='src/ext/equix/hashx/src/libhashx_a-program.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_ext_equix_libhashx_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o src/ext/equix/hashx/src/libhashx_a-program.obj `if test -f 'src/ext/equix/hashx/src/program.c'; then $(CYGPATH_W) 'src/ext/equix/hashx/src/program.c'; else $(CYGPATH_W) '$(srcdir)/src/ext/equix/hashx/src/program.c'; fi` + +src/ext/equix/hashx/src/libhashx_a-program_exec.o: src/ext/equix/hashx/src/program_exec.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_ext_equix_libhashx_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT src/ext/equix/hashx/src/libhashx_a-program_exec.o -MD -MP -MF src/ext/equix/hashx/src/$(DEPDIR)/libhashx_a-program_exec.Tpo -c -o src/ext/equix/hashx/src/libhashx_a-program_exec.o `test -f 'src/ext/equix/hashx/src/program_exec.c' || echo '$(srcdir)/'`src/ext/equix/hashx/src/program_exec.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ext/equix/hashx/src/$(DEPDIR)/libhashx_a-program_exec.Tpo src/ext/equix/hashx/src/$(DEPDIR)/libhashx_a-program_exec.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ext/equix/hashx/src/program_exec.c' object='src/ext/equix/hashx/src/libhashx_a-program_exec.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_ext_equix_libhashx_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o src/ext/equix/hashx/src/libhashx_a-program_exec.o `test -f 'src/ext/equix/hashx/src/program_exec.c' || echo '$(srcdir)/'`src/ext/equix/hashx/src/program_exec.c + +src/ext/equix/hashx/src/libhashx_a-program_exec.obj: src/ext/equix/hashx/src/program_exec.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_ext_equix_libhashx_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT src/ext/equix/hashx/src/libhashx_a-program_exec.obj -MD -MP -MF src/ext/equix/hashx/src/$(DEPDIR)/libhashx_a-program_exec.Tpo -c -o src/ext/equix/hashx/src/libhashx_a-program_exec.obj `if test -f 'src/ext/equix/hashx/src/program_exec.c'; then $(CYGPATH_W) 'src/ext/equix/hashx/src/program_exec.c'; else $(CYGPATH_W) '$(srcdir)/src/ext/equix/hashx/src/program_exec.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ext/equix/hashx/src/$(DEPDIR)/libhashx_a-program_exec.Tpo src/ext/equix/hashx/src/$(DEPDIR)/libhashx_a-program_exec.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ext/equix/hashx/src/program_exec.c' object='src/ext/equix/hashx/src/libhashx_a-program_exec.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_ext_equix_libhashx_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o src/ext/equix/hashx/src/libhashx_a-program_exec.obj `if test -f 'src/ext/equix/hashx/src/program_exec.c'; then $(CYGPATH_W) 'src/ext/equix/hashx/src/program_exec.c'; else $(CYGPATH_W) '$(srcdir)/src/ext/equix/hashx/src/program_exec.c'; fi` + +src/ext/equix/hashx/src/libhashx_a-siphash.o: src/ext/equix/hashx/src/siphash.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_ext_equix_libhashx_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT src/ext/equix/hashx/src/libhashx_a-siphash.o -MD -MP -MF src/ext/equix/hashx/src/$(DEPDIR)/libhashx_a-siphash.Tpo -c -o src/ext/equix/hashx/src/libhashx_a-siphash.o `test -f 'src/ext/equix/hashx/src/siphash.c' || echo '$(srcdir)/'`src/ext/equix/hashx/src/siphash.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ext/equix/hashx/src/$(DEPDIR)/libhashx_a-siphash.Tpo src/ext/equix/hashx/src/$(DEPDIR)/libhashx_a-siphash.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ext/equix/hashx/src/siphash.c' object='src/ext/equix/hashx/src/libhashx_a-siphash.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_ext_equix_libhashx_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o src/ext/equix/hashx/src/libhashx_a-siphash.o `test -f 'src/ext/equix/hashx/src/siphash.c' || echo '$(srcdir)/'`src/ext/equix/hashx/src/siphash.c + +src/ext/equix/hashx/src/libhashx_a-siphash.obj: src/ext/equix/hashx/src/siphash.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_ext_equix_libhashx_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT src/ext/equix/hashx/src/libhashx_a-siphash.obj -MD -MP -MF src/ext/equix/hashx/src/$(DEPDIR)/libhashx_a-siphash.Tpo -c -o src/ext/equix/hashx/src/libhashx_a-siphash.obj `if test -f 'src/ext/equix/hashx/src/siphash.c'; then $(CYGPATH_W) 'src/ext/equix/hashx/src/siphash.c'; else $(CYGPATH_W) '$(srcdir)/src/ext/equix/hashx/src/siphash.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ext/equix/hashx/src/$(DEPDIR)/libhashx_a-siphash.Tpo src/ext/equix/hashx/src/$(DEPDIR)/libhashx_a-siphash.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ext/equix/hashx/src/siphash.c' object='src/ext/equix/hashx/src/libhashx_a-siphash.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_ext_equix_libhashx_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o src/ext/equix/hashx/src/libhashx_a-siphash.obj `if test -f 'src/ext/equix/hashx/src/siphash.c'; then $(CYGPATH_W) 'src/ext/equix/hashx/src/siphash.c'; else $(CYGPATH_W) '$(srcdir)/src/ext/equix/hashx/src/siphash.c'; fi` + +src/ext/equix/hashx/src/libhashx_a-siphash_rng.o: src/ext/equix/hashx/src/siphash_rng.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_ext_equix_libhashx_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT src/ext/equix/hashx/src/libhashx_a-siphash_rng.o -MD -MP -MF src/ext/equix/hashx/src/$(DEPDIR)/libhashx_a-siphash_rng.Tpo -c -o src/ext/equix/hashx/src/libhashx_a-siphash_rng.o `test -f 'src/ext/equix/hashx/src/siphash_rng.c' || echo '$(srcdir)/'`src/ext/equix/hashx/src/siphash_rng.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ext/equix/hashx/src/$(DEPDIR)/libhashx_a-siphash_rng.Tpo src/ext/equix/hashx/src/$(DEPDIR)/libhashx_a-siphash_rng.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ext/equix/hashx/src/siphash_rng.c' object='src/ext/equix/hashx/src/libhashx_a-siphash_rng.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_ext_equix_libhashx_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o src/ext/equix/hashx/src/libhashx_a-siphash_rng.o `test -f 'src/ext/equix/hashx/src/siphash_rng.c' || echo '$(srcdir)/'`src/ext/equix/hashx/src/siphash_rng.c + +src/ext/equix/hashx/src/libhashx_a-siphash_rng.obj: src/ext/equix/hashx/src/siphash_rng.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_ext_equix_libhashx_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT src/ext/equix/hashx/src/libhashx_a-siphash_rng.obj -MD -MP -MF src/ext/equix/hashx/src/$(DEPDIR)/libhashx_a-siphash_rng.Tpo -c -o src/ext/equix/hashx/src/libhashx_a-siphash_rng.obj `if test -f 'src/ext/equix/hashx/src/siphash_rng.c'; then $(CYGPATH_W) 'src/ext/equix/hashx/src/siphash_rng.c'; else $(CYGPATH_W) '$(srcdir)/src/ext/equix/hashx/src/siphash_rng.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ext/equix/hashx/src/$(DEPDIR)/libhashx_a-siphash_rng.Tpo src/ext/equix/hashx/src/$(DEPDIR)/libhashx_a-siphash_rng.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ext/equix/hashx/src/siphash_rng.c' object='src/ext/equix/hashx/src/libhashx_a-siphash_rng.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_ext_equix_libhashx_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o src/ext/equix/hashx/src/libhashx_a-siphash_rng.obj `if test -f 'src/ext/equix/hashx/src/siphash_rng.c'; then $(CYGPATH_W) 'src/ext/equix/hashx/src/siphash_rng.c'; else $(CYGPATH_W) '$(srcdir)/src/ext/equix/hashx/src/siphash_rng.c'; fi` + +src/ext/equix/hashx/src/libhashx_a-virtual_memory.o: src/ext/equix/hashx/src/virtual_memory.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_ext_equix_libhashx_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT src/ext/equix/hashx/src/libhashx_a-virtual_memory.o -MD -MP -MF src/ext/equix/hashx/src/$(DEPDIR)/libhashx_a-virtual_memory.Tpo -c -o src/ext/equix/hashx/src/libhashx_a-virtual_memory.o `test -f 'src/ext/equix/hashx/src/virtual_memory.c' || echo '$(srcdir)/'`src/ext/equix/hashx/src/virtual_memory.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ext/equix/hashx/src/$(DEPDIR)/libhashx_a-virtual_memory.Tpo src/ext/equix/hashx/src/$(DEPDIR)/libhashx_a-virtual_memory.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ext/equix/hashx/src/virtual_memory.c' object='src/ext/equix/hashx/src/libhashx_a-virtual_memory.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_ext_equix_libhashx_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o src/ext/equix/hashx/src/libhashx_a-virtual_memory.o `test -f 'src/ext/equix/hashx/src/virtual_memory.c' || echo '$(srcdir)/'`src/ext/equix/hashx/src/virtual_memory.c + +src/ext/equix/hashx/src/libhashx_a-virtual_memory.obj: src/ext/equix/hashx/src/virtual_memory.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_ext_equix_libhashx_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT src/ext/equix/hashx/src/libhashx_a-virtual_memory.obj -MD -MP -MF src/ext/equix/hashx/src/$(DEPDIR)/libhashx_a-virtual_memory.Tpo -c -o src/ext/equix/hashx/src/libhashx_a-virtual_memory.obj `if test -f 'src/ext/equix/hashx/src/virtual_memory.c'; then $(CYGPATH_W) 'src/ext/equix/hashx/src/virtual_memory.c'; else $(CYGPATH_W) '$(srcdir)/src/ext/equix/hashx/src/virtual_memory.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ext/equix/hashx/src/$(DEPDIR)/libhashx_a-virtual_memory.Tpo src/ext/equix/hashx/src/$(DEPDIR)/libhashx_a-virtual_memory.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ext/equix/hashx/src/virtual_memory.c' object='src/ext/equix/hashx/src/libhashx_a-virtual_memory.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_ext_equix_libhashx_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o src/ext/equix/hashx/src/libhashx_a-virtual_memory.obj `if test -f 'src/ext/equix/hashx/src/virtual_memory.c'; then $(CYGPATH_W) 'src/ext/equix/hashx/src/virtual_memory.c'; else $(CYGPATH_W) '$(srcdir)/src/ext/equix/hashx/src/virtual_memory.c'; fi` + src/ext/keccak-tiny/libkeccak_tiny_a-keccak-tiny-unrolled.o: src/ext/keccak-tiny/keccak-tiny-unrolled.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_ext_keccak_tiny_libkeccak_tiny_a_CFLAGS) $(CFLAGS) -MT src/ext/keccak-tiny/libkeccak_tiny_a-keccak-tiny-unrolled.o -MD -MP -MF src/ext/keccak-tiny/$(DEPDIR)/libkeccak_tiny_a-keccak-tiny-unrolled.Tpo -c -o src/ext/keccak-tiny/libkeccak_tiny_a-keccak-tiny-unrolled.o `test -f 'src/ext/keccak-tiny/keccak-tiny-unrolled.c' || echo '$(srcdir)/'`src/ext/keccak-tiny/keccak-tiny-unrolled.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ext/keccak-tiny/$(DEPDIR)/libkeccak_tiny_a-keccak-tiny-unrolled.Tpo src/ext/keccak-tiny/$(DEPDIR)/libkeccak_tiny_a-keccak-tiny-unrolled.Po @@ -15964,6 +16680,20 @@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_ext_keccak_tiny_libkeccak_tiny_a_CFLAGS) $(CFLAGS) -c -o src/ext/keccak-tiny/libkeccak_tiny_a-keccak-tiny-unrolled.obj `if test -f 'src/ext/keccak-tiny/keccak-tiny-unrolled.c'; then $(CYGPATH_W) 'src/ext/keccak-tiny/keccak-tiny-unrolled.c'; else $(CYGPATH_W) '$(srcdir)/src/ext/keccak-tiny/keccak-tiny-unrolled.c'; fi` +src/ext/polyval/libpolyval_a-polyval.o: src/ext/polyval/polyval.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_ext_polyval_libpolyval_a_CFLAGS) $(CFLAGS) -MT src/ext/polyval/libpolyval_a-polyval.o -MD -MP -MF src/ext/polyval/$(DEPDIR)/libpolyval_a-polyval.Tpo -c -o src/ext/polyval/libpolyval_a-polyval.o `test -f 'src/ext/polyval/polyval.c' || echo '$(srcdir)/'`src/ext/polyval/polyval.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ext/polyval/$(DEPDIR)/libpolyval_a-polyval.Tpo src/ext/polyval/$(DEPDIR)/libpolyval_a-polyval.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ext/polyval/polyval.c' object='src/ext/polyval/libpolyval_a-polyval.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_ext_polyval_libpolyval_a_CFLAGS) $(CFLAGS) -c -o src/ext/polyval/libpolyval_a-polyval.o `test -f 'src/ext/polyval/polyval.c' || echo '$(srcdir)/'`src/ext/polyval/polyval.c + +src/ext/polyval/libpolyval_a-polyval.obj: src/ext/polyval/polyval.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_ext_polyval_libpolyval_a_CFLAGS) $(CFLAGS) -MT src/ext/polyval/libpolyval_a-polyval.obj -MD -MP -MF src/ext/polyval/$(DEPDIR)/libpolyval_a-polyval.Tpo -c -o src/ext/polyval/libpolyval_a-polyval.obj `if test -f 'src/ext/polyval/polyval.c'; then $(CYGPATH_W) 'src/ext/polyval/polyval.c'; else $(CYGPATH_W) '$(srcdir)/src/ext/polyval/polyval.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ext/polyval/$(DEPDIR)/libpolyval_a-polyval.Tpo src/ext/polyval/$(DEPDIR)/libpolyval_a-polyval.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ext/polyval/polyval.c' object='src/ext/polyval/libpolyval_a-polyval.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_ext_polyval_libpolyval_a_CFLAGS) $(CFLAGS) -c -o src/ext/polyval/libpolyval_a-polyval.obj `if test -f 'src/ext/polyval/polyval.c'; then $(CYGPATH_W) 'src/ext/polyval/polyval.c'; else $(CYGPATH_W) '$(srcdir)/src/ext/polyval/polyval.c'; fi` + src/ext/curve25519_donna/lib_libcurve25519_donna_a-curve25519-donna-c64.o: src/ext/curve25519_donna/curve25519-donna-c64.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_lib_libcurve25519_donna_a_CFLAGS) $(CFLAGS) -MT src/ext/curve25519_donna/lib_libcurve25519_donna_a-curve25519-donna-c64.o -MD -MP -MF src/ext/curve25519_donna/$(DEPDIR)/lib_libcurve25519_donna_a-curve25519-donna-c64.Tpo -c -o src/ext/curve25519_donna/lib_libcurve25519_donna_a-curve25519-donna-c64.o `test -f 'src/ext/curve25519_donna/curve25519-donna-c64.c' || echo '$(srcdir)/'`src/ext/curve25519_donna/curve25519-donna-c64.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ext/curve25519_donna/$(DEPDIR)/lib_libcurve25519_donna_a-curve25519-donna-c64.Tpo src/ext/curve25519_donna/$(DEPDIR)/lib_libcurve25519_donna_a-curve25519-donna-c64.Po @@ -19436,6 +20166,34 @@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_trunnel_libor_trunnel_testing_a_CPPFLAGS) $(CPPFLAGS) $(src_trunnel_libor_trunnel_testing_a_CFLAGS) $(CFLAGS) -c -o src/trunnel/libor_trunnel_testing_a-circpad_negotiation.obj `if test -f 'src/trunnel/circpad_negotiation.c'; then $(CYGPATH_W) 'src/trunnel/circpad_negotiation.c'; else $(CYGPATH_W) '$(srcdir)/src/trunnel/circpad_negotiation.c'; fi` +src/trunnel/libor_trunnel_testing_a-conflux.o: src/trunnel/conflux.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_trunnel_libor_trunnel_testing_a_CPPFLAGS) $(CPPFLAGS) $(src_trunnel_libor_trunnel_testing_a_CFLAGS) $(CFLAGS) -MT src/trunnel/libor_trunnel_testing_a-conflux.o -MD -MP -MF src/trunnel/$(DEPDIR)/libor_trunnel_testing_a-conflux.Tpo -c -o src/trunnel/libor_trunnel_testing_a-conflux.o `test -f 'src/trunnel/conflux.c' || echo '$(srcdir)/'`src/trunnel/conflux.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/trunnel/$(DEPDIR)/libor_trunnel_testing_a-conflux.Tpo src/trunnel/$(DEPDIR)/libor_trunnel_testing_a-conflux.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/trunnel/conflux.c' object='src/trunnel/libor_trunnel_testing_a-conflux.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_trunnel_libor_trunnel_testing_a_CPPFLAGS) $(CPPFLAGS) $(src_trunnel_libor_trunnel_testing_a_CFLAGS) $(CFLAGS) -c -o src/trunnel/libor_trunnel_testing_a-conflux.o `test -f 'src/trunnel/conflux.c' || echo '$(srcdir)/'`src/trunnel/conflux.c + +src/trunnel/libor_trunnel_testing_a-conflux.obj: src/trunnel/conflux.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_trunnel_libor_trunnel_testing_a_CPPFLAGS) $(CPPFLAGS) $(src_trunnel_libor_trunnel_testing_a_CFLAGS) $(CFLAGS) -MT src/trunnel/libor_trunnel_testing_a-conflux.obj -MD -MP -MF src/trunnel/$(DEPDIR)/libor_trunnel_testing_a-conflux.Tpo -c -o src/trunnel/libor_trunnel_testing_a-conflux.obj `if test -f 'src/trunnel/conflux.c'; then $(CYGPATH_W) 'src/trunnel/conflux.c'; else $(CYGPATH_W) '$(srcdir)/src/trunnel/conflux.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/trunnel/$(DEPDIR)/libor_trunnel_testing_a-conflux.Tpo src/trunnel/$(DEPDIR)/libor_trunnel_testing_a-conflux.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/trunnel/conflux.c' object='src/trunnel/libor_trunnel_testing_a-conflux.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_trunnel_libor_trunnel_testing_a_CPPFLAGS) $(CPPFLAGS) $(src_trunnel_libor_trunnel_testing_a_CFLAGS) $(CFLAGS) -c -o src/trunnel/libor_trunnel_testing_a-conflux.obj `if test -f 'src/trunnel/conflux.c'; then $(CYGPATH_W) 'src/trunnel/conflux.c'; else $(CYGPATH_W) '$(srcdir)/src/trunnel/conflux.c'; fi` + +src/trunnel/libor_trunnel_testing_a-subproto_request.o: src/trunnel/subproto_request.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_trunnel_libor_trunnel_testing_a_CPPFLAGS) $(CPPFLAGS) $(src_trunnel_libor_trunnel_testing_a_CFLAGS) $(CFLAGS) -MT src/trunnel/libor_trunnel_testing_a-subproto_request.o -MD -MP -MF src/trunnel/$(DEPDIR)/libor_trunnel_testing_a-subproto_request.Tpo -c -o src/trunnel/libor_trunnel_testing_a-subproto_request.o `test -f 'src/trunnel/subproto_request.c' || echo '$(srcdir)/'`src/trunnel/subproto_request.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/trunnel/$(DEPDIR)/libor_trunnel_testing_a-subproto_request.Tpo src/trunnel/$(DEPDIR)/libor_trunnel_testing_a-subproto_request.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/trunnel/subproto_request.c' object='src/trunnel/libor_trunnel_testing_a-subproto_request.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_trunnel_libor_trunnel_testing_a_CPPFLAGS) $(CPPFLAGS) $(src_trunnel_libor_trunnel_testing_a_CFLAGS) $(CFLAGS) -c -o src/trunnel/libor_trunnel_testing_a-subproto_request.o `test -f 'src/trunnel/subproto_request.c' || echo '$(srcdir)/'`src/trunnel/subproto_request.c + +src/trunnel/libor_trunnel_testing_a-subproto_request.obj: src/trunnel/subproto_request.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_trunnel_libor_trunnel_testing_a_CPPFLAGS) $(CPPFLAGS) $(src_trunnel_libor_trunnel_testing_a_CFLAGS) $(CFLAGS) -MT src/trunnel/libor_trunnel_testing_a-subproto_request.obj -MD -MP -MF src/trunnel/$(DEPDIR)/libor_trunnel_testing_a-subproto_request.Tpo -c -o src/trunnel/libor_trunnel_testing_a-subproto_request.obj `if test -f 'src/trunnel/subproto_request.c'; then $(CYGPATH_W) 'src/trunnel/subproto_request.c'; else $(CYGPATH_W) '$(srcdir)/src/trunnel/subproto_request.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/trunnel/$(DEPDIR)/libor_trunnel_testing_a-subproto_request.Tpo src/trunnel/$(DEPDIR)/libor_trunnel_testing_a-subproto_request.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/trunnel/subproto_request.c' object='src/trunnel/libor_trunnel_testing_a-subproto_request.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_trunnel_libor_trunnel_testing_a_CPPFLAGS) $(CPPFLAGS) $(src_trunnel_libor_trunnel_testing_a_CFLAGS) $(CFLAGS) -c -o src/trunnel/libor_trunnel_testing_a-subproto_request.obj `if test -f 'src/trunnel/subproto_request.c'; then $(CYGPATH_W) 'src/trunnel/subproto_request.c'; else $(CYGPATH_W) '$(srcdir)/src/trunnel/subproto_request.c'; fi` + src/ext/trunnel/trunnel_libor_trunnel_a-trunnel.o: src/ext/trunnel/trunnel.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_trunnel_libor_trunnel_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT src/ext/trunnel/trunnel_libor_trunnel_a-trunnel.o -MD -MP -MF src/ext/trunnel/$(DEPDIR)/trunnel_libor_trunnel_a-trunnel.Tpo -c -o src/ext/trunnel/trunnel_libor_trunnel_a-trunnel.o `test -f 'src/ext/trunnel/trunnel.c' || echo '$(srcdir)/'`src/ext/trunnel/trunnel.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ext/trunnel/$(DEPDIR)/trunnel_libor_trunnel_a-trunnel.Tpo src/ext/trunnel/$(DEPDIR)/trunnel_libor_trunnel_a-trunnel.Po @@ -19646,6 +20404,34 @@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_trunnel_libor_trunnel_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o src/trunnel/libor_trunnel_a-circpad_negotiation.obj `if test -f 'src/trunnel/circpad_negotiation.c'; then $(CYGPATH_W) 'src/trunnel/circpad_negotiation.c'; else $(CYGPATH_W) '$(srcdir)/src/trunnel/circpad_negotiation.c'; fi` +src/trunnel/libor_trunnel_a-conflux.o: src/trunnel/conflux.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_trunnel_libor_trunnel_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT src/trunnel/libor_trunnel_a-conflux.o -MD -MP -MF src/trunnel/$(DEPDIR)/libor_trunnel_a-conflux.Tpo -c -o src/trunnel/libor_trunnel_a-conflux.o `test -f 'src/trunnel/conflux.c' || echo '$(srcdir)/'`src/trunnel/conflux.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/trunnel/$(DEPDIR)/libor_trunnel_a-conflux.Tpo src/trunnel/$(DEPDIR)/libor_trunnel_a-conflux.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/trunnel/conflux.c' object='src/trunnel/libor_trunnel_a-conflux.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_trunnel_libor_trunnel_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o src/trunnel/libor_trunnel_a-conflux.o `test -f 'src/trunnel/conflux.c' || echo '$(srcdir)/'`src/trunnel/conflux.c + +src/trunnel/libor_trunnel_a-conflux.obj: src/trunnel/conflux.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_trunnel_libor_trunnel_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT src/trunnel/libor_trunnel_a-conflux.obj -MD -MP -MF src/trunnel/$(DEPDIR)/libor_trunnel_a-conflux.Tpo -c -o src/trunnel/libor_trunnel_a-conflux.obj `if test -f 'src/trunnel/conflux.c'; then $(CYGPATH_W) 'src/trunnel/conflux.c'; else $(CYGPATH_W) '$(srcdir)/src/trunnel/conflux.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/trunnel/$(DEPDIR)/libor_trunnel_a-conflux.Tpo src/trunnel/$(DEPDIR)/libor_trunnel_a-conflux.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/trunnel/conflux.c' object='src/trunnel/libor_trunnel_a-conflux.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_trunnel_libor_trunnel_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o src/trunnel/libor_trunnel_a-conflux.obj `if test -f 'src/trunnel/conflux.c'; then $(CYGPATH_W) 'src/trunnel/conflux.c'; else $(CYGPATH_W) '$(srcdir)/src/trunnel/conflux.c'; fi` + +src/trunnel/libor_trunnel_a-subproto_request.o: src/trunnel/subproto_request.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_trunnel_libor_trunnel_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT src/trunnel/libor_trunnel_a-subproto_request.o -MD -MP -MF src/trunnel/$(DEPDIR)/libor_trunnel_a-subproto_request.Tpo -c -o src/trunnel/libor_trunnel_a-subproto_request.o `test -f 'src/trunnel/subproto_request.c' || echo '$(srcdir)/'`src/trunnel/subproto_request.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/trunnel/$(DEPDIR)/libor_trunnel_a-subproto_request.Tpo src/trunnel/$(DEPDIR)/libor_trunnel_a-subproto_request.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/trunnel/subproto_request.c' object='src/trunnel/libor_trunnel_a-subproto_request.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_trunnel_libor_trunnel_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o src/trunnel/libor_trunnel_a-subproto_request.o `test -f 'src/trunnel/subproto_request.c' || echo '$(srcdir)/'`src/trunnel/subproto_request.c + +src/trunnel/libor_trunnel_a-subproto_request.obj: src/trunnel/subproto_request.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_trunnel_libor_trunnel_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT src/trunnel/libor_trunnel_a-subproto_request.obj -MD -MP -MF src/trunnel/$(DEPDIR)/libor_trunnel_a-subproto_request.Tpo -c -o src/trunnel/libor_trunnel_a-subproto_request.obj `if test -f 'src/trunnel/subproto_request.c'; then $(CYGPATH_W) 'src/trunnel/subproto_request.c'; else $(CYGPATH_W) '$(srcdir)/src/trunnel/subproto_request.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/trunnel/$(DEPDIR)/libor_trunnel_a-subproto_request.Tpo src/trunnel/$(DEPDIR)/libor_trunnel_a-subproto_request.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/trunnel/subproto_request.c' object='src/trunnel/libor_trunnel_a-subproto_request.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_trunnel_libor_trunnel_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o src/trunnel/libor_trunnel_a-subproto_request.obj `if test -f 'src/trunnel/subproto_request.c'; then $(CYGPATH_W) 'src/trunnel/subproto_request.c'; else $(CYGPATH_W) '$(srcdir)/src/trunnel/subproto_request.c'; fi` + src/app/main/tor_cov-tor_main.o: src/app/main/tor_main.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_app_tor_cov_CPPFLAGS) $(CPPFLAGS) $(src_app_tor_cov_CFLAGS) $(CFLAGS) -MT src/app/main/tor_cov-tor_main.o -MD -MP -MF src/app/main/$(DEPDIR)/tor_cov-tor_main.Tpo -c -o src/app/main/tor_cov-tor_main.o `test -f 'src/app/main/tor_main.c' || echo '$(srcdir)/'`src/app/main/tor_main.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/app/main/$(DEPDIR)/tor_cov-tor_main.Tpo src/app/main/$(DEPDIR)/tor_cov-tor_main.Po @@ -20976,6 +21762,34 @@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_test_test_CPPFLAGS) $(CPPFLAGS) $(src_test_test_CFLAGS) $(CFLAGS) -c -o src/test/test-test_config.obj `if test -f 'src/test/test_config.c'; then $(CYGPATH_W) 'src/test/test_config.c'; else $(CYGPATH_W) '$(srcdir)/src/test/test_config.c'; fi` +src/test/test-test_conflux_cell.o: src/test/test_conflux_cell.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_test_test_CPPFLAGS) $(CPPFLAGS) $(src_test_test_CFLAGS) $(CFLAGS) -MT src/test/test-test_conflux_cell.o -MD -MP -MF src/test/$(DEPDIR)/test-test_conflux_cell.Tpo -c -o src/test/test-test_conflux_cell.o `test -f 'src/test/test_conflux_cell.c' || echo '$(srcdir)/'`src/test/test_conflux_cell.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/test/$(DEPDIR)/test-test_conflux_cell.Tpo src/test/$(DEPDIR)/test-test_conflux_cell.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/test/test_conflux_cell.c' object='src/test/test-test_conflux_cell.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_test_test_CPPFLAGS) $(CPPFLAGS) $(src_test_test_CFLAGS) $(CFLAGS) -c -o src/test/test-test_conflux_cell.o `test -f 'src/test/test_conflux_cell.c' || echo '$(srcdir)/'`src/test/test_conflux_cell.c + +src/test/test-test_conflux_cell.obj: src/test/test_conflux_cell.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_test_test_CPPFLAGS) $(CPPFLAGS) $(src_test_test_CFLAGS) $(CFLAGS) -MT src/test/test-test_conflux_cell.obj -MD -MP -MF src/test/$(DEPDIR)/test-test_conflux_cell.Tpo -c -o src/test/test-test_conflux_cell.obj `if test -f 'src/test/test_conflux_cell.c'; then $(CYGPATH_W) 'src/test/test_conflux_cell.c'; else $(CYGPATH_W) '$(srcdir)/src/test/test_conflux_cell.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/test/$(DEPDIR)/test-test_conflux_cell.Tpo src/test/$(DEPDIR)/test-test_conflux_cell.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/test/test_conflux_cell.c' object='src/test/test-test_conflux_cell.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_test_test_CPPFLAGS) $(CPPFLAGS) $(src_test_test_CFLAGS) $(CFLAGS) -c -o src/test/test-test_conflux_cell.obj `if test -f 'src/test/test_conflux_cell.c'; then $(CYGPATH_W) 'src/test/test_conflux_cell.c'; else $(CYGPATH_W) '$(srcdir)/src/test/test_conflux_cell.c'; fi` + +src/test/test-test_conflux_pool.o: src/test/test_conflux_pool.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_test_test_CPPFLAGS) $(CPPFLAGS) $(src_test_test_CFLAGS) $(CFLAGS) -MT src/test/test-test_conflux_pool.o -MD -MP -MF src/test/$(DEPDIR)/test-test_conflux_pool.Tpo -c -o src/test/test-test_conflux_pool.o `test -f 'src/test/test_conflux_pool.c' || echo '$(srcdir)/'`src/test/test_conflux_pool.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/test/$(DEPDIR)/test-test_conflux_pool.Tpo src/test/$(DEPDIR)/test-test_conflux_pool.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/test/test_conflux_pool.c' object='src/test/test-test_conflux_pool.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_test_test_CPPFLAGS) $(CPPFLAGS) $(src_test_test_CFLAGS) $(CFLAGS) -c -o src/test/test-test_conflux_pool.o `test -f 'src/test/test_conflux_pool.c' || echo '$(srcdir)/'`src/test/test_conflux_pool.c + +src/test/test-test_conflux_pool.obj: src/test/test_conflux_pool.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_test_test_CPPFLAGS) $(CPPFLAGS) $(src_test_test_CFLAGS) $(CFLAGS) -MT src/test/test-test_conflux_pool.obj -MD -MP -MF src/test/$(DEPDIR)/test-test_conflux_pool.Tpo -c -o src/test/test-test_conflux_pool.obj `if test -f 'src/test/test_conflux_pool.c'; then $(CYGPATH_W) 'src/test/test_conflux_pool.c'; else $(CYGPATH_W) '$(srcdir)/src/test/test_conflux_pool.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/test/$(DEPDIR)/test-test_conflux_pool.Tpo src/test/$(DEPDIR)/test-test_conflux_pool.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/test/test_conflux_pool.c' object='src/test/test-test_conflux_pool.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_test_test_CPPFLAGS) $(CPPFLAGS) $(src_test_test_CFLAGS) $(CFLAGS) -c -o src/test/test-test_conflux_pool.obj `if test -f 'src/test/test_conflux_pool.c'; then $(CYGPATH_W) 'src/test/test_conflux_pool.c'; else $(CYGPATH_W) '$(srcdir)/src/test/test_conflux_pool.c'; fi` + src/test/test-test_confmgr.o: src/test/test_confmgr.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_test_test_CPPFLAGS) $(CPPFLAGS) $(src_test_test_CFLAGS) $(CFLAGS) -MT src/test/test-test_confmgr.o -MD -MP -MF src/test/$(DEPDIR)/test-test_confmgr.Tpo -c -o src/test/test-test_confmgr.o `test -f 'src/test/test_confmgr.c' || echo '$(srcdir)/'`src/test/test_confmgr.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/test/$(DEPDIR)/test-test_confmgr.Tpo src/test/$(DEPDIR)/test-test_confmgr.Po @@ -21004,6 +21818,20 @@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_test_test_CPPFLAGS) $(CPPFLAGS) $(src_test_test_CFLAGS) $(CFLAGS) -c -o src/test/test-test_confparse.obj `if test -f 'src/test/test_confparse.c'; then $(CYGPATH_W) 'src/test/test_confparse.c'; else $(CYGPATH_W) '$(srcdir)/src/test/test_confparse.c'; fi` +src/test/test-test_congestion_control.o: src/test/test_congestion_control.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_test_test_CPPFLAGS) $(CPPFLAGS) $(src_test_test_CFLAGS) $(CFLAGS) -MT src/test/test-test_congestion_control.o -MD -MP -MF src/test/$(DEPDIR)/test-test_congestion_control.Tpo -c -o src/test/test-test_congestion_control.o `test -f 'src/test/test_congestion_control.c' || echo '$(srcdir)/'`src/test/test_congestion_control.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/test/$(DEPDIR)/test-test_congestion_control.Tpo src/test/$(DEPDIR)/test-test_congestion_control.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/test/test_congestion_control.c' object='src/test/test-test_congestion_control.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_test_test_CPPFLAGS) $(CPPFLAGS) $(src_test_test_CFLAGS) $(CFLAGS) -c -o src/test/test-test_congestion_control.o `test -f 'src/test/test_congestion_control.c' || echo '$(srcdir)/'`src/test/test_congestion_control.c + +src/test/test-test_congestion_control.obj: src/test/test_congestion_control.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_test_test_CPPFLAGS) $(CPPFLAGS) $(src_test_test_CFLAGS) $(CFLAGS) -MT src/test/test-test_congestion_control.obj -MD -MP -MF src/test/$(DEPDIR)/test-test_congestion_control.Tpo -c -o src/test/test-test_congestion_control.obj `if test -f 'src/test/test_congestion_control.c'; then $(CYGPATH_W) 'src/test/test_congestion_control.c'; else $(CYGPATH_W) '$(srcdir)/src/test/test_congestion_control.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/test/$(DEPDIR)/test-test_congestion_control.Tpo src/test/$(DEPDIR)/test-test_congestion_control.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/test/test_congestion_control.c' object='src/test/test-test_congestion_control.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_test_test_CPPFLAGS) $(CPPFLAGS) $(src_test_test_CFLAGS) $(CFLAGS) -c -o src/test/test-test_congestion_control.obj `if test -f 'src/test/test_congestion_control.c'; then $(CYGPATH_W) 'src/test/test_congestion_control.c'; else $(CYGPATH_W) '$(srcdir)/src/test/test_congestion_control.c'; fi` + src/test/test-test_connection.o: src/test/test_connection.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_test_test_CPPFLAGS) $(CPPFLAGS) $(src_test_test_CFLAGS) $(CFLAGS) -MT src/test/test-test_connection.o -MD -MP -MF src/test/$(DEPDIR)/test-test_connection.Tpo -c -o src/test/test-test_connection.o `test -f 'src/test/test_connection.c' || echo '$(srcdir)/'`src/test/test_connection.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/test/$(DEPDIR)/test-test_connection.Tpo src/test/$(DEPDIR)/test-test_connection.Po @@ -21144,6 +21972,20 @@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_test_test_CPPFLAGS) $(CPPFLAGS) $(src_test_test_CFLAGS) $(CFLAGS) -c -o src/test/test-test_crypto_rng.obj `if test -f 'src/test/test_crypto_rng.c'; then $(CYGPATH_W) 'src/test/test_crypto_rng.c'; else $(CYGPATH_W) '$(srcdir)/src/test/test_crypto_rng.c'; fi` +src/test/test-test_crypto_cgo.o: src/test/test_crypto_cgo.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_test_test_CPPFLAGS) $(CPPFLAGS) $(src_test_test_CFLAGS) $(CFLAGS) -MT src/test/test-test_crypto_cgo.o -MD -MP -MF src/test/$(DEPDIR)/test-test_crypto_cgo.Tpo -c -o src/test/test-test_crypto_cgo.o `test -f 'src/test/test_crypto_cgo.c' || echo '$(srcdir)/'`src/test/test_crypto_cgo.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/test/$(DEPDIR)/test-test_crypto_cgo.Tpo src/test/$(DEPDIR)/test-test_crypto_cgo.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/test/test_crypto_cgo.c' object='src/test/test-test_crypto_cgo.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_test_test_CPPFLAGS) $(CPPFLAGS) $(src_test_test_CFLAGS) $(CFLAGS) -c -o src/test/test-test_crypto_cgo.o `test -f 'src/test/test_crypto_cgo.c' || echo '$(srcdir)/'`src/test/test_crypto_cgo.c + +src/test/test-test_crypto_cgo.obj: src/test/test_crypto_cgo.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_test_test_CPPFLAGS) $(CPPFLAGS) $(src_test_test_CFLAGS) $(CFLAGS) -MT src/test/test-test_crypto_cgo.obj -MD -MP -MF src/test/$(DEPDIR)/test-test_crypto_cgo.Tpo -c -o src/test/test-test_crypto_cgo.obj `if test -f 'src/test/test_crypto_cgo.c'; then $(CYGPATH_W) 'src/test/test_crypto_cgo.c'; else $(CYGPATH_W) '$(srcdir)/src/test/test_crypto_cgo.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/test/$(DEPDIR)/test-test_crypto_cgo.Tpo src/test/$(DEPDIR)/test-test_crypto_cgo.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/test/test_crypto_cgo.c' object='src/test/test-test_crypto_cgo.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_test_test_CPPFLAGS) $(CPPFLAGS) $(src_test_test_CFLAGS) $(CFLAGS) -c -o src/test/test-test_crypto_cgo.obj `if test -f 'src/test/test_crypto_cgo.c'; then $(CYGPATH_W) 'src/test/test_crypto_cgo.c'; else $(CYGPATH_W) '$(srcdir)/src/test/test_crypto_cgo.c'; fi` + src/test/test-test_data.o: src/test/test_data.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_test_test_CPPFLAGS) $(CPPFLAGS) $(src_test_test_CFLAGS) $(CFLAGS) -MT src/test/test-test_data.o -MD -MP -MF src/test/$(DEPDIR)/test-test_data.Tpo -c -o src/test/test-test_data.o `test -f 'src/test/test_data.c' || echo '$(srcdir)/'`src/test/test_data.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/test/$(DEPDIR)/test-test_data.Tpo src/test/$(DEPDIR)/test-test_data.Po @@ -21522,6 +22364,20 @@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_test_test_CPPFLAGS) $(CPPFLAGS) $(src_test_test_CFLAGS) $(CFLAGS) -c -o src/test/test-test_hs_metrics.obj `if test -f 'src/test/test_hs_metrics.c'; then $(CYGPATH_W) 'src/test/test_hs_metrics.c'; else $(CYGPATH_W) '$(srcdir)/src/test/test_hs_metrics.c'; fi` +src/test/test-test_hs_pow.o: src/test/test_hs_pow.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_test_test_CPPFLAGS) $(CPPFLAGS) $(src_test_test_CFLAGS) $(CFLAGS) -MT src/test/test-test_hs_pow.o -MD -MP -MF src/test/$(DEPDIR)/test-test_hs_pow.Tpo -c -o src/test/test-test_hs_pow.o `test -f 'src/test/test_hs_pow.c' || echo '$(srcdir)/'`src/test/test_hs_pow.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/test/$(DEPDIR)/test-test_hs_pow.Tpo src/test/$(DEPDIR)/test-test_hs_pow.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/test/test_hs_pow.c' object='src/test/test-test_hs_pow.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_test_test_CPPFLAGS) $(CPPFLAGS) $(src_test_test_CFLAGS) $(CFLAGS) -c -o src/test/test-test_hs_pow.o `test -f 'src/test/test_hs_pow.c' || echo '$(srcdir)/'`src/test/test_hs_pow.c + +src/test/test-test_hs_pow.obj: src/test/test_hs_pow.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_test_test_CPPFLAGS) $(CPPFLAGS) $(src_test_test_CFLAGS) $(CFLAGS) -MT src/test/test-test_hs_pow.obj -MD -MP -MF src/test/$(DEPDIR)/test-test_hs_pow.Tpo -c -o src/test/test-test_hs_pow.obj `if test -f 'src/test/test_hs_pow.c'; then $(CYGPATH_W) 'src/test/test_hs_pow.c'; else $(CYGPATH_W) '$(srcdir)/src/test/test_hs_pow.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/test/$(DEPDIR)/test-test_hs_pow.Tpo src/test/$(DEPDIR)/test-test_hs_pow.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/test/test_hs_pow.c' object='src/test/test-test_hs_pow.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_test_test_CPPFLAGS) $(CPPFLAGS) $(src_test_test_CFLAGS) $(CFLAGS) -c -o src/test/test-test_hs_pow.obj `if test -f 'src/test/test_hs_pow.c'; then $(CYGPATH_W) 'src/test/test_hs_pow.c'; else $(CYGPATH_W) '$(srcdir)/src/test/test_hs_pow.c'; fi` + src/test/test-test_keypin.o: src/test/test_keypin.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_test_test_CPPFLAGS) $(CPPFLAGS) $(src_test_test_CFLAGS) $(CFLAGS) -MT src/test/test-test_keypin.o -MD -MP -MF src/test/$(DEPDIR)/test-test_keypin.Tpo -c -o src/test/test-test_keypin.o `test -f 'src/test/test_keypin.c' || echo '$(srcdir)/'`src/test/test_keypin.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/test/$(DEPDIR)/test-test_keypin.Tpo src/test/$(DEPDIR)/test-test_keypin.Po @@ -22488,6 +23344,20 @@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_test_test_slow_CPPFLAGS) $(CPPFLAGS) $(src_test_test_slow_CFLAGS) $(CFLAGS) -c -o src/test/test_slow-test_process_slow.obj `if test -f 'src/test/test_process_slow.c'; then $(CYGPATH_W) 'src/test/test_process_slow.c'; else $(CYGPATH_W) '$(srcdir)/src/test/test_process_slow.c'; fi` +src/test/test_slow-test_hs_pow_slow.o: src/test/test_hs_pow_slow.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_test_test_slow_CPPFLAGS) $(CPPFLAGS) $(src_test_test_slow_CFLAGS) $(CFLAGS) -MT src/test/test_slow-test_hs_pow_slow.o -MD -MP -MF src/test/$(DEPDIR)/test_slow-test_hs_pow_slow.Tpo -c -o src/test/test_slow-test_hs_pow_slow.o `test -f 'src/test/test_hs_pow_slow.c' || echo '$(srcdir)/'`src/test/test_hs_pow_slow.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/test/$(DEPDIR)/test_slow-test_hs_pow_slow.Tpo src/test/$(DEPDIR)/test_slow-test_hs_pow_slow.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/test/test_hs_pow_slow.c' object='src/test/test_slow-test_hs_pow_slow.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_test_test_slow_CPPFLAGS) $(CPPFLAGS) $(src_test_test_slow_CFLAGS) $(CFLAGS) -c -o src/test/test_slow-test_hs_pow_slow.o `test -f 'src/test/test_hs_pow_slow.c' || echo '$(srcdir)/'`src/test/test_hs_pow_slow.c + +src/test/test_slow-test_hs_pow_slow.obj: src/test/test_hs_pow_slow.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_test_test_slow_CPPFLAGS) $(CPPFLAGS) $(src_test_test_slow_CFLAGS) $(CFLAGS) -MT src/test/test_slow-test_hs_pow_slow.obj -MD -MP -MF src/test/$(DEPDIR)/test_slow-test_hs_pow_slow.Tpo -c -o src/test/test_slow-test_hs_pow_slow.obj `if test -f 'src/test/test_hs_pow_slow.c'; then $(CYGPATH_W) 'src/test/test_hs_pow_slow.c'; else $(CYGPATH_W) '$(srcdir)/src/test/test_hs_pow_slow.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/test/$(DEPDIR)/test_slow-test_hs_pow_slow.Tpo src/test/$(DEPDIR)/test_slow-test_hs_pow_slow.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/test/test_hs_pow_slow.c' object='src/test/test_slow-test_hs_pow_slow.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_test_test_slow_CPPFLAGS) $(CPPFLAGS) $(src_test_test_slow_CFLAGS) $(CFLAGS) -c -o src/test/test_slow-test_hs_pow_slow.obj `if test -f 'src/test/test_hs_pow_slow.c'; then $(CYGPATH_W) 'src/test/test_hs_pow_slow.c'; else $(CYGPATH_W) '$(srcdir)/src/test/test_hs_pow_slow.c'; fi` + src/test/test_slow-test_prob_distr.o: src/test/test_prob_distr.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_test_test_slow_CPPFLAGS) $(CPPFLAGS) $(src_test_test_slow_CFLAGS) $(CFLAGS) -MT src/test/test_slow-test_prob_distr.o -MD -MP -MF src/test/$(DEPDIR)/test_slow-test_prob_distr.Tpo -c -o src/test/test_slow-test_prob_distr.o `test -f 'src/test/test_prob_distr.c' || echo '$(srcdir)/'`src/test/test_prob_distr.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/test/$(DEPDIR)/test_slow-test_prob_distr.Tpo src/test/$(DEPDIR)/test_slow-test_prob_distr.Po @@ -23420,10 +24290,17 @@ -rm -f src/ext/ed25519/donna/$(am__dirstamp) -rm -f src/ext/ed25519/ref10/$(DEPDIR)/$(am__dirstamp) -rm -f src/ext/ed25519/ref10/$(am__dirstamp) + -rm -f src/ext/equix/$(am__dirstamp) + -rm -f src/ext/equix/hashx/src/$(DEPDIR)/$(am__dirstamp) + -rm -f src/ext/equix/hashx/src/$(am__dirstamp) + -rm -f src/ext/equix/src/$(DEPDIR)/$(am__dirstamp) + -rm -f src/ext/equix/src/$(am__dirstamp) -rm -f src/ext/keccak-tiny/$(DEPDIR)/$(am__dirstamp) -rm -f src/ext/keccak-tiny/$(am__dirstamp) -rm -f src/ext/mulodi/$(DEPDIR)/$(am__dirstamp) -rm -f src/ext/mulodi/$(am__dirstamp) + -rm -f src/ext/polyval/$(DEPDIR)/$(am__dirstamp) + -rm -f src/ext/polyval/$(am__dirstamp) -rm -f src/ext/trunnel/$(DEPDIR)/$(am__dirstamp) -rm -f src/ext/trunnel/$(am__dirstamp) -rm -f src/feature/api/$(DEPDIR)/$(am__dirstamp) @@ -23583,14 +24460,16 @@ -rm -f src/core/crypto/$(DEPDIR)/libtor_app_testing_a-onion_fast.Po -rm -f src/core/crypto/$(DEPDIR)/libtor_app_testing_a-onion_ntor.Po -rm -f src/core/crypto/$(DEPDIR)/libtor_app_testing_a-onion_ntor_v3.Po - -rm -f src/core/crypto/$(DEPDIR)/libtor_app_testing_a-onion_tap.Po -rm -f src/core/crypto/$(DEPDIR)/libtor_app_testing_a-relay_crypto.Po + -rm -f src/core/crypto/$(DEPDIR)/libtor_app_testing_a-relay_crypto_cgo.Po + -rm -f src/core/crypto/$(DEPDIR)/libtor_app_testing_a-relay_crypto_tor1.Po -rm -f src/core/crypto/$(DEPDIR)/onion_crypto.Po -rm -f src/core/crypto/$(DEPDIR)/onion_fast.Po -rm -f src/core/crypto/$(DEPDIR)/onion_ntor.Po -rm -f src/core/crypto/$(DEPDIR)/onion_ntor_v3.Po - -rm -f src/core/crypto/$(DEPDIR)/onion_tap.Po -rm -f src/core/crypto/$(DEPDIR)/relay_crypto.Po + -rm -f src/core/crypto/$(DEPDIR)/relay_crypto_cgo.Po + -rm -f src/core/crypto/$(DEPDIR)/relay_crypto_tor1.Po -rm -f src/core/mainloop/$(DEPDIR)/connection.Po -rm -f src/core/mainloop/$(DEPDIR)/cpuworker.Po -rm -f src/core/mainloop/$(DEPDIR)/libtor_app_testing_a-connection.Po @@ -23618,11 +24497,15 @@ -rm -f src/core/or/$(DEPDIR)/circuitstats.Po -rm -f src/core/or/$(DEPDIR)/circuituse.Po -rm -f src/core/or/$(DEPDIR)/command.Po + -rm -f src/core/or/$(DEPDIR)/conflux.Po + -rm -f src/core/or/$(DEPDIR)/conflux_cell.Po + -rm -f src/core/or/$(DEPDIR)/conflux_params.Po + -rm -f src/core/or/$(DEPDIR)/conflux_pool.Po + -rm -f src/core/or/$(DEPDIR)/conflux_sys.Po + -rm -f src/core/or/$(DEPDIR)/conflux_util.Po -rm -f src/core/or/$(DEPDIR)/congestion_control_common.Po -rm -f src/core/or/$(DEPDIR)/congestion_control_flow.Po - -rm -f src/core/or/$(DEPDIR)/congestion_control_nola.Po -rm -f src/core/or/$(DEPDIR)/congestion_control_vegas.Po - -rm -f src/core/or/$(DEPDIR)/congestion_control_westwood.Po -rm -f src/core/or/$(DEPDIR)/connection_edge.Po -rm -f src/core/or/$(DEPDIR)/connection_or.Po -rm -f src/core/or/$(DEPDIR)/crypt_path.Po @@ -23643,11 +24526,15 @@ -rm -f src/core/or/$(DEPDIR)/libtor_app_testing_a-circuitstats.Po -rm -f src/core/or/$(DEPDIR)/libtor_app_testing_a-circuituse.Po -rm -f src/core/or/$(DEPDIR)/libtor_app_testing_a-command.Po + -rm -f src/core/or/$(DEPDIR)/libtor_app_testing_a-conflux.Po + -rm -f src/core/or/$(DEPDIR)/libtor_app_testing_a-conflux_cell.Po + -rm -f src/core/or/$(DEPDIR)/libtor_app_testing_a-conflux_params.Po + -rm -f src/core/or/$(DEPDIR)/libtor_app_testing_a-conflux_pool.Po + -rm -f src/core/or/$(DEPDIR)/libtor_app_testing_a-conflux_sys.Po + -rm -f src/core/or/$(DEPDIR)/libtor_app_testing_a-conflux_util.Po -rm -f src/core/or/$(DEPDIR)/libtor_app_testing_a-congestion_control_common.Po -rm -f src/core/or/$(DEPDIR)/libtor_app_testing_a-congestion_control_flow.Po - -rm -f src/core/or/$(DEPDIR)/libtor_app_testing_a-congestion_control_nola.Po -rm -f src/core/or/$(DEPDIR)/libtor_app_testing_a-congestion_control_vegas.Po - -rm -f src/core/or/$(DEPDIR)/libtor_app_testing_a-congestion_control_westwood.Po -rm -f src/core/or/$(DEPDIR)/libtor_app_testing_a-connection_edge.Po -rm -f src/core/or/$(DEPDIR)/libtor_app_testing_a-connection_or.Po -rm -f src/core/or/$(DEPDIR)/libtor_app_testing_a-crypt_path.Po @@ -23664,6 +24551,7 @@ -rm -f src/core/or/$(DEPDIR)/libtor_app_testing_a-protover.Po -rm -f src/core/or/$(DEPDIR)/libtor_app_testing_a-reasons.Po -rm -f src/core/or/$(DEPDIR)/libtor_app_testing_a-relay.Po + -rm -f src/core/or/$(DEPDIR)/libtor_app_testing_a-relay_msg.Po -rm -f src/core/or/$(DEPDIR)/libtor_app_testing_a-scheduler.Po -rm -f src/core/or/$(DEPDIR)/libtor_app_testing_a-scheduler_kist.Po -rm -f src/core/or/$(DEPDIR)/libtor_app_testing_a-scheduler_vanilla.Po @@ -23681,6 +24569,7 @@ -rm -f src/core/or/$(DEPDIR)/protover.Po -rm -f src/core/or/$(DEPDIR)/reasons.Po -rm -f src/core/or/$(DEPDIR)/relay.Po + -rm -f src/core/or/$(DEPDIR)/relay_msg.Po -rm -f src/core/or/$(DEPDIR)/scheduler.Po -rm -f src/core/or/$(DEPDIR)/scheduler_kist.Po -rm -f src/core/or/$(DEPDIR)/scheduler_vanilla.Po @@ -23753,9 +24642,24 @@ -rm -f src/ext/ed25519/ref10/$(DEPDIR)/libed25519_ref10_a-sc_muladd.Po -rm -f src/ext/ed25519/ref10/$(DEPDIR)/libed25519_ref10_a-sc_reduce.Po -rm -f src/ext/ed25519/ref10/$(DEPDIR)/libed25519_ref10_a-sign.Po + -rm -f src/ext/equix/hashx/src/$(DEPDIR)/libhashx_a-blake2.Po + -rm -f src/ext/equix/hashx/src/$(DEPDIR)/libhashx_a-compiler.Po + -rm -f src/ext/equix/hashx/src/$(DEPDIR)/libhashx_a-compiler_a64.Po + -rm -f src/ext/equix/hashx/src/$(DEPDIR)/libhashx_a-compiler_x86.Po + -rm -f src/ext/equix/hashx/src/$(DEPDIR)/libhashx_a-context.Po + -rm -f src/ext/equix/hashx/src/$(DEPDIR)/libhashx_a-hashx.Po + -rm -f src/ext/equix/hashx/src/$(DEPDIR)/libhashx_a-program.Po + -rm -f src/ext/equix/hashx/src/$(DEPDIR)/libhashx_a-program_exec.Po + -rm -f src/ext/equix/hashx/src/$(DEPDIR)/libhashx_a-siphash.Po + -rm -f src/ext/equix/hashx/src/$(DEPDIR)/libhashx_a-siphash_rng.Po + -rm -f src/ext/equix/hashx/src/$(DEPDIR)/libhashx_a-virtual_memory.Po + -rm -f src/ext/equix/src/$(DEPDIR)/libequix_a-context.Po + -rm -f src/ext/equix/src/$(DEPDIR)/libequix_a-equix.Po + -rm -f src/ext/equix/src/$(DEPDIR)/libequix_a-solver.Po -rm -f src/ext/keccak-tiny/$(DEPDIR)/libkeccak_tiny_a-keccak-tiny-unrolled.Po -rm -f src/ext/mulodi/$(DEPDIR)/lib_libtor_ctime_a-mulodi4.Po -rm -f src/ext/mulodi/$(DEPDIR)/lib_libtor_ctime_testing_a-mulodi4.Po + -rm -f src/ext/polyval/$(DEPDIR)/libpolyval_a-polyval.Po -rm -f src/ext/trunnel/$(DEPDIR)/trunnel_libor_trunnel_a-trunnel.Po -rm -f src/ext/trunnel/$(DEPDIR)/trunnel_libor_trunnel_testing_a-trunnel.Po -rm -f src/feature/api/$(DEPDIR)/core_libtor_app_testing_a-tor_api.Po @@ -23897,6 +24801,7 @@ -rm -f src/feature/hs/$(DEPDIR)/core_libtor_app_testing_a-hs_metrics.Po -rm -f src/feature/hs/$(DEPDIR)/core_libtor_app_testing_a-hs_metrics_entry.Po -rm -f src/feature/hs/$(DEPDIR)/core_libtor_app_testing_a-hs_ob.Po + -rm -f src/feature/hs/$(DEPDIR)/core_libtor_app_testing_a-hs_pow.Po -rm -f src/feature/hs/$(DEPDIR)/core_libtor_app_testing_a-hs_service.Po -rm -f src/feature/hs/$(DEPDIR)/core_libtor_app_testing_a-hs_stats.Po -rm -f src/feature/hs/$(DEPDIR)/core_libtor_app_testing_a-hs_sys.Po @@ -23915,6 +24820,7 @@ -rm -f src/feature/hs/$(DEPDIR)/hs_metrics.Po -rm -f src/feature/hs/$(DEPDIR)/hs_metrics_entry.Po -rm -f src/feature/hs/$(DEPDIR)/hs_ob.Po + -rm -f src/feature/hs/$(DEPDIR)/hs_pow.Po -rm -f src/feature/hs/$(DEPDIR)/hs_service.Po -rm -f src/feature/hs/$(DEPDIR)/hs_stats.Po -rm -f src/feature/hs/$(DEPDIR)/hs_sys.Po @@ -24350,8 +25256,11 @@ -rm -f src/test/$(DEPDIR)/test-test_circuituse.Po -rm -f src/test/$(DEPDIR)/test-test_compat_libevent.Po -rm -f src/test/$(DEPDIR)/test-test_config.Po + -rm -f src/test/$(DEPDIR)/test-test_conflux_cell.Po + -rm -f src/test/$(DEPDIR)/test-test_conflux_pool.Po -rm -f src/test/$(DEPDIR)/test-test_confmgr.Po -rm -f src/test/$(DEPDIR)/test-test_confparse.Po + -rm -f src/test/$(DEPDIR)/test-test_congestion_control.Po -rm -f src/test/$(DEPDIR)/test-test_connection.Po -rm -f src/test/$(DEPDIR)/test-test_conscache.Po -rm -f src/test/$(DEPDIR)/test-test_consdiff.Po @@ -24360,6 +25269,7 @@ -rm -f src/test/$(DEPDIR)/test-test_controller.Po -rm -f src/test/$(DEPDIR)/test-test_controller_events.Po -rm -f src/test/$(DEPDIR)/test-test_crypto.Po + -rm -f src/test/$(DEPDIR)/test-test_crypto_cgo.Po -rm -f src/test/$(DEPDIR)/test-test_crypto_ope.Po -rm -f src/test/$(DEPDIR)/test-test_crypto_openssl.Po -rm -f src/test/$(DEPDIR)/test-test_crypto_rng.Po @@ -24391,6 +25301,7 @@ -rm -f src/test/$(DEPDIR)/test-test_hs_metrics.Po -rm -f src/test/$(DEPDIR)/test-test_hs_ntor.Po -rm -f src/test/$(DEPDIR)/test-test_hs_ob.Po + -rm -f src/test/$(DEPDIR)/test-test_hs_pow.Po -rm -f src/test/$(DEPDIR)/test-test_hs_service.Po -rm -f src/test/$(DEPDIR)/test-test_keypin.Po -rm -f src/test/$(DEPDIR)/test-test_link_handshake.Po @@ -24458,6 +25369,7 @@ -rm -f src/test/$(DEPDIR)/test_slow-ptr_helpers.Po -rm -f src/test/$(DEPDIR)/test_slow-rng_test_helpers.Po -rm -f src/test/$(DEPDIR)/test_slow-test_crypto_slow.Po + -rm -f src/test/$(DEPDIR)/test_slow-test_hs_pow_slow.Po -rm -f src/test/$(DEPDIR)/test_slow-test_prob_distr.Po -rm -f src/test/$(DEPDIR)/test_slow-test_process_slow.Po -rm -f src/test/$(DEPDIR)/test_slow-test_ptr_slow.Po @@ -24571,6 +25483,7 @@ -rm -f src/tools/$(DEPDIR)/tor_runner.Po -rm -f src/trunnel/$(DEPDIR)/libor_trunnel_a-channelpadding_negotiation.Po -rm -f src/trunnel/$(DEPDIR)/libor_trunnel_a-circpad_negotiation.Po + -rm -f src/trunnel/$(DEPDIR)/libor_trunnel_a-conflux.Po -rm -f src/trunnel/$(DEPDIR)/libor_trunnel_a-congestion_control.Po -rm -f src/trunnel/$(DEPDIR)/libor_trunnel_a-ed25519_cert.Po -rm -f src/trunnel/$(DEPDIR)/libor_trunnel_a-extension.Po @@ -24580,8 +25493,10 @@ -rm -f src/trunnel/$(DEPDIR)/libor_trunnel_a-pwbox.Po -rm -f src/trunnel/$(DEPDIR)/libor_trunnel_a-sendme_cell.Po -rm -f src/trunnel/$(DEPDIR)/libor_trunnel_a-socks5.Po + -rm -f src/trunnel/$(DEPDIR)/libor_trunnel_a-subproto_request.Po -rm -f src/trunnel/$(DEPDIR)/libor_trunnel_testing_a-channelpadding_negotiation.Po -rm -f src/trunnel/$(DEPDIR)/libor_trunnel_testing_a-circpad_negotiation.Po + -rm -f src/trunnel/$(DEPDIR)/libor_trunnel_testing_a-conflux.Po -rm -f src/trunnel/$(DEPDIR)/libor_trunnel_testing_a-congestion_control.Po -rm -f src/trunnel/$(DEPDIR)/libor_trunnel_testing_a-ed25519_cert.Po -rm -f src/trunnel/$(DEPDIR)/libor_trunnel_testing_a-extension.Po @@ -24591,6 +25506,7 @@ -rm -f src/trunnel/$(DEPDIR)/libor_trunnel_testing_a-pwbox.Po -rm -f src/trunnel/$(DEPDIR)/libor_trunnel_testing_a-sendme_cell.Po -rm -f src/trunnel/$(DEPDIR)/libor_trunnel_testing_a-socks5.Po + -rm -f src/trunnel/$(DEPDIR)/libor_trunnel_testing_a-subproto_request.Po -rm -f src/trunnel/hs/$(DEPDIR)/libor_trunnel_a-cell_establish_intro.Po -rm -f src/trunnel/hs/$(DEPDIR)/libor_trunnel_a-cell_introduce1.Po -rm -f src/trunnel/hs/$(DEPDIR)/libor_trunnel_a-cell_rendezvous.Po @@ -24673,14 +25589,16 @@ -rm -f src/core/crypto/$(DEPDIR)/libtor_app_testing_a-onion_fast.Po -rm -f src/core/crypto/$(DEPDIR)/libtor_app_testing_a-onion_ntor.Po -rm -f src/core/crypto/$(DEPDIR)/libtor_app_testing_a-onion_ntor_v3.Po - -rm -f src/core/crypto/$(DEPDIR)/libtor_app_testing_a-onion_tap.Po -rm -f src/core/crypto/$(DEPDIR)/libtor_app_testing_a-relay_crypto.Po + -rm -f src/core/crypto/$(DEPDIR)/libtor_app_testing_a-relay_crypto_cgo.Po + -rm -f src/core/crypto/$(DEPDIR)/libtor_app_testing_a-relay_crypto_tor1.Po -rm -f src/core/crypto/$(DEPDIR)/onion_crypto.Po -rm -f src/core/crypto/$(DEPDIR)/onion_fast.Po -rm -f src/core/crypto/$(DEPDIR)/onion_ntor.Po -rm -f src/core/crypto/$(DEPDIR)/onion_ntor_v3.Po - -rm -f src/core/crypto/$(DEPDIR)/onion_tap.Po -rm -f src/core/crypto/$(DEPDIR)/relay_crypto.Po + -rm -f src/core/crypto/$(DEPDIR)/relay_crypto_cgo.Po + -rm -f src/core/crypto/$(DEPDIR)/relay_crypto_tor1.Po -rm -f src/core/mainloop/$(DEPDIR)/connection.Po -rm -f src/core/mainloop/$(DEPDIR)/cpuworker.Po -rm -f src/core/mainloop/$(DEPDIR)/libtor_app_testing_a-connection.Po @@ -24708,11 +25626,15 @@ -rm -f src/core/or/$(DEPDIR)/circuitstats.Po -rm -f src/core/or/$(DEPDIR)/circuituse.Po -rm -f src/core/or/$(DEPDIR)/command.Po + -rm -f src/core/or/$(DEPDIR)/conflux.Po + -rm -f src/core/or/$(DEPDIR)/conflux_cell.Po + -rm -f src/core/or/$(DEPDIR)/conflux_params.Po + -rm -f src/core/or/$(DEPDIR)/conflux_pool.Po + -rm -f src/core/or/$(DEPDIR)/conflux_sys.Po + -rm -f src/core/or/$(DEPDIR)/conflux_util.Po -rm -f src/core/or/$(DEPDIR)/congestion_control_common.Po -rm -f src/core/or/$(DEPDIR)/congestion_control_flow.Po - -rm -f src/core/or/$(DEPDIR)/congestion_control_nola.Po -rm -f src/core/or/$(DEPDIR)/congestion_control_vegas.Po - -rm -f src/core/or/$(DEPDIR)/congestion_control_westwood.Po -rm -f src/core/or/$(DEPDIR)/connection_edge.Po -rm -f src/core/or/$(DEPDIR)/connection_or.Po -rm -f src/core/or/$(DEPDIR)/crypt_path.Po @@ -24733,11 +25655,15 @@ -rm -f src/core/or/$(DEPDIR)/libtor_app_testing_a-circuitstats.Po -rm -f src/core/or/$(DEPDIR)/libtor_app_testing_a-circuituse.Po -rm -f src/core/or/$(DEPDIR)/libtor_app_testing_a-command.Po + -rm -f src/core/or/$(DEPDIR)/libtor_app_testing_a-conflux.Po + -rm -f src/core/or/$(DEPDIR)/libtor_app_testing_a-conflux_cell.Po + -rm -f src/core/or/$(DEPDIR)/libtor_app_testing_a-conflux_params.Po + -rm -f src/core/or/$(DEPDIR)/libtor_app_testing_a-conflux_pool.Po + -rm -f src/core/or/$(DEPDIR)/libtor_app_testing_a-conflux_sys.Po + -rm -f src/core/or/$(DEPDIR)/libtor_app_testing_a-conflux_util.Po -rm -f src/core/or/$(DEPDIR)/libtor_app_testing_a-congestion_control_common.Po -rm -f src/core/or/$(DEPDIR)/libtor_app_testing_a-congestion_control_flow.Po - -rm -f src/core/or/$(DEPDIR)/libtor_app_testing_a-congestion_control_nola.Po -rm -f src/core/or/$(DEPDIR)/libtor_app_testing_a-congestion_control_vegas.Po - -rm -f src/core/or/$(DEPDIR)/libtor_app_testing_a-congestion_control_westwood.Po -rm -f src/core/or/$(DEPDIR)/libtor_app_testing_a-connection_edge.Po -rm -f src/core/or/$(DEPDIR)/libtor_app_testing_a-connection_or.Po -rm -f src/core/or/$(DEPDIR)/libtor_app_testing_a-crypt_path.Po @@ -24754,6 +25680,7 @@ -rm -f src/core/or/$(DEPDIR)/libtor_app_testing_a-protover.Po -rm -f src/core/or/$(DEPDIR)/libtor_app_testing_a-reasons.Po -rm -f src/core/or/$(DEPDIR)/libtor_app_testing_a-relay.Po + -rm -f src/core/or/$(DEPDIR)/libtor_app_testing_a-relay_msg.Po -rm -f src/core/or/$(DEPDIR)/libtor_app_testing_a-scheduler.Po -rm -f src/core/or/$(DEPDIR)/libtor_app_testing_a-scheduler_kist.Po -rm -f src/core/or/$(DEPDIR)/libtor_app_testing_a-scheduler_vanilla.Po @@ -24771,6 +25698,7 @@ -rm -f src/core/or/$(DEPDIR)/protover.Po -rm -f src/core/or/$(DEPDIR)/reasons.Po -rm -f src/core/or/$(DEPDIR)/relay.Po + -rm -f src/core/or/$(DEPDIR)/relay_msg.Po -rm -f src/core/or/$(DEPDIR)/scheduler.Po -rm -f src/core/or/$(DEPDIR)/scheduler_kist.Po -rm -f src/core/or/$(DEPDIR)/scheduler_vanilla.Po @@ -24843,9 +25771,24 @@ -rm -f src/ext/ed25519/ref10/$(DEPDIR)/libed25519_ref10_a-sc_muladd.Po -rm -f src/ext/ed25519/ref10/$(DEPDIR)/libed25519_ref10_a-sc_reduce.Po -rm -f src/ext/ed25519/ref10/$(DEPDIR)/libed25519_ref10_a-sign.Po + -rm -f src/ext/equix/hashx/src/$(DEPDIR)/libhashx_a-blake2.Po + -rm -f src/ext/equix/hashx/src/$(DEPDIR)/libhashx_a-compiler.Po + -rm -f src/ext/equix/hashx/src/$(DEPDIR)/libhashx_a-compiler_a64.Po + -rm -f src/ext/equix/hashx/src/$(DEPDIR)/libhashx_a-compiler_x86.Po + -rm -f src/ext/equix/hashx/src/$(DEPDIR)/libhashx_a-context.Po + -rm -f src/ext/equix/hashx/src/$(DEPDIR)/libhashx_a-hashx.Po + -rm -f src/ext/equix/hashx/src/$(DEPDIR)/libhashx_a-program.Po + -rm -f src/ext/equix/hashx/src/$(DEPDIR)/libhashx_a-program_exec.Po + -rm -f src/ext/equix/hashx/src/$(DEPDIR)/libhashx_a-siphash.Po + -rm -f src/ext/equix/hashx/src/$(DEPDIR)/libhashx_a-siphash_rng.Po + -rm -f src/ext/equix/hashx/src/$(DEPDIR)/libhashx_a-virtual_memory.Po + -rm -f src/ext/equix/src/$(DEPDIR)/libequix_a-context.Po + -rm -f src/ext/equix/src/$(DEPDIR)/libequix_a-equix.Po + -rm -f src/ext/equix/src/$(DEPDIR)/libequix_a-solver.Po -rm -f src/ext/keccak-tiny/$(DEPDIR)/libkeccak_tiny_a-keccak-tiny-unrolled.Po -rm -f src/ext/mulodi/$(DEPDIR)/lib_libtor_ctime_a-mulodi4.Po -rm -f src/ext/mulodi/$(DEPDIR)/lib_libtor_ctime_testing_a-mulodi4.Po + -rm -f src/ext/polyval/$(DEPDIR)/libpolyval_a-polyval.Po -rm -f src/ext/trunnel/$(DEPDIR)/trunnel_libor_trunnel_a-trunnel.Po -rm -f src/ext/trunnel/$(DEPDIR)/trunnel_libor_trunnel_testing_a-trunnel.Po -rm -f src/feature/api/$(DEPDIR)/core_libtor_app_testing_a-tor_api.Po @@ -24987,6 +25930,7 @@ -rm -f src/feature/hs/$(DEPDIR)/core_libtor_app_testing_a-hs_metrics.Po -rm -f src/feature/hs/$(DEPDIR)/core_libtor_app_testing_a-hs_metrics_entry.Po -rm -f src/feature/hs/$(DEPDIR)/core_libtor_app_testing_a-hs_ob.Po + -rm -f src/feature/hs/$(DEPDIR)/core_libtor_app_testing_a-hs_pow.Po -rm -f src/feature/hs/$(DEPDIR)/core_libtor_app_testing_a-hs_service.Po -rm -f src/feature/hs/$(DEPDIR)/core_libtor_app_testing_a-hs_stats.Po -rm -f src/feature/hs/$(DEPDIR)/core_libtor_app_testing_a-hs_sys.Po @@ -25005,6 +25949,7 @@ -rm -f src/feature/hs/$(DEPDIR)/hs_metrics.Po -rm -f src/feature/hs/$(DEPDIR)/hs_metrics_entry.Po -rm -f src/feature/hs/$(DEPDIR)/hs_ob.Po + -rm -f src/feature/hs/$(DEPDIR)/hs_pow.Po -rm -f src/feature/hs/$(DEPDIR)/hs_service.Po -rm -f src/feature/hs/$(DEPDIR)/hs_stats.Po -rm -f src/feature/hs/$(DEPDIR)/hs_sys.Po @@ -25440,8 +26385,11 @@ -rm -f src/test/$(DEPDIR)/test-test_circuituse.Po -rm -f src/test/$(DEPDIR)/test-test_compat_libevent.Po -rm -f src/test/$(DEPDIR)/test-test_config.Po + -rm -f src/test/$(DEPDIR)/test-test_conflux_cell.Po + -rm -f src/test/$(DEPDIR)/test-test_conflux_pool.Po -rm -f src/test/$(DEPDIR)/test-test_confmgr.Po -rm -f src/test/$(DEPDIR)/test-test_confparse.Po + -rm -f src/test/$(DEPDIR)/test-test_congestion_control.Po -rm -f src/test/$(DEPDIR)/test-test_connection.Po -rm -f src/test/$(DEPDIR)/test-test_conscache.Po -rm -f src/test/$(DEPDIR)/test-test_consdiff.Po @@ -25450,6 +26398,7 @@ -rm -f src/test/$(DEPDIR)/test-test_controller.Po -rm -f src/test/$(DEPDIR)/test-test_controller_events.Po -rm -f src/test/$(DEPDIR)/test-test_crypto.Po + -rm -f src/test/$(DEPDIR)/test-test_crypto_cgo.Po -rm -f src/test/$(DEPDIR)/test-test_crypto_ope.Po -rm -f src/test/$(DEPDIR)/test-test_crypto_openssl.Po -rm -f src/test/$(DEPDIR)/test-test_crypto_rng.Po @@ -25481,6 +26430,7 @@ -rm -f src/test/$(DEPDIR)/test-test_hs_metrics.Po -rm -f src/test/$(DEPDIR)/test-test_hs_ntor.Po -rm -f src/test/$(DEPDIR)/test-test_hs_ob.Po + -rm -f src/test/$(DEPDIR)/test-test_hs_pow.Po -rm -f src/test/$(DEPDIR)/test-test_hs_service.Po -rm -f src/test/$(DEPDIR)/test-test_keypin.Po -rm -f src/test/$(DEPDIR)/test-test_link_handshake.Po @@ -25548,6 +26498,7 @@ -rm -f src/test/$(DEPDIR)/test_slow-ptr_helpers.Po -rm -f src/test/$(DEPDIR)/test_slow-rng_test_helpers.Po -rm -f src/test/$(DEPDIR)/test_slow-test_crypto_slow.Po + -rm -f src/test/$(DEPDIR)/test_slow-test_hs_pow_slow.Po -rm -f src/test/$(DEPDIR)/test_slow-test_prob_distr.Po -rm -f src/test/$(DEPDIR)/test_slow-test_process_slow.Po -rm -f src/test/$(DEPDIR)/test_slow-test_ptr_slow.Po @@ -25661,6 +26612,7 @@ -rm -f src/tools/$(DEPDIR)/tor_runner.Po -rm -f src/trunnel/$(DEPDIR)/libor_trunnel_a-channelpadding_negotiation.Po -rm -f src/trunnel/$(DEPDIR)/libor_trunnel_a-circpad_negotiation.Po + -rm -f src/trunnel/$(DEPDIR)/libor_trunnel_a-conflux.Po -rm -f src/trunnel/$(DEPDIR)/libor_trunnel_a-congestion_control.Po -rm -f src/trunnel/$(DEPDIR)/libor_trunnel_a-ed25519_cert.Po -rm -f src/trunnel/$(DEPDIR)/libor_trunnel_a-extension.Po @@ -25670,8 +26622,10 @@ -rm -f src/trunnel/$(DEPDIR)/libor_trunnel_a-pwbox.Po -rm -f src/trunnel/$(DEPDIR)/libor_trunnel_a-sendme_cell.Po -rm -f src/trunnel/$(DEPDIR)/libor_trunnel_a-socks5.Po + -rm -f src/trunnel/$(DEPDIR)/libor_trunnel_a-subproto_request.Po -rm -f src/trunnel/$(DEPDIR)/libor_trunnel_testing_a-channelpadding_negotiation.Po -rm -f src/trunnel/$(DEPDIR)/libor_trunnel_testing_a-circpad_negotiation.Po + -rm -f src/trunnel/$(DEPDIR)/libor_trunnel_testing_a-conflux.Po -rm -f src/trunnel/$(DEPDIR)/libor_trunnel_testing_a-congestion_control.Po -rm -f src/trunnel/$(DEPDIR)/libor_trunnel_testing_a-ed25519_cert.Po -rm -f src/trunnel/$(DEPDIR)/libor_trunnel_testing_a-extension.Po @@ -25681,6 +26635,7 @@ -rm -f src/trunnel/$(DEPDIR)/libor_trunnel_testing_a-pwbox.Po -rm -f src/trunnel/$(DEPDIR)/libor_trunnel_testing_a-sendme_cell.Po -rm -f src/trunnel/$(DEPDIR)/libor_trunnel_testing_a-socks5.Po + -rm -f src/trunnel/$(DEPDIR)/libor_trunnel_testing_a-subproto_request.Po -rm -f src/trunnel/hs/$(DEPDIR)/libor_trunnel_a-cell_establish_intro.Po -rm -f src/trunnel/hs/$(DEPDIR)/libor_trunnel_a-cell_introduce1.Po -rm -f src/trunnel/hs/$(DEPDIR)/libor_trunnel_a-cell_rendezvous.Po @@ -25773,11 +26728,6 @@ true FORCE: -# fallback_consensus - -# If we don't have it, fake it. -src_config_fallback-consensus: - touch src/config/fallback-consensus oss-fuzz-prereqs: \ src/test/libtor-testing.a @@ -25786,8 +26736,6 @@ test-fuzz-corpora: $(FUZZERS) $(top_srcdir)/src/test/fuzz_static_testcases.sh - doc/HACKING/tracing/Tracing.md \ - doc/HACKING/tracing/EventsCircuit.md # Generate the html documentation from asciidoc, but don't do # machine-specific replacements yet @@ -25958,10 +26906,9 @@ # # Run the IPv4 tests in $(ipv4_flavors), unconditionally # - tor relays and directory authorities require IPv4. -# Run the IPv6 tests in $(ipv6_flavors), if IPv6 is available -# - 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 +# Run the IPv6 tests in $(ipv6_flavors), unconditionally +# - clients don't technically require IPv6, but it's not worth +# supporting running this test suite on such systems. # - some IPv6 tests may fail without an IPv6 DNS server # (see #16971 and #17011) # Run the mixed tests in $(mixed_flavors), if a tor-stable binary is available @@ -25978,25 +26925,9 @@ echo "Running IPv4 flavors: $(ipv4_flavors)."; \ flavors="$$flavors $(ipv4_flavors)"; \ fi; \ - test_network_ipv6=false; \ - if test -n "$(ipv6_flavors)" || \ - test -n "$(ipv6_mixed_flavors)"; then \ - if ping6 -q -c 1 -o ::1 >/dev/null 2>&1 || \ - ping6 -q -c 1 -W 1 ::1 >/dev/null 2>&1 || \ - ping -6 -c 1 -W 1 ::1 >/dev/null 2>&1; then \ - test_network_ipv6=true; \ - fi; \ - fi; \ if test -n "$(ipv6_flavors)"; then \ - if test "$$test_network_ipv6" = "true"; then \ - echo "ping6 ::1 or ping ::1 succeeded, running IPv6" \ - "flavors: $(ipv6_flavors)."; \ - flavors="$$flavors $(ipv6_flavors)"; \ - else \ - echo "ping6 ::1 and ping ::1 failed, skipping IPv6" \ - "flavors: $(ipv6_flavors)."; \ - skip_flavors="$$skip_flavors $(ipv6_flavors)"; \ - fi; \ + echo "Running IPv6 flavors: $(ipv6_flavors)."; \ + flavors="$$flavors $(ipv6_flavors)"; \ fi; \ test_network_mixed=false; \ if test -n "$(mixed_flavors)" || \ @@ -26017,8 +26948,7 @@ fi; \ fi; \ if test -n "$(ipv6_mixed_flavors)"; then \ - if test "$$test_network_ipv6" = "true" && \ - test "$$test_network_mixed" = "true"; then \ + if test "$$test_network_mixed" = "true"; then \ echo "Running IPv6 mixed flavors:" \ "$(ipv6_mixed_flavors)."; \ flavors="$$flavors $(ipv6_mixed_flavors)"; \ diff -Nru tor-0.4.7.16/Makefile.nmake tor-0.4.9.6/Makefile.nmake --- tor-0.4.7.16/Makefile.nmake 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/Makefile.nmake 1970-01-01 00:00:00.000000000 +0000 @@ -1,19 +0,0 @@ -all: - cd src/common - $(MAKE) /F Makefile.nmake - cd ../../src/ext - $(MAKE) /F Makefile.nmake - cd ../../src/or - $(MAKE) /F Makefile.nmake - cd ../../src/test - $(MAKE) /F Makefile.nmake - -clean: - cd src/common - $(MAKE) /F Makefile.nmake clean - cd ../../src/ext - $(MAKE) /F Makefile.nmake clean - cd ../../src/or - $(MAKE) /F Makefile.nmake clean - cd ../../src/test - $(MAKE) /F Makefile.nmake clean diff -Nru tor-0.4.7.16/README.md tor-0.4.9.6/README.md --- tor-0.4.7.16/README.md 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/README.md 2026-03-25 14:30:34.000000000 +0000 @@ -58,13 +58,16 @@ Download new versions: -- https://www.torproject.org/download/download.html +- https://www.torproject.org/download/tor -Documentation, including links to installation and setup instructions: +How to verify Tor source: -- https://www.torproject.org/docs/documentation.html +- https://support.torproject.org/little-t-tor/ -Frequently Asked Questions: +Documentation and Frequently Asked Questions: -- https://www.torproject.org/docs/faq.html +- https://support.torproject.org/ +How to run a Tor relay: + +- https://community.torproject.org/relay/ diff -Nru tor-0.4.7.16/ReleaseNotes tor-0.4.9.6/ReleaseNotes --- tor-0.4.7.16/ReleaseNotes 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/ReleaseNotes 2026-03-25 14:30:34.000000000 +0000 @@ -2,9 +2,759 @@ 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.7.16 - 2023-11-03 +Changes in version 0.4.9.6 - 2026-03-25 + This is a security release fixing major bugfixes that could possibly lead to + remote crashing relays. We strongly recommend upgrading as soon as possible. + + o Major bugfix (security): + - Fix a stack overflow of 11 bytes on malicious CREATED2. This lead + to a remote crash. TROVE-2026-003. Reported-by: Anas Cherni of + Calif.io. Fixes bug 41231; bugfix on 0.4.9.1-alpha. + + o Major bugfix (security, conflux): + - Fix a memory compare using the wrong length. This could lead to a + remote crash when using the conflux subsystem. TROVE-2026-004. + Fixes bug 41232; bugfix on 0.4.8.1-alpha. + + o Minor bugfixes (security): + - Fix a series of defense in depth security issues found across the + codebase. Fixes bug 41228; bugfix on 0.3.5.1-alpha. + + o Minor bugfixes (portability): + - (Hopefully) fix our polyval implementation on big-endian + platforms. Fixes bug 41215; bugfix on 0.4.9.3-alpha. + + o Minor features (fallbackdir): + - Regenerate fallback directories generated on March 25, 2026. + + o Minor features (geoip data): + - Update the geoip files to match the IPFire Location Database, as + retrieved on 2026/03/25. + + +Changes in version 0.4.9.5 - 2026-02-12 + This first stable release in the 0.4.9 series introduces a new + circuit-level encryption design for better client security, as well + as a more scalable way for large relay operators to annotate which + relays they run so clients can avoid using too many of them in a + single circuit. + + o Major features (cryptography): + - Clients and relays can now negotiate Counter Galois Onion (CGO) + relay cryptography, as designed by Jean Paul Degabriele, + Alessandro Melloni, Jean-Pierre Münch, and Martijn Stam. CGO + provides improved resistance to several kinds of tagging attacks, + better forward secrecy, and better forgery resistance. Closes + ticket 41047. Implements proposal 359. + + o Major features (path selection): + - Clients and relays now support "happy families", a system to + simplify relay family operation and improve directory performance. + With "happy families", relays in a family share a secret "family + key", which they use to prove their membership in the family. + Implements proposal 321; closes ticket 41009. Note that until + enough clients are upgraded, relay operators will still need to + configure MyFamily lists. But once clients no longer depend on + those lists, we will be able to remove them entirely, thereby + simplifying family operation, and making microdescriptor downloads + approximately 80% smaller. For more information, see + https://community.torproject.org/relay/setup/post-install/family-ids/ + + o Major bugfixes (conflux): + - Ensure conflux guards obey family and subnet restrictions. Fixes + bug 40976; bugfix on 0.4.8.1-alpha. + + o Major bugfixes (controller events): + - Fix spikes occurring in bandwidth cache events on control connection. + Fixes bug 31524; bugfix on 0.0.9pre5. + + o Major bugfixes (sandbox): + - Fix sandbox to work on architectures that use Linux's generic + syscall interface, extending support for AArch64 (ARM64) and + adding support for RISC-V, allowing test_include.sh and the + sandbox unit tests to pass on these systems even when building + with fragile hardening enabled. Fixes bugs 40465 and 40599; bugfix + on 0.2.5.1-alpha. + + o Minor features (client security, reliability): + - When KeepaliveIsolateSOCKSAuth is keeping a circuit alive, expire + the circuit based on when it was last in use for any stream, not + (as we did before) based on when a stream was last attached to it. + Closes ticket 41157. Implements a minimal version of Proposal 368. + + o Minor features (exit relays): + - Implement reevaluating new exit policy against existing + connections. This is controlled by new config option + ReevaluateExitPolicy, defaulting to 0. Closes ticket 40676. + - Implement a token-bucket based rate limiter for stream creation + and resolve request. It is configured by the DoSStream* family of + configuration options. Closes ticket 40736. + - Add Monero ports to the ReducedExitPolicy. Closes ticket 41168. + + o Minor features (bridges): + - Save complete bridge lines to 'datadir/bridgelines'. Closes + ticket 29128. + + o Minor features (client extensibility): + - Implement new HTTPTunnelPort features for interoperability with + Arti's HTTP CONNECT proxy. This work adds new headers to requests + to and replies from the HttpConnectPort, support for OPTIONS + requests, tightens the expected syntax for Proxy-Authorization, + and increases defense-in-depth against some kinds of cross-site + HTTP attacks. Closes ticket 41156. Implements proposal 365. + - Detect invalid SOCKS5 username/password combinations according to + new extended parameters syntax. (Currently, this rejects any + SOCKS5 username beginning with "", except for the username + "0". Such usernames are now reserved to communicate + additional parameters with other Tor implementations.) Implements + proposal 351. + + o Minor features (sandboxing): + - Allow the fstatat64 and statx syscalls on i386 architecture when + glibc >= 2.33. On i386, glibc uses fstatat64 instead of newfstatat + for stat operations, and statx for time64 support. Without this, + SIGHUP configuration reload fails when using sandbox mode with + %include directives on i386 with Debian Bookworm or newer. + - Allow the lstat64 syscall on i386 architecture. This syscall is + used by glob() in glibc 2.36+ when processing %include directives + with directory patterns. + + o Minor features (security): + - Increase the size of our finite-field Diffie Hellman TLS group + (which we should never actually use!) to 2048 bits. Part of + ticket 41067. + - Require TLS version 1.2 or later. (Version 1.3 support will be + required in the near future.) Part of ticket 41067. + - Update TLS 1.2 client cipher list to match current Firefox. Part + of ticket 41067. + - Verify needle is smaller than haystack before calling memmem. + Closes ticket 40854. + + o Minor features (onion services): + - Add 3 more keywords to the ADD_ONION control command: + PoWDefensesEnabled, PoWQueueRate and PoWQueueBurst which correspond + to HiddenServicePoWDefensesEnabled, HiddenServicePoWQueueRate and + HiddenServicePoWQueueBurst from torrc. + - Reduce the minimum value of hsdir_interval to match recent tor- + spec change. + + o Minor feature (directory authority): + - Introduce MinimalAcceptedServerVersion to allow configuring + the minimum accepted relay version without requiring a new tor + release. Closes ticket 40817. + + o Minor features (metrics port): + - New metrics on the MetricsPort for the number of BUG() calls that + occurred at runtime. Fixes bugs 40839 and 41104; bugfix on + 0.4.7.1-alpha. + - Handle rephist tracking of ntor and ntor_v3 handshakes + individually such that MetricsPort exposes the correct values. + Fixes bug 40638; bugfix on 0.4.7.11. + - Add new metrics for relays on the MetricsPort namely the count of + drop cell, destroy cell and the number of circuit protocol + violation seen that lead to a circuit close. Closes ticket 40816. + + o Minor features (forward-compatibility): + - We now correctly parse microdescriptors and router descriptors + that do not include TAP onion keys. (For backward compatibility, + authorities continue to require these keys.) Implements part of + proposal 350. + + o Minor features (portability, android): + - Use /data/local/tmp for data storage on Android by default. Closes + ticket 40487. Patch from Hans-Christoph Steiner. + + o Minor features (directory authority): + - Export unsigned consensus documents once we have seen a threshold + of signatures, as a step toward the consensus transparency + experiment. + + o Minor features (fallbackdir): + - Regenerate fallback directories generated on February 12, 2026. + + o Minor features (geoip data): + - Update the geoip files to match the IPFire Location Database, + as retrieved on 2026/02/12. + + o Minor features (windows): + - Various compilation fixes for our Windows CI. Closes ticket 41214. + + o Minor bugfixes (exit relays): + - Clip every returned DNS TTL to 60 (RESOLVED) in order to mitigate + an exit DNS cache oracle. Fixes bug 40979; bugfix on 0.3.5.1-alpha. + + o Minor bugfixes (spec conformance): + - Set the length field correctly on RELAY_COMMAND_CONFLUX_SWITCH + messages. Previously, it was always set to the maximum value. + Fixes bug 41056; bugfix on 0.4.8.1-alpha. + - Do not treat "15" as a recognized remote END reason code. + Formerly, we treated it as synonymous with a local ENTRYPOLICY, + which isn't a valid remote code at all. Fixes bug 41171; bugfix + on 0.2.0.8-alpha. + + o Minor bugfixes (tooling): + - Fix a false positive valgrind related to inspecting a bitfield + next to another uninitialized bitfield. Fixes bug 41182; bugfix + on 0.3.3.2-alpha. + - Fix minor warnings from newer versions of shellcheck and clang. + Fixes bug 41166; bugfix on 0.4.3.1-alpha and several + other versions. + - Fix a warning when compiling with GCC 14.2. Closes 41032. + + o Minor bugfixes (threads): + - Make thread control POSIX compliant. Fixes bug 41109; bugfix + on 0.4.8.17. + + o Minor bugfix (client DNS): + - Handle empty DNS reply without sending back an error and instead + send back NOERROR (RFC1035 error code 0x0). Fixes bug 40248; + bugfix on 0.3.5.1-alpha. + + o Minor bugfixes (directory authorities): + - After we added layer-two vanguards, directory authorities wouldn't + think any of their vanguards were suitable for circuits, leading + to a "Failed to find node for hop #2 of our path. Discarding this + circuit." log message once per second from startup until they made + a fresh consensus. Now they look to their existing consensus on + startup, letting them build circuits properly from the beginning. + Fixes bug 40802; bugfix on 0.4.7.1-alpha. + + o Minor bugfixes (tests): + - Fix a test failure with OpenSSL builds running at security level 1 + or greater, which does not permit SHA-1 certificates. Fixes bug + 41021; bugfix on 0.2.8.1-alpha. + + o Minor bugfixes (bridges): + - Don't warn when BridgeRelay is 1 and ExitRelay is explicitly set + to 0. Fixes bug 40884; bugfix on 0.4.8.3-rc. + + o Minor bugfixes (conflux, client): + - Avoid a non fatal assert caused by data coming in on a conflux set + that is being freed during shutdown. Fixes bug 40870; bugfix + on 0.4.8.1-alpha. + + o Minor bugfixes (testing network): + - Enabling TestingTorNetwork no longer forces fast hidden service + intro point rotation. This reduces noise and errors when using + hidden services with TestingTorNetwork enabled. Fixes bug 40922; + bugfix on 0.3.2.1-alpha. + + o Minor bugfixes (relay): + - Refuse to overwrite an existing *.secret_family_key when running + tor --keygen-family. Fixes bug 41184; bugfix on 0.4.9.1-alpha. + + o New system requirements: + - When built with LibreSSL, Tor now requires LibreSSL 3.7 or later. + Part of ticket 41059. + - When built with OpenSSL, Tor now requires OpenSSL 1.1.1 or later. + (We strongly recommend 3.0 or later, but still build with 1.1.1, + even though it is not supported by the OpenSSL team, due to its + presence in Debian oldstable.) Part of ticket 41059. + + o Removed features (relays): + - Relays no longer support clients that falsely advertise TLS + ciphers they don't really support. (Clients have not done this + since 0.2.3.17-beta). Part of ticket 41031. + - Relays no longer support clients that require obsolete v1 and v2 + link handshakes. (The v3 link handshake has been supported since + 0.2.3.6-alpha). Part of ticket 41031. + - Relays no longer support the obsolete TAP circuit extension + protocol. (For backward compatibility, however, relays still + continue to include TAP keys in their descriptors.) Implements + part of proposal 350. + - Relays no longer support the obsolete "RSA-SHA256-TLSSecret" + authentication method, which used a dangerously short RSA key, and + which required access TLS session internals. The current method + ("Ed25519-SHA256-RFC5705") has been supported since 0.3.0.1-alpha. + Closes ticket 41020. + + o Removed features (directory authorities): + - Directory authorities no longer support consensus methods before + method 32. Closes ticket 40835. + - We include a new consensus method that removes support for + computing "package" lines in consensus documents. This feature was + never used, and support for including it in our votes was removed + in 0.4.2.1-alpha. Finishes implementation of proposal 301. + + +Changes in version 0.4.8.22 - 2026-01-28 + This is likely the very last release of the 0.4.8.x series. Three major + bugfixes detailed below including two affecting directory servers (basically + all relays). We strongly recommend upgrading as soon as possible. + + o Major bugfixes (security): + - Avoid an out-of-bounds read error that could occur with + V1-formatted EXTEND cells. Fixes bug 41180; bugfix on 0.4.8.1-alpha. + This is tracked as TROVE-2025-016. + + o Major bugfixes (directory servers): + - Allow old clients to fetch the consensus even if they use version + 0 of the SENDME protocol. In mid 2025 we changed the required + minimum version of the "FlowCtrl" protocol to 1, meaning directory + caches hang up on clients that send a version 0 SENDME cell. Since + old clients were no longer able to retrieve the consensus, they + couldn't learn about this required minimum version -- meaning + we've had many many old clients loading down directory servers for + the past months. Fixes bug 41191; bugfix on 0.4.1.1-alpha. + - Don't count networkstatus serves until they finish. When we + started serving a consensus document but the client didn't receive + all of it, we were still counting that as a success in our stats. + This mistake, which can be triggered for example by obsolete + clients or by DPI-based censorship, led to wildly inflated user + counts because we estimate total users in the world based on + successful consensus fetches. Fixes bug 41192; bugfix + on 0.2.1.1-alpha. + + o Minor feature (testing, CI): + - Bump the CI version of chutney to the current version as of + 2026-01-21 (3338f5c). + + o Minor features (debugging, compression): + - Do not check for compression bombs for buffers smaller than 5MB + (increased from 64 KB). Fixes ticket 40739; bugfix on 0.2.1.29. + + o Minor features (directory servers): + - Track how many times directory servers begin serving networkstatus + documents, so we can compare it to the number of times we finish + serving them. Motivated by the fixes in ticket 41192. + + o Minor features (fallbackdir): + - Regenerate fallback directories generated on January 28, 2026. + + o Minor features (geoip data): + - Update the geoip files to match the IPFire Location Database, as + retrieved on 2026/01/28. + + o Minor bugfixes (relay): + - Downgrade "Error relaying cell across rendezvous" log warn to info + as the error condition is possible under normal circumstances. Fixes + bug 40951; bugfix on 0.3.5.1-alpha. + + o Code simplification and refactoring: + - Simplify SOCKS4a parsing to avoid the (false) appearance of + integer underflows, and to make the logic more obvious. Fixes bug + 41190; bugfix on 0.3.5.1-alpha. + + +Changes in version 0.4.8.21 - 2025-11-17 + This release is a continuation of the previous one and addresses additional + Conflux-related issues identified through further testing and feedback from + relay operators. We strongly recommend upgrading as soon as possible. + + o Major bugfixes (conflux, exit): + - When dequeuing out-of-order conflux cells, the circuit could be + closed in between two dequeues, which could lead to mishandling + a NULL pointer. Fixes bug 41162; bugfix on 0.4.8.4. + + o Minor feature (compiler flag): + - Add -mbranch-protection=standard for arm64. + + o Minor features (fallbackdir): + - Regenerate fallback directories generated on November 17, 2025. + + o Minor features (geoip data): + - Update the geoip files to match the IPFire Location Database, as + retrieved on 2025/11/17. + + o Minor bugfixes (bridges, pluggable transport): + - Fix a bug causing the initial tor process to hang instead of + exiting with RunAsDaemon, when pluggable transports are used. + Fixes bug 41088; bugfix on 0.4.8.1-alpha. + + +Changes in version 0.4.8.20 - 2025-11-10 + This release fixes several bugs related to Conflux edge cases as well as + adding a new hardening compiler flag if supported. + + o Minor feature (compiler flag): + - Add -fcf-protection=full if supported by the compiler. + Implements ticket 41139. + + o Minor features (fallbackdir): + - Regenerate fallback directories generated on November 10, 2025. + + o Minor features (geoip data): + - Update the geoip files to match the IPFire Location Database, as + retrieved on 2025/11/10. + + o Minor bugfixes (conflux fragile asserts): + - Fix the root cause of some conflux fragile asserts when a control + port listener is attached. Fixes bug 41037; bugfix on 0.4.8.16. + + o Minor bugfixes (conflux, relay): + - Fix a series of conflux edge cases about sequence number + arithmetic and OOM handler kicking in under heavy memory pressure. + Fixes bug 41155; bugfix on 0.4.8.4. + + +Changes in version 0.4.8.19 - 2025-10-06 + This release provides major bugfixes for a LibreSSL issue and a flow control + C-tor specific problem (not protocol). We strongly recommend you upgrade as + soon as possible. + + o Major bugfixes (client, TLS): + - Fix some clients not being able to connect to LibreSSL relays. + Fixes bug 41134; bugfix on 0.4.8.17. + + o Minor bugfixes (stream flow control performance): + - Use a 5 ms grace period to allow an edge connection to flush its + stream data to the socket before sending an XOFF. This + significantly reduces the number of XON/XOFF messages sent when + (1) the application is reading stream data at a fast rate, and (2) + conflux is enabled. Fixes part of bug 41130; bugfix on 0.4.7.2-alpha. + + o Minor features (fallbackdir): + - Regenerate fallback directories generated on October 06, 2025. + + o Minor features (geoip data): + - Update the geoip files to match the IPFire Location Database, as + retrieved on 2025/10/06. + + o Minor bugfix (process): + - Avoid closing all possible FDs when spawning a process (PT). On + some systems, this could lead to 3+ minutes hang. Fixes bug 40990; + bugfix on 0.3.5.1-alpha. + + +Changes in version 0.4.8.18 - 2025-09-16 + This is a minor release with a major onion service directory cache (HSDir) + bug fix. A series of minor bugfixes as well. As always, we strongly recommend + to upgrade as soon as possible. + + o Major bugfixes (onion service directory cache): + - Preserve the download counter of an onion service descriptor + across descriptor uploads, so that recently updated descriptors + don't get pruned if there is memory pressure soon after update. + Additionally, create a separate torrc option MaxHSDirCacheBytes + that defaults to the former 20% of MaxMemInQueues threshold, but + can be controlled by relay operators under DoS. Also enforce this + threshold during HSDir uploads. Fixes bug 41006; bugfix + on 0.4.8.14. + + o Minor feature (padding, logging): + - Reduce the amount of messages being logged related to channel + padding timeout when log level is "notice". + + o Minor features (fallbackdir): + - Regenerate fallback directories generated on September 16, 2025. + + o Minor features (geoip data): + - Update the geoip files to match the IPFire Location Database, as + retrieved on 2025/09/16. + + o Minor bugfix (conflux): + - Remove the pending nonce if we realize that the nonce of the + unlinked circuit is not tracked anymore. Should avoid the non + fatal assert triggered with a control port circuit event. Fixes + bug 41037; bugfix on 0.4.8.15. + + o Minor bugfixes (circuit handling): + - Prevent circuit_mark_for_close() from being called twice on the + same circuit. Second fix attempt Fixes bug 41106; bugfix + on 0.4.8.17. + + +Changes in version 0.4.8.17 - 2025-06-30 + This is a minor providing a series of minor features especially in the realm + of TLS. It also brings a new set of recommended and required sub protocols. + And finally, few minor bugfixes, nothing major. As always, we strongly + recommend you upgrade as soon as possible. + + o Minor features (security, TLS): + - When we are running with OpenSSL 3.5.0 or later, support using the + ML-KEM768 for post-quantum key agreement. Closes ticket 41041. + + o Minor feature (client, TLS): + - Set the TLS 1.3 cipher list instead of falling back on the + default value. + + o Minor features (fallbackdir): + - Regenerate fallback directories generated on June 30, 2025. + + o Minor features (geoip data): + - Update the geoip files to match the IPFire Location Database, as + retrieved on 2025/06/30. + + o Minor features (hsdesc POW): + - Tolerate multiple PoW schemes in onion service descriptors, for + future extensibility. Implements torspec ticket 272. + + o Minor features (performance TLS): + - When running with with OpenSSL 3.0.0 or later, support using + X25519 for TLS key agreement. (This should slightly improve + performance for TLS session establishment.) + + o Minor features (portability): + - Fix warnings when compiling with GCC 15. Closes ticket 41079. + + o Minor features (recommended protocols): + - Directory authorities now vote to recommend that clients support + certain protocols beyond those that are required. These include + improved support for connecting to relays on IPv6, NtorV3, and + congestion control. Part of ticket 40836. + + o Minor features (required protocols): + - Directory authorities now vote to require clients to support the + authenticated SENDME feature, which was introduced in + 0.4.1.1-alpha. Part of ticket 40836. + - Directory authorities now vote to require relays to support + certain protocols, all of which have been implemented since + 0.4.7.4-alpha or earlier. These include improved support for + connecting to relays on IPv6, NtorV3, running as a rate-limited + introduction point, authenticated SENDMEs, and congestion control. + Part of ticket 40836. + + o Minor bugfix (conflux): + - Avoid a non fatal assert when describing a conflux circuit on the + control port after being prepped to be freed. Fixes bug 41037; + bugfix on 0.4.8.15. + + o Minor bugfixes (circuit handling): + - Prevent circuit_mark_for_close() from being called twice on the + same circuit. Fixes bug 40951; bugfix on 0.4.8.16-dev. + + o Minor bugfixes (compiler warnings): + - Make sure the two bitfields in the half-closed edge struct are + unsigned, as we're using them for boolean values and assign 1 to + them. Fixes bug 40911; bugfix on 0.4.7.2-alpha. + + o Minor bugfixes (threads, memory): + - Improvements in cleanup of resources used by threads. Fixes bug + 40991; bugfix on 0.4.8.13-dev. + - Rework start and exit of worker threads. + + +Changes in version 0.4.8.16 - 2025-03-24 + This is a quick second release since 0.4.8.15 due to a typo in a directory + authority rule file. This only affects directory authorities. + + o Minor features (geoip data): + - Update the geoip files to match the IPFire Location Database, as + retrieved on 2025/03/24. + + o Minor bugfix (dirauth): + - Fix typo in flag assignment approved-routers file. Fixes bug + 41035; bugfix on 0.4.8.15. + + +Changes in version 0.4.8.15 - 2025-03-20 + This is a minor release fixing a sandbox issue for bandwidth authority and a + conflux issue on the control port. It also has a client fix about relay flag + usage. + + o Minor feature (testing, CI): + - Use a fixed version of chutney (be881a1e) instead of its current + HEAD. This version should also be preferred when testing locally. + + o Minor features (continuous integration): + - Upgrade CI runners to use Debian Bookworm instead of Bullseye. + Closes ticket 41029. + + o Minor features (fallbackdir): + - Regenerate fallback directories generated on March 20, 2025. + + o Minor features (geoip data): + - Update the geoip files to match the IPFire Location Database, as + retrieved on 2025/03/20. + + o Minor bugfixes (control port): + - Correctly report conflux pair information to controller fields. + Fixes bug 40872; bugfix on 0.4.8.1-alpha. + + o Minor bugfixes (relay flag usage): + - Fix client usage of the MiddleOnly flag so that MiddleOnly relays + are not used as HS IP or RP by clients or services. Additionally, + give dirauths the ability to remove specific flags, as an + alternative to MiddleOnly. Fixes bug 41023; bugfix on 0.4.7.2-alpha. + + o Minor bugfixes (sandbox, bwauth): + - Fix sandbox to work for bandwidth authority. Fixes bug 40933; + bugfix on 0.2.2.1-alpha. + + +Changes in version 0.4.8.14 - 2025-02-05 + Minor release fixing a major bug affecting onion service directory cache, + also known as HSDir. Furthermore, the fallbackdir list had more than 25% of + its entries unreachable or gone from the consensus. As usual, we strongly + recommend to update to this version as soon as possible. + + o Major bugfixes (onion service directory cache): + - When the OOM killer kicks in, cleanup the descriptor cache of an + HSDir by looking at the lowest downloaded count instead of time in + cache. Fixes bug 40996; bugfix on 0.3.5.1-alpha. + + o Minor feature (testing): + - test-network now unconditionally includes IPv6 instead of trying + to detect IPv6 support. + + o Minor features (fallbackdir): + - Regenerate fallback directories generated on February 05, 2025. + + o Minor features (geoip data): + - Update the geoip files to match the IPFire Location Database, as + retrieved on 2025/02/05. + + o Minor bugfixes (memory): + - Fix a pointer free that wasn't set to NULL afterwards which could + be reused by calling back in the free all function. Fixes bug + 40989; bugfix on 0.4.8.13. + + +Changes in version 0.4.8.13 - 2024-10-24 + This minor release fixes an important client circuit building (conflux + related) bug which led to performance degradation and extra load on the + network. Some minor memory leaks fixes as well as an important minor feature + for pluggable transports. We strongly recommend to update as soon as possible + for clients in order to neutralize this conflux bug. + + o Major bugfixes (circuit building): + - Conflux circuit building was ignoring the "predicted ports" + feature, which aims to make Tor stop building circuits if there + have been no user requests lately. This bug led to every idle Tor + on the network building and discarding circuits every 30 seconds, + which added overall load to the network, used bandwidth and + battery from clients that weren't actively using their Tor, and + kept sockets open on guards which added connection padding + essentially forever. Fixes bug 40981; bugfix on 0.4.8.1-alpha. + + o Minor feature (bridges, pluggable transport): + - Add STATUS TYPE=version handler for Pluggable Transport. This + allows us to gather version statistics on Pluggable Transport + usage from bridge servers on our metrics portal. Closes + ticket 11101. + + o Minor features (fallbackdir): + - Regenerate fallback directories generated on October 24, 2024. + + o Minor features (geoip data): + - Update the geoip files to match the IPFire Location Database, as + retrieved on 2024/10/24. + + o Minor bugfixes (memleak, authority): + - Fix a small memleak when computing a new consensus. This only + affects directory authorities. Fixes bug 40966; bugfix + on 0.3.5.1-alpha. + + o Minor bugfixes (memory): + - Fix memory leaks of the CPU worker code during shutdown. Fixes bug + 833; bugfix on 0.3.5.1-alpha. + + +Changes in version 0.4.8.12 - 2024-06-06 + This is a minor release with couple bugfixes affecting conflux and logging. + We also have the return of faravahar directory authority with new keys and + address. + + o Minor feature (dirauth): + - Add back faravahar with a new address and new keys. Closes 40689. + + o Minor features (fallbackdir): + - Regenerate fallback directories generated on June 06, 2024. + + o Minor features (geoip data): + - Update the geoip files to match the IPFire Location Database, as + retrieved on 2024/06/06. + + o Minor bugfix (circuit): + - Remove a log_warn being triggered by a protocol violation that + already emits a protocol warning log. Fixes bug 40932; bugfix + on 0.4.8.1-alpha. + + o Minor bugfixes (conflux): + - Avoid a potential hard assert (crash) when sending a cell on a + Conflux set. Fixes bug 40921; bugfix on 0.4.8.1-alpha. + - Make sure we don't process a closed circuit when packaging data. + This lead to a non fatal BUG() spamming logs. Fixes bug 40908; + bugfix on 0.4.8.1-alpha. + + +Changes in version 0.4.8.11 - 2024-04-10 + This is a minor release mostly to upgrade the fallbackdir list. + Directory authorities running this version will now automatically + reject relays running the end of life 0.4.7.x version. + + o Minor features (directory authorities): + - Reject 0.4.7.x series at the authority level. Closes ticket 40896. + + o Minor feature (dirauth, tor26): + - New IP address and keys. + + o Minor feature (directory authority): + - Allow BandwidthFiles "node_id" KeyValue without the dollar sign at + the start of the hexdigit, in order to easier database queries + combining Tor documents in which the relays fingerprint does not + include it. Fixes bug 40891; bugfix on 0.4.7 (all supported + versions of Tor). + + o Minor features (fallbackdir): + - Regenerate fallback directories generated on April 10, 2024. + + o Minor features (geoip data): + - Update the geoip files to match the IPFire Location Database, as + retrieved on 2024/04/10. + + o Minor bugfixes (directory authorities): + - Add a warning when publishing a vote or signatures to another + directory authority fails. Fixes bug 40910; bugfix + on 0.2.0.3-alpha. + + +Changes in version 0.4.8.10 - 2023-12-08 + This is a security release fixing a high severity bug (TROVE-2023-007) + affecting Exit relays supporting Conflux. We strongly recommend to update as + soon as possible. + + o Major bugfixes (TROVE-2023-007, exit): + - Improper error propagation from a safety check in conflux leg + linking led to a desynchronization of which legs were part of a + conflux set, ultimately causing a UAF and NULL pointer dereference + crash on Exit relays. Fixes bug 40897; bugfix on 0.4.8.1-alpha. + + o Minor features (fallbackdir): + - Regenerate fallback directories generated on December 08, 2023. + + o Minor features (geoip data): + - Update the geoip files to match the IPFire Location Database, as + retrieved on 2023/12/08. + + o Minor bugfixes (bridges, statistics): + - Correctly report statistics for client count over pluggable + transports. Fixes bug 40871; bugfix on 0.4.8.4. + + +Changes in version 0.4.8.9 - 2023-11-09 + This is another security release fixing a high severity bug affecting onion + services which is tracked by TROVE-2023-006. We are also releasing a guard + major bugfix as well. If you are an onion service operator, we strongly + recommend to update as soon as possible. + + o Major bugfixes (guard usage): + - When Tor excluded a guard due to temporary circuit restrictions, + it considered *additional* primary guards for potential usage by + that circuit. This could result in more than the specified number + of guards (currently 2) being used, long-term, by the tor client. + This could happen when a Guard was also selected as an Exit node, + but it was exacerbated by the Conflux guard restrictions. Both + instances have been fixed. Fixes bug 40876; bugfix + on 0.3.0.1-alpha. + + o Major bugfixes (onion service, TROVE-2023-006): + - Fix a possible hard assert on a NULL pointer when recording a + failed rendezvous circuit on the service side for the MetricsPort. + Fixes bug 40883; bugfix on 0.4.8.1-alpha. + + o Minor features (fallbackdir): + - Regenerate fallback directories generated on November 09, 2023. + + o Minor features (geoip data): + - Update the geoip files to match the IPFire Location Database, as + retrieved on 2023/11/09. + + +Changes in version 0.4.8.8 - 2023-11-03 We are releasing today a fix for a high security issue, TROVE-2023-004, that - is affecting relays. Please upgrade as soon as posssible. + is affecting relays. Also a few minor bugfixes detailed below. Please upgrade + as soon as possible. o Major bugfixes (TROVE-2023-004, relay): - Mitigate an issue when Tor compiled with OpenSSL can crash during @@ -18,11 +768,39 @@ - Update the geoip files to match the IPFire Location Database, as retrieved on 2023/11/03. + o Minor bugfixes (directory authority): + - Look at the network parameter "maxunmeasuredbw" with the correct + spelling. Fixes bug 40869; bugfix on 0.4.6.1-alpha. + + o Minor bugfixes (vanguards addon support): + - Count the conflux linked cell as valid when it is successfully + processed. This will quiet a spurious warn in the vanguards addon. + Fixes bug 40878; bugfix on 0.4.8.1-alpha. + + +Changes in version 0.4.8.7 - 2023-09-25 + This version fixes a single major bug in the Conflux subsystem on the client + side. See below for more information. The upcoming Tor Browser 13 stable will + pick this up. + + o Major bugfixes (conflux): + - Fix an issue that prevented us from pre-building more conflux sets + after existing sets had been used. Fixes bug 40862; bugfix + on 0.4.8.1-alpha. -Changes in version 0.4.7.15 - 2023-09-18 - This version contains an important fix for onion service regarding congestion - control and its reliability. Apart from that, very minor bugfixes. We - strongly recommend all onion service operators to update immediately. + o Minor features (fallbackdir): + - Regenerate fallback directories generated on September 25, 2023. + + o Minor features (geoip data): + - Update the geoip files to match the IPFire Location Database, as + retrieved on 2023/09/25. + + +Changes in version 0.4.8.6 - 2023-09-18 + This version contains an important fix for onion services regarding + congestion control and its reliability. Apart from that, unneeded BUG + warnings have been suppressed especially about a compression bomb seen + on relays. o Major bugfixes (onion service): - Fix a reliability issue where services were expiring their @@ -31,6 +809,10 @@ intro points. Bug reported and fixed by gitlab user @hyunsoo.kim676. Fixes bug 40858; bugfix on 0.4.7.5-alpha. + o Minor features (debugging, compression): + - Log the input and output buffer sizes when we detect a potential + compression bomb. Diagnostic for ticket 40739. + o Minor features (fallbackdir): - Regenerate fallback directories generated on September 18, 2023. @@ -38,17 +820,16 @@ - Update the geoip files to match the IPFire Location Database, as retrieved on 2023/09/18. - o Minor features (testing): - - Enable Doxygen and Stem tests for 0.4.8 and clean-up some logic - for handling versions of Tor that are no longer supported. Closes - ticket 40859. - - o Minor bugfixes (compression): - - Right after compression/decompression work is done, check for - errors. Before this, we would consider compression bomb before - that and then looking for errors leading to false positive on that - log warning. Fixes bug 40739; bugfix on 0.3.5.1-alpha. Patch - by "cypherpunks". + o Minor bugfix (defensive programming): + - Disable multiple BUG warnings of a missing relay identity key when + starting an instance of Tor compiled without relay support. Fixes + bug 40848; bugfix on 0.4.3.1-alpha. + + o Minor bugfixes (bridge authority): + - When reporting a pseudo-networkstatus as a bridge authority, or + answering "ns/purpose/*" controller requests, include accurate + published-on dates from our list of router descriptors. Fixes bug + 40855; bugfix on 0.4.8.1-alpha. o Minor bugfixes (compression, zstd): - Use less frightening language and lower the log-level of our run- @@ -56,53 +837,315 @@ subsystem. Fixes bug 40815; bugfix on 0.4.3.1-alpha. -Changes in version 0.4.7.14 - 2023-07-26 - This version contains several minor fixes and one major bugfix affecting - vanguards (onion service). As usual, we recommend upgrading to this version - as soon as possible. +Changes in version 0.4.8.5 - 2023-08-30 + Quick second release after the first stable few days ago fixing minor + annoying bugfixes creating log BUG stacktrace. We also fix BSD compilation + failures and PoW unit test. + + o Minor features (fallbackdir): + - Regenerate fallback directories generated on August 30, 2023. + + o Minor features (geoip data): + - Update the geoip files to match the IPFire Location Database, as + retrieved on 2023/08/30. + + o Minor bugfix (NetBSD, compilation): + - Fix compilation issue on NetBSD by avoiding an unnecessary + dependency on "huge" page mappings in Equi-X. Fixes bug 40843; + bugfix on 0.4.8.1-alpha. + + o Minor bugfix (NetBSD, testing): + - Fix test failures in "crypto/hashx" and "slow/crypto/equix" on + x86_64 and aarch64 NetBSD hosts, by adding support for + PROT_MPROTECT() flags. Fixes bug 40844; bugfix on 0.4.8.1-alpha. + + o Minor bugfixes (conflux): + - Demote a relay-side warn about too many legs to ProtocolWarn, as + there are conditions that it can briefly happen during set + construction. Also add additional set logging details for all + error cases. Fixes bug 40841; bugfix on 0.4.8.1-alpha. + - Prevent non-fatal assert stacktrace caused by using conflux sets + during their teardown process. Fixes bug 40842; bugfix + on 0.4.8.1-alpha. + + +Changes in version 0.4.8.4 - 2023-08-23 + Finally, this is the very first stable release of the 0.4.8.x series making, + among other features, Proof-of-Work (prop#327) and Conflux (prop#329) + available to the entire network. Several new features and a lot of bugfixes + detailed below. + + o Major feature (denial of service): + - Extend DoS protection to partially opened channels and known relays. + Because re-entry is not allowed anymore, we can apply DoS protections + onto known IP namely relays. Fixes bug 40821; bugfix on 0.3.5.1-alpha. + + o Major features (onion service, proof-of-work): + - Implement proposal 327 (Proof-Of-Work). This is aimed at thwarting + introduction flooding DoS attacks by introducing a dynamic Proof-Of-Work + protocol that occurs over introduction circuits. This introduces several + torrc options prefixed with "HiddenServicePoW" in order to control this + feature. By default, this is disabled. Closes ticket 40634. + + o Major features (conflux): + - Implement Proposal 329 (conflux traffic splitting). Conflux splits + traffic across two circuits to Exits that support the protocol. These + circuits are pre-built only, which means that if the pre- built conflux + pool runs out, regular circuits will then be used. When using conflux + circuit pairs, clients choose the lower-latency circuit to send data to + the Exit. When the Exit sends data to the client, it maximizes + throughput, by fully utilizing both circuits in a multiplexed fashion. + Alternatively, clients can request that the Exit optimize for latency + when transmitting to them, by setting the torrc option 'ConfluxClientUX + latency'. Onion services are not currently supported, but will be in + arti. Many other future optimizations will also be possible using this + protocol. Closes ticket 40593. + + o Major features (dirauth): + - Directory authorities and relays now interact properly with directory + authorities if they change addresses. In the past, they would continue to + upload votes, signatures, descriptors, etc to the hard-coded address in + the configuration. Now, if the directory authority is listed in the + consensus at a different address, they will direct queries to this new + address. Implements ticket 40705. + + o Major bugfixes (conflux): + - Fix a relay-side crash caused by side effects of the fix for bug + 40827. Reverts part of that fix that caused the crash and adds additional + log messages to help find the root cause. Fixes bug 40834; bugfix on + 0.4.8.3-rc. + + o Major bugfixes (conflux): + - Fix a relay-side assert crash caused by attempts to use a conflux circuit + between circuit close and free, such that no legs were on the conflux + set. Fixed by nulling out the stream's circuit back- pointer when the + last leg is removed. Additional checks and log messages have been added + to detect other cases. Fixes bug 40827; bugfix on 0.4.8.1-alpha. + + o Major bugfixes (proof of work, onion service, hashx): + - Fix a very rare buffer overflow in hashx, specific to the dynamic + compiler on aarch64 platforms. Fixes bug 40833; bugfix on 0.4.8.2-alpha. o Major bugfixes (vanguards): - - Rotate to a new L2 vanguard whenever an existing one loses the - Stable or Fast flag. Previously, we would leave these relays in - the L2 vanguard list but never use them, and if all of our - vanguards end up like this we wouldn't have any middle nodes left - to choose from so we would fail to make onion-related circuits. - Fixes bug 40805; bugfix on 0.4.7.1-alpha. + - Rotate to a new L2 vanguard whenever an existing one loses the Stable or + Fast flag. Previously, we would leave these relays in the L2 vanguard + list but never use them, and if all of our vanguards end up like this we + wouldn't have any middle nodes left to choose from so we would fail to + make onion-related circuits. Fixes bug 40805; bugfix on 0.4.7.1-alpha. + + o Minor features (bridge): + - warn when a bridge is also configure to be an exit relay. + Closes ticket 40819. + + o Minor features (geoip data): + - Update the geoip files to match the IPFire Location Database, as + retrieved on 2023/08/23. + + o Minor features (fallbackdir): + - Regenerate fallback directories generated on August 23, 2023. + + o Minor features (testing): + - All Rust code is now linted (cargo clippy) as part of GitLab CI, and + existing warnings have been fixed. + - Any unit tests written in Rust now run as part of GitLab CI. o Minor feature (CI): - Update CI to use Debian Bullseye for runners. + o Minor feature (client, IPv6): + - Make client able to pick IPv6 relays by default now meaning + ClientUseIPv6 option now defaults to 1. Closes ticket 40785. + + o Minor feature (compilation): + - Fix returning something other than "Unknown N/A" as libc version + if we build tor on an O.S. like DragonFlyBSD, FreeBSD, OpenBSD + or NetBSD. + + o Minor feature (cpuworker): + - Always use the number of threads for our CPU worker pool to the + number of core available but cap it to a minimum of 2 in case of a + single core. Fixes bug 40713; bugfix on 0.3.5.1-alpha. + o Minor feature (lzma): - Fix compiler warnings for liblzma >= 5.3.1. Closes ticket 40741. + o Minor feature (MetricsPort, relay): + - Expose time until online keys expires on the MetricsPort. Closes + ticket 40546. + + o Minor feature (MetricsPort, relay, onion service): + - Add metrics for the relay side onion service interactions counting + seen cells. Closes ticket 40797. Patch by "friendly73". + o Minor features (directory authorities): - Directory authorities now include their AuthDirMaxServersPerAddr config option in the consensus parameter section of their vote. Now external tools can better predict how they will behave. Implements ticket 40753. + o Minor features (directory authority): + - Add a new consensus method in which the "published" times on + router entries in a microdesc consensus are all set to a + meaningless fixed date. Doing this will make the download size for + compressed microdesc consensus diffs much smaller. Part of ticket + 40130; implements proposal 275. + + o Minor features (network documents): + - Clients and relays no longer track the "published on" time + declared for relays in any consensus documents. When reporting + this time on the control port, they instead report a fixed date in + the future. Part of ticket 40130. + o Minor features (fallbackdir): - - Regenerate fallback directories generated on July 26, 2023. + - Regenerate fallback directories generated on June 01, 2023. o Minor features (geoip data): - Update the geoip files to match the IPFire Location Database, as - retrieved on 2023/07/26. + retrieved on 2023/06/01. - o Minor bugfix (relay, logging): - - The wrong max queue cell size was used in a protocol warning - logging statement. Fixes bug 40745; bugfix on 0.4.7.1-alpha. + o Minor features (hs, metrics): + - Add tor_hs_rend_circ_build_time and tor_hs_intro_circ_build_time + histograms to measure hidden service rend/intro circuit build time + durations. Part of ticket 40757. + + o Minor features (metrics): + - Add a `reason` label to the HS error metrics. Closes ticket 40758. + - Add service side metrics for REND and introduction request + failures. Closes ticket 40755. + - Add support for histograms. Part of ticket 40757. + + o Minor features (pluggable transports): + - Automatically restart managed Pluggable Transport processes when + their process terminate. Resolves ticket 33669. + + o Minor features (portability, compilation): + - Use OpenSSL 1.1 APIs for LibreSSL, fixing LibreSSL 3.5 + compatibility. Fixes issue 40630; patch by Alex Xu (Hello71). + + o Minor features (relay): + - Do not warn about configuration options that may expose a non- + anonymous onion service. Closes ticket 40691. + + o Minor features (relays): + - Trigger OOS when bind fails with EADDRINUSE. This improves + fairness when a large number of exit connections are requested, + and properly signals exhaustion to the network. Fixes issue 40597; + patch by Alex Xu (Hello71). + + o Minor features (tests): + - Avoid needless key reinitialization with OpenSSL during unit + tests, saving significant time. Patch from Alex Xu. + + o Minor bugfix (hs): + - Fix compiler warnings in equix and hashx when building with clang. + Closes ticket 40800. + + o Minor bugfix (FreeBSD, compilation): + - Fix compilation issue on FreeBSD by properly importing + sys/param.h. Fixes bug 40825; bugfix on 0.4.8.1-alpha. + + o Minor bugfixes (compression): + - Right after compression/decompression work is done, check for + errors. Before this, we would consider compression bomb before + that and then looking for errors leading to false positive on that + log warning. Fixes bug 40739; bugfix on 0.3.5.1-alpha. Patch + by "cypherpunks". o Minor bugfixes (compilation): - Fix all -Werror=enum-int-mismatch warnings. No behavior change. Fixes bug 40824; bugfix on 0.3.5.1-alpha. + o Minor bugfixes (protocol warn): + - Wrap a handful of cases where ProtocolWarning logs could emit IP + addresses. Fixes bug 40828; bugfix on 0.3.5.1-alpha. + + o Minor bugfix (congestion control): + - Reduce the accepted range of a circuit's negotiated 'cc_sendme_inc' + to be +/- 1 from the consensus parameter value. Fixes bug 40569; + bugfix on 0.4.7.4-alpha. + - Remove unused congestion control algorithms and BDP calculation + code, now that we have settled on and fully tuned Vegas. Fixes bug + 40566; bugfix on 0.4.7.4-alpha. + - Update default congestion control parameters to match consensus. + Fixes bug 40709; bugfix on 0.4.7.4-alpha. + + o Minor bugfixes (compilation): + - Fix "initializer is not a constant" compilation error that + manifests itself on gcc versions < 8.1 and MSVC. Fixes bug 40773; + bugfix on 0.4.8.1-alpha + + o Minor bugfixes (conflux): + - Count leg launch attempts prior to attempting to launch them. This + avoids infinite launch attempts due to internal circuit building + failures. Additionally, double-check that we have enough exits in + our consensus overall, before attempting to launch conflux sets. + Fixes bug 40811; bugfix on 0.4.8.1-alpha. + - Fix a case where we were resuming reading on edge connections that + were already marked for close. Fixes bug 40801; bugfix + on 0.4.8.1-alpha. + - Fix stream attachment order when creating conflux circuits, so + that stream attachment happens after finishing the full link + handshake, rather than upon set finalization. Fixes bug 40801; + bugfix on 0.4.8.1-alpha. + - Handle legs being closed or destroyed before computing an RTT + (resulting in warns about too many legs). Fixes bug 40810; bugfix + on 0.4.8.1-alpha. + - Remove a "BUG" warning from conflux_pick_first_leg that can be + triggered by broken or malicious clients. Fixes bug 40801; bugfix + on 0.4.8.1-alpha. + + o Minor bugfixes (KIST): + - Prevent KISTSchedRunInterval from having values of 0 or 1, neither + of which work properly. Additionally, make a separate + KISTSchedRunIntervalClient parameter, so that the client and relay + KIST values can be set separately. Set the default of both to 2ms. + Fixes bug 40808; bugfix on 0.3.2.1-alpha. + + o Minor bugfix (relay, logging): + - The wrong max queue cell size was used in a protocol warning + logging statement. Fixes bug 40745; bugfix on 0.4.7.1-alpha. + + o Minor bugfixes (logging): + - Avoid ""double-quoting"" strings in several log messages. Fixes + bug 22723; bugfix on 0.1.2.2-alpha. + - Correct a log message when cleaning microdescriptors. Fixes bug + 40619; bugfix on 0.2.5.4-alpha. + o Minor bugfixes (metrics): - Decrement hs_intro_established_count on introduction circuit close. Fixes bug 40751; bugfix on 0.4.7.12. + o Minor bugfixes (pluggable transports, windows): + - Remove a warning `BUG()` that could occur when attempting to + execute a non-existing pluggable transport on Windows. Fixes bug + 40596; bugfix on 0.4.0.1-alpha. + + o Minor bugfixes (relay): + - Remove a "BUG" warning for an acceptable race between a circuit + close and considering that circuit active. Fixes bug 40647; bugfix + on 0.3.5.1-alpha. + - Remove a harmless "Bug" log message that can happen in + relay_addr_learn_from_dirauth() on relays during startup. Finishes + fixing bug 40231. Fixes bug 40523; bugfix on 0.4.5.4-rc. + o Minor bugfixes (sandbox): - Allow membarrier for the sandbox. And allow rt_sigprocmask when compiled with LTTng. Fixes bug 40799; bugfix on 0.3.5.1-alpha. + - Fix sandbox support on AArch64 systems. More "*at" variants of + syscalls are now supported. Signed 32 bit syscall parameters are + checked more precisely, which should lead to lower likelihood of + breakages with future compiler and libc releases. Fixes bug 40599; + bugfix on 0.4.4.3-alpha. + + o Minor bugfixes (state file): + - Avoid a segfault if the state file doesn't contains TotalBuildTimes + along CircuitBuildAbandonedCount being above 0. Fixes bug 40437; + bugfix on 0.3.5.1-alpha. + + o Removed features: + - Remove the RendPostPeriod option. This was primarily used in + Version 2 Onion Services and after its deprecation isn't needed + anymore. Closes ticket 40431. Patch by Neel Chauhan. Changes in version 0.4.7.13 - 2023-01-12 @@ -114,7 +1157,7 @@ o Major bugfixes (congestion control): - Avoid incrementing the congestion window when the window is not - fully in use. Thia prevents overshoot in cases where long periods + fully in use. This prevents overshoot in cases where long periods of low activity would allow our congestion window to grow, and then get followed by a burst, which would cause queue overload. Also improve the increment checks for RFC3742. Fixes bug 40732; @@ -167,6 +1210,35 @@ on tor-0.4.6.1-alpha. +Changes in version 0.4.5.16 - 2023-01-12 + This version has one major bugfix for relay and a security fix, + TROVE-2022-002, affecting clients. We strongly recommend to upgrade to our + 0.4.7.x stable series. As a reminder, this series is EOL on February 15th, + 2023. + + o Major bugfixes (relay): + - When opening a channel because of a circuit request that did not + include an Ed25519 identity, record the Ed25519 identity that we + actually received, so that we can use the channel for other + circuit requests that _do_ list an Ed25519 identity. (Previously + we had code to record this identity, but a logic bug caused it to + be disabled.) Fixes bug 40563; bugfix on 0.3.0.1-alpha. Patch + from "cypherpunks". + + o Major bugfixes (TROVE-2022-002, client): + - The SafeSocks option had its logic inverted for SOCKS4 and + SOCKS4a. It would let the unsafe SOCKS4 pass but not the safe + SOCKS4a one. This is TROVE-2022-002 which was reported on + Hackerone by "cojabo". Fixes bug 40730; bugfix on 0.3.5.1-alpha. + + o Minor features (fallbackdir): + - Regenerate fallback directories generated on January 12, 2023. + + o Minor features (geoip data): + - Update the geoip files to match the IPFire Location Database, as + retrieved on 2023/01/12. + + Changes in version 0.4.7.12 - 2022-12-06 This version contains a major change that is a new key for moria1. Also, new metrics are exported on the MetricsPort for the congestion control @@ -194,6 +1266,43 @@ used by our thread pool. Fixes bug 40719; bugfix on 0.3.5.1-alpha. +Changes in version 0.4.5.15 - 2022-12-06 + This version has several major changes for directory authorities. And a + major bugfix on OSX. Again, we strongly recommend to upgrade to our 0.4.7.x + series latest stable. This series is EOL on February 15th, 2023. + + o Directory authority changes (dizum): + - Change dizum IP address. Closes ticket 40687. + + o Directory authority changes (Faravahar): + - Remove Faravahar until its operator, Sina, set it back up online + outside of Team Cymru network. Closes ticket 40688. + + o Directory authority changes (moria1): + - Rotate the relay identity key and v3 identity key for moria1. They + have been online for more than a decade and refreshing keys + periodically is good practice. Advertise new ports too, to avoid + confusion. Closes ticket 40722. + + o Major bugfixes (OSX): + - Fix coarse-time computation on Apple platforms (like Mac M1) where + the Mach absolute time ticks do not correspond directly to + nanoseconds. Previously, we computed our shift value wrong, which + led us to give incorrect timing results. Fixes bug 40684; bugfix + on 0.3.3.1-alpha. + + o Major bugfixes (relay): + - Improve security of our DNS cache by randomly clipping the TTL + value. TROVE-2021-009. Fixes bug 40674; bugfix on 0.3.5.1-alpha. + + o Minor features (fallbackdir): + - Regenerate fallback directories generated on December 06, 2022. + + o Minor features (geoip data): + - Update the geoip files to match the IPFire Location Database, as + retrieved on 2022/12/06. + + Changes in version 0.4.7.11 - 2022-11-10 This version contains several major fixes aimed at helping defend against network denial of service. It is also extending drastically the MetricsPort @@ -331,6 +1440,32 @@ Fixes bug 40658; bugfix on 0.4.7.9. +Changes in version 0.4.6.12 - 2022-08-12 + This version updates the geoip cache that we generate from IPFire location + database to use the August 9th, 2022 one. Everyone MUST update to this + latest release else circuit path selection and relay metrics are badly + affected. + + o Major bugfixes (geoip data): + - IPFire informed us on August 12th that databases generated after + (including) August 10th did not have proper ARIN network allocations. We + are updating the database to use the one generated on August 9th, 2022. + Fixes bug 40658; bugfix on 0.4.6.11. + + +Changes in version 0.4.5.14 - 2022-08-12 + This version updates the geoip cache that we generate from IPFire location + database to use the August 9th, 2022 one. Everyone MUST update to this + latest release else circuit path selection and relay metrics are badly + affected. + + o Major bugfixes (geoip data): + - IPFire informed us on August 12th that databases generated after + (including) August 10th did not have proper ARIN network allocations. We + are updating the database to use the one generated on August 9th, 2022. + Fixes bug 40658; bugfix on 0.4.5.13. + + Changes in version 0.4.7.9 - 2022-08-11 This version contains several major fixes aimed at reducing memory pressure on relays and possible side-channel. It also contains a major bugfix related to @@ -406,6 +1541,143 @@ 40649; bugfix on 0.1.2.4-alpha. +Changes in version 0.4.6.11 - 2022-08-11 + This version contains two major fixes aimed at reducing memory pressure on + relays and possible side-channel. The rest of the fixes were backported for + stability or safety purposes. + + This is the very LAST version of this series. As of August 1st 2022, it is + end-of-life (EOL). We thus strongly recommend to upgrade to the latest + stable of the 0.4.7.x series. + + o Major bugfixes (relay): + - Remove OR connections btrack subsystem entries when the connections + close normally. Before this, we would only remove the entry on error and + thus leaking memory for each normal OR connections. Fixes bug 40604; + bugfix on 0.4.0.1-alpha. + - Stop sending TRUNCATED cell and instead close the circuit from which we + received a DESTROY cell. This makes every relay in the circuit path to + stop queuing cells. Fixes bug 40623; bugfix on 0.1.0.2-rc. + + o Minor features (fallbackdir): + - Regenerate fallback directories generated on August 11, 2022. + + o Minor features (geoip data): + - Update the geoip files to match the IPFire Location Database, as + retrieved on 2022/08/11. + + o Minor features (linux seccomp2 sandbox): + - Permit the clone3 syscall, which is apparently used in glibc-2.34 + and later. Closes ticket 40590. + + o Minor bugfixes (controller, path bias): + - When a circuit's path is specified, in full or in part, from the + controller API, do not count that circuit towards our path-bias + calculations. (Doing so was incorrect, since we cannot tell + whether the controller is selecting relays randomly.) Resolves a + "Bug" warning. Fixes bug 40515; bugfix on 0.2.4.10-alpha. + + o Minor bugfixes (defense in depth): + - Change a test in the netflow padding code to make it more + _obviously_ safe against remotely triggered crashes. (It was safe + against these before, but not obviously so.) Fixes bug 40645; + bugfix on 0.3.1.1-alpha. + + o Minor bugfixes (linux seccomp2 sandbox): + - Allow the rseq system call in the sandbox. This solves a crash + issue with glibc 2.35 on Linux. Patch from pmu-ipf. Fixes bug + 40601; bugfix on 0.3.5.11. + + o Minor bugfixes (metrics port, onion service): + - The MetricsPort line for an onion service with multiple ports are now + unique that is one line per port. Before this, all ports of an onion + service would be on the same line which violates the Prometheus rules of + unique labels. Fixes bug 40581; bugfix on 0.4.5.1-alpha. + + o Minor bugfixes (onion service, client): + - Fix a fatal assert due to a guard subsystem recursion triggered by + the onion service client. Fixes bug 40579; bugfix on 0.3.5.1-alpha. + + o Minor bugfixes (performance, DoS): + - Fix one case of a not-especially viable denial-of-service attack + found by OSS-Fuzz in our consensus-diff parsing code. This attack + causes a lot small of memory allocations and then immediately + frees them: this is only slow when running with all the sanitizers + enabled. Fixes one case of bug 40472; bugfix on 0.3.1.1-alpha. + + o Minor bugfixes (relay): + - Do not propagate either forward or backward a DESTROY remote reason when + closing a circuit in order to avoid a possible side channel. Fixes bug + 40649; bugfix on 0.1.2.4-alpha. + + +Changes in version 0.4.5.13 - 2022-08-11 + This version contains two major fixes aimed at reducing memory pressure on + relays and possible side-channel. The rest of the fixes were backported for + stability or safety purposes. We strongly recommend to upgrade your relay to + this version or, ideally, to the latest stable of the 0.4.7.x series. + + o Major bugfixes (relay): + - Remove OR connections btrack subsystem entries when the connections + close normally. Before this, we would only remove the entry on error and + thus leaking memory for each normal OR connections. Fixes bug 40604; + bugfix on 0.4.0.1-alpha. + - Stop sending TRUNCATED cell and instead close the circuit from which we + received a DESTROY cell. This makes every relay in the circuit path to + stop queuing cells. Fixes bug 40623; bugfix on 0.1.0.2-rc. + + o Minor features (fallbackdir): + - Regenerate fallback directories generated on August 11, 2022. + + o Minor features (geoip data): + - Update the geoip files to match the IPFire Location Database, as + retrieved on 2022/08/11. + + o Minor features (linux seccomp2 sandbox): + - Permit the clone3 syscall, which is apparently used in glibc-2.34 + and later. Closes ticket 40590. + + o Minor bugfixes (controller, path bias): + - When a circuit's path is specified, in full or in part, from the + controller API, do not count that circuit towards our path-bias + calculations. (Doing so was incorrect, since we cannot tell + whether the controller is selecting relays randomly.) Resolves a + "Bug" warning. Fixes bug 40515; bugfix on 0.2.4.10-alpha. + + o Minor bugfixes (defense in depth): + - Change a test in the netflow padding code to make it more + _obviously_ safe against remotely triggered crashes. (It was safe + against these before, but not obviously so.) Fixes bug 40645; + bugfix on 0.3.1.1-alpha. + + o Minor bugfixes (linux seccomp2 sandbox): + - Allow the rseq system call in the sandbox. This solves a crash + issue with glibc 2.35 on Linux. Patch from pmu-ipf. Fixes bug + 40601; bugfix on 0.3.5.11. + + o Minor bugfixes (metrics port, onion service): + - The MetricsPort line for an onion service with multiple ports are now + unique that is one line per port. Before this, all ports of an onion + service would be on the same line which violates the Prometheus rules of + unique labels. Fixes bug 40581; bugfix on 0.4.5.1-alpha. + + o Minor bugfixes (onion service, client): + - Fix a fatal assert due to a guard subsystem recursion triggered by + the onion service client. Fixes bug 40579; bugfix on 0.3.5.1-alpha. + + o Minor bugfixes (performance, DoS): + - Fix one case of a not-especially viable denial-of-service attack + found by OSS-Fuzz in our consensus-diff parsing code. This attack + causes a lot small of memory allocations and then immediately + frees them: this is only slow when running with all the sanitizers + enabled. Fixes one case of bug 40472; bugfix on 0.3.1.1-alpha. + + o Minor bugfixes (relay): + - Do not propagate either forward or backward a DESTROY remote reason when + closing a circuit in order to avoid a possible side channel. Fixes bug + 40649; bugfix on 0.1.2.4-alpha. + + Changes in version 0.4.7.8 - 2022-06-17 This version fixes several bugfixes including a High severity security issue categorized as a Denial of Service. Everyone running an earlier version @@ -476,7 +1748,7 @@ Exit, Guard, HSDir, and V2Dir; and in favor of BadExit. Implements part of proposal 335. Based on a patch from Neel Chauhan. - o Major features (Proposal 332, onion services, guard selection algorithm): + o Major features (Proposal 333, onion services, guard selection algorithm): - Clients and onion services now choose four long-lived "layer 2" guard relays for use as the middle hop in all onion circuits. These relays are kept in place for a randomized duration averaging diff -Nru tor-0.4.7.16/acinclude.m4 tor-0.4.9.6/acinclude.m4 --- tor-0.4.7.16/acinclude.m4 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/acinclude.m4 2026-03-25 14:30:34.000000000 +0000 @@ -9,6 +9,8 @@ [ if test -d "$1/lib"; then LDFLAGS="-L$1/lib $LDFLAGS" + elif test -d "$1/lib64"; then + LDFLAGS="-L$1/lib64 $LDFLAGS" else LDFLAGS="-L$1 $LDFLAGS" fi @@ -28,6 +30,9 @@ if test -d "$1/lib"; then TOR_LDFLAGS_$2="-L$1/lib" TOR_LIBDIR_$2="$1/lib" + elif test -d "$1/lib64"; then + TOR_LDFLAGS_$2="-L$1/lib64" + TOR_LIBDIR_$2="$1/lib64" else TOR_LDFLAGS_$2="-L$1" TOR_LIBDIR_$2="$1" diff -Nru tor-0.4.7.16/aclocal.m4 tor-0.4.9.6/aclocal.m4 --- tor-0.4.7.16/aclocal.m4 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/aclocal.m4 2026-03-25 14:30:34.000000000 +0000 @@ -1230,6 +1230,7 @@ AC_SUBST([am__untar]) ]) # _AM_PROG_TAR +m4_include([m4/ax_check_compile_flag.m4]) m4_include([m4/ax_check_sign.m4]) m4_include([m4/ax_compiler_vendor.m4]) m4_include([m4/ax_compiler_version.m4]) diff -Nru tor-0.4.7.16/configure tor-0.4.9.6/configure --- tor-0.4.7.16/configure 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/configure 2026-03-25 14:30:34.000000000 +0000 @@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.69 for tor 0.4.7.16. +# Generated by GNU Autoconf 2.69 for tor 0.4.9.6. # # # Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. @@ -577,8 +577,8 @@ # Identity of this package. PACKAGE_NAME='tor' PACKAGE_TARNAME='tor' -PACKAGE_VERSION='0.4.7.16' -PACKAGE_STRING='tor 0.4.7.16' +PACKAGE_VERSION='0.4.9.6' +PACKAGE_STRING='tor 0.4.9.6' PACKAGE_BUGREPORT='' PACKAGE_URL='' @@ -624,6 +624,7 @@ am__EXEEXT_TRUE LTLIBOBJS LIBOBJS +HASHX_SIZE TOR_WARNING_FLAGS LOCALSTATEDIR BINDIR @@ -708,6 +709,8 @@ ac_ct_AR AR TOR_MODULES_ALL_ENABLED +BUILD_MODULE_POW_FALSE +BUILD_MODULE_POW_TRUE BUILD_MODULE_DIRAUTH_FALSE BUILD_MODULE_DIRAUTH_TRUE BUILD_MODULE_DIRCACHE_FALSE @@ -849,6 +852,7 @@ enable_option_checking enable_silent_rules enable_dependency_tracking +enable_gpl enable_openbsd_malloc enable_static_openssl enable_static_libevent @@ -888,6 +892,7 @@ enable_android enable_module_relay enable_module_dirauth +enable_module_pow with_tor_user with_tor_group with_libevent_dir @@ -1468,7 +1473,7 @@ # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures tor 0.4.7.16 to adapt to many kinds of systems. +\`configure' configures tor 0.4.9.6 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1538,7 +1543,7 @@ if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of tor 0.4.7.16:";; + short | recursive ) echo "Configuration of tor 0.4.9.6:";; esac cat <<\_ACEOF @@ -1552,6 +1557,9 @@ do not reject slow dependency extractors --disable-dependency-tracking speeds up one-time build + --enable-gpl allow the inclusion of GPL-licensed code, building a + version of tor and libtor covered by the GPL rather + than its usual 3-clause BSD license --enable-openbsd-malloc use malloc code from OpenBSD. Linux only. Deprecated: see --with-malloc --enable-static-openssl link against a static openssl library. Requires @@ -1629,6 +1637,9 @@ Build tor without the Directory Authority module: tor can not run as a directory authority or bridge authority + --disable-module-pow Build tor without proof-of-work denial of service + mitigation, normally available when building with + --enable-gpl --enable-lzma enable support for the LZMA compression scheme. --enable-zstd enable support for the Zstandard compression scheme. --disable-largefile omit support for large files @@ -1754,7 +1765,7 @@ test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -tor configure 0.4.7.16 +tor configure 0.4.9.6 generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. @@ -2459,7 +2470,7 @@ This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by tor $as_me 0.4.7.16, which was +It was created by tor $as_me 0.4.9.6, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ @@ -2825,7 +2836,7 @@ # only shuts down for missing "required protocols" when those protocols # are listed as required by a consensus after this date. -$as_echo "#define APPROX_RELEASE_DATE \"2023-11-03\"" >>confdefs.h +$as_echo "#define APPROX_RELEASE_DATE \"2026-03-25\"" >>confdefs.h # "foreign" means we don't follow GNU package layout standards @@ -3346,7 +3357,7 @@ # Define the identity of the package. PACKAGE='tor' - VERSION='0.4.7.16' + VERSION='0.4.9.6' cat >>confdefs.h <<_ACEOF @@ -5193,6 +5204,25 @@ $as_echo "$as_me: set PKG_CONFIG_PATH=$PKG_CONFIG_PATH to support cross-compiling" >&6;} fi +# License options + +# Check whether --enable-gpl was given. +if test "${enable_gpl+set}" = set; then : + enableval=$enable_gpl; +fi + +license_option=BSD +if test "x$enable_gpl" = xyes; then : + + +$as_echo "#define ENABLE_GPL 1" >>confdefs.h + + license_option=GPL + +fi + +# Optional features + # Check whether --enable-openbsd-malloc was given. if test "${enable_openbsd_malloc+set}" = set; then : enableval=$enable_openbsd_malloc; @@ -5975,6 +6005,7 @@ # the summary. + # Check whether --enable-module-relay was given. if test "${enable_module_relay+set}" = set; then : enableval=$enable_module_relay; @@ -6008,6 +6039,7 @@ fi + # Check whether --enable-module-dirauth was given. if test "${enable_module_dirauth+set}" = set; then : enableval=$enable_module_dirauth; @@ -6027,6 +6059,26 @@ fi + +# Check whether --enable-module-pow was given. +if test "${enable_module_pow+set}" = set; then : + enableval=$enable_module_pow; +fi + + if test "x$license_option" = "xGPL" && test "x$enable_module_pow" != "xno"; then + BUILD_MODULE_POW_TRUE= + BUILD_MODULE_POW_FALSE='#' +else + BUILD_MODULE_POW_TRUE='#' + BUILD_MODULE_POW_FALSE= +fi + +if test -z "$BUILD_MODULE_POW_TRUE"; then : + +$as_echo "#define HAVE_MODULE_POW 1" >>confdefs.h + +fi + TOR_MODULES_ALL_ENABLED= @@ -6039,6 +6091,9 @@ MODULE=DIRCACHE TOR_MODULES_ALL_ENABLED="${TOR_MODULES_ALL_ENABLED} -DHAVE_MODULE_${MODULE}=1" + MODULE=POW + TOR_MODULES_ALL_ENABLED="${TOR_MODULES_ALL_ENABLED} -DHAVE_MODULE_${MODULE}=1" + if test -n "$ac_tool_prefix"; then @@ -8922,6 +8977,41 @@ fi +saved_CFLAGS="$CFLAGS" +CFLAGS="$CFLAGS -Werror" +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for __attribute__((nonstring))" >&5 +$as_echo_n "checking for __attribute__((nonstring))... " >&6; } +if ${tor_cv_c_attr_nonstring+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + __attribute__((nonstring)) const char foo[5] = "abcde"; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + tor_cv_c_attr_nonstring=yes +else + tor_cv_c_attr_nonstring=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $tor_cv_c_attr_nonstring" >&5 +$as_echo "$tor_cv_c_attr_nonstring" >&6; } +CFLAGS="$saved_CFLAGS" + +if test "$tor_cv_c_attr_nonstring" = "yes"; then + +$as_echo "#define HAVE_ATTR_NONSTRING 1" >>confdefs.h + +fi + TORUSER=_tor # Check whether --with-tor-user was given. @@ -10154,6 +10244,8 @@ if test -d "$tor_trydir/lib"; then LDFLAGS="-L$tor_trydir/lib $LDFLAGS" + elif test -d "$tor_trydir/lib64"; then + LDFLAGS="-L$tor_trydir/lib64 $LDFLAGS" else LDFLAGS="-L$tor_trydir $LDFLAGS" fi @@ -10322,6 +10414,8 @@ if test -d "$tor_cv_library_libevent_dir/lib"; then LDFLAGS="-L$tor_cv_library_libevent_dir/lib $LDFLAGS" + elif test -d "$tor_cv_library_libevent_dir/lib64"; then + LDFLAGS="-L$tor_cv_library_libevent_dir/lib64 $LDFLAGS" else LDFLAGS="-L$tor_cv_library_libevent_dir $LDFLAGS" fi @@ -10341,6 +10435,9 @@ if test -d "$tor_cv_library_libevent_dir/lib"; then TOR_LDFLAGS_libevent="-L$tor_cv_library_libevent_dir/lib" TOR_LIBDIR_libevent="$tor_cv_library_libevent_dir/lib" + elif test -d "$tor_cv_library_libevent_dir/lib64"; then + TOR_LDFLAGS_libevent="-L$tor_cv_library_libevent_dir/lib64" + TOR_LIBDIR_libevent="$tor_cv_library_libevent_dir/lib64" else TOR_LDFLAGS_libevent="-L$tor_cv_library_libevent_dir" TOR_LIBDIR_libevent="$tor_cv_library_libevent_dir" @@ -10804,6 +10901,35 @@ fi + + save_CFLAGS="$CFLAGS" + save_LIBS="$LIBS" + LIBS="$LIBS $NSS_LIBS" + CFLAGS="$CFLAGS $NSS_CFLAGS" + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether NSS defines ssl_kea_ecdh_hybrid(_psk)" >&5 +$as_echo_n "checking whether NSS defines ssl_kea_ecdh_hybrid(_psk)... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + #include + int v = (int) ssl_kea_ecdh_hybrid_psk; + int v2 = (int) ssl_kea_ecdh_hybrid; + +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; }; + +$as_echo "#define NSS_HAS_ECDH_HYBRID 1" >>confdefs.h + + +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + LIBS="$save_LIBS" + CPPFLAGS="$save_CPPFLAGS" fi @@ -10826,8 +10952,8 @@ fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: Now, we'll look for OpenSSL >= 1.0.1" >&5 -$as_echo "$as_me: Now, we'll look for OpenSSL >= 1.0.1" >&6;} +{ $as_echo "$as_me:${as_lineno-$LINENO}: Now, we'll look for OpenSSL." >&5 +$as_echo "$as_me: Now, we'll look for OpenSSL." >&6;} tryopenssldir="" @@ -10876,6 +11002,8 @@ if test -d "$tor_trydir/lib"; then LDFLAGS="-L$tor_trydir/lib $LDFLAGS" + elif test -d "$tor_trydir/lib64"; then + LDFLAGS="-L$tor_trydir/lib64 $LDFLAGS" else LDFLAGS="-L$tor_trydir $LDFLAGS" fi @@ -11025,6 +11153,8 @@ if test -d "$tor_cv_library_openssl_dir/lib"; then LDFLAGS="-L$tor_cv_library_openssl_dir/lib $LDFLAGS" + elif test -d "$tor_cv_library_openssl_dir/lib64"; then + LDFLAGS="-L$tor_cv_library_openssl_dir/lib64 $LDFLAGS" else LDFLAGS="-L$tor_cv_library_openssl_dir $LDFLAGS" fi @@ -11044,6 +11174,9 @@ if test -d "$tor_cv_library_openssl_dir/lib"; then TOR_LDFLAGS_openssl="-L$tor_cv_library_openssl_dir/lib" TOR_LIBDIR_openssl="$tor_cv_library_openssl_dir/lib" + elif test -d "$tor_cv_library_openssl_dir/lib64"; then + TOR_LDFLAGS_openssl="-L$tor_cv_library_openssl_dir/lib64" + TOR_LIBDIR_openssl="$tor_cv_library_openssl_dir/lib64" else TOR_LDFLAGS_openssl="-L$tor_cv_library_openssl_dir" TOR_LIBDIR_openssl="$tor_cv_library_openssl_dir" @@ -11166,14 +11299,35 @@ CPPFLAGS="$TOR_CPPFLAGS_openssl $CPPFLAGS" -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for OpenSSL >= 3.0.0" >&5 -$as_echo_n "checking for OpenSSL >= 3.0.0... " >&6; } +for ac_header in openssl/engine.h +do : + ac_fn_c_check_header_mongrel "$LINENO" "openssl/engine.h" "ac_cv_header_openssl_engine_h" "$ac_includes_default" +if test "x$ac_cv_header_openssl_engine_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_OPENSSL_ENGINE_H 1 +_ACEOF + +else + as_fn_error $? "Missing required header openssl/engine.h. + +On Debian/Ubuntu install: libssl-dev +On Fedora/RHEL install: openssl-devel-engine + +Then re-run configure." "$LINENO" 5 +fi + +done + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for OpenSSL implementation" >&5 +$as_echo_n "checking for OpenSSL implementation... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include -#if !defined(LIBRESSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER >= 0x30000000L -#error "you_have_version_3" +#if defined(LIBRESSL_VERSION_NUMBER) +#error "this is libressl, no worries" #endif int @@ -11185,25 +11339,30 @@ } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; }; + openssl_impl=openssl + { $as_echo "$as_me:${as_lineno-$LINENO}: result: OpenSSL" >&5 +$as_echo "OpenSSL" >&6; } $as_echo "#define OPENSSL_SUPPRESS_DEPRECATED 1" >>confdefs.h + +else + openssl_impl=libressl + { $as_echo "$as_me:${as_lineno-$LINENO}: result: LibreSSL" >&5 +$as_echo "LibreSSL" >&6; } + fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for OpenSSL < 1.0.1" >&5 -$as_echo_n "checking for OpenSSL < 1.0.1... " >&6; } +if test "x$openssl_impl" = "xopenssl"; then +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for OpenSSL < 1.1.1" >&5 +$as_echo_n "checking for OpenSSL < 1.1.1... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include -#if !defined(LIBRESSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER < 0x1000100fL -#error "too old" +#if !defined(LIBRESSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER < 0x10101000L +#error "openssl too old" #endif int @@ -11218,20 +11377,23 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } else - as_fn_error $? "OpenSSL is too old. We require 1.0.1 or later. You can specify a path to a newer one with --with-openssl-dir." "$LINENO" 5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + as_fn_error $? "Your version of OpenSSL is too old. We require 1.1.1 or later, and you should use 3.5 if possible." "$LINENO" 5 + fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether LibreSSL TLS 1.3 APIs are busted" >&5 -$as_echo_n "checking whether LibreSSL TLS 1.3 APIs are busted... " >&6; } +if test "x$openssl_impl" = "xlibressl"; then +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for LibreSSL < 3.7.0" >&5 +$as_echo_n "checking for LibreSSL < 3.7.0... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include -#if defined(LIBRESSL_VERSION_NUMBER) && \ - LIBRESSL_VERSION_NUMBER >= 0x3020100fL && \ - LIBRESSL_VERSION_NUMBER < 0x3040100fL -#error "oh no" +#if defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x3070000fL +#error "libressl too old" #endif int @@ -11246,9 +11408,13 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } else - as_fn_error $? "This version of LibreSSL won't work with Tor. Please upgrade to LibreSSL 3.4.1 or later. (Or downgrade to 3.2.0 if you really must.)" "$LINENO" 5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + as_fn_error $? "Your version of LibreSSL is too old. We require 3.7.0 or later." "$LINENO" 5 + fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -11322,30 +11488,10 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $openssl_ver_mismatch" >&5 $as_echo "$openssl_ver_mismatch" >&6; } -ac_fn_c_check_member "$LINENO" "struct ssl_method_st" "get_cipher_by_char" "ac_cv_member_struct_ssl_method_st_get_cipher_by_char" "#include - -" -if test "x$ac_cv_member_struct_ssl_method_st_get_cipher_by_char" = xyes; then : - -cat >>confdefs.h <<_ACEOF -#define HAVE_STRUCT_SSL_METHOD_ST_GET_CIPHER_BY_CHAR 1 -_ACEOF - - -fi - - for ac_func in \ - ERR_load_KDF_strings \ EVP_PBE_scrypt \ - 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 \ - TLS_method \ + SSL_set_ciphersuites do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` @@ -11359,56 +11505,6 @@ done -ac_fn_c_check_member "$LINENO" "SSL" "state" "ac_cv_member_SSL_state" "#include - -" -if test "x$ac_cv_member_SSL_state" = xyes; then : - -cat >>confdefs.h <<_ACEOF -#define HAVE_SSL_STATE 1 -_ACEOF - - -fi - - -# The cast to long int works around a bug in the HP C Compiler -# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects -# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. -# This bug is HP SR number 8606223364. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of SHA_CTX" >&5 -$as_echo_n "checking size of SHA_CTX... " >&6; } -if ${ac_cv_sizeof_SHA_CTX+:} false; then : - $as_echo_n "(cached) " >&6 -else - if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (SHA_CTX))" "ac_cv_sizeof_SHA_CTX" "$ac_includes_default -#include - -"; then : - -else - if test "$ac_cv_type_SHA_CTX" = yes; then - { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error 77 "cannot compute sizeof (SHA_CTX) -See \`config.log' for more details" "$LINENO" 5; } - else - ac_cv_sizeof_SHA_CTX=0 - fi -fi - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_SHA_CTX" >&5 -$as_echo "$ac_cv_sizeof_SHA_CTX" >&6; } - - - -cat >>confdefs.h <<_ACEOF -#define SIZEOF_SHA_CTX $ac_cv_sizeof_SHA_CTX -_ACEOF - - - fi # enable_nss @@ -11543,6 +11639,8 @@ if test -d "$tor_trydir/lib"; then LDFLAGS="-L$tor_trydir/lib $LDFLAGS" + elif test -d "$tor_trydir/lib64"; then + LDFLAGS="-L$tor_trydir/lib64 $LDFLAGS" else LDFLAGS="-L$tor_trydir $LDFLAGS" fi @@ -11689,6 +11787,8 @@ if test -d "$tor_cv_library_zlib_dir/lib"; then LDFLAGS="-L$tor_cv_library_zlib_dir/lib $LDFLAGS" + elif test -d "$tor_cv_library_zlib_dir/lib64"; then + LDFLAGS="-L$tor_cv_library_zlib_dir/lib64 $LDFLAGS" else LDFLAGS="-L$tor_cv_library_zlib_dir $LDFLAGS" fi @@ -11708,6 +11808,9 @@ if test -d "$tor_cv_library_zlib_dir/lib"; then TOR_LDFLAGS_zlib="-L$tor_cv_library_zlib_dir/lib" TOR_LIBDIR_zlib="$tor_cv_library_zlib_dir/lib" + elif test -d "$tor_cv_library_zlib_dir/lib64"; then + TOR_LDFLAGS_zlib="-L$tor_cv_library_zlib_dir/lib64" + TOR_LIBDIR_zlib="$tor_cv_library_zlib_dir/lib64" else TOR_LDFLAGS_zlib="-L$tor_cv_library_zlib_dir" TOR_LIBDIR_zlib="$tor_cv_library_zlib_dir" @@ -13400,6 +13503,141 @@ +# From https://gcc.gnu.org/onlinedocs/gcc/Instrumentation-Options.html: +# +# Enable code instrumentation to increase program security by checking that +# target addresses of control-flow transfer instructions are valid. This +# prevents diverting the flow of control to an unexpected target. This is +# intended to protect against such threats as Return-oriented Programming +# (ROP), and similarly call/jmp-oriented programming (COP/JOP). + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the compiler accepts -fcf-protection=full" >&5 +$as_echo_n "checking whether the compiler accepts -fcf-protection=full... " >&6; } +if ${tor_cv_cflags__fcf_protection_full+:} false; then : + $as_echo_n "(cached) " >&6 +else + + tor_saved_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -pedantic -Werror -fcf-protection=full" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + tor_cv_cflags__fcf_protection_full=yes +else + tor_cv_cflags__fcf_protection_full=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + if test x != x; then + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + tor_can_link__fcf_protection_full=yes +else + tor_can_link__fcf_protection_full=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + + fi + CFLAGS="$tor_saved_CFLAGS" + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $tor_cv_cflags__fcf_protection_full" >&5 +$as_echo "$tor_cv_cflags__fcf_protection_full" >&6; } + if test x$tor_cv_cflags__fcf_protection_full = xyes; then + CFLAGS="$CFLAGS -fcf-protection=full" + else + true + fi + + + +# The equivalent for arm64 (#41139) + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the compiler accepts -mbranch-protection=standard" >&5 +$as_echo_n "checking whether the compiler accepts -mbranch-protection=standard... " >&6; } +if ${tor_cv_cflags__mbranch_protection_standard+:} false; then : + $as_echo_n "(cached) " >&6 +else + + tor_saved_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -pedantic -Werror -mbranch-protection=standard" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + tor_cv_cflags__mbranch_protection_standard=yes +else + tor_cv_cflags__mbranch_protection_standard=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + if test x != x; then + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + tor_can_link__mbranch_protection_standard=yes +else + tor_can_link__mbranch_protection_standard=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + + fi + CFLAGS="$tor_saved_CFLAGS" + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $tor_cv_cflags__mbranch_protection_standard" >&5 +$as_echo "$tor_cv_cflags__mbranch_protection_standard" >&6; } + if test x$tor_cv_cflags__mbranch_protection_standard = xyes; then + CFLAGS="$CFLAGS -mbranch-protection=standard" + else + true + fi + + + + if test "x$enable_seccomp" != "xno"; then for ac_header in seccomp.h @@ -20045,67 +20283,6 @@ - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the compiler accepts -Wextra-semi" >&5 -$as_echo_n "checking whether the compiler accepts -Wextra-semi... " >&6; } -if ${tor_cv_cflags__Wextra_semi+:} false; then : - $as_echo_n "(cached) " >&6 -else - - tor_saved_CFLAGS="$CFLAGS" - CFLAGS="$CFLAGS -pedantic -Werror -Wextra-semi" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main () -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - tor_cv_cflags__Wextra_semi=yes -else - tor_cv_cflags__Wextra_semi=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - if test x != x; then - - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main () -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - tor_can_link__Wextra_semi=yes -else - tor_can_link__Wextra_semi=no -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext - - fi - CFLAGS="$tor_saved_CFLAGS" - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $tor_cv_cflags__Wextra_semi" >&5 -$as_echo "$tor_cv_cflags__Wextra_semi" >&6; } - if test x$tor_cv_cflags__Wextra_semi = xyes; then - TOR_WARNING_FLAGS="$TOR_WARNING_FLAGS -Wextra-semi" CFLAGS="$CFLAGS -Wextra-semi" - else - true - fi - - - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the compiler accepts -Wextra-tokens" >&5 $as_echo_n "checking whether the compiler accepts -Wextra-tokens... " >&6; } if ${tor_cv_cflags__Wextra_tokens+:} false; then : @@ -28829,6 +29006,42 @@ + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler accepts -Wextra-semi" >&5 +$as_echo_n "checking whether the C compiler accepts -Wextra-semi... " >&6; } +if ${ax_cv_check_cflags__Werror__Wextra_semi+:} false; then : + $as_echo_n "(cached) " >&6 +else + + ax_check_save_flags=$CFLAGS + CFLAGS="$CFLAGS -Werror -Wextra-semi" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ax_cv_check_cflags__Werror__Wextra_semi=yes +else + ax_cv_check_cflags__Werror__Wextra_semi=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + CFLAGS=$ax_check_save_flags +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_check_cflags__Werror__Wextra_semi" >&5 +$as_echo "$ax_cv_check_cflags__Werror__Wextra_semi" >&6; } +if test "x$ax_cv_check_cflags__Werror__Wextra_semi" = xyes; then : + CFLAGS="$CFLAGS -Wextra-semi" +else + : +fi + + W_FLAGS="$W_FLAGS -W -Wfloat-equal -Wundef -Wpointer-arith" @@ -28946,6 +29159,22 @@ esac fi +# These HashX parameter definitions are needed in CPPFLAGS when compiling +# the equix and hashx ext modules, but elsewhere in tor we can use orconfig.h + + +HASHX_SIZE=8 + + +$as_echo "#define HASHX_SIZE 8" >>confdefs.h + + +$as_echo "#define HASHX_STATIC 1" >>confdefs.h + + +$as_echo "#define EQUIX_STATIC 1" >>confdefs.h + + CPPFLAGS="$CPPFLAGS $TOR_CPPFLAGS_libevent $TOR_CPPFLAGS_openssl $TOR_CPPFLAGS_zlib" ac_config_files="$ac_config_files Doxyfile Makefile contrib/operator-tools/tor.logrotate src/config/torrc.sample src/config/torrc.minimal scripts/maint/checkOptionDocs.pl warning_flags" @@ -29190,6 +29419,10 @@ as_fn_error $? "conditional \"BUILD_MODULE_DIRAUTH\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi +if test -z "${BUILD_MODULE_POW_TRUE}" && test -z "${BUILD_MODULE_POW_FALSE}"; then + as_fn_error $? "conditional \"BUILD_MODULE_POW\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then as_fn_error $? "conditional \"am__fastdepCC\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 @@ -29656,7 +29889,7 @@ # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by tor $as_me 0.4.7.16, which was +This file was extended by tor $as_me 0.4.9.6, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -29722,7 +29955,7 @@ cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ -tor config.status 0.4.7.16 +tor config.status 0.4.9.6 configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" @@ -30999,6 +31232,135 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + $as_echo_n " " + + $as_echo_n " " + + + + + $as_echo_n """License Option$PPRINT_COLOR_RST: " + $as_echo "${PPRINT_COLOR_BLD}$license_option$PPRINT_COLOR_RST" + + + + + + + + $as_echo test "x$enable_fatal_warnings" = "xyes" && value=1 || value=0 @@ -33011,6 +33373,13 @@ $as_echo "${PPRINT_COLOR_SUBTITLE}Modules$PPRINT_COLOR_RST" +# Modules have documentation hints indicating how they can be enabled +# or disabled, and those hints can select which version of our message +# to show based on variables at configure-time. +# +# Each "module_option_hints()" macro, if it exists, must +# visit exactly one HINT_* macro using shell conditionals. + if test -z "$BUILD_MODULE_RELAY_TRUE"; then : value=1 @@ -33019,6 +33388,9 @@ fi + if test "x$value" = x1; then : + + test $value -eq 0 && pprint_msg="$PPRINT_NO_MSG" || pprint_msg="$PPRINT_YES_MSG" @@ -33126,6 +33498,168 @@ +else + + + + + test $value -eq 0 && pprint_msg="$PPRINT_NO_MSG" || pprint_msg="$PPRINT_YES_MSG" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + $as_echo_n " " + + $as_echo_n " " + + + + + $as_echo_n """relay$PPRINT_COLOR_RST: " + $as_echo "${PPRINT_COLOR_BLD}$pprint_msg$PPRINT_COLOR_RST" + + + + + + + + + + + + + +fi + if test -z "$BUILD_MODULE_DIRAUTH_TRUE"; then : @@ -33135,6 +33669,9 @@ fi + if test "x$value" = x1; then : + + test $value -eq 0 && pprint_msg="$PPRINT_NO_MSG" || pprint_msg="$PPRINT_YES_MSG" @@ -33234,6 +33771,164 @@ +else + + + + + test $value -eq 0 && pprint_msg="$PPRINT_NO_MSG" || pprint_msg="$PPRINT_YES_MSG" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + $as_echo_n " " + + $as_echo_n " " + + + + + $as_echo_n """dirauth$PPRINT_COLOR_RST: " + $as_echo "${PPRINT_COLOR_BLD}$pprint_msg$PPRINT_COLOR_RST" + + + + + + + + + + + + + +fi + if test -z "$BUILD_MODULE_DIRCACHE_TRUE"; then : @@ -33245,6 +33940,8 @@ + + test $value -eq 0 && pprint_msg="$PPRINT_NO_MSG" || pprint_msg="$PPRINT_YES_MSG" @@ -33396,6 +34093,418 @@ + + if test -z "$BUILD_MODULE_POW_TRUE"; then : + value=1 +else + value=0 +fi + + + if test "x$value" = x1; then : + + + + + test $value -eq 0 && pprint_msg="$PPRINT_NO_MSG" || pprint_msg="$PPRINT_YES_MSG" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + $as_echo_n " " + + $as_echo_n " " + + + + + $as_echo_n """pow (--disable-module-pow)$PPRINT_COLOR_RST: " + $as_echo "${PPRINT_COLOR_BLD}$pprint_msg$PPRINT_COLOR_RST" + + + + + + + + + + + + + +else + if test "x$license_option" != "xGPL"; then : + + + + + test $value -eq 0 && pprint_msg="$PPRINT_NO_MSG" || pprint_msg="$PPRINT_YES_MSG" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + $as_echo_n " " + + $as_echo_n " " + + + + + $as_echo_n """pow (requires --enable-gpl)$PPRINT_COLOR_RST: " + $as_echo "${PPRINT_COLOR_BLD}$pprint_msg$PPRINT_COLOR_RST" + + + + + + + + + + + + + +else + + + + + test $value -eq 0 && pprint_msg="$PPRINT_NO_MSG" || pprint_msg="$PPRINT_YES_MSG" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + $as_echo_n " " + + $as_echo_n " " + + + + + $as_echo_n """pow$PPRINT_COLOR_RST: " + $as_echo "${PPRINT_COLOR_BLD}$pprint_msg$PPRINT_COLOR_RST" + + + + + + + + + + + + + +fi +fi + + + $as_echo diff -Nru tor-0.4.7.16/configure.ac tor-0.4.9.6/configure.ac --- tor-0.4.7.16/configure.ac 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/configure.ac 2026-03-25 14:30:34.000000000 +0000 @@ -4,7 +4,7 @@ dnl See LICENSE for licensing information AC_PREREQ([2.63]) -AC_INIT([tor],[0.4.7.16]) +AC_INIT([tor],[0.4.9.6]) AC_CONFIG_SRCDIR([src/app/main/tor_main.c]) AC_CONFIG_MACRO_DIR([m4]) @@ -18,7 +18,7 @@ # 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, ["2023-11-03"], # for 0.4.7.16 +AC_DEFINE(APPROX_RELEASE_DATE, ["2026-03-25"], # for 0.4.9.6 [Approximate date when this software was released. (Updated when the version changes.)]) # "foreign" means we don't follow GNU package layout standards @@ -51,6 +51,19 @@ AC_MSG_NOTICE([set PKG_CONFIG_PATH=$PKG_CONFIG_PATH to support cross-compiling]) fi +# License options + +AC_ARG_ENABLE(gpl, + AS_HELP_STRING(--enable-gpl, [allow the inclusion of GPL-licensed code, building a version of tor and libtor covered by the GPL rather than its usual 3-clause BSD license])) +license_option=BSD +AS_IF([test "x$enable_gpl" = xyes], + [ + AC_DEFINE(ENABLE_GPL, 1, [Defined if tor is building in GPL-licensed mode.]) + license_option=GPL + ]) + +# Optional features + 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, @@ -358,7 +371,7 @@ dnl --- dnl All our modules. -m4_define(MODULES, relay dirauth dircache) +m4_define([MODULES], [relay dirauth dircache pow]) # Some modules are only disabled through another option. For those, we don't # want to print the help in the summary at the end of the configure. Any entry @@ -367,6 +380,9 @@ m4_set_add_all([MODULES_WITH_NO_OPTIONS], [dircache]) dnl Relay module. +m4_define([module_option_hints(relay)], + [AS_IF([test "x$value" = x1], [HINT_OPT([--disable-module-relay])], + [HINT_NONE])]) AC_ARG_ENABLE([module-relay], AS_HELP_STRING([--disable-module-relay], [Build tor without the Relay modules: tor can not run as a relay, bridge, or authority. Implies --disable-module-dirauth])) @@ -384,6 +400,9 @@ [Compile with directory cache support])) dnl Directory Authority module. +m4_define([module_option_hints(dirauth)], + [AS_IF([test "x$value" = x1], [HINT_OPT([--disable-module-dirauth])], + [HINT_NONE])]) AC_ARG_ENABLE([module-dirauth], AS_HELP_STRING([--disable-module-dirauth], [Build tor without the Directory Authority module: tor can not run as a directory authority or bridge authority])) @@ -392,6 +411,19 @@ AC_DEFINE([HAVE_MODULE_DIRAUTH], [1], [Compile with Directory Authority feature support])) +dnl Hidden Service Proof-of-Work module. +m4_define([module_option_hints(pow)], + [AS_IF([test "x$value" = x1], [HINT_OPT([--disable-module-pow])], + [AS_IF([test "x$license_option" != "xGPL"], [HINT_OPT([requires --enable-gpl])], + [HINT_NONE])])]) +AC_ARG_ENABLE([module-pow], + AS_HELP_STRING([--disable-module-pow], + [Build tor without proof-of-work denial of service mitigation, normally available when building with --enable-gpl])) +AM_CONDITIONAL(BUILD_MODULE_POW, + [test "x$license_option" = "xGPL" && test "x$enable_module_pow" != "xno"]) +AM_COND_IF(BUILD_MODULE_POW, + AC_DEFINE([HAVE_MODULE_POW], [1], [Compile with proof-of-work support])) + dnl Helper variables. TOR_MODULES_ALL_ENABLED= AC_DEFUN([ADD_MODULE], [ @@ -538,6 +570,21 @@ AC_DEFINE(HAVE_ATTR_FALLTHROUGH, [1], [defined if we have the fallthrough attribute.]) fi +saved_CFLAGS="$CFLAGS" +CFLAGS="$CFLAGS -Werror" +AC_CACHE_CHECK([for __attribute__((nonstring))], + tor_cv_c_attr_nonstring, + [AC_COMPILE_IFELSE( + [AC_LANG_PROGRAM([], + [[ __attribute__((nonstring)) const char foo[5] = "abcde"; ]])], + [tor_cv_c_attr_nonstring=yes], + [tor_cv_c_attr_nonstring=no] )]) +CFLAGS="$saved_CFLAGS" + +if test "$tor_cv_c_attr_nonstring" = "yes"; then + AC_DEFINE(HAVE_ATTR_NONSTRING, [1], [defined if we have the nonstring attribute.]) +fi + TORUSER=_tor AC_ARG_WITH(tor-user, AS_HELP_STRING(--with-tor-user=NAME, [specify username for tor daemon]), @@ -947,6 +994,23 @@ [have_nss=no; AC_MSG_ERROR([You asked for NSS but I can't find it, $pkg_config_user_action, or set NSS_CFLAGS and NSS_LIBS.])]) AC_SUBST(NSS_CFLAGS) AC_SUBST(NSS_LIBS) + + save_CFLAGS="$CFLAGS" + save_LIBS="$LIBS" + LIBS="$LIBS $NSS_LIBS" + CFLAGS="$CFLAGS $NSS_CFLAGS" + AC_MSG_CHECKING([whether NSS defines ssl_kea_ecdh_hybrid(_psk)]) + AC_COMPILE_IFELSE([AC_LANG_SOURCE([[ + #include + int v = (int) ssl_kea_ecdh_hybrid_psk; + int v2 = (int) ssl_kea_ecdh_hybrid; + ]], [[]])], + [ AC_MSG_RESULT([yes]); + AC_DEFINE(NSS_HAS_ECDH_HYBRID, 1, [whether nss defines ecdh_hybrid key exchange.]) + ], + [ AC_MSG_RESULT([no]) ]) + LIBS="$save_LIBS" + CPPFLAGS="$save_CPPFLAGS" fi dnl ------------------------------------------------------ @@ -968,7 +1032,7 @@ fi ]) -AC_MSG_NOTICE([Now, we'll look for OpenSSL >= 1.0.1]) +AC_MSG_NOTICE([Now, we'll look for OpenSSL.]) TOR_SEARCH_LIBRARY(openssl, $tryssldir, [-lssl -lcrypto $TOR_LIB_GDI $TOR_LIB_WS32 $TOR_LIB_CRYPT32], [#include char *getenv(const char *);], @@ -1008,38 +1072,58 @@ dnl work. (See ticket tor#40166.) For now, we disable the deprecation dnl warnings. -AC_MSG_CHECKING([for OpenSSL >= 3.0.0]) +dnl --- Check for OpenSSL engine header --- +AC_CHECK_HEADERS([openssl/engine.h], [], + [AC_MSG_ERROR([Missing required header openssl/engine.h. + +On Debian/Ubuntu install: libssl-dev +On Fedora/RHEL install: openssl-devel-engine + +Then re-run configure.])]) + + +AC_MSG_CHECKING([for OpenSSL implementation]) AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ #include -#if !defined(LIBRESSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER >= 0x30000000L -#error "you_have_version_3" +#if defined(LIBRESSL_VERSION_NUMBER) +#error "this is libressl, no worries" #endif ]], [[]])], - [ AC_MSG_RESULT([no]) ], - [ AC_MSG_RESULT([yes]); - AC_DEFINE(OPENSSL_SUPPRESS_DEPRECATED, 1, [disable openssl deprecated-function warnings]) ]) + [ openssl_impl=openssl + AC_MSG_RESULT([OpenSSL]) + AC_DEFINE(OPENSSL_SUPPRESS_DEPRECATED, 1, [disable openssl deprecated-function warnings]) + ], + [ openssl_impl=libressl + AC_MSG_RESULT([LibreSSL]) + ]) -AC_MSG_CHECKING([for OpenSSL < 1.0.1]) +if test "x$openssl_impl" = "xopenssl"; then +AC_MSG_CHECKING([for OpenSSL < 1.1.1]) AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ #include -#if !defined(LIBRESSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER < 0x1000100fL -#error "too old" +#if !defined(LIBRESSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER < 0x10101000L +#error "openssl too old" #endif ]], [[]])], [ AC_MSG_RESULT([no]) ], - [ AC_MSG_ERROR([OpenSSL is too old. We require 1.0.1 or later. You can specify a path to a newer one with --with-openssl-dir.]) ]) + [ AC_MSG_RESULT([yes]) + AC_MSG_ERROR([Your version of OpenSSL is too old. We require 1.1.1 or later, and you should use 3.5 if possible.]) + ]) +fi -AC_MSG_CHECKING([whether LibreSSL TLS 1.3 APIs are busted]) +if test "x$openssl_impl" = "xlibressl"; then +AC_MSG_CHECKING([for LibreSSL < 3.7.0]) AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ #include -#if defined(LIBRESSL_VERSION_NUMBER) && \ - LIBRESSL_VERSION_NUMBER >= 0x3020100fL && \ - LIBRESSL_VERSION_NUMBER < 0x3040100fL -#error "oh no" +#if defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x3070000fL +#error "libressl too old" #endif ]], [[]])], [ AC_MSG_RESULT([no]) ], - [ AC_MSG_ERROR([This version of LibreSSL won't work with Tor. Please upgrade to LibreSSL 3.4.1 or later. (Or downgrade to 3.2.0 if you really must.)]) ]) + [ AC_MSG_RESULT([yes]) + AC_MSG_ERROR([Your version of LibreSSL is too old. We require 3.7.0 or later.]) + ]) +fi AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ #include @@ -1076,34 +1160,14 @@ fi], [openssl_ver_mismatch=cross]) AC_MSG_RESULT([$openssl_ver_mismatch]) -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 \ - 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 \ - TLS_method \ - ]) - -dnl Check if OpenSSL structures are opaque -AC_CHECK_MEMBERS([SSL.state], , , -[#include -]) - -AC_CHECK_SIZEOF(SHA_CTX, , [AC_INCLUDES_DEFAULT() -#include + SSL_set_ciphersuites ]) fi # enable_nss @@ -1442,6 +1506,17 @@ dnl code will work. TOR_CHECK_CFLAGS(-fasynchronous-unwind-tables) +# From https://gcc.gnu.org/onlinedocs/gcc/Instrumentation-Options.html: +# +# Enable code instrumentation to increase program security by checking that +# target addresses of control-flow transfer instructions are valid. This +# prevents diverting the flow of control to an unexpected target. This is +# intended to protect against such threats as Return-oriented Programming +# (ROP), and similarly call/jmp-oriented programming (COP/JOP). +TOR_CHECK_CFLAGS(-fcf-protection=full) +# The equivalent for arm64 (#41139) +TOR_CHECK_CFLAGS(-mbranch-protection=standard) + dnl ============================================================ dnl Check for libseccomp @@ -2357,7 +2432,6 @@ -Wexplicit-ownership-type -Wextern-initializer -Wextra - -Wextra-semi -Wextra-tokens -Wflexible-array-extensions -Wfloat-conversion @@ -2505,6 +2579,8 @@ [TOR_WARNING_FLAGS="$TOR_WARNING_FLAGS warning_flag" CFLAGS="$CFLAGS warning_flag"], true) ]) + AX_CHECK_COMPILE_FLAG([-Wextra-semi], [CFLAGS="$CFLAGS -Wextra-semi"], [], [-Werror]) + dnl We should re-enable this in some later version. Clang doesn't dnl mind, but it causes trouble with GCC. dnl -Wstrict-overflow=2 @@ -2567,6 +2643,17 @@ esac fi +# These HashX parameter definitions are needed in CPPFLAGS when compiling +# the equix and hashx ext modules, but elsewhere in tor we can use orconfig.h + +m4_define([equix_hashx_size], [8]) +[HASHX_SIZE=]equix_hashx_size +AC_SUBST([HASHX_SIZE]) +AC_DEFINE([HASHX_SIZE], equix_hashx_size, + [Output size in bytes for the internal customization of HashX]) +AC_DEFINE([HASHX_STATIC], [1], [We statically link with HashX]) +AC_DEFINE([EQUIX_STATIC], [1], [We statically link with EquiX]) + CPPFLAGS="$CPPFLAGS $TOR_CPPFLAGS_libevent $TOR_CPPFLAGS_openssl $TOR_CPPFLAGS_zlib" AC_CONFIG_FILES([ @@ -2645,6 +2732,7 @@ PPRINT_PROP_STRING([Compiler], [$CC]) PPRINT_PROP_STRING([Host OS], [$host_os]) +PPRINT_PROP_STRING([License Option], [$license_option]) AS_ECHO test "x$enable_fatal_warnings" = "xyes" && value=1 || value=0 @@ -2713,12 +2801,22 @@ AS_ECHO PPRINT_SUBTITLE([Modules]) +# Modules have documentation hints indicating how they can be enabled +# or disabled, and those hints can select which version of our message +# to show based on variables at configure-time. +# +# Each "module_option_hints()" macro, if it exists, must +# visit exactly one HINT_* macro using shell conditionals. + m4_foreach_w([mname], MODULES, [ AM_COND_IF(m4_join([], [BUILD_MODULE_], m4_toupper([]mname[])), value=1, value=0) - m4_set_contains([MODULES_WITH_NO_OPTIONS], mname, - PPRINT_PROP_BOOL([mname], $value), - PPRINT_PROP_BOOL([mname (--disable-module-mname)], $value)) + m4_pushdef([HINT_OPT], [PPRINT_PROP_BOOL](mname ($1), [[$value]])) + m4_pushdef([HINT_NONE], [PPRINT_PROP_BOOL](mname, [[$value]])) + m4_ifdef([module_option_hints](mname), + [m4_indir([module_option_hints](mname))], + [HINT_NONE]) + m4_popdef([HINT_OPT], [HINT_NONE]) ] ) diff -Nru tor-0.4.7.16/contrib/client-tools/torify tor-0.4.9.6/contrib/client-tools/torify --- tor-0.4.7.16/contrib/client-tools/torify 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/contrib/client-tools/torify 2026-03-25 14:30:34.000000000 +0000 @@ -37,25 +37,8 @@ shift esac -# taken from Debian's Developer's Reference, 6.4 -pathfind() { - OLDIFS="$IFS" - IFS=: - for p in $PATH; do - if [ -x "$p/$*" ]; then - IFS="$OLDIFS" - return 0 - fi - done - IFS="$OLDIFS" - return 1 -} - -if pathfind torsocks; then +if command -v torsocks > /dev/null; then exec torsocks "$@" - 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 fi - diff -Nru tor-0.4.7.16/contrib/win32build/tor-mingw.nsi.in tor-0.4.9.6/contrib/win32build/tor-mingw.nsi.in --- tor-0.4.7.16/contrib/win32build/tor-mingw.nsi.in 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/contrib/win32build/tor-mingw.nsi.in 2026-03-25 14:30:34.000000000 +0000 @@ -8,13 +8,13 @@ !include "LogicLib.nsh" !include "FileFunc.nsh" !insertmacro GetParameters -!define VERSION "0.4.7.16" +!define VERSION "0.4.9.6" !define INSTALLER "tor-${VERSION}-win32.exe" !define WEBSITE "https://www.torproject.org/" !define LICENSE "LICENSE" !define BIN "..\bin" ;BIN is where it expects to find tor.exe, tor-resolve.exe - - + + SetCompressor /SOLID LZMA ;Tighter compression RequestExecutionLevel user ;Updated for Vista compatibility OutFile ${INSTALLER} @@ -29,7 +29,7 @@ VIAddVersionKey "ProductName" "The Onion Router: Tor" VIAddVersionKey "Comments" "${WEBSITE}" VIAddVersionKey "LegalTrademarks" "Three line BSD" -VIAddVersionKey "LegalCopyright" "©2004-2008, Roger Dingledine, Nick Mathewson. ©2009 The Tor Project, Inc. " +VIAddVersionKey "LegalCopyright" "©2004-2008, Roger Dingledine, Nick Mathewson. ©2009 The Tor Project, Inc. " VIAddVersionKey "FileDescription" "Tor is an implementation of Onion Routing. You can read more at ${WEBSITE}" VIAddVersionKey "FileVersion" "${VERSION}" @@ -121,7 +121,7 @@ Section "Desktop" Desktop SetOutPath $INSTDIR - CreateShortCut "$DESKTOP\Tor.lnk" "$INSTDIR\tor.exe" "" "$INSTDIR\tor.ico" + CreateShortCut "$DESKTOP\Tor.lnk" "$INSTDIR\tor.exe" "" "$INSTDIR\tor.ico" SectionEnd Section /o "Run at startup" Startup diff -Nru tor-0.4.7.16/contrib/win32build/tor.nsi.in tor-0.4.9.6/contrib/win32build/tor.nsi.in --- tor-0.4.7.16/contrib/win32build/tor.nsi.in 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/contrib/win32build/tor.nsi.in 2026-03-25 14:30:34.000000000 +0000 @@ -5,8 +5,8 @@ ; NOTE: This file might be obsolete. Look at tor-mingw.nsi.in instead. ;----------------------------------------- ; How to make an installer: -; Step 0. If you are a Tor maintainer, make sure that tor.nsi and -; src/win32/orconfig.h all have the correct version number. +; Step 0. If you are a Tor maintainer, make sure that tor.nsi has +; the correct version number. ; Step 1. Download and install OpenSSL. Make sure that the OpenSSL ; version listed below matches the one you downloaded. ; Step 2. Download and install NSIS (http://nsis.sourceforge.net) diff -Nru tor-0.4.7.16/debian/.debian-ci.yml tor-0.4.9.6/debian/.debian-ci.yml --- tor-0.4.7.16/debian/.debian-ci.yml 2026-04-05 21:26:56.000000000 +0000 +++ tor-0.4.9.6/debian/.debian-ci.yml 2026-04-05 21:26:56.000000000 +0000 @@ -1,5 +1,6 @@ variables: - TORGIT: https://git.torproject.org/tor.git + TORGIT: https://gitlab.torproject.org/tpo/core/tor.git + PRISTINETARGIT: https://gitlab.torproject.org/tpo/core/debian/tor-pristine-upstream.git BUILDUSER: build DEBIAN_FRONTEND: "noninteractive" @@ -11,21 +12,13 @@ .rule_condition_branch_debian: &rule_condition_branch_debian | $CI_COMMIT_TAG == null && $CI_COMMIT_BRANCH =~ /^debian-(main$|[0-9].*)/ && $CI_COMMIT_BRANCH !~ /^debian-0\.3\.5($|[.-])/ -.rule_condition_branch_debian_0_3_5: &rule_condition_branch_debian_0_3_5 | - $CI_COMMIT_TAG == null && $CI_COMMIT_BRANCH =~ /^debian-0\.3\.5($|[.-])/ - .rule_condition_tag_debian: &rule_condition_tag_debian | $CI_COMMIT_TAG =~ /^debian-tor-/ && $CI_COMMIT_TAG !~ /^debian-tor-0\.3\.5\./ -.rule_condition_tag_debian_0_3_5: &rule_condition_tag_debian_0_3_5 | - $CI_COMMIT_TAG =~ /^debian-tor-0\.3\.5\./ - workflow: rules: - if: *rule_condition_branch_debian - - if: *rule_condition_branch_debian_0_3_5 - if: *rule_condition_tag_debian - - if: *rule_condition_tag_debian_0_3_5 default: after_script: @@ -51,13 +44,13 @@ .build_source_common: &build_source_common stage: build - image: debian:stable-slim + image: containers.torproject.org/tpo/tpa/base-images/debian:stable tags: [ tpa ] before_script: - rm -rf build-env - *apt-init - apt-get install sudo - - apt-get install build-essential + - apt-get install adduser build-essential - apt-get install $(cat debian/.debian-ci/"${CI_JOB_NAME}"/build-depends) - adduser --system --group --disabled-password --shell /bin/sh --home "$CI_PROJECT_DIR"/build-env "${BUILDUSER}" artifacts: @@ -70,13 +63,17 @@ timeout: 6h variables: GIT_STRATEGY: none - tags: [ $RUNNER_TAG, $HOSTING_PROVIDER_TAG, $PHYSICAL_TAG ] + tags: [ $HOSTING_PROVIDER_TAG, $DOCKER_ARCH ] before_script: - rm -rf build-env binary-packages - *apt-init - apt-get install sudo - - apt-get install build-essential devscripts reprepro fakeroot - image: ${DOCKER_ARCH}/${OS}:${SUITE}${IMAGE_EXTENSION} + - apt-get install adduser build-essential devscripts reprepro fakeroot + #image: ${DOCKER_ARCH}/${OS}:${SUITE}${IMAGE_EXTENSION} + image: containers.torproject.org/tpo/tpa/base-images/${OS}:${SUITE} + retry: + max: 2 + when: runner_system_failure script: - 'echo "SUITE: $SUITE"' @@ -153,135 +150,27 @@ .matrix_full: &matrix_full - OS: debian - SUITE: [ 'sid', 'buster', 'bullseye', 'bookworm', 'trixie' ] + SUITE: [ 'sid', 'bookworm', 'trixie', 'forky' ] DOCKER_ARCH: amd64 - RUNNER_TAG: amd64 - HOSTING_PROVIDER_TAG: tpa - PHYSICAL_TAG: tpa # we don't care about physical - IMAGE_EXTENSION: '-slim' - - OS: debian - SUITE: [ 'sid', 'buster', 'bullseye', 'bookworm', 'trixie' ] - DOCKER_ARCH: i386 - RUNNER_TAG: amd64 HOSTING_PROVIDER_TAG: tpa - PHYSICAL_TAG: physical - IMAGE_EXTENSION: '-slim' - SPECIAL: [ '' ] - OS: debian - DOCKER_ARCH: 'arm64v8' - SUITE: [ 'sid', 'buster', 'bullseye', 'bookworm', 'trixie' ] - RUNNER_TAG: aarch64 + SUITE: [ 'sid', 'bookworm', 'trixie', 'forky' ] + DOCKER_ARCH: arm64 HOSTING_PROVIDER_TAG: osuosl - PHYSICAL_TAG: osuosl # we don't care about physical - IMAGE_EXTENSION: '-slim' - SPECIAL: [ '' ] - - OS: debian - SUITE: 'bullseye' - DOCKER_ARCH: amd64 - RUNNER_TAG: amd64 - HOSTING_PROVIDER_TAG: tpa - PHYSICAL_TAG: tpa # we don't care about physical - IMAGE_EXTENSION: '-slim' - SPECIAL: [ 'bpo11' ] - - OS: debian - SUITE: 'bullseye' - DOCKER_ARCH: i386 - RUNNER_TAG: amd64 - HOSTING_PROVIDER_TAG: tpa - PHYSICAL_TAG: physical - IMAGE_EXTENSION: '-slim' - SPECIAL: [ 'bpo11' ] - OS: debian SUITE: 'bookworm' DOCKER_ARCH: amd64 - RUNNER_TAG: amd64 - HOSTING_PROVIDER_TAG: tpa - PHYSICAL_TAG: tpa # we don't care about physical - IMAGE_EXTENSION: '-slim' - SPECIAL: [ 'bpo12' ] - - OS: debian - SUITE: 'bookworm' - DOCKER_ARCH: i386 - RUNNER_TAG: amd64 HOSTING_PROVIDER_TAG: tpa - PHYSICAL_TAG: physical - IMAGE_EXTENSION: '-slim' SPECIAL: [ 'bpo12' ] - OS: ubuntu - SUITE: [ 'xenial', 'bionic' ] + SUITE: [ 'jammy', 'noble', 'plucky', 'questing' ] DOCKER_ARCH: amd64 - RUNNER_TAG: amd64 - HOSTING_PROVIDER_TAG: tpa - PHYSICAL_TAG: tpa # we don't care about physical - IMAGE_EXTENSION: [ '' ] - - OS: ubuntu - SUITE: [ 'xenial', 'bionic' ] - DOCKER_ARCH: i386 - RUNNER_TAG: amd64 - HOSTING_PROVIDER_TAG: tpa - PHYSICAL_TAG: physical - IMAGE_EXTENSION: [ '' ] - SPECIAL: [ '' ] - - OS: ubuntu - SUITE: [ 'focal', 'jammy', 'lunar', 'mantic' ] - DOCKER_ARCH: 'amd64' - RUNNER_TAG: amd64 HOSTING_PROVIDER_TAG: tpa - PHYSICAL_TAG: tpa # we don't care about physical - IMAGE_EXTENSION: [ '' ] - SPECIAL: [ '' ] - OS: ubuntu - SUITE: [ 'xenial', 'bionic', 'focal', 'jammy', 'lunar', 'mantic' ] - DOCKER_ARCH: 'arm64v8' - RUNNER_TAG: 'aarch64' + SUITE: [ 'jammy', 'noble', 'plucky', 'questing' ] + DOCKER_ARCH: arm64 HOSTING_PROVIDER_TAG: osuosl - PHYSICAL_TAG: osuosl # we don't care about physical - IMAGE_EXTENSION: [ '' ] - SPECIAL: [ '' ] - -.matrix_tor_0_3_5: &matrix_tor_0_3_5 - - OS: debian - SUITE: [ 'buster' ] - DOCKER_ARCH: ['amd64', 'i386'] - RUNNER_TAG: amd64 - HOSTING_PROVIDER_TAG: tpa - PHYSICAL_TAG: tpa # we don't care about physical - IMAGE_EXTENSION: '-slim' - SPECIAL: [ '' ] - - OS: debian - DOCKER_ARCH: 'arm64v8' - SUITE: [ 'buster' ] - RUNNER_TAG: aarch64 - HOSTING_PROVIDER_TAG: osuosl - PHYSICAL_TAG: osuosl # we don't care about physical - IMAGE_EXTENSION: '-slim' - SPECIAL: [ '' ] - - - OS: ubuntu - SUITE: [ 'xenial', 'bionic' ] - DOCKER_ARCH: ['amd64', 'i386'] - RUNNER_TAG: amd64 - HOSTING_PROVIDER_TAG: tpa - PHYSICAL_TAG: tpa # we don't care about physical - IMAGE_EXTENSION: [ '' ] - SPECIAL: [ '' ] - - OS: ubuntu - SUITE: 'focal' - DOCKER_ARCH: 'amd64' - RUNNER_TAG: amd64 - HOSTING_PROVIDER_TAG: tpa - PHYSICAL_TAG: tpa # we don't care about physical - IMAGE_EXTENSION: [ '' ] - SPECIAL: [ '' ] - - OS: ubuntu - SUITE: [ 'xenial', 'bionic', 'focal' ] - DOCKER_ARCH: 'arm64v8' - RUNNER_TAG: 'aarch64' - HOSTING_PROVIDER_TAG: osuosl - PHYSICAL_TAG: osuosl # we don't care about physical - IMAGE_EXTENSION: [ '' ] - SPECIAL: [ '' ] ########################### @@ -291,7 +180,6 @@ build_source: rules: - if: *rule_condition_branch_debian - - if: *rule_condition_branch_debian_0_3_5 <<: *build_source_common variables: GIT_STRATEGY: fetch @@ -299,10 +187,10 @@ script: - git tag -f this-build - sudo -i -u "${BUILDUSER}" mkdir src + - sudo -i -u "${BUILDUSER}" git config --global --add safe.directory "*" - sudo -i -u "${BUILDUSER}" git clone file://"${CI_PROJECT_DIR}" --branch this-build --depth 1 src/debian-tor - sudo -i -u "${BUILDUSER}" git clone "$TORGIT" src/tor # this should not need network now: - - sudo -i -u "${BUILDUSER}" git config --global --add safe.directory "*" - sudo -i -u "${BUILDUSER}" --preserve-env=CI_COMMIT_BRANCH src/debian-tor/debian/.debian-ci/"${CI_JOB_NAME}"/build-script - mv -v --no-target-directory build-env/RESULT source-packages @@ -315,14 +203,6 @@ matrix: *matrix_full needs: [ 'build_source' ] -build_binary_0_3_5: - <<: *build_binary_common - rules: - - if: *rule_condition_branch_debian_0_3_5 - parallel: - matrix: *matrix_tor_0_3_5 - needs: [ 'build_source' ] - ########################### ## release builds @@ -330,7 +210,6 @@ build_source-release: rules: - if: *rule_condition_tag_debian - - if: *rule_condition_tag_debian_0_3_5 <<: *build_source_common variables: # pristine-tar wants the repo @@ -338,16 +217,16 @@ GIT_DEPTH: 0 script: - sudo -i -u "${BUILDUSER}" mkdir src + - sudo -i -u "${BUILDUSER}" git config --global --add safe.directory "*" - sudo -i -u "${BUILDUSER}" git clone "${CI_PROJECT_DIR}" --branch "${CI_COMMIT_TAG}" src/debian-tor - - sudo -i -u "${BUILDUSER}" git clone https://git.torproject.org/debian/tor-pristine-upstream.git --branch master --depth 1 src/pristine-upstream - - sudo -i -u "${BUILDUSER}" git clone https://git.torproject.org/debian/tor-pristine-upstream.git --branch pristine-tar-signatures --depth 1 src/pristine-upstream-signatures + - sudo -i -u "${BUILDUSER}" git clone "${PRISTINETARGIT}" --branch master --depth 1 src/pristine-upstream + - sudo -i -u "${BUILDUSER}" git clone "${PRISTINETARGIT}" --branch pristine-tar-signatures --depth 1 src/pristine-upstream-signatures - sudo -i -u "${BUILDUSER}" mkdir keyrings - sudo -i -u "${BUILDUSER}" gpg --no-default-keyring --keyring ./keyrings/upstream.gpg --import "${TOR_DEBIAN_RELEASE_KEYRING_UPSTREAM}" - sudo -i -u "${BUILDUSER}" gpg --no-default-keyring --keyring ./keyrings/debian.gpg --import "${TOR_DEBIAN_RELEASE_KEYRING_DEBIAN}" # this should not need network now: - - sudo -i -u "${BUILDUSER}" git config --global --add safe.directory "*" - sudo -i -u "${BUILDUSER}" --preserve-env=CI_COMMIT_TAG src/debian-tor/debian/.debian-ci/"${CI_JOB_NAME}"/build-script - mv -v --no-target-directory build-env/RESULT source-packages @@ -360,14 +239,6 @@ matrix: *matrix_full needs: [ 'build_source-release' ] -build_binary-release_0_3_5: - <<: *build_binary_common - rules: - - if: *rule_condition_tag_debian_0_3_5 - parallel: - matrix: *matrix_tor_0_3_5 - needs: [ 'build_source-release' ] - ########################### ########################### @@ -375,7 +246,7 @@ deploy: stage: deploy - image: debian:stable-slim + image: containers.torproject.org/tpo/tpa/base-images/debian:stable tags: [ tpa ] variables: GIT_STRATEGY: none @@ -403,9 +274,8 @@ collect_artifacts: rules: - if: *rule_condition_tag_debian - - if: *rule_condition_tag_debian_0_3_5 stage: deploy - image: debian:stable-slim + image: containers.torproject.org/tpo/tpa/base-images/debian:stable tags: [ tpa ] variables: GIT_STRATEGY: none @@ -417,4 +287,4 @@ paths: - binary-packages - source-packages - expire_in: 1 month + expire_in: 6 months diff -Nru tor-0.4.7.16/debian/changelog tor-0.4.9.6/debian/changelog --- tor-0.4.7.16/debian/changelog 2026-04-05 21:26:56.000000000 +0000 +++ tor-0.4.9.6/debian/changelog 2026-04-05 21:26:56.000000000 +0000 @@ -1,19 +1,169 @@ -tor (0.4.7.16-1) bookworm-security; urgency=medium +tor (0.4.9.6-0+deb12u1) bookworm-security; urgency=medium + + * Upload 0.4.9.x tree to debian-security for bookworm/Debian 12/oldstable + as the 0.4.7 tree is end-of-life. + * Keep systemd files in /lib (as opposed to /usr/lib) + + -- Peter Palfrader Sun, 05 Apr 2026 09:31:58 +0200 + +tor (0.4.9.6-1) unstable; urgency=medium + + * New upstream version. + * Drop 64b5638b backport patch + + -- Jérôme Charaoui Wed, 25 Mar 2026 14:55:12 -0400 + +tor (0.4.9.5-2) unstable; urgency=medium + + * Include 64b5638b from + https://gitlab.torproject.org/tpo/core/tor/-/merge_requests/990 + to fix issues on big-endian systems (closes: #1128946) + * tests/setup-onion-service: include onionshare -> onionshare-cli dependency + change from the debian-main branch, also dropping the unzip dependency. + + -- Peter Palfrader Thu, 26 Feb 2026 12:29:42 +0100 + +tor (0.4.9.5-1) unstable; urgency=medium + + * New upsteam tree. + + -- Jérôme Charaoui Thu, 12 Feb 2026 13:11:02 -0500 + +tor (0.4.8.22-1) unstable; urgency=medium + + * New upstream version. + + -- Jérôme Charaoui Wed, 28 Jan 2026 14:36:16 -0500 + +tor (0.4.8.21-1) unstable; urgency=medium + + * New upstream version. + + -- Jérôme Charaoui Mon, 17 Nov 2025 15:05:05 -0500 + +tor (0.4.8.20-1) unstable; urgency=medium + + * New upstream version. + + -- Jérôme Charaoui Mon, 10 Nov 2025 15:37:11 -0500 + +tor (0.4.8.19-1) unstable; urgency=medium + + * New upstream version. + + -- Gabriel Filion Thu, 09 Oct 2025 16:31:29 -0400 + +tor (0.4.8.18-1) unstable; urgency=medium + + * New upstream version. + + -- Jérôme Charaoui Tue, 16 Sep 2025 13:05:13 -0400 + +tor (0.4.8.17-1) unstable; urgency=medium + + * New upstream version. + + -- Gabriel Filion Thu, 17 Jul 2025 15:37:06 -0400 + +tor (0.4.8.16-1) unstable; urgency=medium + + * New upstream version. + + -- Jérôme Charaoui Tue, 25 Mar 2025 14:01:26 -0400 + +tor (0.4.8.15-1) unstable; urgency=medium + + * New upstream version. + * Drop sandboxing patch which has been merged upstream. + + -- Jérôme Charaoui Thu, 20 Mar 2025 15:02:20 -0400 + +tor (0.4.8.14-1) unstable; urgency=medium + + * New upstream version. + + -- Peter Palfrader Sat, 08 Feb 2025 10:39:20 +0100 + +tor (0.4.8.13-2) unstable; urgency=medium + + * Incorporate work by Helmut Grohne, Chris Hofstaedtler and others to + install systemd services into /usr (DEP17 M2; closes: #1073748). + + -- Peter Palfrader Thu, 31 Oct 2024 19:49:08 +0100 + +tor (0.4.8.13-1) unstable; urgency=medium + + * New upstream version. + * Include patch from + https://gitlab.torproject.org/tpo/core/tor/-/merge_requests/821 + to make sandboxing work again in some cases. + + -- Peter Palfrader Mon, 28 Oct 2024 20:13:37 +0100 + +tor (0.4.8.12-1) unstable; urgency=medium + + * New upstream version. + + -- Peter Palfrader Thu, 06 Jun 2024 16:47:06 +0200 + +tor (0.4.8.11-1) unstable; urgency=medium * New upstream version. - * Target bookworm-security: - o Major bugfixes (TROVE-2023-004, relay): - - Mitigate an issue when Tor compiled with OpenSSL can crash during - handshake with a remote relay. Fixes bug 40874; bugfix - on 0.2.7.2-alpha. - -- Peter Palfrader Tue, 14 Nov 2023 19:01:38 +0100 + -- Peter Palfrader Fri, 12 Apr 2024 09:22:56 +0200 -tor (0.4.7.15-1) bookworm; urgency=medium +tor (0.4.8.10-1) unstable; urgency=medium * New upstream version. - -- Peter Palfrader Mon, 18 Sep 2023 21:59:09 +0200 + -- Peter Palfrader Sun, 10 Dec 2023 20:09:09 +0100 + +tor (0.4.8.9-1) unstable; urgency=medium + + * New upstream version. + + -- Peter Palfrader Fri, 10 Nov 2023 18:29:41 +0100 + +tor (0.4.8.8-1) unstable; urgency=medium + + * New upstream version. + + -- Peter Palfrader Sun, 05 Nov 2023 18:58:59 +0100 + +tor (0.4.8.7-1) unstable; urgency=medium + + * New upstream version. + + -- Peter Palfrader Wed, 04 Oct 2023 19:58:14 +0200 + +tor (0.4.8.6-1) unstable; urgency=medium + + * New upstream version. + + -- Peter Palfrader Mon, 18 Sep 2023 20:07:19 +0200 + +tor (0.4.8.5-1) unstable; urgency=medium + + * New upstream version. + * Retire postinst code that deals with broken keys from 2008 + and apparmor migrations from 2012. + * tor.postinst: use command -v in place of which. + + -- Peter Palfrader Wed, 30 Aug 2023 20:19:26 +0200 + +tor (0.4.8.4-2) unstable; urgency=medium + + * Enable building with the Proof-of-Work feature by configuring with + --enable-gpl. Note that this causes the resulting binary to be covered + by the GPL. + + -- Peter Palfrader Thu, 24 Aug 2023 08:02:38 +0200 + +tor (0.4.8.4-1) unstable; urgency=medium + + * New upstream tree. + + -- Peter Palfrader Wed, 23 Aug 2023 21:51:49 +0200 tor (0.4.7.13-1) unstable; urgency=medium diff -Nru tor-0.4.7.16/debian/copyright tor-0.4.9.6/debian/copyright --- tor-0.4.7.16/debian/copyright 2026-04-05 21:26:56.000000000 +0000 +++ tor-0.4.9.6/debian/copyright 2026-04-05 21:26:56.000000000 +0000 @@ -51,6 +51,12 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================== + +Note however that since we build tor with --enable-gpl this may and will allow +the inclusion of GPL-licensed code from libraries, building a version of tor +and libtor covered by the GPL rather than its usual 3-clause BSD license. + +=============================================================================== strlcat and strlcpy by Todd C. Miller are licensed under the following license: * Copyright (c) 1998 Todd C. Miller diff -Nru tor-0.4.7.16/debian/micro-revision.i tor-0.4.9.6/debian/micro-revision.i --- tor-0.4.7.16/debian/micro-revision.i 2026-04-05 21:26:56.000000000 +0000 +++ tor-0.4.9.6/debian/micro-revision.i 2026-04-05 21:26:56.000000000 +0000 @@ -1 +1 @@ -"fe45677575ab4f99" +"67d83a6b7dd2a191" diff -Nru tor-0.4.7.16/debian/misc/backport tor-0.4.9.6/debian/misc/backport --- tor-0.4.7.16/debian/misc/backport 2026-04-05 21:26:56.000000000 +0000 +++ tor-0.4.9.6/debian/misc/backport 2026-04-05 21:26:56.000000000 +0000 @@ -41,6 +41,7 @@ bullseye d11.bullseye 1 bookworm d12.bookworm 1 trixie d13.trixie 1 +forky d14.forky 1 lenny-bpo bpo5 1 lenny-backports squeeze-bpo bpo6 1 squeeze-backports @@ -51,6 +52,7 @@ bullseye-bpo bpo11 1 bullseye-backports bookworm-bpo bpo12 1 bookworm-backports trixie-bpo bpo13 1 trixie-backports +forky-bpo bpo14 1 forky-backports dapper dapper 1 edgy edgy 1 @@ -88,6 +90,10 @@ kinetic kinetic 1 lunar lunar 1 mantic mantic 1 +noble noble 1 +oracular oracular 1 +plucky plucky 1 +questing questing 1 EOF ) if [ -z "$result" ] ; then diff -Nru tor-0.4.7.16/debian/misc/build-tor-sources tor-0.4.9.6/debian/misc/build-tor-sources --- tor-0.4.7.16/debian/misc/build-tor-sources 2026-04-05 21:26:56.000000000 +0000 +++ tor-0.4.9.6/debian/misc/build-tor-sources 2026-04-05 21:26:56.000000000 +0000 @@ -33,319 +33,326 @@ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -assert_files_dont_exist () { - local pkg="$1"; shift - local debian_version="$1"; - if [ -z "$debian_version" ]; then - echo "assert_files_dont_exist called without debian_version" >&2 - exit 1; - fi - - if [ -e "${pkg}_$debian_version.diff.gz" ] ; then - echo "${pkg}_$debian_version.diff.gz already exists" >&2 - exit 1; - fi - if [ -e "${pkg}_$debian_version.dsc" ] ; then - echo "${pkg}_$debian_version.dsc already exists" >&2 - exit 1; - fi - if [ -e "${pkg}_$debian_version""_amd64.deb" ] ; then - echo "${pkg}_$debian_version""_amd64.deb already exists" >&2 - exit 1; - fi - if [ -e "${pkg}_$debian_version""_amd64.changes" ] ; then - echo "${pkg}_$debian_version""_amd64.changes already exists" >&2 - exit 1; - fi +assert_files_dont_exist() { + local pkg="$1" + shift + local debian_version="$1" + if [ -z "$debian_version" ]; then + echo "assert_files_dont_exist called without debian_version" >&2 + exit 1 + fi + + if [ -e "${pkg}_$debian_version.diff.gz" ]; then + echo "${pkg}_$debian_version.diff.gz already exists" >&2 + exit 1 + fi + if [ -e "${pkg}_$debian_version.dsc" ]; then + echo "${pkg}_$debian_version.dsc already exists" >&2 + exit 1 + fi + if [ -e "${pkg}_$debian_version""_amd64.deb" ]; then + echo "${pkg}_$debian_version""_amd64.deb already exists" >&2 + exit 1 + fi + if [ -e "${pkg}_$debian_version""_amd64.changes" ]; then + echo "${pkg}_$debian_version""_amd64.changes already exists" >&2 + exit 1 + fi } get_debian_version() { - local dir="$1"; shift - local which="${1:-}"; shift - - if [ -z "$which" ]; then - ( cd $dir && dpkg-parsechangelog | grep-dctrl -n -s Version '' ) - else - local v=$(get_debian_version $dir) - case "$which" in - upstream) echo "${v%-*}" ;; - debrev) echo "${v##*-}" ;; - *) - echo >&2 "Unknown key '$which' in get_debian_version" - exit 1 - esac - fi + local dir="$1" + shift + local which="${1:-}" + shift + + if [ -z "$which" ]; then + (cd $dir && dpkg-parsechangelog | grep-dctrl -n -s Version '') + else + local v=$(get_debian_version $dir) + case "$which" in + upstream) echo "${v%-*}" ;; + debrev) echo "${v##*-}" ;; + *) + echo >&2 "Unknown key '$which' in get_debian_version" + exit 1 + ;; + esac + fi } # remove_completely ... 0 replace hardening-includes with hardening-wrapper # 1 get rid entirely hardening_backport() { - local remove_completely="$1" + local remove_completely="$1" - sed -i -e '/^Build-Depends/ s/, *hardening-includes//' debian/control - if [ "$remove_completely" = 0 ]; then - sed -i -e '/^Build-Depends/ s/$/, hardening-wrapper/' debian/control - fi - - if [ "$remove_completely" = 0 ]; then - sed -i -e 's#include /usr/share/hardening-includes/hardening.make#export DEB_BUILD_HARDENING=1#' debian/rules - sed -i -e '/export DEB_BUILD_HARDENING=1/ a export DEB_BUILD_HARDENING_DEBUG=1' debian/rules - else - sed -i -e 's#include /usr/share/hardening-includes/hardening.make##' debian/rules - fi - - if [ "$remove_completely" = 0 ]; then - dch --append "Replace hardening-includes use with hardening-wrapper." - else - dch --append "Completely remove hardening-includes use." - fi + sed -i -e '/^Build-Depends/ s/, *hardening-includes//' debian/control + if [ "$remove_completely" = 0 ]; then + sed -i -e '/^Build-Depends/ s/$/, hardening-wrapper/' debian/control + fi + + if [ "$remove_completely" = 0 ]; then + sed -i -e 's#include /usr/share/hardening-includes/hardening.make#export DEB_BUILD_HARDENING=1#' debian/rules + sed -i -e '/export DEB_BUILD_HARDENING=1/ a export DEB_BUILD_HARDENING_DEBUG=1' debian/rules + else + sed -i -e 's#include /usr/share/hardening-includes/hardening.make##' debian/rules + fi + + if [ "$remove_completely" = 0 ]; then + dch --append "Replace hardening-includes use with hardening-wrapper." + else + dch --append "Completely remove hardening-includes use." + fi } remove_runit() { - if grep -q dh-runit debian/control; then - sed -i -e '/^Build-Depends/ s/, *dh-runit\([^,]*\)\?//' debian/control - dch --append "Remove dh-runit build dependency and --with-runit for backport." - fi - sed -i -e "s/--with[[:space:]]*runit//" debian/rules + if grep -q dh-runit debian/control; then + sed -i -e '/^Build-Depends/ s/, *dh-runit\([^,]*\)\?//' debian/control + dch --append "Remove dh-runit build dependency and --with-runit for backport." + fi + sed -i -e "s/--with[[:space:]]*runit//" debian/rules } old_dh_systemd() { - dch --append "Restore build-dependency on dh-systemd and lower debhelper version requirement to 9.20160114" - sed -i -e '/^Build-Depends/ s/debhelper [^,]*, */debhelper (>= 9.20160114), dh-systemd [linux-any], /' debian/control + dch --append "Restore build-dependency on dh-systemd and lower debhelper version requirement to 9.20160114" + sed -i -e '/^Build-Depends/ s/debhelper [^,]*, */debhelper (>= 9.20160114), dh-systemd [linux-any], /' debian/control } - +systemd_in_lib() { + dch --append "Keep systemd files in /lib (as opposed to /usr/lib)" + sed -i -e 's,usr/lib/systemd,lib/systemd,' debian/tor.install debian/tor.dirs +} bp1() { - local pkg="$1"; shift - local dir="$1"; shift - local sid_debian_version="$1"; shift - local dist="$1"; shift - - dpkg-source -x ${pkg}_$sid_debian_version.dsc - (cd $dir; backport $dist) + local pkg="$1" + shift + local dir="$1" + shift + local sid_debian_version="$1" + shift + local dist="$1" + shift + + dpkg-source -x ${pkg}_$sid_debian_version.dsc + ( + cd $dir + backport $dist + ) } bp2() { - local pkg="$1"; shift - local dir="$1"; shift - local origtar="$1"; shift - - local debian_version=$(get_debian_version $dir) - assert_files_dont_exist $pkg $debian_version - dpkg-source -b $dir $origtar - rm -r $dir + local pkg="$1" + shift + local dir="$1" + shift + local origtar="$1" + shift + + local debian_version=$(get_debian_version $dir) + assert_files_dont_exist $pkg $debian_version + dpkg-source -b $dir $origtar + rm -r $dir } backport_all() { - local pkg="$1"; shift - local dir="$1"; shift - local origtar="$1"; shift - local sid_debian_version="$1"; shift - - # sid - ################################################# - # null - - # buster - ################################################# - bp1 $pkg $dir $sid_debian_version buster - (cd $dir; remove_runit) - bp2 $pkg $dir $origtar - - # bullseye - ################################################# - bp1 $pkg $dir $sid_debian_version bullseye - bp2 $pkg $dir $origtar - - # bookworm - ################################################# - bp1 $pkg $dir $sid_debian_version bookworm - bp2 $pkg $dir $origtar - - # trixie - ################################################# - bp1 $pkg $dir $sid_debian_version trixie - bp2 $pkg $dir $origtar - - - # xenial (EOL: Apr 2021, 2026-04) - ################################################# - bp1 $pkg $dir $sid_debian_version xenial - (cd $dir; old_dh_systemd) - (cd $dir; remove_runit) - bp2 $pkg $dir $origtar - - # bionic (EOL: Apr 2023, 2028-04) - ################################################# - bp1 $pkg $dir $sid_debian_version bionic - (cd $dir; remove_runit) - bp2 $pkg $dir $origtar - - # focal (EOL: 2025-04, 2030-04) - ################################################# - bp1 $pkg $dir $sid_debian_version focal - bp2 $pkg $dir $origtar - - # jammy (EOL: 2027-04-21, 2032-04) - ################################################# - bp1 $pkg $dir $sid_debian_version jammy - bp2 $pkg $dir $origtar - - # lunar (EOL: 2024-01) - ################################################# - bp1 $pkg $dir $sid_debian_version lunar - bp2 $pkg $dir $origtar - - # mantic (EOL: 202????) - ################################################# - bp1 $pkg $dir $sid_debian_version mantic - bp2 $pkg $dir $origtar - - ################################################# - ## BPO - ################################################# - - # Backport to bookworm(debian 12) backports - dpkg-source -x ${pkg}_$sid_debian_version.dsc - ( - cd $dir - dch --bpo '' - head debian/changelog - sed -i -e '1,3s/bullseye-backports/bookworm-backports/' debian/changelog - sed -i -e '1s/bpo11/bpo12/' debian/changelog - ) - bp2 $pkg $dir $origtar - - # Backport to bullseye(debian 11) sloppy backports - dpkg-source -x ${pkg}_$sid_debian_version.dsc - ( - cd $dir - dch --bpo '' - head debian/changelog - sed -i -e '1,3s/bullseye-backports/bullseye-backports-sloppy/' debian/changelog - #sed -i -e '1s/bpo12/bpo11/' debian/changelog - ) - bp2 $pkg $dir $origtar + local pkg="$1" + shift + local dir="$1" + shift + local origtar="$1" + shift + local sid_debian_version="$1" + shift + + # sid + ################################################# + # null + + # bookworm + ################################################# + bp1 $pkg $dir $sid_debian_version bookworm + ( + cd $dir + systemd_in_lib + ) + bp2 $pkg $dir $origtar + + # trixie + ################################################# + bp1 $pkg $dir $sid_debian_version trixie + bp2 $pkg $dir $origtar + + # forky + ################################################# + bp1 $pkg $dir $sid_debian_version forky + bp2 $pkg $dir $origtar + + # jammy (EOL: 2027-04-21, 2032-04) + ################################################# + bp1 $pkg $dir $sid_debian_version jammy + ( + cd $dir + systemd_in_lib + ) + bp2 $pkg $dir $origtar + + # noble (EOL: 2036-04) + ################################################# + bp1 $pkg $dir $sid_debian_version noble + bp2 $pkg $dir $origtar + + # plucky (EOL: 2026-01) + ################################################# + bp1 $pkg $dir $sid_debian_version plucky + bp2 $pkg $dir $origtar + + # questing (EOL: 2026-07) + ################################################# + bp1 $pkg $dir $sid_debian_version questing + bp2 $pkg $dir $origtar + + ################################################# + ## BPO + ################################################# + + # Backport to trixie(debian 13) backports + dpkg-source -x ${pkg}_$sid_debian_version.dsc + ( + cd $dir + dch --bpo '' + head debian/changelog + ) + bp2 $pkg $dir $origtar + + # Backport to bookworm(debian 12) sloppy backports + dpkg-source -x ${pkg}_$sid_debian_version.dsc + ( + cd $dir + dch --bpo '' + systemd_in_lib + head debian/changelog + sed -i -e '1,3s/trixie-backports/bookworm-backports-sloppy/' debian/changelog + sed -i -e '1s/bpo13/bpo12/' debian/changelog + ) + bp2 $pkg $dir $origtar } main() { - local origtar="$1"; shift - local deb_revision="$1"; shift - local gitdir="$1"; shift - local pkg="$1"; shift - - [ -d local-build ] || mkdir local-build - - if [ -z "$origtar" ] ; then - echo "Usage: $0 [debian-revision]" >&2 - exit 1; - fi - - - if [ ! -e "$origtar" ] ; then - echo "$origtar does not exist." >&2 - exit 1; - fi - - if [ "${origtar#${pkg}-}" != $origtar ]; then - ver="$origtar" - ver=${ver#${pkg}-} - ver=${ver%.tar.gz} - neworig="${pkg}_$ver.orig.tar.gz" - if ! [ -e "$neworig" ]; then - ln -v "$origtar" "$neworig" - fi - echo "Using $neworig instead of $origtar" - origtar="$neworig" - fi - - local dir - local dir_version - dir=`tar tzf $origtar 2>/dev/null | head -n1` - dir="${dir%%/}" - dir_version="${dir##${pkg}-}" - if [ -e "$dir" ] ; then - echo "$dir already exists." >&2 - exit 1; - fi - tar xzf $origtar - git clone -n -s "$gitdir" git-"$dir" - local tag="debian-${pkg}-$dir_version-${deb_revision//\~/_}" - (cd "git-$dir" && git checkout $tag) - if diff -qr "git-$dir" "$dir" --exclude .git | grep -v '^Only in ' | grep --color .; then - echo "Differenced detected." - exit 1 - fi - (cd "git-$dir" && echo "\"`git rev-parse --short=16 "$tag"`\"" > "debian/micro-revision.i") - cp -av "git-$dir/debian" "$dir" - rm -rf "git-$dir" - - - debian_upstream_version=$(get_debian_version $dir upstream) - if [ "$origtar" != "${pkg}_$debian_upstream_version.orig.tar.gz" ] ; then - echo "possible mismatch: $origtar but $debian_upstream_version in debian/changelog" >&2 - exit 1; - fi - - debian_version=$(get_debian_version $dir) - sid_debian_version="$debian_version" - assert_files_dont_exist $pkg $debian_version - dpkg-source -b $dir $origtar - rm -r $dir - - - - # local - ################################################# - cd local-build - dpkg-source -x ../${pkg}_$debian_version.dsc - cd ${pkg}-$debian_upstream_version - debuild -j8 -rfakeroot -uc -us - cd ../.. - + local origtar="$1" + shift + local deb_revision="$1" + shift + local gitdir="$1" + shift + local pkg="$1" + shift + + [ -d local-build ] || mkdir local-build + + if [ -z "$origtar" ]; then + echo "Usage: $0 [debian-revision]" >&2 + exit 1 + fi + + if [ ! -e "$origtar" ]; then + echo "$origtar does not exist." >&2 + exit 1 + fi + + if [ "${origtar#${pkg}-}" != $origtar ]; then + ver="$origtar" + ver=${ver#${pkg}-} + ver=${ver%.tar.gz} + neworig="${pkg}_$ver.orig.tar.gz" + if ! [ -e "$neworig" ]; then + ln -v "$origtar" "$neworig" + fi + echo "Using $neworig instead of $origtar" + origtar="$neworig" + fi + + local dir + local dir_version + dir=$(tar tzf $origtar 2>/dev/null | head -n1) + dir="${dir%%/}" + dir_version="${dir##${pkg}-}" + if [ -e "$dir" ]; then + echo "$dir already exists." >&2 + exit 1 + fi + tar xzf $origtar + git clone -n -s "$gitdir" git-"$dir" + local tag="debian-${pkg}-$dir_version-${deb_revision//\~/_}" + (cd "git-$dir" && git checkout $tag) + if diff -qr "git-$dir" "$dir" --exclude .git | grep -v '^Only in ' | grep --color .; then + echo "Differenced detected." + exit 1 + fi + (cd "git-$dir" && echo "\"$(git rev-parse --short=16 "$tag")\"" >"debian/micro-revision.i") + cp -av "git-$dir/debian" "$dir" + rm -rf "git-$dir" + + debian_upstream_version=$(get_debian_version $dir upstream) + if [ "$origtar" != "${pkg}_$debian_upstream_version.orig.tar.gz" ]; then + echo "possible mismatch: $origtar but $debian_upstream_version in debian/changelog" >&2 + exit 1 + fi + + debian_version=$(get_debian_version $dir) + sid_debian_version="$debian_version" + assert_files_dont_exist $pkg $debian_version + dpkg-source -b $dir $origtar + rm -r $dir + + # local + ################################################# + cd local-build + dpkg-source -x ../${pkg}_$debian_version.dsc + cd ${pkg}-$debian_upstream_version + debuild -j8 -rfakeroot -uc -us + cd ../.. - [ "$DO_BACKPORTS" -gt 0 ] && backport_all "$pkg" "$dir" "$origtar" "$sid_debian_version" + [ "$DO_BACKPORTS" -gt 0 ] && backport_all "$pkg" "$dir" "$origtar" "$sid_debian_version" - echo - echo "All done" + echo + echo "All done" } usage() { - cat << EOF + cat < EOF } # this is hardcoded to weasel's directory layout. sorry. case "$(basename $0)" in - build-tor-sources) - DO_BACKPORTS=1 - while getopts "hB" option; do - case "$option" in - h) - usage - exit - ;; - B) - DO_BACKPORTS=0 - ;; - *) - usage >&2 - exit 1 - ;; - esac - done - shift $(($OPTIND - 1)) - - set -e - set -x - GITDIR="${GITDIR:-$HOME/projects/tor/tor}" - if ! [ -e "$GITDIR/.git" ] ; then - echo >&2 "\$GITDIR does not exist or does not have a .git. It needs to point to the tor git repository." - exit 1 - fi - PKG="tor" - DO_BPO=1 - main "${1:-}" ${2:-1} $GITDIR $PKG - ;; +build-tor-sources) + DO_BACKPORTS=1 + while getopts "hB" option; do + case "$option" in + h) + usage + exit + ;; + B) + DO_BACKPORTS=0 + ;; + *) + usage >&2 + exit 1 + ;; + esac + done + shift $(($OPTIND - 1)) + + set -e + set -x + GITDIR="${GITDIR:-$HOME/projects/tor/tor}" + if ! [ -e "$GITDIR/.git" ]; then + echo >&2 "\$GITDIR does not exist or does not have a .git. It needs to point to the tor git repository." + exit 1 + fi + PKG="tor" + DO_BPO=1 + main "${1:-}" ${2:-1} $GITDIR $PKG + ;; esac diff -Nru tor-0.4.7.16/debian/misc/new-tor-release tor-0.4.9.6/debian/misc/new-tor-release --- tor-0.4.7.16/debian/misc/new-tor-release 2026-04-05 21:26:56.000000000 +0000 +++ tor-0.4.9.6/debian/misc/new-tor-release 2026-04-05 21:26:56.000000000 +0000 @@ -38,8 +38,8 @@ set -e set -u -TORGIT="$HOME/projects/tor/tor" -TORDEBBASE="$HOME/projects/debian/debian/tor" +TORGIT="${TORGIT:-$HOME/projects/tor/tor}" +TORDEBBASE="${TORDEBBASE:-$HOME/projects/debian/debian/tor}" cd "$TORGIT" if [ -n "$(git status --porcelain)" ]; then @@ -114,21 +114,21 @@ # get current branch current_branch=$(git rev-parse --abbrev-ref HEAD) tar=$(basename $tarball) -git co pristine-tar +git checkout pristine-tar if [ -e "$tar.id" ]; then echo >&1 "Tarball already committed." else pristine-tar commit "$tarball" "$tag" fi -git co pristine-tar-signatures +git checkout pristine-tar-signatures if [ -e "$tarball.asc" ] ; then if [ -e "$tar.asc" ]; then echo >&1 "Tarball signature already committed." else cp "$tarball.asc" . git add "$tar.asc" - git ci -m "Add $tar.asc" "$tar.asc" + git commit -m "Add $tar.asc" "$tar.asc" fi elif [ -e "${tarball}.sha256sum" ] && [ -e "${tarball}.sha256sum.asc" ] ; then if [ -e "$tar.sha256sum" ] && [ -e "$tar.sha256sum.asc" ] ; then @@ -136,7 +136,7 @@ else cp "${tarball}.sha256sum" "${tarball}.sha256sum.asc" . git add "${tar}.sha256sum" "${tar}.sha256sum.asc" - git ci -m "Add ${tar}.sha256sum, ${tar}.sha256sum.asc" "${tar}.sha256sum" "${tar}.sha256sum.asc" + git commit -m "Add ${tar}.sha256sum, ${tar}.sha256sum.asc" "${tar}.sha256sum" "${tar}.sha256sum.asc" fi else echo >&2 "No way to verify upstream tarball." @@ -144,7 +144,7 @@ fi git push -git co "$current_branch" +git checkout "$current_branch" debtag="debian-tor-$chlogversion" if ! git tag -v "$debtag"; then diff -Nru tor-0.4.7.16/debian/misc/new-tor-release-prepare tor-0.4.9.6/debian/misc/new-tor-release-prepare --- tor-0.4.7.16/debian/misc/new-tor-release-prepare 2026-04-05 21:26:56.000000000 +0000 +++ tor-0.4.9.6/debian/misc/new-tor-release-prepare 2026-04-05 21:26:56.000000000 +0000 @@ -29,8 +29,8 @@ set -e set -u -TORGIT="$HOME/projects/tor/tor" -TORDEBBASE="$HOME/projects/debian/debian/tor" +TORGIT="${TORGIT:-$HOME/projects/tor/tor}" +TORDEBBASE="${TORDEBBASE:-$HOME/projects/debian/debian/tor}" cd "$TORGIT" if [ -n "$(git status --porcelain)" ]; then @@ -115,7 +115,7 @@ git merge --no-ff --commit --no-edit "$tag" dch --newversion "$version" "New upstream version." dch --release '' -git ci -m "New upstream version: $upv" debian/changelog -git co "$branch" +git commit -m "New upstream version: $upv" debian/changelog +git checkout "$branch" git merge --no-ff --commit --no-edit "$merge_branch" git branch -d "$merge_branch" diff -Nru tor-0.4.7.16/debian/rules tor-0.4.9.6/debian/rules --- tor-0.4.7.16/debian/rules 2026-04-05 21:26:56.000000000 +0000 +++ tor-0.4.9.6/debian/rules 2026-04-05 21:26:56.000000000 +0000 @@ -39,7 +39,8 @@ --localstatedir=/var \ --sysconfdir=/etc \ --disable-silent-rules \ - --enable-gcc-warnings-advisory + --enable-gcc-warnings-advisory \ + --enable-gpl override_dh_clean: ! [ -e debian/micro-revision.i ] || rm -f ./micro-revision.i diff -Nru tor-0.4.7.16/debian/tests/control tor-0.4.9.6/debian/tests/control --- tor-0.4.7.16/debian/tests/control 2026-04-05 21:26:56.000000000 +0000 +++ tor-0.4.9.6/debian/tests/control 2026-04-05 21:26:56.000000000 +0000 @@ -4,5 +4,5 @@ # Restrictions: isolation-container Tests: setup-onion-service -Depends: tor, netcat-openbsd, torsocks, curl, onionshare, colorized-logs, unzip, diffutils +Depends: tor, netcat-openbsd, torsocks, curl, onionshare-cli, colorized-logs, diffutils Restrictions: flaky diff -Nru tor-0.4.7.16/debian/tests/setup-onion-service tor-0.4.9.6/debian/tests/setup-onion-service --- tor-0.4.7.16/debian/tests/setup-onion-service 2026-04-05 21:26:56.000000000 +0000 +++ tor-0.4.9.6/debian/tests/setup-onion-service 2026-04-05 21:26:56.000000000 +0000 @@ -89,7 +89,7 @@ echo "================" fi echo "(Re-)Launching onionshare." - pipetty onionshare --debug data > "$ONIONSHARELOG" 2>&1 & + pipetty onionshare-cli --public --verbose data > "$ONIONSHARELOG" 2>&1 & onionsharepid="$!" fi } @@ -139,7 +139,7 @@ timeout=600 while [ "$timeout" -ge 0 ]; do - url=$(grep '^http.*\.onion/' "$ONIONSHARELOG" || true) + url=$(grep --only-matching 'http.*\.onion' "$ONIONSHARELOG" || true) [ -n "$url" ] && break sleep 1 launchshare @@ -156,7 +156,7 @@ --retry 5 \ --max-time 300 \ --location \ - -o data.zip \ + -o data.out \ --stderr - \ "$url/download" && rc=0 || rc=$? @@ -167,9 +167,7 @@ echo "Comparing file." -(mkdir unzip && cd unzip && unzip ../data.zip) - -if cmp data unzip/data; then +if cmp data data.out; then echo "Successfully downloaded file." exit 0 else diff -Nru tor-0.4.7.16/debian/tor.postinst tor-0.4.9.6/debian/tor.postinst --- tor-0.4.7.16/debian/tor.postinst 2026-04-05 21:26:56.000000000 +0000 +++ tor-0.4.9.6/debian/tor.postinst 2026-04-05 21:26:56.000000000 +0000 @@ -39,101 +39,15 @@ fi done -which restorecon >/dev/null 2>&1 && restorecon /var/lib/tor +command -v restorecon >/dev/null 2>&1 && restorecon /var/lib/tor chown debian-tor:debian-tor /var/lib/tor chmod 02700 /var/lib/tor -which restorecon >/dev/null 2>&1 && restorecon /var/log/tor +command -v restorecon >/dev/null 2>&1 && restorecon /var/log/tor chown debian-tor:adm /var/log/tor chmod 02750 /var/log/tor -move_away_keys=0 - -if [ "$1" = "configure" ] && - [ -e /var/lib/tor/keys ] && - [ ! -z "$2" ]; then - if dpkg --compare-versions "$2" lt 0.1.2.19-2; then - move_away_keys=1 - elif dpkg --compare-versions "$2" gt 0.2.0 && - dpkg --compare-versions "$2" lt 0.2.0.26-rc; then - move_away_keys=1 - fi -fi -if [ "$move_away_keys" = "1" ]; then - echo "Retiring possibly compromised keys. See /usr/share/doc/tor/NEWS.Debian.gz" - echo "and /var/lib/tor/keys/moved-away-by-tor-package/README.REALLY for" - echo "further information." - if ! [ -d /var/lib/tor/keys/moved-away-by-tor-package ]; then - mkdir /var/lib/tor/keys/moved-away-by-tor-package - cat > /var/lib/tor/keys/moved-away-by-tor-package/README.REALLY << EOF -It has been discovered that the random number generator in Debian's -openssl package is predictable. This is caused by an incorrect -Debian-specific change to the openssl package (CVE-2008-0166). As a -result, cryptographic key material may be guessable. - -See Debian Security Advisory number 1571 (DSA-1571) for more information: -http://lists.debian.org/debian-security-announce/2008/msg00152.html - -The Debian package for Tor has moved away the onion keys upon package -upgrade, and it will have moved away your identity key if it was created -in the affected timeframe. There is no sure way to automatically tell -if your key was created with an affected openssl library, so this move -is done unconditionally. - -If you have restarted Tor since this change (and the package probably -did that for you already unless you configured your system differently) -then the Tor daemon already created new keys for itself and in all -likelyhood is already working just fine with new keys. - -If you are absolutely certain that your identity key was created with -a non-affected version of openssl and for some reason you have to retain -the old identity, then you can move back the copy of secret_id_key to -/var/lib/tor/keys. Do not move back the onion keys, they were created -only recently since they are temporary keys with a lifetime of only a few -days anyway. - -Sincerely, -Peter Palfrader, Tue, 13 May 2008 13:32:23 +0200 -EOF - fi - for f in secret_onion_key secret_onion_key.old; do - if [ -e /var/lib/tor/keys/"$f" ]; then - mv -v /var/lib/tor/keys/"$f" /var/lib/tor/keys/moved-away-by-tor-package/"$f" - fi - done - if [ -e /var/lib/tor/keys/secret_id_key ]; then - id_mtime=`stat -c %Y /var/lib/tor/keys/secret_id_key` - sept=`date -d '2006-09-10' +%s` - if [ "$id_mtime" -gt "$sept" ] ; then - mv -v /var/lib/tor/keys/secret_id_key /var/lib/tor/keys/moved-away-by-tor-package/secret_id_key - fi - fi -fi - -# clean out apparmor policy files that we shipped with -# Tor 0.2.3.16-alpha-1 in experimental and -# Tor 0.2.3.17-beta-1 in unstable. -if [ "$1" = "configure" ] && - [ -e /etc/apparmor.d/usr.sbin.tor ] && - [ ! -z "$2" ] && - dpkg --compare-versions "$2" le 0.2.3.17-beta-1; then - checksum="`md5sum /etc/apparmor.d/usr.sbin.tor | awk '{print $1}'`" - pkg_md5="`dpkg-query -W -f='${Conffiles}' tor | awk '$1=="/etc/apparmor.d/usr.sbin.tor" {print $2}'`" - if [ "$checksum" = "$pkg_md5" ]; then - if command -v apparmor_parser > /dev/null 2>&1 ; then - apparmor_parser --remove -T -W /etc/apparmor.d/usr.sbin.tor || true - fi - - rm -f "/etc/apparmor.d/usr.sbin.tor" - rm -f "/etc/apparmor.d/disable/usr.sbin.tor" || true - rm -f "/etc/apparmor.d/force-complain/usr.sbin.tor" || true - rm -f "/etc/apparmor.d/local/usr.sbin.tor" || true - rmdir /etc/apparmor.d/local 2>/dev/null || true - rmdir /etc/apparmor.d 2>/dev/null || true - fi -fi - tor_error_init() { echo "Tor was unable to start due to configuration errors."; echo "Please fix them and manually restart the tor daemon using"; diff -Nru tor-0.4.7.16/doc/HACKING/ReleasingTor.md tor-0.4.9.6/doc/HACKING/ReleasingTor.md --- tor-0.4.7.16/doc/HACKING/ReleasingTor.md 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/doc/HACKING/ReleasingTor.md 2026-03-25 14:30:34.000000000 +0000 @@ -53,6 +53,12 @@ (Version bumps apply to `maint`; anything touching the changelog should apply only to `main` or `release`.) + When updating the version, it will be on `maint` branches and so to + merge-forward, use `git merge -s ours`. For instance, if merging the + version change of `maint-0.4.5` into `maint-0.4.6`, do on `maint-0.4.6` + this command: `git merge -s ours maint-0.4.5`. And then you can proceed + with a git-merge-forward. + 2. For the ChangeLog and ReleaseNotes, you need to write a blurb at the top explaining a bit the release. @@ -70,7 +76,7 @@ 1. Run `./build.sh` which will download everything you need, including the latest tarballs from the release CI, and auto-commit the signatures if - the checksum match. You will need to confim the commits. + the checksum match. You will need to confirm the commits. 2. If all is good, `git push origin main` your signatures. @@ -120,26 +126,38 @@ 2. Merge upstream the artifacts from the `patches` job in the `Post-process` stage of the CI release pipeline. + Like step (2.1) above, the `-dev` version bump need to be done manually + with a `git merge -s ours`. + 3. Write and post the release announcement for the `forum.torproject.net` in the `News -> Tor Release Announcement` category. If possible, mention in which Tor Browser version (with dates) the release will be in. This usually only applies to the latest stable. - 4. Inform `tor-talk@lists.torproject.org` with the releasing pointing to + 4. Inform `tor-announce@lists.torproject.org` with the releasing pointing to the Forum. Append the ChangeLog there. We do this until we can automate such post from the forum directly. -### New Stable + 5. Update torproject.org website by submitting a MR to + https://gitlab.torproject.org/tpo/web/tpo - 1. Create the `maint-x.y.z` and `release-x.y.z` branches and update the - `./scripts/git/git-list-tor-branches.sh` with the new version. + The `databags/versions.ini` file is the one to change with the newly + released version(s). - 2. Add the new version in `./scripts/ci/ci-driver.sh`. +### New Stable - 3. Forward port the ChangeLog and ReleaseNotes into main branch. Remove any - change logs of stable releases in ReleaseNotes. + 1. Create the `maint-x.y.z` and `release-x.y.z` branches at the version + tag. Then update the `./scripts/git/git-list-tor-branches.sh` with the + new version. + + 2. Update `./scripts/git/git-list-tor-branches.sh` and + `./scripts/ci/ci-driver.sh` with the new version in `maint-x.y.z` and + then merge forward into main. (If you haven't pushed remotely the new + branches, merge the local branch). + 3. In `main`, bump version to the next series: `tor-x.y.0-alpha-dev` and + then tag it: `git tag -s tor-x.y.0-alpha-dev` ## Appendix: An alternative means to notify packagers diff -Nru tor-0.4.7.16/doc/HACKING/WritingTests.md tor-0.4.9.6/doc/HACKING/WritingTests.md --- tor-0.4.7.16/doc/HACKING/WritingTests.md 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/doc/HACKING/WritingTests.md 2026-03-25 14:30:34.000000000 +0000 @@ -336,7 +336,7 @@ implemented. In either case, make sure to consider common cases *and* edge cases; success -cases and failure csaes. +cases and failure cases. For example, consider testing this function: diff -Nru tor-0.4.7.16/doc/HACKING/tracing/EventsCircuit.md tor-0.4.9.6/doc/HACKING/tracing/EventsCircuit.md --- tor-0.4.7.16/doc/HACKING/tracing/EventsCircuit.md 1970-01-01 00:00:00.000000000 +0000 +++ tor-0.4.9.6/doc/HACKING/tracing/EventsCircuit.md 2026-03-25 14:30:34.000000000 +0000 @@ -0,0 +1,139 @@ +# Circuit Subsystem Trace Events + +The circuit subsystem emits a series of tracing events related to a circuit +object life cycle and its state change. + +This document describes each event as in what data they record and what they +represent. + +## Background + +There are two types of circuits: origin and OR (onion router). Both of them +are derived from a base object called a general circuit. + +- Origin circuits are the ones initiated by tor itself so client or onion + service circuits for instance. + +- OR circuits are the ones going through us that we have not initiated and + thus only seen by relays. + +Many operations are done on the base (general) circuit, and some are specific +to an origin or OR. The following section describes each of them by circuit +type. + +## Trace Events + +For the LTTng tracer, the subsystem name of these events is: `tor_circuit`. + +Also, unless specified otherwise, every event emits a common set of parameters +thus they should always be expected in the following order: + +- `circ_id`: For an origin circuit, this is the global circuit identifier used + in a cell. For an OR circuit, the value is 0. + +- `purpose`: Purpose of the circuit as in what it is used for. Note that this + can change during the lifetime of a circuit. See `CIRCUIT_PURPOSE_*` in + `core/or/circuitlist.h` for an exhaustive list of the possible values. + +- `state`: State of a circuit. This changes during the lifetime of a circuit. + See `CIRCUIT_STATE_*` in `core/or/circuitlist.h` for an exhaustive list of + the possible values. + +Now, the tracing events. + +### General Circuit (`circuit_t`) + +The following events are triggered for the base circuit object and thus apply +to all types of circuits. + + * `free`: A circuit object is freed that is memory is released and not + usable anymore. After this event, no more events will be emitted for the + specific circuit object. + + * `mark_for_close`: A circuit object is marked for close that is scheduled + to be closed in a later mainloop periodic event. + + Extra parameters: + + - `end_reason`: Reason why the circuit is closed. Tor often changes that + reason to something generic sometimes in order to avoid leaking internal + reasons to the end point. Thus, this value can be different from + orig_close_reason. + + - `orig_close_reason`: Original reason why the circuit is closed. That + value never changes and contains the internal reason why we close it. It + is **never** this reason that is sent back on the circuit. + + * `change_purpose`: Purpose change. + + Extra parameters: + + (`purpose` parameter is not present) + + - `old_purpose`: Previous purpose that is no longer. + + - `new_purpose`: New purpose assigned to the circuit. + + * `change_state`: State change. + + Extra parameters: + + (`state` parameter is not present) + + - `old_state`: Previous state that is no longer. + + - `new_state`: New state assigned to the circuit. + +### Origin Circuit (`origin_circuit_t`) + +The following events are triggered only for origin circuits. + + * `new_origin`: New origin circuit has been created meaning it has been + newly allocated, initialized and added to the global list. + + * `establish`: Circuit is being established. This is the initial first step + where the path was selected and a connection to the first hop has been + launched. + + * `cannibalized`: Circuit has been cannibalized. This happens when we have + an already opened unused circuit (preemptive circuits) and it was picked. + + * `first_onion_skin`: First onion skin was sent that is the handshake with + the first hop. + + Extra parameters: + + - `fingerprint`: Identity digest (RSA) of the first hop. + + * `intermediate_onion_skin`: An intermediate onion skin was sent which can + be why any hops after the first one. There is thus `N - 1` of these events + where `N` is the total number of hops in the path. + + Extra parameters: + + - `fingerprint`: Identity digest (RSA) of the next hop. + + * `opened`: Circuit just became opened which means that all hops down the + path have negotiated the handshake between them and us and the circuit is + now ready to send cells. + + * `timeout`: Circuit has timed out that is we waited too long for the + circuit to be built. + + * `idle_timeout`: Circuit has timed out due to idleness. This is controlled + by the MaxCircuitDirtiness parameter which is 10 min by default. + +For the common use case of a 3-hop circuit, the following events should be +seen in this order: + + `new_origin` -> `establish` -> `first_onion_skin` -> + `intermediate_onion_skin` -> `intermediate_onion_skin` -> `opened` + +### OR Circuit (`or_circuit_t`) + +The following events are triggered only for OR circuits. For each of them, the +`circ_id` parameter is not present since it would always be 0. The `purpose` +and `state` remain. + + * `new_or`: New OR circuit has been created meaning it has been newly + allocated, initialized and added to the global list. diff -Nru tor-0.4.7.16/doc/HACKING/tracing/README.md tor-0.4.9.6/doc/HACKING/tracing/README.md --- tor-0.4.7.16/doc/HACKING/tracing/README.md 1970-01-01 00:00:00.000000000 +0000 +++ tor-0.4.9.6/doc/HACKING/tracing/README.md 2026-03-25 14:30:34.000000000 +0000 @@ -0,0 +1,163 @@ +# Tracing + +This document describes how the event tracing subsystem works in tor so +developers can add events to the code base but also hook them to an event +tracing framework (i.e. tracer). + +## WARNING ## + +Tracing the tor daemon **always** generates sensitive data if used in +production (on the public network). + +It **is** ethical for researchers to use tracing for their own tor client (for +example: building paths, timings, or performance). + +It is **NOT** ethical to archive, publish or keep data containing other users' +activity such as relay data or anything that handles users' traffic. This +of course includes any logs below notice level. + +Publishing analysis of tracing data containing user traffic is **NOT** safe +either. + +In other words, tracing data that contains other users's activity is **NOT** +safe to publish in any form. + +## Basics ### + +Tracing is separated in two different concepts. The tracing API and the +tracing probes. + +The API is in `src/lib/trace/` which defines how to call tracepoints in the +tor code. Every C files should include `src/lib/trace/events.h` if they want +to call a tracepoint. + +The probes are what actually record the tracepoint data. Because they often +need to access specific subsystem objects, the probes are within each +subsystem. They are defined in the `trace-probes-.c` files. + +### Events + +A trace event is basically a function from which we can pass any data that we +want to collect. In addition, we specify a context for the event such as the +subsystem and an event name. + +A trace event in tor has the following standard format: + +```c +tor_trace(subsystem, event_name, args...); +``` + +The `subsystem` parameter is the name of the subsystem the trace event is in. +For example that could be "scheduler" or "vote" or "hs". The idea is to add +some context to the event so when we collect them we know where it's coming +from. + +The `event_name` is the name of the event which adds better semantic to the +event. + +The `args` can be any number of arguments we want to collect. + +Here is an example of a possible tracepoint in main(): + +```c +tor_trace(main, init_phase, argc); +``` + +The above is a tracepoint in the `main` subsystem with `init_phase` as the +event name and the `int argc` is passed to the event as one argument. + +How `argc` is collected or used has nothing to do with the instrumentation +(adding trace events to the code). It is the work of the tracer so this is why +the trace events and collection framework (tracer) are decoupled. You _can_ +have trace events without a tracer. + +### Instrumentation ### + +In `src/lib/trace/events.h`, we map the high level `tor_trace()` macro to one +or many enabled instrumentation. + +Currently, we have 3 types of possible instrumentation: + +1. Debug + + This will map every tracepoint to `log_debug()`. However, none of the + arguments will be passed on because we don't know their type nor the string + format of the debug log. The output is standardized like this: + +``` +[debug] __FUNC__: Tracepoint from subsystem hit. +``` + +2. USDT + + User Statically-Defined Tracing (USDT) is a kind of probe which can be + handled by a variety of tracers such as SystemTap, DTrace, perf, eBPF and + ftrace. + + For each tracer, one will need to define the ABI in order for the tracer to + be able to extract the data from the tracepoint objects. For instance, the + tracer needs to know how to print the circuit state of a `circuit_t` + object. + +3. LTTng-UST + + LTTng Userspace is a tracer that has it own type of instrumentation. The + probe definitions are created within the C code and is strongly typed. + + For more information, see https://lttng.org/docs. + +## Build System + +This section describes how the instrumentation is integrated into the build +system of tor. + +By default, every tracing events are disabled in tor that is `tor_trace()` is +a NOP thus has no execution cost time. + +To enable a specific instrumentation, there are configure options: + +1. Debug: `--enable-tracing-instrumentation-debug` + +2. USDT: `--enable-tracing-instrumentation-usdt` + +3. LTTng: `--enable-tracing-instrumentation-lttng` + +They can all be used together or independently. If one of them is set, +`HAVE_TRACING` define is set. And for each instrumentation, a +`USE_TRACING_INSTRUMENTATION_` is set. + +## Adding a Tracepoint ## + +This is pretty easy. Let's say you want to add a trace event in +`src/feature/rend/rendcache.c`, you first need to include this file: + +```c +#include "lib/trace/events.h" +``` + +Then, the `tor_trace()` macro can be used with the specific format detailed +before in a previous section. As an example: + +```c +tor_trace(hs, store_desc_as_client, desc, desc_id); +``` + +For `Debug` instrumentation, you have nothing else to do. + +For `USDT`, instrumentation, you will need to define the probes in a way the +specific tracer can understand. For instance, SystemTap requires you to define +a `tapset` for each tracepoints. + +For `LTTng`, you will need to define the probes in the +`trace-probes-.{c|h}` file. See the `trace-probes-circuit.{c|h}` +file as an example and https://lttng.org/docs/v2.11/#doc-instrumenting. + +## Performance ## + +A word about performance when a tracepoint is enabled. One of the goal of a +tracepoint (USDT, LTTng-UST, ...) is that they can be enabled or disabled. By +default, they are disabled which means the tracer will not record the data but +it has to do a check thus the cost is basically the one of a `branch`. + +If enabled, then the performance depends on the tracer. In the case of +LTTng-UST, the event costs around 110nsec. diff -Nru tor-0.4.7.16/doc/asciidoc-helper.sh tor-0.4.9.6/doc/asciidoc-helper.sh --- tor-0.4.7.16/doc/asciidoc-helper.sh 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/doc/asciidoc-helper.sh 2026-03-25 14:30:34.000000000 +0000 @@ -12,8 +12,10 @@ exit 1 fi -SOURCE_DATE_EPOCH="$(git show --no-patch --format='%ct')" -export SOURCE_DATE_EPOCH +if [ -z "$SOURCE_DATE_EPOCH" ]; then + SOURCE_DATE_EPOCH="$(git -C "$(dirname "$0")" show --no-patch --format='%ct')" + export SOURCE_DATE_EPOCH +fi output=$3 diff -Nru tor-0.4.7.16/doc/include.am tor-0.4.9.6/doc/include.am --- tor-0.4.7.16/doc/include.am 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/doc/include.am 2026-03-25 14:30:34.000000000 +0000 @@ -56,10 +56,10 @@ doc/HACKING/HelpfulTools.md \ doc/HACKING/HowToReview.md \ doc/HACKING/Module.md \ - doc/HACKING/ReleasingTor.md \ - doc/HACKING/WritingTests.md - doc/HACKING/tracing/Tracing.md \ - doc/HACKING/tracing/EventsCircuit.md + doc/HACKING/ReleasingTor.md \ + doc/HACKING/WritingTests.md \ + doc/HACKING/tracing/EventsCircuit.md \ + doc/HACKING/tracing/README.md docdir = @docdir@ diff -Nru tor-0.4.7.16/doc/man/tor-gencert.1.in tor-0.4.9.6/doc/man/tor-gencert.1.in --- tor-0.4.7.16/doc/man/tor-gencert.1.in 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/doc/man/tor-gencert.1.in 2026-03-25 14:30:34.000000000 +0000 @@ -2,12 +2,12 @@ .\" Title: tor-gencert .\" Author: Tor Project, Inc. .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 11/03/2023 +.\" Date: 03/25/2026 .\" Manual: Tor Manual .\" Source: Tor .\" Language: English .\" -.TH "TOR\-GENCERT" "1" "11/03/2023" "Tor" "Tor Manual" +.TH "TOR\-GENCERT" "1" "03/25/2026" "Tor" "Tor Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- diff -Nru tor-0.4.7.16/doc/man/tor-print-ed-signing-cert.1.in tor-0.4.9.6/doc/man/tor-print-ed-signing-cert.1.in --- tor-0.4.7.16/doc/man/tor-print-ed-signing-cert.1.in 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/doc/man/tor-print-ed-signing-cert.1.in 2026-03-25 14:30:34.000000000 +0000 @@ -2,12 +2,12 @@ .\" Title: tor-print-ed-signing-cert .\" Author: Tor Project, Inc. .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 11/03/2023 +.\" Date: 03/25/2026 .\" Manual: Tor Manual .\" Source: Tor .\" Language: English .\" -.TH "TOR\-PRINT\-ED\-SIGN" "1" "11/03/2023" "Tor" "Tor Manual" +.TH "TOR\-PRINT\-ED\-SIGN" "1" "03/25/2026" "Tor" "Tor Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- diff -Nru tor-0.4.7.16/doc/man/tor-resolve.1.in tor-0.4.9.6/doc/man/tor-resolve.1.in --- tor-0.4.7.16/doc/man/tor-resolve.1.in 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/doc/man/tor-resolve.1.in 2026-03-25 14:30:34.000000000 +0000 @@ -2,12 +2,12 @@ .\" Title: tor-resolve .\" Author: Peter Palfrader .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 11/03/2023 +.\" Date: 03/25/2026 .\" Manual: Tor Manual .\" Source: Tor .\" Language: English .\" -.TH "TOR\-RESOLVE" "1" "11/03/2023" "Tor" "Tor Manual" +.TH "TOR\-RESOLVE" "1" "03/25/2026" "Tor" "Tor Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- diff -Nru tor-0.4.7.16/doc/man/tor.1.in tor-0.4.9.6/doc/man/tor.1.in --- tor-0.4.7.16/doc/man/tor.1.in 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/doc/man/tor.1.in 2026-03-25 14:30:34.000000000 +0000 @@ -2,12 +2,12 @@ .\" Title: tor .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 11/03/2023 +.\" Date: 03/25/2026 .\" Manual: Tor Manual .\" Source: Tor .\" Language: English .\" -.TH "TOR" "1" "11/03/2023" "Tor" "Tor Manual" +.TH "TOR" "1" "03/25/2026" "Tor" "Tor Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -220,6 +220,16 @@ directory of your Tor daemon, and make sure that they are owned by the user actually running the Tor daemon on your system\&. .RE .PP +\fB\-\-keygen\-family\fR \fIbasename\fR +.RS 4 +Generate a new family ID key in +\fIbasename\fR\&.secret_family_key\&. To use this key, install it on every relay in your family\&. (Put it in the relay\(cqs +KeyDirectory\&.) Also, store the corresponding family ID in +\fIbasename\fR\&.public_family_id\&. Then enable the corresponding FamilyID option on your relays\&. This command overwrites these files if they already exist\&. See +https://community\&.torproject\&.org/relay/setup/post\-install/family\-ids/ +for more information\&. +.RE +.PP \fB\-\-passphrase\-fd\fR \fIFILEDES\fR .RS 4 File descriptor to read the passphrase from\&. Note that unlike with the tor\-gencert program, the entire file contents are read and used as the passphrase, including any trailing newlines\&. If the file descriptor is not specified, the passphrase is read from the terminal by default\&. @@ -340,6 +350,16 @@ as its command\-line options, and forwards its traffic to it\&. It\(cqs the duty of that proxy to properly forward the traffic to the bridge\&. (Default: none) .RE .PP +\fBConfluxEnabled\fR \fB0\fR|\fB1\fR|\fBauto\fR +.RS 4 +If this option is set to 1, general purpose traffic will use Conflux which is traffic splitting among multiple legs (circuits)\&. Onion services are not supported at the moment\&. Default value is set to "auto" meaning the consensus is used to decide unless set\&. (Default: auto) +.RE +.PP +\fBConfluxClientUX\fR \fBthroughput\fR|\fBlatency\fR|\fBthroughput_lowmem\fR|\fBlatency_lowmem\fR +.RS 4 +This option configures the user experience that the client requests from the exit, for data that the exit sends to the client\&. The default is "throughput", which maximizes throughput\&. "Latency" will tell the exit to only use the circuit with lower latency for all data\&. The lowmem versions minimize queue usage memory at the client\&. (Default: "throughput") +.RE +.PP \fBConnLimit\fR \fINUM\fR .RS 4 The minimum number of file descriptors that must be available to the Tor process before it will start\&. Tor will ask the OS for as many file descriptors as the OS will allow (you can find this by "ulimit \-H \-n")\&. If this number is less than ConnLimit, then Tor will refuse to start\&. @@ -766,12 +786,12 @@ .PP \fBRelayBandwidthBurst\fR \fIN\fR \fBbytes\fR|\fBKBytes\fR|\fBMBytes\fR|\fBGBytes\fR|\fBTBytes\fR|\fBKBits\fR|\fBMBits\fR|\fBGBits\fR|\fBTBits\fR .RS 4 -If not 0, limit the maximum token bucket size (also known as the burst) for _relayed traffic_ to the given number of bytes in each direction\&. They do not include directory fetches by the relay (from authority or other relays), because that is considered "client" activity\&. (Default: 0) +If not 0, limit the maximum token bucket size (also known as the burst) for _relayed traffic_ to the given number of bytes in each direction\&. They do not include directory fetches by the relay (from authority or other relays), because that is considered "client" activity\&. (Default: 0) RelayBandwidthBurst defaults to the value of RelayBandwidthRate if unset\&. .RE .PP \fBRelayBandwidthRate\fR \fIN\fR \fBbytes\fR|\fBKBytes\fR|\fBMBytes\fR|\fBGBytes\fR|\fBTBytes\fR|\fBKBits\fR|\fBMBits\fR|\fBGBits\fR|\fBTBits\fR .RS 4 -If not 0, a separate token bucket limits the average incoming bandwidth usage for _relayed traffic_ on this node to the specified number of bytes per second, and the average outgoing bandwidth usage to that same value\&. Relayed traffic currently is calculated to include answers to directory requests, but that may change in future versions\&. They do not include directory fetches by the relay (from authority or other relays), because that is considered "client" activity\&. (Default: 0) +If not 0, a separate token bucket limits the average incoming bandwidth usage for _relayed traffic_ on this node to the specified number of bytes per second, and the average outgoing bandwidth usage to that same value\&. Relayed traffic currently is calculated to include answers to directory requests, but that may change in future versions\&. They do not include directory fetches by the relay (from authority or other relays), because that is considered "client" activity\&. (Default: 0) RelayBandwidthRate defaults to the value of RelayBandwidthBurst if unset\&. .RE .PP \fBRephistTrackTime\fR \fIN\fR \fBseconds\fR|\fBminutes\fR|\fBhours\fR|\fBdays\fR|\fBweeks\fR @@ -789,7 +809,7 @@ Tor can scrub potentially sensitive strings from log messages (e\&.g\&. addresses) by replacing them with the string [scrubbed]\&. This way logs can still be useful, but they don\(cqt leave behind personally identifying information about what sites a user might have visited\&. -If this option is set to 0, Tor will not perform any scrubbing, if it is set to 1, all potentially sensitive strings are replaced\&. If it is set to relay, all log messages generated when acting as a relay are sanitized, but all messages generated when acting as a client are not\&. Note: Tor may not heed this option when logging at log levels below Notice\&. (Default: 1) +If this option is set to 0, Tor will not perform any scrubbing, if it is set to 1, all potentially sensitive strings are replaced\&. If it is set to relay, all log messages generated when acting as a relay are sanitized, but all messages generated when acting as a client are not\&. Note: Tor may not heed this option when logging at log levels more verbose than Notice\&. (Default: 1) .RE .PP \fBSandbox\fR \fB0\fR|\fB1\fR @@ -891,7 +911,7 @@ .RS 4 .\} .nf -The only protocol supported right now \*(Aqhaproxy\*(Aq\&. This option is only for +The only protocol supported right now is \*(Aqhaproxy\*(Aq\&. This option is only for clients\&. (Default: none) + .fi .if n \{\ @@ -1054,7 +1074,7 @@ to 0 to disable IPv4\&. Note that clients configured with an IPv6 address in a \fBBridge\fR, proxy, or pluggable transportline will try connecting over IPv6 even if \fBClientUseIPv6\fR -is set to 0\&. (Default: 0) +is set to 0\&. (Default: 1) .RE .PP \fBConnectionPadding\fR \fB0\fR|\fB1\fR|\fBauto\fR @@ -2283,6 +2303,14 @@ If ExitRelay is set to "auto", then Tor checks the ExitPolicy, ReducedExitPolicy, and IPv6Exit options\&. If at least one of these options is set, Tor behaves as if ExitRelay were set to 1\&. If none of these exit policy options are set, Tor behaves as if ExitRelay were set to 0\&. (Default: auto) .RE .PP +\fBReevaluateExitPolicy\fR \fB0\fR|\fB1\fR +.RS 4 +If set, reevaluate the exit policy on existing connections when reloading configuration\&. + + +When the exit policy of an exit node change while reloading configuration, connections made prior to this change could violate the new policy\&. By setting this to 1, Tor will check if such connections exist, and mark them for termination\&. (Default: 0) +.RE +.PP \fBExtendAllowPrivateAddresses\fR \fB0\fR|\fB1\fR .RS 4 When this option is enabled, Tor will connect to relays on localhost, RFC1918 addresses, and so on\&. In particular, Tor will make direct OR connections, and Tor routers allow EXTEND requests, to these private addresses\&. (Tor will always allow connections to bridges, proxies, and pluggable transports configured on private addresses\&.) Enabling this option can create security issues; you should probably leave it off\&. (Default: 0) @@ -2331,6 +2359,14 @@ message designed to help developers instrumenting Tor\(cqs main event loop\&. (Default: 0) .RE .PP +\fBMaxHSDirCacheBytes\fR \fIN\fR \fBbytes\fR|\fBKBytes\fR|\fBMBytes\fR|\fBGBytes\fR +.RS 4 +This option configures a threshold of Hidden Service Directory memory consumption above which your Tor relay will begin to prune the least\-frequently accessed hidden service descriptors from the relay\(cqs HSDir cache\&. If set to 0, this will default to 20% of MaxMemInQueues\&. (Default: 0) + + +This pruning used to be done as part of MaxMemInQueues, but it has been decoupled to allow more fine\-grained control of descriptor cache size under DDoS conditions\&. +.RE +.PP \fBMaxMemInQueues\fR \fIN\fR \fBbytes\fR|\fBKBytes\fR|\fBMBytes\fR|\fBGBytes\fR .RS 4 This option configures a threshold above which Tor will assume that it needs to stop queueing or buffering data because it\(cqs about to run out of memory\&. If it hits this threshold, it will begin killing circuits until it has recovered at least 10% of this memory\&. Do not set this option too low, or your relay may be unreliable under load\&. This option only affects some queues, so the actual process size will be larger than this\&. If this option is set to 0, Tor will try to pick a reasonable default based on your system\(cqs physical memory\&. (Default: 0) @@ -2354,6 +2390,29 @@ Note: do not use MyFamily when configuring your Tor instance as a bridge\&. .RE .PP +\fBFamilyId\fR \fIident\fR +.RS 4 +Configure this relay to be part of a family identified by a shared secret family key with the given key identity\&. A corresponding family key must be stored in the relay\(cqs key directory, with a filename ending with "\&.secret_family_key"\&. This option can appear multiple times\&. Family keys are generated with "\-\-keygen\-family"; this also generates the value you should use in the +\fIident\fR +field in a file ending with "\&.public_family_id"\&. For information on generating and installing a family key, see +https://community\&.torproject\&.org/relay/setup/post\-install/family\-ids/ + +In the future, this will be the preferred way for relays to advertise family membership\&. But for now, relay families should configure both this option +\fIand\fR +MyFamily, so older clients will still recognize the relays\*(Aq family membership\&. + +(Note that if the seccomp2 Sandbox feature is enabled, it is not possible to change the key filenames while Tor is running\&.) +.RE +.PP +\fBFamilyId\fR \fB * \fR +.RS 4 +Configure this relay to be part of +\fIevery\fR +family identified by any family ID key found in the family key directory\&. Only filenames ending with "\&.secret\e_family\e_key" are considered\&. Specifying family IDs in this way makes it unnecessary to adjust the configuration file if the family key is rotated, but it increases the likelihood of accidentally using a different set of family keys than the ones you had expected\&. +.RE +.sp +\fBFamilyKeyDirectory\fR \fIdirectory\fR: Configure a directory to use, in place of the key directory, when searching for family ID keys\&. +.PP \fBNickname\fR \fIname\fR .RS 4 Set the server\(cqs nickname to \*(Aqname\*(Aq\&. Nicknames must be between 1 and 19 characters inclusive, and must contain only the characters [a\-zA\-Z0\-9]\&. If not set, @@ -2664,7 +2723,7 @@ .sp -1 .IP \(bu 2.3 .\} -Onionskins are starting to be dropped\&. +A certain ratio of ntor onionskins are dropped\&. .RE .sp .RS 4 @@ -2686,31 +2745,22 @@ .sp -1 .IP \(bu 2.3 .\} -(Exit only) DNS timeout occurs X% of the time over Y seconds (values controlled by consensus parameters, see param\-spec\&.txt)\&. - -If ExtraInfoStatistics is enabled, it can also put two more specific overload lines in the extra\-info document if at least one of these conditions is met: -.RE -.sp -.RS 4 -.ie n \{\ -\h'-04'\(bu\h'+03'\c -.\} -.el \{\ -.sp -1 -.IP \(bu 2.3 -.\} TCP Port exhaustion\&. -.RE .sp +.if n \{\ .RS 4 -.ie n \{\ -\h'-04'\(bu\h'+03'\c .\} -.el \{\ -.sp -1 -.IP \(bu 2.3 +.nf + + +If ExtraInfoStatistics is enabled, it can also put two more specific +overload lines in the extra\-info document if at least one of these +conditions is met: + \- Connection rate limits have been reached (read and write side)\&. + \- File descriptors are exhausted\&. +.fi +.if n \{\ +.RE .\} -Connection rate limits have been reached (read and write side)\&. .RE .RE .PP @@ -2901,9 +2951,39 @@ Refuse establishment of rendezvous points for single hop clients\&. In other words, if a client directly connects to the relay and sends an ESTABLISH_RENDEZVOUS cell, it is silently dropped\&. "auto" means use the consensus parameter\&. If not defined in the consensus, the value is 0\&. (Default: auto) .RE .sp -As for onion services, only one possible mitigation exists\&. It was intended to protect the network first and thus do not help the service availability or reachability\&. +The following options are useful only for a exit relay\&. +.PP +\fBDoSStreamCreationEnabled\fR \fB0\fR|\fB1\fR|\fBauto\fR +.RS 4 +Enable the stream DoS mitigation\&. If set to 1 (enabled), tor will apply rate limit on the creation of new streams and dns requests per circuit\&. "auto" means use the consensus parameter\&. If not defined in the consensus, the value is 0\&. (Default: auto) +.RE +.PP +\fBDoSStreamCreationDefenseType\fR \fINUM\fR +.RS 4 +This is the type of defense applied to a detected circuit or stream for the stream mitigation\&. The possible values are: + +1: No defense\&. + +2: Reject the stream or resolve request\&. + +3: Close the circuit creating too many streams\&. + +"0" means use the consensus parameter\&. If not defined in the consensus, the value is 2\&. (Default: 0) +.RE +.PP +\fBDoSStreamCreationRate\fR \fINUM\fR +.RS 4 +The allowed rate of stream creation from a single circuit per second\&. Coupled with the burst (see below), if the limit is reached, actions can be taken against the stream or circuit (DoSStreamCreationDefenseType)\&. If not defined or set to 0, it is controlled by a consensus parameter\&. If not defined in the consensus, the value is 100\&. (Default: 0) +.RE +.PP +\fBDoSStreamCreationBurst\fR \fINUM\fR +.RS 4 +The allowed burst of stream creation from a circuit per second\&. See the DoSStreamCreationRate for more details on this detection\&. If not defined or set to 0, it is controlled by a consensus parameter\&. If not defined in the consensus, the value is 300\&. (Default: 0) +.RE +.sp +For onion services, mitigations are a work in progress and multiple options are currently available\&. .sp -The mitigation we put in place is a rate limit of the amount of introduction that happens at the introduction point for a service\&. In other words, it rates limit the number of clients that are attempting to reach the service at the introduction point instead of at the service itself\&. +The introduction point defense is a rate limit on the number of introduction requests that will be forwarded to a service by each of its honest introduction point routers\&. This can prevent some types of overwhelming floods from reaching the service, but it will also prevent legitimate clients from establishing new connections\&. .sp The following options are per onion service: .PP @@ -2934,9 +3014,39 @@ .sp This might be too much for your use case or not, fine tuning these values is hard and are likely different for each service operator\&. .sp -Why is this not helping reachability of the service? Because the defenses are at the introduction point, an attacker can easily flood all introduction point rendering the service unavailable due to no client being able to pass through\&. But, the service itself is not overwhelmed with connetions allowing it to function properly for the few clients that were able to go through or other any services running on the same tor instance\&. +Why is this not helping reachability of the service? Because the defenses are at the introduction point, an attacker can easily flood all introduction point rendering the service unavailable due to no client being able to pass through\&. But, the service itself is not overwhelmed with connections allowing it to function properly for the few clients that were able to go through or other any services running on the same tor instance\&. .sp The bottom line is that this protects the network by preventing an onion service to flood the network with new rendezvous circuits that is reducing load on the network\&. +.sp +A secondary mitigation is available, based on prioritized dispatch of rendezvous circuits for new connections\&. The queue is ordered based on effort a client chooses to spend at computing a proof\-of\-work function\&. +.sp +The following options are per onion service: +.PP +\fBHiddenServicePoWDefensesEnabled\fR \fB0\fR|\fB1\fR +.RS 4 +Enable proof\-of\-work based service DoS mitigation\&. If set to 1 (enabled), tor will include parameters for an optional client puzzle in the encrypted portion of this hidden service\(cqs descriptor\&. Incoming rendezvous requests will be prioritized based on the amount of effort a client chooses to make when computing a solution to the puzzle\&. The service will periodically update a suggested amount of effort, based on attack load, and disable the puzzle entirely when the service is not overloaded\&. (Default: 0) +.RE +.PP +\fBHiddenServicePoWQueueRate\fR \fINUM\fR +.RS 4 +The sustained rate of rendezvous requests to dispatch per second from the priority queue\&. Has no effect when proof\-of\-work is disabled\&. If this is set to 0 there\(cqs no explicit limit and we will process requests as quickly as possible\&. (Default: 250) +.RE +.PP +\fBHiddenServicePoWQueueBurst\fR \fINUM\fR +.RS 4 +The maximum burst size for rendezvous requests handled from the priority queue at once\&. (Default: 2500) +.RE +.sp +These options are applicable to both onion services and their clients: +.PP +\fBCompiledProofOfWorkHash\fR \fB0\fR|\fB1\fR|\fBauto\fR +.RS 4 +When proof\-of\-work DoS mitigation is active, both the services themselves and the clients which connect will use a dynamically generated hash function as part of the puzzle computation\&. + +If this option is set to 1, puzzles will only be solved and verified using the compiled implementation (about 20x faster) and we choose to fail rather than using a slower fallback\&. If it\(cqs 0, the compiler will never be used\&. By default, the compiler is always tried if possible but the interpreter is available as a fallback\&. (Default: auto) +.RE +.sp +See also \-\-list\-modules, these proof of work options have no effect unless the "pow" module is enabled at compile time\&. .SH "DIRECTORY AUTHORITY SERVER OPTIONS" .sp The following options enable operation as a directory authority, and control how Tor behaves as a directory authority\&. You should not need to adjust any of them if you\(cqre running a regular relay or exit server on the public Tor network\&. @@ -3077,7 +3187,7 @@ .PP \fBAuthDirRejectRequestsUnderLoad\fR \fB0\fR|\fB1\fR .RS 4 -If set, the directory authority will start rejecting directory requests from non relay connections by sending a 503 error code if it is under bandwidth pressure (reaching the configured limit if any)\&. Relays will always tried to be answered even if this is on\&. (Default: 1) +If set, the directory authority will start rejecting directory requests from non relay connections by sending a 503 error code if it is under bandwidth pressure (reaching the configured limit if any)\&. Relays will always be answered even if this is on\&. (Default: 1) .RE .sp \fBAuthDirBadExitCCs\fR \fICC\fR,\&... @@ -3193,6 +3303,11 @@ should be set too\&. .RE .PP +\fBMinimalAcceptedServerVersion\fR \fISTRING\fR +.RS 4 +STRING is the oldest Tor version accepted by the directory authority for relays and bridge\&. Any older version will be rejected\&. (Default: 0\&.4\&.7\&.0\-alpha\-dev) +.RE +.PP \fBV3AuthDistDelay\fR \fIN\fR \fBseconds\fR|\fBminutes\fR|\fBhours\fR .RS 4 V3 authoritative directories only\&. Configures the server\(cqs preferred delay between publishing its consensus and signature and assuming it has all the signatures from all the other authorities\&. Note that the actual time used is not the server\(cqs preferred time, but the consensus of all preferences\&. (Default: 5 minutes) @@ -3415,7 +3530,7 @@ .\} .nf Revoking a client can be done by removing their "\&.auth" file, however the -revocation will be in effect only after the tor process gets restarted even if +revocation will be in effect only after the tor process gets restarted or if a SIGHUP takes place\&. .fi .if n \{\ @@ -3491,7 +3606,6 @@ TestingDirConnectionMaxStall 30 seconds TestingEnableConnBwEvent 1 TestingEnableCellStatsEvent 1 -RendPostPeriod 2 minutes .fi .if n \{\ .RE @@ -3982,6 +4096,13 @@ file holds the previously generated key, which the relay uses to handle any requests that were made by clients that didn\(cqt have the new one\&. .RE .PP +\fIKeyDirectory\fR/\fIkeyname\fR\fB\&.secret_family_key\fR +.RS 4 +A relay family\(cqs family identity key\&. Used to prove membership in a relay family\&. See +https://community\&.torproject\&.org/relay/setup/post\-install/family\-ids/ +for more information\&. +.RE +.PP \fIDataDirectory\fR/\fBfingerprint\fR .RS 4 Only used by servers\&. Contains the fingerprint of the server\(cqs RSA identity key\&. @@ -3997,6 +4118,11 @@ Only used by bridges\&. Contains the hashed fingerprint of the bridge\(cqs identity key\&. (That is, the hash of the hash of the identity key\&.) .RE .PP +\fIDataDirectory\fR/\fBbridgelines\fR +.RS 4 +Only used by bridges\&. Contains the bridge lines that clients can use to connect using pluggable transports\&. +.RE +.PP \fIDataDirectory\fR/\fBapproved\-routers\fR .RS 4 Only used by authoritative directory servers\&. Each line lists a status and an identity, separated by whitespace\&. Identities can be hex\-encoded RSA fingerprints, or base\-64 encoded ed25519 public keys\&. See the @@ -4071,7 +4197,7 @@ Only used by servers\&. This file is used to collect approximate counts of what fraction of the traffic is hidden service rendezvous traffic, and approximately how many hidden services the relay has seen\&. .RE .PP -\fIDataDirectory\fR/\fBnetworkstatus\-bridges`\fR +\fIDataDirectory\fR/\fBnetworkstatus\-bridges\fR .RS 4 Only used by authoritative bridge directories\&. Contains information about bridges that have self\-reported themselves to the bridge authority\&. .RE diff -Nru tor-0.4.7.16/doc/man/tor.1.txt tor-0.4.9.6/doc/man/tor.1.txt --- tor-0.4.7.16/doc/man/tor.1.txt 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/doc/man/tor.1.txt 2026-03-25 14:30:34.000000000 +0000 @@ -168,6 +168,16 @@ make sure that they are owned by the user actually running the Tor daemon on your system. +[[opt-keygen-family]] **`--keygen-family`** __basename__:: + Generate a new family ID key in __basename__`.secret_family_key`. + To use this key, install it on every relay in your family. + (Put it in the relay's `KeyDirectory`.) + Also, store the corresponding family ID in __basename__`.public_family_id`. + Then enable the corresponding FamilyID option on your relays. + This command overwrites these files if they already exist. + See https://community.torproject.org/relay/setup/post-install/family-ids/ + for more information. + **`--passphrase-fd`** __FILEDES__:: File descriptor to read the passphrase from. Note that unlike with the tor-gencert program, the entire file contents are read and used as @@ -335,7 +345,7 @@ to mess with it. (Default: -1) [[ClientTransportPlugin]] **ClientTransportPlugin** __transport__ socks4|socks5 __IP__:__PORT__:: -**ClientTransportPlugin** __transport__ exec __path-to-binary__ [options]:: +[[ClientTransportPlugin-2]] **ClientTransportPlugin** __transport__ exec __path-to-binary__ [options]:: In its first form, when set along with a corresponding Bridge line, the Tor client forwards its traffic to a SOCKS-speaking proxy on "IP:PORT". (IPv4 addresses should written as-is; IPv6 addresses should be wrapped in @@ -348,6 +358,19 @@ forwards its traffic to it. It's the duty of that proxy to properly forward the traffic to the bridge. (Default: none) +[[ConfluxEnabled]] **ConfluxEnabled** **0**|**1**|**auto**:: + If this option is set to 1, general purpose traffic will use Conflux which + is traffic splitting among multiple legs (circuits). Onion services are not + supported at the moment. Default value is set to "auto" meaning the + consensus is used to decide unless set. (Default: auto) + +[[ConfluxClientUX]] **ConfluxClientUX** **throughput**|**latency**|**throughput_lowmem**|**latency_lowmem**:: + This option configures the user experience that the client requests from + the exit, for data that the exit sends to the client. The default is + "throughput", which maximizes throughput. "Latency" will tell the exit to + only use the circuit with lower latency for all data. The lowmem versions + minimize queue usage memory at the client. (Default: "throughput") + [[ConnLimit]] **ConnLimit** __NUM__:: The minimum number of file descriptors that must be available to the Tor process before it will start. Tor will ask the OS for as many file @@ -860,6 +883,7 @@ \_relayed traffic_ to the given number of bytes in each direction. They do not include directory fetches by the relay (from authority or other relays), because that is considered "client" activity. (Default: 0) + RelayBandwidthBurst defaults to the value of RelayBandwidthRate if unset. [[RelayBandwidthRate]] **RelayBandwidthRate** __N__ **bytes**|**KBytes**|**MBytes**|**GBytes**|**TBytes**|**KBits**|**MBits**|**GBits**|**TBits**:: If not 0, a separate token bucket limits the average incoming bandwidth @@ -869,6 +893,7 @@ requests, but that may change in future versions. They do not include directory fetches by the relay (from authority or other relays), because that is considered "client" activity. (Default: 0) + RelayBandwidthRate defaults to the value of RelayBandwidthBurst if unset. [[RephistTrackTime]] **RephistTrackTime** __N__ **seconds**|**minutes**|**hours**|**days**|**weeks**:: Tells an authority, or other node tracking node reliability and history, @@ -891,7 +916,8 @@ set to 1, all potentially sensitive strings are replaced. If it is set to relay, all log messages generated when acting as a relay are sanitized, but all messages generated when acting as a client are not. - Note: Tor may not heed this option when logging at log levels below Notice. + Note: Tor may not heed this option when logging at log levels more + verbose than Notice. (Default: 1) [[Sandbox]] **Sandbox** **0**|**1**:: @@ -995,7 +1021,7 @@ equivalent option for directory connections, because all Tor client versions that support this option download directory documents via OR connections. + + - The only protocol supported right now 'haproxy'. This option is only for + The only protocol supported right now is 'haproxy'. This option is only for clients. (Default: none) + + The HAProxy version 1 proxy protocol is described in detail at @@ -1172,7 +1198,7 @@ entry nodes over IPv6. For IPv6 only hosts, you need to also set **ClientUseIPv4** to 0 to disable IPv4. Note that clients configured with an IPv6 address in a **Bridge**, proxy, or pluggable transportline will - try connecting over IPv6 even if **ClientUseIPv6** is set to 0. (Default: 0) + try connecting over IPv6 even if **ClientUseIPv6** is set to 0. (Default: 1) [[ConnectionPadding]] **ConnectionPadding** **0**|**1**|**auto**:: This option governs Tor's use of padding to defend against some forms of @@ -2370,6 +2396,16 @@ policy options are set, Tor behaves as if ExitRelay were set to 0. (Default: auto) +[[ReevaluateExitPolicy]] **ReevaluateExitPolicy** **0**|**1**:: + If set, reevaluate the exit policy on existing connections when reloading + configuration. + + + + When the exit policy of an exit node change while reloading configuration, + connections made prior to this change could violate the new policy. By + setting this to 1, Tor will check if such connections exist, and mark them + for termination. + (Default: 0) + [[ExtendAllowPrivateAddresses]] **ExtendAllowPrivateAddresses** **0**|**1**:: When this option is enabled, Tor will connect to relays on localhost, RFC1918 addresses, and so on. In particular, Tor will make direct OR @@ -2414,6 +2450,16 @@ level __notice__ message designed to help developers instrumenting Tor's main event loop. (Default: 0) +[[MaxHSDirCacheBytes]] **MaxHSDirCacheBytes** __N__ **bytes**|**KBytes**|**MBytes**|**GBytes**:: + This option configures a threshold of Hidden Service Directory memory + consumption above which your Tor relay will begin to prune the least-frequently + accessed hidden service descriptors from the relay's HSDir cache. + If set to 0, this will default to 20% of MaxMemInQueues. (Default: 0) + + + + This pruning used to be done as part of MaxMemInQueues, but it has been + decoupled to allow more fine-grained control of descriptor cache size under + DDoS conditions. + [[MaxMemInQueues]] **MaxMemInQueues** __N__ **bytes**|**KBytes**|**MBytes**|**GBytes**:: This option configures a threshold above which Tor will assume that it needs to stop queueing or buffering data because it's about to run out of @@ -2447,6 +2493,40 @@ Note: do not use MyFamily when configuring your Tor instance as a bridge. +[[FamilyId]] **FamilyId** __ident__:: + Configure this relay to be part of a family + identified by a shared secret family key with the given key identity. + A corresponding family key must be stored in the relay's key directory, + with a filename ending with ".secret\_family\_key". + This option can appear multiple times. + Family keys are generated with "--keygen-family"; + this also generates the value you should use in the __ident__ field + in a file ending with ".public\_family\_id". + For information on generating and installing a family + key, see https://community.torproject.org/relay/setup/post-install/family-ids/ + + + In the future, this will be the preferred way for relays + to advertise family membership. + But for now, relay families should configure + both this option _and_ MyFamily, so older clients + will still recognize the relays' family membership. + + + (Note that if the seccomp2 Sandbox feature is enabled, + it is not possible to change the key filenames while Tor is running.) + +[[FamilyIdStar]] **FamilyId** ** * **:: + Configure this relay to be part of _every_ family + identified by any family ID key found in the family key directory. + Only filenames ending with ".secret\_family\_key" are considered. + Specifying family IDs in this way makes it unnecessary to adjust the + configuration file if the family key is rotated, + but it increases the likelihood of accidentally using a different + set of family keys than the ones you had expected. + +[[FamilyKeyDirectory]] **FamilyKeyDirectory** __directory__: + Configure a directory to use, in place of the key directory, + when searching for family ID keys. + [[Nickname]] **Nickname** __name__:: Set the server's nickname to \'name'. Nicknames must be between 1 and 19 characters inclusive, and must contain only the characters [a-zA-Z0-9]. @@ -2780,17 +2860,16 @@ + A relay is considered overloaded if at least one of these conditions is met: - - Onionskins are starting to be dropped. + - A certain ratio of ntor onionskins are dropped. - The OOM was invoked. + - TCP Port exhaustion. - - (Exit only) DNS timeout occurs X% of the time over Y seconds (values - controlled by consensus parameters, see param-spec.txt). + If ExtraInfoStatistics is enabled, it can also put two more specific overload lines in the extra-info document if at least one of these conditions is met: - - TCP Port exhaustion. - Connection rate limits have been reached (read and write side). + - File descriptors are exhausted. [[PaddingStatistics]] **PaddingStatistics** **0**|**1**:: Relays and bridges only. @@ -3012,15 +3091,53 @@ consensus parameter. If not defined in the consensus, the value is 0. (Default: auto) +The following options are useful only for a exit relay. + +[[DoSStreamCreationEnabled]] **DoSStreamCreationEnabled** **0**|**1**|**auto**:: + + Enable the stream DoS mitigation. If set to 1 (enabled), tor will apply + rate limit on the creation of new streams and dns requests per circuit. + "auto" means use the consensus parameter. If not defined in the consensus, + the value is 0. (Default: auto) + +[[DoSStreamCreationDefenseType]] **DoSStreamCreationDefenseType** __NUM__:: + + This is the type of defense applied to a detected circuit or stream for the + stream mitigation. The possible values are: + + + 1: No defense. + + + 2: Reject the stream or resolve request. + + + 3: Close the circuit creating too many streams. + + + "0" means use the consensus parameter. If not defined in the consensus, the value is 2. + (Default: 0) + +[[DoSStreamCreationRate]] **DoSStreamCreationRate** __NUM__:: -As for onion services, only one possible mitigation exists. It was intended to -protect the network first and thus do not help the service availability or -reachability. - -The mitigation we put in place is a rate limit of the amount of introduction -that happens at the introduction point for a service. In other words, it rates -limit the number of clients that are attempting to reach the service at the -introduction point instead of at the service itself. + The allowed rate of stream creation from a single circuit per second. Coupled + with the burst (see below), if the limit is reached, actions can be taken + against the stream or circuit (DoSStreamCreationDefenseType). If not defined or + set to 0, it is controlled by a consensus parameter. If not defined in the + consensus, the value is 100. (Default: 0) + +[[DoSStreamCreationBurst]] **DoSStreamCreationBurst** __NUM__:: + + The allowed burst of stream creation from a circuit per second. + See the DoSStreamCreationRate for more details on this detection. If + not defined or set to 0, it is controlled by a consensus parameter. If not + defined in the consensus, the value is 300. (Default: 0) + + +For onion services, mitigations are a work in progress and multiple options +are currently available. + +The introduction point defense is a rate limit on the number of introduction +requests that will be forwarded to a service by each of its honest +introduction point routers. This can prevent some types of overwhelming floods +from reaching the service, but it will also prevent legitimate clients from +establishing new connections. The following options are per onion service: @@ -3066,7 +3183,7 @@ Why is this not helping reachability of the service? Because the defenses are at the introduction point, an attacker can easily flood all introduction point rendering the service unavailable due to no client being able to pass through. -But, the service itself is not overwhelmed with connetions allowing it to +But, the service itself is not overwhelmed with connections allowing it to function properly for the few clients that were able to go through or other any services running on the same tor instance. @@ -3074,6 +3191,51 @@ service to flood the network with new rendezvous circuits that is reducing load on the network. +A secondary mitigation is available, based on prioritized dispatch of rendezvous +circuits for new connections. The queue is ordered based on effort a client +chooses to spend at computing a proof-of-work function. + +The following options are per onion service: + +[[HiddenServicePoWDefensesEnabled]] **HiddenServicePoWDefensesEnabled** **0**|**1**:: + + Enable proof-of-work based service DoS mitigation. If set to 1 (enabled), + tor will include parameters for an optional client puzzle in the encrypted + portion of this hidden service's descriptor. Incoming rendezvous requests + will be prioritized based on the amount of effort a client chooses to make + when computing a solution to the puzzle. The service will periodically update + a suggested amount of effort, based on attack load, and disable the puzzle + entirely when the service is not overloaded. + (Default: 0) + +[[HiddenServicePoWQueueRate]] **HiddenServicePoWQueueRate** __NUM__:: + + The sustained rate of rendezvous requests to dispatch per second from + the priority queue. Has no effect when proof-of-work is disabled. + If this is set to 0 there's no explicit limit and we will process + requests as quickly as possible. + (Default: 250) + +[[HiddenServicePoWQueueBurst]] **HiddenServicePoWQueueBurst** __NUM__:: + + The maximum burst size for rendezvous requests handled from the + priority queue at once. (Default: 2500) + +These options are applicable to both onion services and their clients: + +[[CompiledProofOfWorkHash]] **CompiledProofOfWorkHash** **0**|**1**|**auto**:: + When proof-of-work DoS mitigation is active, both the services themselves + and the clients which connect will use a dynamically generated hash + function as part of the puzzle computation. + + + If this option is set to 1, puzzles will only be solved and verified using + the compiled implementation (about 20x faster) and we choose to fail rather + than using a slower fallback. If it's 0, the compiler will never be used. + By default, the compiler is always tried if possible but the interpreter is + available as a fallback. (Default: auto) + +See also <>, these proof of work options +have no effect unless the "`pow`" module is enabled at compile time. == DIRECTORY AUTHORITY SERVER OPTIONS @@ -3193,7 +3355,7 @@ If set, the directory authority will start rejecting directory requests from non relay connections by sending a 503 error code if it is under bandwidth pressure (reaching the configured limit if any). Relays will - always tried to be answered even if this is on. (Default: 1) + always be answered even if this is on. (Default: 1) //Out of order because it logically belongs with the other CCs options. [[AuthDirBadExitCCs]] **AuthDirBadExitCCs** __CC__,... + @@ -3311,6 +3473,11 @@ multiple times: the values from multiple lines are spliced together. When this is set then **VersioningAuthoritativeDirectory** should be set too. +[[MinimalAcceptedServerVersion]] **MinimalAcceptedServerVersion** __STRING__:: + STRING is the oldest Tor version accepted by the directory authority for + relays and bridge. Any older version will be rejected. + (Default: 0.4.7.0-alpha-dev) + [[V3AuthDistDelay]] **V3AuthDistDelay** __N__ **seconds**|**minutes**|**hours**:: V3 authoritative directories only. Configures the server's preferred delay between publishing its consensus and signature and assuming it has all the @@ -3532,7 +3699,7 @@ configured, the service will be accessible to anyone with the onion address. Revoking a client can be done by removing their ".auth" file, however the - revocation will be in effect only after the tor process gets restarted even if + revocation will be in effect only after the tor process gets restarted or if a SIGHUP takes place. Client side: @@ -3588,7 +3755,6 @@ TestingDirConnectionMaxStall 30 seconds TestingEnableConnBwEvent 1 TestingEnableCellStatsEvent 1 - RendPostPeriod 2 minutes [[TestingAuthDirTimeToLearnReachability]] **TestingAuthDirTimeToLearnReachability** __N__ **seconds**|**minutes**|**hours**:: After starting as an authority, do not make claims about whether routers @@ -3929,6 +4095,12 @@ generated key, which the relay uses to handle any requests that were made by clients that didn't have the new one. +__KeyDirectory__/__keyname__**`.secret_family_key`**:: + A relay family's family identity key. + Used to prove membership in a relay family. + See https://community.torproject.org/relay/setup/post-install/family-ids/ + for more information. + __DataDirectory__/**`fingerprint`**:: Only used by servers. Contains the fingerprint of the server's RSA identity key. @@ -3941,6 +4113,10 @@ Only used by bridges. Contains the hashed fingerprint of the bridge's identity key. (That is, the hash of the hash of the identity key.) +__DataDirectory__/**`bridgelines`**:: + Only used by bridges. Contains the bridge lines that clients can use to + connect using pluggable transports. + __DataDirectory__/**`approved-routers`**:: Only used by authoritative directory servers. Each line lists a status and an identity, separated by whitespace. Identities can be hex-encoded RSA @@ -4006,7 +4182,7 @@ of what fraction of the traffic is hidden service rendezvous traffic, and approximately how many hidden services the relay has seen. -__DataDirectory__/**networkstatus-bridges`**:: +__DataDirectory__/**`networkstatus-bridges`**:: Only used by authoritative bridge directories. Contains information about bridges that have self-reported themselves to the bridge authority. diff -Nru tor-0.4.7.16/doc/man/tor.html.in tor-0.4.9.6/doc/man/tor.html.in --- tor-0.4.7.16/doc/man/tor.html.in 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/doc/man/tor.html.in 2026-03-25 14:30:34.000000000 +0000 @@ -1008,6 +1008,21 @@ daemon on your system.

+ --keygen-family basename +
+
+

+ Generate a new family ID key in basename.secret_family_key. + To use this key, install it on every relay in your family. + (Put it in the relay’s KeyDirectory.) + Also, store the corresponding family ID in basename.public_family_id. + Then enable the corresponding FamilyID option on your relays. + This command overwrites these files if they already exist. + See https://community.torproject.org/relay/setup/post-install/family-ids/ + for more information. +

+
+
--passphrase-fd FILEDES
@@ -1236,7 +1251,7 @@ ClientTransportPlugin transport socks4|socks5 IP:PORT
-ClientTransportPlugin transport exec path-to-binary [options] + ClientTransportPlugin transport exec path-to-binary [options]

@@ -1254,6 +1269,29 @@

+ ConfluxEnabled 0|1|auto +
+
+

+ If this option is set to 1, general purpose traffic will use Conflux which + is traffic splitting among multiple legs (circuits). Onion services are not + supported at the moment. Default value is set to "auto" meaning the + consensus is used to decide unless set. (Default: auto) +

+
+
+ ConfluxClientUX throughput|latency|throughput_lowmem|latency_lowmem +
+
+

+ This option configures the user experience that the client requests from + the exit, for data that the exit sends to the client. The default is + "throughput", which maximizes throughput. "Latency" will tell the exit to + only use the circuit with lower latency for all data. The lowmem versions + minimize queue usage memory at the client. (Default: "throughput") +

+
+
ConnLimit NUM
@@ -2072,6 +2110,7 @@ _relayed traffic_ to the given number of bytes in each direction. They do not include directory fetches by the relay (from authority or other relays), because that is considered "client" activity. (Default: 0) + RelayBandwidthBurst defaults to the value of RelayBandwidthRate if unset.

@@ -2086,6 +2125,7 @@ requests, but that may change in future versions. They do not include directory fetches by the relay (from authority or other relays), because that is considered "client" activity. (Default: 0) + RelayBandwidthRate defaults to the value of RelayBandwidthBurst if unset.

@@ -2123,7 +2163,8 @@ set to 1, all potentially sensitive strings are replaced. If it is set to relay, all log messages generated when acting as a relay are sanitized, but all messages generated when acting as a client are not. - Note: Tor may not heed this option when logging at log levels below Notice. + Note: Tor may not heed this option when logging at log levels more + verbose than Notice. (Default: 1)

@@ -2276,7 +2317,7 @@

-
The only protocol supported right now 'haproxy'. This option is only for
+
The only protocol supported right now is 'haproxy'. This option is only for
 clients. (Default: none) +
@@ -2569,7 +2610,7 @@ entry nodes over IPv6. For IPv6 only hosts, you need to also set ClientUseIPv4 to 0 to disable IPv4. Note that clients configured with an IPv6 address in a Bridge, proxy, or pluggable transportline will - try connecting over IPv6 even if ClientUseIPv6 is set to 0. (Default: 0) + try connecting over IPv6 even if ClientUseIPv6 is set to 0. (Default: 1)

@@ -4394,6 +4435,21 @@

+ ReevaluateExitPolicy 0|1 +
+
+

+ If set, reevaluate the exit policy on existing connections when reloading + configuration.
+
+ When the exit policy of an exit node change while reloading configuration, + connections made prior to this change could violate the new policy. By + setting this to 1, Tor will check if such connections exist, and mark them + for termination. + (Default: 0) +

+
+
ExtendAllowPrivateAddresses 0|1
@@ -4478,6 +4534,21 @@

+ MaxHSDirCacheBytes N bytes|KBytes|MBytes|GBytes +
+
+

+ This option configures a threshold of Hidden Service Directory memory + consumption above which your Tor relay will begin to prune the least-frequently + accessed hidden service descriptors from the relay’s HSDir cache. + If set to 0, this will default to 20% of MaxMemInQueues. (Default: 0)
+
+ This pruning used to be done as part of MaxMemInQueues, but it has been + decoupled to allow more fine-grained control of descriptor cache size under + DDoS conditions. +

+
+
MaxMemInQueues N bytes|KBytes|MBytes|GBytes
@@ -4526,6 +4597,51 @@

+ FamilyId ident +
+
+

+ Configure this relay to be part of a family + identified by a shared secret family key with the given key identity. + A corresponding family key must be stored in the relay’s key directory, + with a filename ending with ".secret_family_key". + This option can appear multiple times. + Family keys are generated with "--keygen-family"; + this also generates the value you should use in the ident field + in a file ending with ".public_family_id". + For information on generating and installing a family + key, see https://community.torproject.org/relay/setup/post-install/family-ids/ +
+ In the future, this will be the preferred way for relays + to advertise family membership. + But for now, relay families should configure + both this option and MyFamily, so older clients + will still recognize the relays' family membership. +
+ (Note that if the seccomp2 Sandbox feature is enabled, + it is not possible to change the key filenames while Tor is running.) +

+
+
+ FamilyId * +
+
+

+ Configure this relay to be part of every family + identified by any family ID key found in the family key directory. + Only filenames ending with ".secret\_family\_key" are considered. + Specifying family IDs in this way makes it unnecessary to adjust the + configuration file if the family key is rotated, + but it increases the likelihood of accidentally using a different + set of family keys than the ones you had expected. +

+
+ +

FamilyKeyDirectory directory: + Configure a directory to use, in place of the key directory, + when searching for family ID keys.

+
+
Nickname name
@@ -5043,7 +5159,7 @@
  • -Onionskins are starting to be dropped. +A certain ratio of ntor onionskins are dropped.

  • @@ -5053,23 +5169,17 @@
  • -(Exit only) DNS timeout occurs X% of the time over Y seconds (values - controlled by consensus parameters, see param-spec.txt). -
    - If ExtraInfoStatistics is enabled, it can also put two more specific - overload lines in the extra-info document if at least one of these - conditions is met: -

    -
  • -
  • -

    TCP Port exhaustion.

    -
  • -
  • -

    -Connection rate limits have been reached (read and write side). -

    +
    +
    +
     +
    +If ExtraInfoStatistics is enabled, it can also put two more specific
    +overload lines in the extra-info document if at least one of these
    +conditions is met:
    +    - Connection rate limits have been reached (read and write side).
    +    - File descriptors are exhausted.
    +
@@ -5392,13 +5502,68 @@

-

As for onion services, only one possible mitigation exists. It was intended to -protect the network first and thus do not help the service availability or -reachability.

-

The mitigation we put in place is a rate limit of the amount of introduction -that happens at the introduction point for a service. In other words, it rates -limit the number of clients that are attempting to reach the service at the -introduction point instead of at the service itself.

+

The following options are useful only for a exit relay.

+
+
+ DoSStreamCreationEnabled 0|1|auto +
+
+

+ Enable the stream DoS mitigation. If set to 1 (enabled), tor will apply + rate limit on the creation of new streams and dns requests per circuit. + "auto" means use the consensus parameter. If not defined in the consensus, + the value is 0. (Default: auto) +

+
+
+ DoSStreamCreationDefenseType NUM +
+
+

+ This is the type of defense applied to a detected circuit or stream for the + stream mitigation. The possible values are: +
+ 1: No defense. +
+ 2: Reject the stream or resolve request. +
+ 3: Close the circuit creating too many streams. +
+ "0" means use the consensus parameter. If not defined in the consensus, the value is 2. + (Default: 0) +

+
+
+ DoSStreamCreationRate NUM +
+
+

+ The allowed rate of stream creation from a single circuit per second. Coupled + with the burst (see below), if the limit is reached, actions can be taken + against the stream or circuit (DoSStreamCreationDefenseType). If not defined or + set to 0, it is controlled by a consensus parameter. If not defined in the + consensus, the value is 100. (Default: 0) +

+
+
+ DoSStreamCreationBurst NUM +
+
+

+ The allowed burst of stream creation from a circuit per second. + See the DoSStreamCreationRate for more details on this detection. If + not defined or set to 0, it is controlled by a consensus parameter. If not + defined in the consensus, the value is 300. (Default: 0) +

+
+
+

For onion services, mitigations are a work in progress and multiple options +are currently available.

+

The introduction point defense is a rate limit on the number of introduction +requests that will be forwarded to a service by each of its honest +introduction point routers. This can prevent some types of overwhelming floods +from reaching the service, but it will also prevent legitimate clients from +establishing new connections.

The following options are per onion service:

@@ -5457,12 +5622,75 @@

Why is this not helping reachability of the service? Because the defenses are at the introduction point, an attacker can easily flood all introduction point rendering the service unavailable due to no client being able to pass through. -But, the service itself is not overwhelmed with connetions allowing it to +But, the service itself is not overwhelmed with connections allowing it to function properly for the few clients that were able to go through or other any services running on the same tor instance.

The bottom line is that this protects the network by preventing an onion service to flood the network with new rendezvous circuits that is reducing load on the network.

+

A secondary mitigation is available, based on prioritized dispatch of rendezvous +circuits for new connections. The queue is ordered based on effort a client +chooses to spend at computing a proof-of-work function.

+

The following options are per onion service:

+
+
+ HiddenServicePoWDefensesEnabled 0|1 +
+
+

+ Enable proof-of-work based service DoS mitigation. If set to 1 (enabled), + tor will include parameters for an optional client puzzle in the encrypted + portion of this hidden service’s descriptor. Incoming rendezvous requests + will be prioritized based on the amount of effort a client chooses to make + when computing a solution to the puzzle. The service will periodically update + a suggested amount of effort, based on attack load, and disable the puzzle + entirely when the service is not overloaded. + (Default: 0) +

+
+
+ HiddenServicePoWQueueRate NUM +
+
+

+ The sustained rate of rendezvous requests to dispatch per second from + the priority queue. Has no effect when proof-of-work is disabled. + If this is set to 0 there’s no explicit limit and we will process + requests as quickly as possible. + (Default: 250) +

+
+
+ HiddenServicePoWQueueBurst NUM +
+
+

+ The maximum burst size for rendezvous requests handled from the + priority queue at once. (Default: 2500) +

+
+
+

These options are applicable to both onion services and their clients:

+
+
+ CompiledProofOfWorkHash 0|1|auto +
+
+

+ When proof-of-work DoS mitigation is active, both the services themselves + and the clients which connect will use a dynamically generated hash + function as part of the puzzle computation. +
+ If this option is set to 1, puzzles will only be solved and verified using + the compiled implementation (about 20x faster) and we choose to fail rather + than using a slower fallback. If it’s 0, the compiler will never be used. + By default, the compiler is always tried if possible but the interpreter is + available as a fallback. (Default: auto) +

+
+
+

See also --list-modules, these proof of work options +have no effect unless the "pow" module is enabled at compile time.

@@ -5667,7 +5895,7 @@ If set, the directory authority will start rejecting directory requests from non relay connections by sending a 503 error code if it is under bandwidth pressure (reaching the configured limit if any). Relays will - always tried to be answered even if this is on. (Default: 1) + always be answered even if this is on. (Default: 1)

@@ -5878,6 +6106,16 @@

+ MinimalAcceptedServerVersion STRING +
+
+

+ STRING is the oldest Tor version accepted by the directory authority for + relays and bridge. Any older version will be rejected. + (Default: 0.4.7.0-alpha-dev) +

+
+
V3AuthDistDelay N seconds|minutes|hours
@@ -6213,7 +6451,7 @@
Revoking a client can be done by removing their ".auth" file, however the
-revocation will be in effect only after the tor process gets restarted even if
+revocation will be in effect only after the tor process gets restarted or if
 a SIGHUP takes place.

Client side:

@@ -6278,8 +6516,7 @@ TestingClientMaxIntervalWithoutRequest 5 seconds TestingDirConnectionMaxStall 30 seconds TestingEnableConnBwEvent 1 -TestingEnableCellStatsEvent 1 -RendPostPeriod 2 minutes
+TestingEnableCellStatsEvent 1
@@ -6972,6 +7209,17 @@

+KeyDirectory/keyname.secret_family_key +
+
+

+ A relay family’s family identity key. + Used to prove membership in a relay family. + See https://community.torproject.org/relay/setup/post-install/family-ids/ + for more information. +

+
+
DataDirectory/fingerprint
@@ -6999,6 +7247,15 @@

+DataDirectory/bridgelines +
+
+

+ Only used by bridges. Contains the bridge lines that clients can use to + connect using pluggable transports. +

+
+
DataDirectory/approved-routers
@@ -7129,7 +7386,7 @@

-DataDirectory/networkstatus-bridges` +DataDirectory/networkstatus-bridges

diff -Nru tor-0.4.7.16/doc/man/torify.1.in tor-0.4.9.6/doc/man/torify.1.in --- tor-0.4.7.16/doc/man/torify.1.in 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/doc/man/torify.1.in 2026-03-25 14:30:34.000000000 +0000 @@ -2,12 +2,12 @@ .\" Title: torify .\" Author: Tor Project, Inc. .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 11/03/2023 +.\" Date: 03/25/2026 .\" Manual: Tor Manual .\" Source: Tor .\" Language: English .\" -.TH "TORIFY" "1" "11/03/2023" "Tor" "Tor Manual" +.TH "TORIFY" "1" "03/25/2026" "Tor" "Tor Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- diff -Nru tor-0.4.7.16/m4/ax_check_compile_flag.m4 tor-0.4.9.6/m4/ax_check_compile_flag.m4 --- tor-0.4.7.16/m4/ax_check_compile_flag.m4 1970-01-01 00:00:00.000000000 +0000 +++ tor-0.4.9.6/m4/ax_check_compile_flag.m4 2026-03-25 14:30:34.000000000 +0000 @@ -0,0 +1,53 @@ +# =========================================================================== +# https://www.gnu.org/software/autoconf-archive/ax_check_compile_flag.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_CHECK_COMPILE_FLAG(FLAG, [ACTION-SUCCESS], [ACTION-FAILURE], [EXTRA-FLAGS], [INPUT]) +# +# DESCRIPTION +# +# Check whether the given FLAG works with the current language's compiler +# or gives an error. (Warnings, however, are ignored) +# +# ACTION-SUCCESS/ACTION-FAILURE are shell commands to execute on +# success/failure. +# +# If EXTRA-FLAGS is defined, it is added to the current language's default +# flags (e.g. CFLAGS) when the check is done. The check is thus made with +# the flags: "CFLAGS EXTRA-FLAGS FLAG". This can for example be used to +# force the compiler to issue an error when a bad flag is given. +# +# INPUT gives an alternative input source to AC_COMPILE_IFELSE. +# +# NOTE: Implementation based on AX_CFLAGS_GCC_OPTION. Please keep this +# macro in sync with AX_CHECK_{PREPROC,LINK}_FLAG. +# +# LICENSE +# +# Copyright (c) 2008 Guido U. Draheim +# Copyright (c) 2011 Maarten Bosmans +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice +# and this notice are preserved. This file is offered as-is, without any +# warranty. + +#serial 7 + +AC_DEFUN([AX_CHECK_COMPILE_FLAG], +[AC_PREREQ(2.64)dnl for _AC_LANG_PREFIX and AS_VAR_IF +AS_VAR_PUSHDEF([CACHEVAR],[ax_cv_check_[]_AC_LANG_ABBREV[]flags_$4_$1])dnl +AC_CACHE_CHECK([whether the _AC_LANG compiler accepts $1], CACHEVAR, [ + ax_check_save_flags=$[]_AC_LANG_PREFIX[]FLAGS + _AC_LANG_PREFIX[]FLAGS="$[]_AC_LANG_PREFIX[]FLAGS $4 $1" + AC_COMPILE_IFELSE([m4_default([$5],[AC_LANG_PROGRAM()])], + [AS_VAR_SET(CACHEVAR,[yes])], + [AS_VAR_SET(CACHEVAR,[no])]) + _AC_LANG_PREFIX[]FLAGS=$ax_check_save_flags]) +AS_VAR_IF(CACHEVAR,yes, + [m4_default([$2], :)], + [m4_default([$3], :)]) +AS_VAR_POPDEF([CACHEVAR])dnl +])dnl AX_CHECK_COMPILE_FLAGS diff -Nru tor-0.4.7.16/orconfig.h.in tor-0.4.9.6/orconfig.h.in --- tor-0.4.7.16/orconfig.h.in 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/orconfig.h.in 2026-03-25 14:30:34.000000000 +0000 @@ -6,7 +6,7 @@ /* All assert failures are fatal */ #undef ALL_BUGS_ARE_FATAL -/* # for 0.4.7.16 Approximate date when this software was released. (Updated +/* # for 0.4.9.6 Approximate date when this software was released. (Updated when the version changes.) */ #undef APPROX_RELEASE_DATE @@ -47,6 +47,9 @@ hardening */ #undef ENABLE_FRAGILE_HARDENING +/* Defined if tor is building in GPL-licensed mode. */ +#undef ENABLE_GPL + /* Defined if we default to host local appdata paths on Windows */ #undef ENABLE_LOCAL_APPDATA @@ -65,6 +68,9 @@ /* Define if enum is always signed */ #undef ENUM_VALS_ARE_SIGNED +/* We statically link with EquiX */ +#undef EQUIX_STATIC + /* Define to nothing if C supports flexible array members, and to 1 if it does not. That way, with a declaration like `struct s { int n; double d[FLEXIBLE_ARRAY_MEMBER]; };', the struct hack can be used with pre-C99 @@ -74,6 +80,12 @@ MSVC and with C++ compilers. */ #undef FLEXIBLE_ARRAY_MEMBER +/* Output size in bytes for the internal customization of HashX */ +#undef HASHX_SIZE + +/* We statically link with HashX */ +#undef HASHX_STATIC + /* Define to 1 if you have the `accept4' function. */ #undef HAVE_ACCEPT4 @@ -83,6 +95,9 @@ /* defined if we have the fallthrough attribute. */ #undef HAVE_ATTR_FALLTHROUGH +/* defined if we have the nonstring attribute. */ +#undef HAVE_ATTR_NONSTRING + /* Define to 1 if you have the `backtrace' function. */ #undef HAVE_BACKTRACE @@ -129,9 +144,6 @@ /* Define to 1 if you have the header file. */ #undef HAVE_ERRNO_H -/* Define to 1 if you have the `ERR_load_KDF_strings' function. */ -#undef HAVE_ERR_LOAD_KDF_STRINGS - /* Define to 1 if you have the `evdns_base_get_nameserver_addr' function. */ #undef HAVE_EVDNS_BASE_GET_NAMESERVER_ADDR @@ -344,6 +356,9 @@ /* Compile with directory cache support */ #undef HAVE_MODULE_DIRCACHE +/* Compile with proof-of-work support */ +#undef HAVE_MODULE_POW + /* Compile with Relay feature support */ #undef HAVE_MODULE_RELAY @@ -366,6 +381,9 @@ /* Define to 1 if you have the header file. */ #undef HAVE_NET_PFVAR_H +/* Define to 1 if you have the header file. */ +#undef HAVE_OPENSSL_ENGINE_H + /* Define to 1 if you have the `pipe' function. */ #undef HAVE_PIPE @@ -426,29 +444,11 @@ /* Define to 1 if the system has the type `ssize_t'. */ #undef HAVE_SSIZE_T -/* Define to 1 if you have the `SSL_CIPHER_find' function. */ -#undef HAVE_SSL_CIPHER_FIND - -/* Define to 1 if you have the `SSL_CTX_set1_groups_list' function. */ -#undef HAVE_SSL_CTX_SET1_GROUPS_LIST - /* Define to 1 if you have the `SSL_CTX_set_security_level' function. */ #undef HAVE_SSL_CTX_SET_SECURITY_LEVEL -/* Define to 1 if you have the `SSL_get_client_ciphers' function. */ -#undef HAVE_SSL_GET_CLIENT_CIPHERS - -/* Define to 1 if you have the `SSL_get_client_random' function. */ -#undef HAVE_SSL_GET_CLIENT_RANDOM - -/* Define to 1 if you have the `SSL_get_server_random' function. */ -#undef HAVE_SSL_GET_SERVER_RANDOM - -/* Define to 1 if you have the `SSL_SESSION_get_master_key' function. */ -#undef HAVE_SSL_SESSION_GET_MASTER_KEY - -/* Define to 1 if `state' is a member of `SSL'. */ -#undef HAVE_SSL_STATE +/* Define to 1 if you have the `SSL_set_ciphersuites' function. */ +#undef HAVE_SSL_SET_CIPHERSUITES /* Define to 1 if you have the `statvfs' function. */ #undef HAVE_STATVFS @@ -510,10 +510,6 @@ /* Define to 1 if `sin_len' is a member of `struct sockaddr_in'. */ #undef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN -/* Define to 1 if `get_cipher_by_char' is a member of `struct ssl_method_st'. - */ -#undef HAVE_STRUCT_SSL_METHOD_ST_GET_CIPHER_BY_CHAR - /* Define to 1 if `tcpi_snd_mss' is a member of `struct tcp_info'. */ #undef HAVE_STRUCT_TCP_INFO_TCPI_SND_MSS @@ -619,9 +615,6 @@ /* Define to 1 if you have the `timingsafe_memcmp' function. */ #undef HAVE_TIMINGSAFE_MEMCMP -/* Define to 1 if you have the `TLS_method' function. */ -#undef HAVE_TLS_METHOD - /* Compiled with tracing support */ #undef HAVE_TRACING @@ -676,6 +669,9 @@ /* Define to 1 iff malloc(0) returns a pointer */ #undef MALLOC_ZERO_WORKS +/* whether nss defines ecdh_hybrid key exchange. */ +#undef NSS_HAS_ECDH_HYBRID + /* Define to 1 iff memset(0) sets pointers to NULL */ #undef NULL_REP_IS_ZERO_BYTES @@ -727,9 +723,6 @@ /* The size of `pid_t', as computed by sizeof. */ #undef SIZEOF_PID_T -/* The size of `SHA_CTX', as computed by sizeof. */ -#undef SIZEOF_SHA_CTX - /* The size of `short', as computed by sizeof. */ #undef SIZEOF_SHORT diff -Nru tor-0.4.7.16/scripts/maint/checkOptionDocs.pl.in tor-0.4.9.6/scripts/maint/checkOptionDocs.pl.in --- tor-0.4.7.16/scripts/maint/checkOptionDocs.pl.in 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/scripts/maint/checkOptionDocs.pl.in 2026-03-25 14:30:34.000000000 +0000 @@ -41,9 +41,16 @@ my $considerNextLine = 0; open(F, "@abs_top_srcdir@/doc/man/tor.1.txt") or die; while () { - if (m!^(?:\[\[([A-za-z0-9_]+)\]\] *)?\*\*([A-Za-z0-9_]+)\*\*!) { + if (m!^(?:\[\[([A-za-z0-9_]+)\]\] *)?\*\*([A-Za-z0-9_]+)\*\*! && $considerNextLine) { $manPageOptions{$2} = 1; print "Missing an anchor: $2\n" unless (defined $1 or $2 eq 'tor'); + $considerNextLine = 1; + } elsif (m!^\s*$! or + m!^\s*\+\s*$! or + m!^\s*//!) { + $considerNextLine = 1; + } else { + $considerNextLine = 0; } } close F; diff -Nru tor-0.4.7.16/scripts/maint/practracker/practracker.py tor-0.4.9.6/scripts/maint/practracker/practracker.py --- tor-0.4.7.16/scripts/maint/practracker/practracker.py 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/scripts/maint/practracker/practracker.py 2026-03-25 14:30:34.000000000 +0000 @@ -24,7 +24,7 @@ from __future__ import print_function from __future__ import unicode_literals -import codecs, os, sys +import io, os, sys import metrics import util @@ -64,7 +64,7 @@ ####################################################### def open_file(fname): - return codecs.open(fname, 'r', encoding='utf-8') + return io.open(fname, 'r', encoding='utf-8') def consider_file_size(fname, f): """Consider the size of 'f' and yield an FileSizeItem for it. diff -Nru tor-0.4.7.16/src/app/config/auth_dirs.inc tor-0.4.9.6/src/app/config/auth_dirs.inc --- tor-0.4.7.16/src/app/config/auth_dirs.inc 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/app/config/auth_dirs.inc 2026-03-25 14:30:34.000000000 +0000 @@ -2,9 +2,9 @@ "v3ident=F533C81CEF0BC0267857C99B2F471ADF249FA232 " "128.31.0.39:9231 1A25C6358DB91342AA51720A5038B72742732498", "tor26 orport=443 " - "v3ident=14C131DFC5C6F93646BE72FA1401C02A8DF2E8B4 " - "ipv6=[2001:858:2:2:aabb:0:563b:1526]:443 " - "86.59.21.38:80 847B 1F85 0344 D787 6491 A548 92F9 0493 4E4E B85D", + "v3ident=2F3DF9CA0E5D36F2685A2DA67184EB8DCB8CBA8C " + "ipv6=[2a02:16a8:662:2203::1]:443 " + "217.196.147.77:80 FAA4 BCA4 A6AC 0FB4 CA2F 8AD5 A11D 9E12 2BA8 94F6", "dizum orport=443 " "v3ident=E8A9C45EDE6D711294FADF8E7951F4DE6CA56B58 " "45.66.35.11:80 7EA6 EAD6 FD83 083C 538F 4403 8BBF A077 587D D755", @@ -29,3 +29,6 @@ "v3ident=27102BC123E7AF1D4741AE047E160C91ADC76B21 " "ipv6=[2620:13:4000:6000::1000:118]:443 " "204.13.164.118:80 24E2 F139 121D 4394 C54B 5BCC 368B 3B41 1857 C413", +"faravahar orport=443 " + "v3ident=70849B868D606BAECFB6128C5E3D782029AA394F " + "216.218.219.41:80 E3E4 2D35 F801 C9D5 AB23 584E 0025 D56F E2B3 3396", diff -Nru tor-0.4.7.16/src/app/config/config.c tor-0.4.9.6/src/app/config/config.c --- tor-0.4.7.16/src/app/config/config.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/app/config/config.c 2026-03-25 14:30:34.000000000 +0000 @@ -77,6 +77,7 @@ #include "core/or/circuitmux_ewma.h" #include "core/or/circuitstats.h" #include "core/or/connection_edge.h" +#include "trunnel/conflux.h" #include "core/or/dos.h" #include "core/or/policies.h" #include "core/or/relay.h" @@ -88,9 +89,11 @@ #include "feature/control/control.h" #include "feature/control/control_auth.h" #include "feature/control/control_events.h" +#include "feature/dircache/dirserv.h" #include "feature/dirclient/dirclient_modes.h" #include "feature/hibernate/hibernate.h" #include "feature/hs/hs_config.h" +#include "feature/hs/hs_pow.h" #include "feature/metrics/metrics.h" #include "feature/nodelist/dirlist.h" #include "feature/nodelist/networkstatus.h" @@ -179,7 +182,7 @@ #define MAX_CONSTRAINED_TCP_BUFFER 262144 /* 256k */ /** macro to help with the bulk rename of *DownloadSchedule to - * *DowloadInitialDelay . */ + * *DownloadInitialDelay . */ #ifndef COCCI #define DOWNLOAD_SCHEDULE(name) \ { (#name "DownloadSchedule"), (#name "DownloadInitialDelay"), 0, 1 } @@ -375,8 +378,12 @@ OBSOLETE("ClientAutoIPv6ORPort"), V(ClientRejectInternalAddresses, BOOL, "1"), V(ClientTransportPlugin, LINELIST, NULL), - V(ClientUseIPv6, BOOL, "0"), + V(ClientUseIPv6, BOOL, "1"), V(ClientUseIPv4, BOOL, "1"), + V(CompiledProofOfWorkHash, AUTOBOOL, "auto"), + V(ConfluxEnabled, AUTOBOOL, "auto"), + VAR("ConfluxClientUX", STRING, ConfluxClientUX_option, + "throughput"), V(ConnLimit, POSINT, "1000"), V(ConnDirectionStatistics, BOOL, "0"), V(ConstrainedSockets, BOOL, "0"), @@ -463,6 +470,9 @@ V(UseDefaultFallbackDirs, BOOL, "1"), OBSOLETE("FallbackNetworkstatusFile"), + VAR("FamilyId", LINELIST, FamilyId_lines, NULL), + VAR_IMMUTABLE("FamilyKeyDirectory", + FILENAME, FamilyKeyDirectory_option, NULL), V(FascistFirewall, BOOL, "0"), V(FirewallPorts, CSV, ""), OBSOLETE("FastFirstHopPK"), @@ -476,6 +486,13 @@ #ifdef _WIN32 V(GeoIPFile, FILENAME, ""), V(GeoIPv6File, FILENAME, ""), +#elif defined(__ANDROID__) + /* Android apps use paths that are configured at runtime. + * /data/local/tmp is guaranteed to exist, but will only be + * usable by the 'shell' and 'root' users, so this fallback is + * for debugging only. */ + V(GeoIPFile, FILENAME, "/data/local/tmp/geoip"), + V(GeoIPv6File, FILENAME, "/data/local/tmp/geoip6"), #else V(GeoIPFile, FILENAME, SHARE_DATADIR PATH_SEPARATOR "tor" PATH_SEPARATOR "geoip"), @@ -507,6 +524,9 @@ LINELIST_S, RendConfigLines, NULL), VAR("HiddenServiceOnionBalanceInstance", LINELIST_S, RendConfigLines, NULL), + VAR("HiddenServicePoWDefensesEnabled", LINELIST_S, RendConfigLines, NULL), + VAR("HiddenServicePoWQueueRate", LINELIST_S, RendConfigLines, NULL), + VAR("HiddenServicePoWQueueBurst", LINELIST_S, RendConfigLines, NULL), VAR("HiddenServiceStatistics", BOOL, HiddenServiceStatistics_option, "1"), V(ClientOnionAuthDir, FILENAME, NULL), OBSOLETE("CloseHSClientCircuitsImmediatelyOnTimeout"), @@ -548,6 +568,7 @@ V(MaxClientCircuitsPending, POSINT, "32"), V(MaxConsensusAgeForDiffs, INTERVAL, "0 seconds"), VAR("MaxMemInQueues", MEMUNIT, MaxMemInQueues_raw, "0"), + VAR("MaxHSDirCacheBytes", MEMUNIT, MaxHSDirCacheBytes, "0"), OBSOLETE("MaxOnionsPending"), V(MaxOnionQueueDelay, MSEC_INTERVAL, "0"), V(MaxUnparseableDescSizeToLog, MEMUNIT, "10 MB"), @@ -624,10 +645,10 @@ V(RejectPlaintextPorts, CSV, ""), V(RelayBandwidthBurst, MEMUNIT, "0"), V(RelayBandwidthRate, MEMUNIT, "0"), - V(RendPostPeriod, INTERVAL, "1 hour"), /* Used internally. */ V(RephistTrackTime, INTERVAL, "24 hours"), V_IMMUTABLE(RunAsDaemon, BOOL, "0"), V(ReducedExitPolicy, BOOL, "0"), + V(ReevaluateExitPolicy, BOOL, "0"), OBSOLETE("RunTesting"), // currently unused V_IMMUTABLE(Sandbox, BOOL, "0"), V(SafeLogging, STRING, "1"), @@ -987,6 +1008,7 @@ config_line_t *changes = config_get_changes(get_options_mgr(), old_options, new_val); control_event_conf_changed(changes); + connection_reapply_exit_policy(changes); config_free_lines(changes); } @@ -1026,11 +1048,17 @@ } tor_free(options->DataDirectory); tor_free(options->CacheDirectory); + tor_free(options->FamilyKeyDirectory); tor_free(options->KeyDirectory); tor_free(options->BridgePassword_AuthDigest_); tor_free(options->command_arg); tor_free(options->master_key_fname); config_free_lines(options->MyFamily); + if (options->FamilyIds) { + SMARTLIST_FOREACH(options->FamilyIds, + ed25519_public_key_t *, k, tor_free(k)); + smartlist_free(options->FamilyIds); + } } /** Release all memory allocated in options @@ -2470,6 +2498,9 @@ .command=CMD_LIST_FINGERPRINT }, { .name="--keygen", .command=CMD_KEYGEN }, + { .name="--keygen-family", + .command=CMD_KEYGEN_FAMILY, + .takes_argument=ARGUMENT_NECESSARY }, { .name="--key-expiration", .takes_argument=ARGUMENT_OPTIONAL, .command=CMD_KEY_EXPIRATION }, @@ -2728,11 +2759,19 @@ static void list_enabled_modules(void) { - printf("%s: %s\n", "relay", have_module_relay() ? "yes" : "no"); - printf("%s: %s\n", "dirauth", have_module_dirauth() ? "yes" : "no"); - // We don't list dircache, because it cannot be enabled or disabled - // independently from relay. Listing it here would proliferate - // test variants in test_parseconf.sh to no useful purpose. + static const struct { + const char *name; + bool have; + } list[] = { + { "relay", have_module_relay() }, + { "dirauth", have_module_dirauth() }, + { "dircache", have_module_dircache() }, + { "pow", have_module_pow() } + }; + + for (unsigned i = 0; i < sizeof list / sizeof list[0]; i++) { + printf("%s: %s\n", list[i].name, list[i].have ? "yes" : "no"); + } } /** Prints compile-time and runtime library versions. */ @@ -2974,19 +3013,11 @@ return 0; } -/** Lowest allowable value for RendPostPeriod; if this is too low, hidden - * services can overload the directory system. */ -#define MIN_REND_POST_PERIOD (10*60) -#define MIN_REND_POST_PERIOD_TESTING (5) - /** Highest allowable value for CircuitsAvailableTimeout. * If this is too large, client connections will stay open for too long, * incurring extra padding overhead. */ #define MAX_CIRCS_AVAILABLE_TIME (24*60*60) -/** Highest allowable value for RendPostPeriod. */ -#define MAX_DIR_PERIOD ((7*24*60*60)/2) - /** Lowest allowable value for MaxCircuitDirtiness; if this is too low, Tor * will generate too many circuits and potentially overload the network. */ #define MIN_MAX_CIRCUIT_DIRTINESS 10 @@ -3540,27 +3571,27 @@ return -1; } + options->ConfluxClientUX = CONFLUX_UX_HIGH_THROUGHPUT; + if (options->ConfluxClientUX_option) { + if (!strcmp(options->ConfluxClientUX_option, "latency")) + options->ConfluxClientUX = CONFLUX_UX_MIN_LATENCY; + else if (!strcmp(options->ConfluxClientUX_option, "throughput")) + options->ConfluxClientUX = CONFLUX_UX_HIGH_THROUGHPUT; + else if (!strcmp(options->ConfluxClientUX_option, "latency_lowmem")) + options->ConfluxClientUX = CONFLUX_UX_LOW_MEM_LATENCY; + else if (!strcmp(options->ConfluxClientUX_option, "throughput_lowmem")) + options->ConfluxClientUX = CONFLUX_UX_LOW_MEM_THROUGHPUT; + else + REJECT("ConfluxClientUX must be 'latency', 'throughput, " + "'latency_lowmem', or 'throughput_lowmem'"); + } + if (options_validate_publish_server(old_options, options, msg) < 0) return -1; if (options_validate_relay_padding(old_options, options, msg) < 0) return -1; - const int min_rendpostperiod = - options->TestingTorNetwork ? - MIN_REND_POST_PERIOD_TESTING : MIN_REND_POST_PERIOD; - if (options->RendPostPeriod < min_rendpostperiod) { - log_warn(LD_CONFIG, "RendPostPeriod option is too short; " - "raising to %d seconds.", min_rendpostperiod); - options->RendPostPeriod = min_rendpostperiod; - } - - if (options->RendPostPeriod > MAX_DIR_PERIOD) { - log_warn(LD_CONFIG, "RendPostPeriod is too large; clipping to %ds.", - MAX_DIR_PERIOD); - options->RendPostPeriod = MAX_DIR_PERIOD; - } - /* Check the Single Onion Service options */ if (options_validate_single_onion(options, msg) < 0) return -1; @@ -4496,6 +4527,10 @@ if (config_line_find(cmdline_only_options, "--version")) { printf("Tor version %s.\n",get_version()); +#ifdef ENABLE_GPL + printf("This build of Tor is covered by the GNU General Public License " + "(https://www.gnu.org/licenses/gpl-3.0.en.html)\n"); +#endif printf("Tor is running on %s with Libevent %s, " "%s %s, Zlib %s, Liblzma %s, Libzstd %s and %s %s as libc.\n", get_uname(), @@ -6885,6 +6920,15 @@ } else { return tor_strdup(get_windows_conf_root()); } +#elif defined(__ANDROID__) + /* Android apps can only use paths that are configured at runtime. + * /data/local/tmp is guaranteed to exist, but is only usable by the + * 'shell' and 'root' users, so this fallback is for debugging only. */ + if (val) { + return tor_strdup(val); + } else { + return tor_strdup("/data/local/tmp"); + } #else /* !defined(_WIN32) */ const char *d = val; if (!d) @@ -6949,6 +6993,17 @@ options->CacheDirectory = tor_strdup(options->DataDirectory); } + tor_free(options->FamilyKeyDirectory); + if (options->FamilyKeyDirectory_option) { + options->FamilyKeyDirectory = + get_data_directory(options->FamilyKeyDirectory_option); + if (!options->FamilyKeyDirectory) + return -1; + } else { + /* Default to the key directory. */ + options->FamilyKeyDirectory = tor_strdup(options->KeyDirectory); + } + return 0; } @@ -7280,7 +7335,7 @@ } /* Check whether an address has already been set against the options - * depending on address family and destination type. Any exsting + * depending on address family and destination type. Any existing * value will lead to a fail, even if it is the same value. If not * set and not only validating, copy it into this location too. * Returns 0 on success or -1 if this address is already set. diff -Nru tor-0.4.7.16/src/app/config/fallback_dirs.inc tor-0.4.9.6/src/app/config/fallback_dirs.inc --- tor-0.4.7.16/src/app/config/fallback_dirs.inc 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/app/config/fallback_dirs.inc 2026-03-25 14:30:34.000000000 +0000 @@ -3,1095 +3,1108 @@ /* timestamp=20210412000000 */ /* source=offer-list */ // -// Generated on: Fri, 03 Nov 2023 13:18:42 +0000 +// Generated on: Wed, 25 Mar 2026 14:14:46 +0000 -"46.148.21.35 orport=9001 id=81CBB1260140645450D8F599C8A9BDD289FF8530" -/* nickname=Linstal3 */ +"46.232.251.183 orport=9001 id=66EEF68A3307E63D59CE34969A710F1FA697DE83" +" ipv6=[2a03:4000:2b:41f:0:1d:0:fe]:9001" +/* nickname=theonlyone */ /* extrainfo=0 */ /* ===== */ , -"158.255.212.178 orport=8443 id=D941D380E5228E7B4D372AF4D484629A96DC48B9" -" ipv6=[2a03:f80:ed15:158:255:212:178:2]:8443" -/* nickname=Tardis */ +"109.70.100.245 orport=443 id=9E03B94B16FF39EA2019CE7BF5C6C8BBF84CD675" +" ipv6=[2a03:e600:100:c3::10]:443" +/* nickname=lamarr */ /* extrainfo=0 */ /* ===== */ , -"146.59.12.188 orport=9001 id=1BD6462B856754E9C826B220B4C47E59D0479109" -" ipv6=[2001:41d0:601:1100::4c5f]:9001" -/* nickname=funrelay */ +"64.65.1.64 orport=443 id=55B3EAD57AF13B6306ACF59ECCDC5E6E24EF575A" +/* nickname=wifisfuneral */ /* extrainfo=0 */ /* ===== */ , -"217.182.196.71 orport=443 id=63B32F7E5389E8DBC5E1BCEFE48312DA7CCEF5D6" -/* nickname=torte */ +"141.95.86.17 orport=9001 id=C94D0985BD317B514DDBED8ECD5EC99FB60DD1F6" +" ipv6=[2001:41d0:701:1100::5a30]:9001" +/* nickname=DemonsysEU */ /* extrainfo=0 */ /* ===== */ , -"108.62.103.193 orport=443 id=1A66C02A119D6F842F550685E0051C4AE23B8BE8" -/* nickname=CoVna */ +"64.65.1.67 orport=443 id=4A167C3AA47077BA679DDFA3167CF98464CEAFE5" +/* nickname=ralofamerica */ /* extrainfo=0 */ /* ===== */ , -"90.35.255.14 orport=9001 id=9301CDCBCE6E606FC2A571AC822D095364EE4A52" -/* nickname=srvrelay01 */ +"192.121.108.118 orport=9001 id=A02AB2C40AB744F451CCCE38781D8E05676CC15E" +" ipv6=[2a09:be40:28fb:1337::f00d]:9001" +/* nickname=Relay06MaskAD */ /* extrainfo=0 */ /* ===== */ , -"157.245.96.142 orport=9001 id=FA810B674C8043F662EBA339A3D1E2C042E2DFD6" -/* nickname=OpenWave */ +"62.66.145.248 orport=9001 id=32D6F1E338860568A1E3CA1CFD4D84EC7485EC34" +/* nickname=LilleVemmelund */ /* extrainfo=0 */ /* ===== */ , -"185.220.103.9 orport=443 id=70ACA07D9276277B82E909C1439E19CCA2FB16CC" -/* nickname=CalyxInstitute21 */ +"194.147.140.102 orport=995 id=2C6D0929C0D00B3461670AF874B5418164A7D1F2" +" ipv6=[2001:67c:440:f887:194:147:140:102]:995" +/* nickname=tor102 */ /* extrainfo=0 */ /* ===== */ , -"192.42.116.186 orport=9003 id=B48ED936B2FF3A776A333AE8A81D464BEA8FF560" -" ipv6=[2001:67c:6ec:203:192:42:116:186]:9003" -/* nickname=NTH34R4 */ +"45.84.107.84 orport=443 id=9CB75E6343DDB8E38F78A20E9525604F05988FA2" +/* nickname=MicrosoftSucks */ /* extrainfo=0 */ /* ===== */ , -"94.23.29.204 orport=443 id=76543749510CD00CB16E1DD4940CAA8FAC727F58" -" ipv6=[2001:41d0:2:1ecc::]:443" -/* nickname=TORfrance */ +"5.255.127.222 orport=9001 id=4B61EC04E1797D8688475BD24EDA450914497D84" +/* nickname=Dopamine */ /* extrainfo=0 */ /* ===== */ , -"65.21.73.109 orport=9001 id=46BACCCE4BC3CAA63D2FE770DA2AE3CF401B9CF0" -" ipv6=[2a01:4f9:3b:4def:65:21:73:109]:9001" -/* nickname=SORGaming */ +"45.80.158.93 orport=143 id=F260B54AD13D7A9AAA72E67DD583F30037EF7FFA" +" ipv6=[2a12:a800:2:1:45:80:158:93]:143" +/* nickname=Quetzalcoatl */ /* extrainfo=0 */ /* ===== */ , -"185.22.172.106 orport=9201 id=CD5316A75554C2DADB87EF3624E95D848C309CE8" -" ipv6=[2a00:1838:36:29::9201]:9201" -/* nickname=Assange003ru2 */ +"45.138.16.107 orport=9100 id=D88B5B35EF4D5EF11F5B670C364F812D0349B8DB" +" ipv6=[2a12:a800:2:1:45:138:16:107]:9100" +/* nickname=Quetzalcoatl */ /* extrainfo=0 */ /* ===== */ , -"89.58.45.9 orport=9001 id=D18F666B0510B633B741713D667E11D3D7B4DA25" -" ipv6=[2a03:4000:67:d31:481d:9dff:fe88:77e3]:9001" -/* nickname=qwertzuiop20221011 */ +"45.95.169.43 orport=9001 id=213038B323FF8737A55C9DA15FEA1C9BBC4785D3" +/* nickname=Challanger */ /* extrainfo=0 */ /* ===== */ , -"23.129.64.141 orport=443 id=6A642CAF73BDBEC64DD9A44B9B973C70B3E74707" -" ipv6=[2620:18c:0:192::141]:443" -/* nickname=YouAreLoved */ +"66.42.113.136 orport=443 id=D1D586F7356CD497AA7344A1A04F16B62B97E3C5" +/* nickname=marleybone3a */ /* extrainfo=0 */ /* ===== */ , -"198.98.62.56 orport=9941 id=587B1EAF1E22E148EFB010DAA337ACDCD4DB5CBA" -" ipv6=[2605:6400:10:4b0::1]:9941" -/* nickname=alxu */ +"171.25.193.131 orport=443 id=8F1C04C57F554DBCA7E02F6BC200AA474DC833AE" +" ipv6=[2001:67c:289c:4::132]:443" +/* nickname=DFRI126 */ /* extrainfo=0 */ /* ===== */ , -"185.220.101.198 orport=8443 id=A67E042D395D54E0BF0112A3BC90924036BE296B" -" ipv6=[2a0b:f4c2:2:1::198]:8443" -/* nickname=ForPrivacyNET */ +"23.129.64.176 orport=443 id=E234C5568893454711240DAD886FE315EF275DDB" +" ipv6=[2620:18c:0:192::e0:176]:443" +/* nickname=dimensiondoor */ /* extrainfo=0 */ /* ===== */ , -"190.2.133.227 orport=9001 id=8B889E04C60E30D511013189D3C2ADCE522E1F3C" -/* nickname=bobtail */ +"62.72.47.105 orport=8100 id=9DA3641B237AF84095C3D057F472106F1E32CCB0" +" ipv6=[2407:3640:2259:6302::1]:8100" +/* nickname=Quetzalcoatl */ /* extrainfo=0 */ /* ===== */ , -"93.99.104.18 orport=9001 id=175D823779FBA9B6CCF1A1001FD19456073D60AF" -" ipv6=[2a01:5e0:36:cf2a::1]:9001" -/* nickname=Slumlord */ +"185.232.68.247 orport=443 id=F31A8ECBF669CC4E6B1C14866EBD25C13A70F296" +" ipv6=[2a03:4000:4e:f3:689c:c6ff:fe24:89b4]:443" +/* nickname=CryptoCactus */ /* extrainfo=0 */ /* ===== */ , -"85.214.147.9 orport=443 id=0FDC9A7D60608123CF5432F6E25C6E4BC23E7938" -/* nickname=SchweinfurtsTor2 */ +"82.160.220.21 orport=9001 id=A262706ED4F731025FAFBF56636C224EEF51B127" +/* nickname=speedtest10ge */ /* extrainfo=0 */ /* ===== */ , -"178.254.41.45 orport=443 id=EC167B8C9A38A0F5F79D4A01479035760E0D3D63" -" ipv6=[2a00:6800:3:6d2::3]:443" -/* nickname=zensursula */ +"95.214.53.96 orport=8447 id=FD4831DD801161346FACD52452633088EA356271" +" ipv6=[2a03:cfc0:8000:7::5fd6:3560]:8447" +/* nickname=bauruine */ /* extrainfo=0 */ /* ===== */ , -"144.24.197.112 orport=443 id=8D1C918251A835561B67BA59F8A88648D9412BFC" -" ipv6=[2603:c026:c102:5ff:2603:c026:c102:5ff]:443" -/* nickname=Kurumi */ +"45.76.61.27 orport=9001 id=CA3A394AAF64EE2E91296348BBBC66DCCEAA5FA5" +/* nickname=ugh */ /* extrainfo=0 */ /* ===== */ , -"37.221.192.121 orport=443 id=9ADB43D842852F4DE03B3502FA90CBAB9F040A95" -" ipv6=[2a03:4000:8:69a:74ab:8fff:fe06:a47a]:443" -/* nickname=fokaia */ +"51.195.119.154 orport=9300 id=959779FD7167FD412B3B098457B04433F572AAEB" +" ipv6=[2001:41d0:701:1100::3231]:9300" +/* nickname=prsv */ /* extrainfo=0 */ /* ===== */ , -"185.241.208.202 orport=9000 id=F3E6F01671C087AD318BBA47FCD08B65D1A4460E" -/* nickname=Aramis */ +"94.23.121.150 orport=8080 id=4D0F2ADB9CD55C3EBD14823D54B6541B99A51C19" +/* nickname=Unnamed */ /* extrainfo=0 */ /* ===== */ , -"46.22.212.230 orport=443 id=04DFE047ACDF7A6620ACA782FAFC5EF1AE7F4754" -/* nickname=takei */ +"124.198.131.173 orport=143 id=B6AF9746C05714E5B90063F44DC2C7FF5F96E051" +" ipv6=[2a12:a800:11:1:124:198:131:173]:143" +/* nickname=Quetzalcoatl */ /* extrainfo=0 */ /* ===== */ , -"104.244.72.132 orport=9000 id=16355C1C0B02AF69618AE6A517A526B8A6B98B9B" -" ipv6=[2605:6400:30:f82f:7de1:3de3:8947:bc6a]:9000" -/* nickname=Quetzalcoatl */ +"23.129.64.215 orport=443 id=3809938D5786CD2886C856578316AE3FF62FCCBD" +" ipv6=[2620:18c:0:192::e0:215]:443" +/* nickname=eo215 */ /* extrainfo=0 */ /* ===== */ , -"91.143.87.136 orport=443 id=51C367582993D68F8215610B85A99902C945324B" -" ipv6=[2a02:180:6:1::2eff]:443" -/* nickname=Planetclaire65 */ +"87.98.237.152 orport=9001 id=DFCE8C606B821A59D0E0E11AEF8C30FD22BBCC2B" +/* nickname=Unnamed */ /* extrainfo=0 */ /* ===== */ , -"185.241.208.206 orport=9300 id=99A333B824BF47D2C9F2C6DDCBAB856324D428E5" -/* nickname=Aramis */ +"104.244.79.44 orport=9100 id=CCCFD8D5FD21AC796234D914F1B7CC33ADCE52F8" +" ipv6=[2605:6400:30:f38b:28b3:cd24:51f3:e412]:9100" +/* nickname=Quetzalcoatl */ /* extrainfo=0 */ /* ===== */ , -"185.220.103.119 orport=443 id=9164248F9C9A62FF22C93685D365EA7478A00123" -/* nickname=psychopomp3 */ +"83.228.205.178 orport=8888 id=26C55AC78E6B2C3BB9DF304DBDD8A1E1D7D5F4DF" +" ipv6=[2001:1600:13:101::c39]:8888" +/* nickname=CyberDiplomacy */ /* extrainfo=0 */ /* ===== */ , -"108.51.129.7 orport=9001 id=C7643EF0BC0E452C293534D6429D1D7937776483" -/* nickname=UrbanTorRelay */ +"194.26.192.186 orport=9200 id=1C62E9E7977A0C9B6F5D14FFCAF5515C95204C8D" +" ipv6=[2a12:a800:1:1:194:26:192:186]:9200" +/* nickname=prsv */ /* extrainfo=0 */ /* ===== */ , -"91.208.184.123 orport=443 id=ACF8FC6C14032A045B44F6B98525EE5C0472DD50" -/* nickname=TorDiversity */ +"46.20.33.223 orport=9100 id=B1AAE82FBCB8ECB429A6149626D3BB6410364EA1" +/* nickname=0uijabroad */ /* extrainfo=0 */ /* ===== */ , -"185.243.218.202 orport=9443 id=93028381191D88A5E8821AC175CB8B5ADEA8BCFC" -" ipv6=[2a03:94e0:2421:dead::1]:9443" -/* nickname=bauruine */ +"46.4.74.237 orport=8080 id=4CF204F66452C89712B9CF513A213C1F03D8F706" +" ipv6=[2a01:4f8:140:522c::2]:8080" +/* nickname=Indigold */ /* extrainfo=0 */ /* ===== */ , -"155.248.194.143 orport=26666 id=56E9882FC7B62C4F2A951C5E2D570D6E74F15C6D" -/* nickname=iDidEditTheConfig */ +"64.65.62.48 orport=443 id=EC488394FDF79BF2E846DA5D4148FC18163BB29B" +/* nickname=lildarkie */ /* extrainfo=0 */ /* ===== */ , -"92.35.20.235 orport=1025 id=88D5F0BD87F9BC1A96FCBFDCEDB1C0E6BAB1D14E" -" ipv6=[2001:470:dd6d::21]:1025" -/* nickname=DiraE2yhvB */ +"102.130.127.117 orport=443 id=26B466A5152B058DB26878731AE453D22A8F4B21" +/* nickname=alpha191 */ /* extrainfo=0 */ /* ===== */ , -"95.216.33.58 orport=443 id=56927E61B51E6F363FB55498150A6DDFCF7077F2" -" ipv6=[2a01:4f9:2a:2145::2]:443" -/* nickname=Akka */ +"192.42.116.45 orport=443 id=0DE135A4D0ECCB5D57F8B71BF8E22958FC4146A7" +" ipv6=[2001:67c:e60:c0c:192:42:116:45]:443" +/* nickname=NTH45R1 */ /* extrainfo=0 */ /* ===== */ , -"107.189.4.23 orport=9100 id=0E2FF5BF873DF2FDBABE42DBF042D350DE794F15" -" ipv6=[2605:6400:30:ecc4:83a6:a119:41fe:f2f9]:9100" -/* nickname=Quetzalcoatl */ +"38.190.150.6 orport=9004 id=00E1290EBA8EE2D60119754DBD9AD1067B2A7712" +/* nickname=xkoloke */ /* extrainfo=0 */ /* ===== */ , -"148.251.41.235 orport=9001 id=FC1E441E097BA36930AA2F615EFB325AF76D2595" -" ipv6=[2a01:4f8:201:922f::1]:9001" -/* nickname=torcatgirlcloud */ +"185.243.218.138 orport=443 id=EC99A6385A22B6A9552AB10DCFC37F1682BCB321" +" ipv6=[2a03:94e0:ffff:185:243:218:0:138]:443" +/* nickname=lukast */ /* extrainfo=0 */ /* ===== */ , -"87.106.229.54 orport=443 id=65F39CA1E4CEF4BB5EA5D26F687599205AF61502" -" ipv6=[2001:ba0:1800:61::1]:443" -/* nickname=Schnurpselpeter */ +"185.227.70.134 orport=443 id=1F348BF999D4F7BE263270F5A24F69FCCEC1399C" +" ipv6=[2a12:bec0:20b:6b35::1]:443" +/* nickname=fluffypancakes006nl */ /* extrainfo=0 */ /* ===== */ , -"185.112.144.198 orport=9001 id=9279F00D4C3CDC5D3F46EA837F6CF537BC186CD0" -/* nickname=Unnamed */ +"45.80.158.142 orport=110 id=2EF3F194E34705F9E13021BAC7B394653329243A" +" ipv6=[2a12:a800:2:1:45:80:158:142]:110" +/* nickname=Quetzalcoatl */ /* extrainfo=0 */ /* ===== */ , -"173.249.8.113 orport=443 id=C86C538EF0A24E010342F30DBCACC2A7EB7CA833" -" ipv6=[2a02:c207:3004:1074::1]:443" -/* nickname=charon */ +"205.206.0.92 orport=9109 id=F86698F2977D6A1216215C2CCE540BC84A8508DC" +/* nickname=edmCentral0 */ /* extrainfo=0 */ /* ===== */ , -"51.159.34.131 orport=47168 id=AAFF4A997543DB0D881F4F11638485B7D471FECE" -" ipv6=[2001:bc8:2ecd:caed:746f:7200:746f:7200]:47168" -/* nickname=jceaonline */ +"45.80.158.249 orport=8430 id=D138382EBA7B84EF8BBC669B0A961AF758AC8FA8" +" ipv6=[2a12:a800:2:1:45:80:158:249]:8430" +/* nickname=Quetzalcoatl */ /* extrainfo=0 */ /* ===== */ , -"185.220.101.68 orport=9100 id=B452A3023AC41AB923823E1F8521DB2C05590678" -/* nickname=CCCStuttgartBer */ +"194.26.192.46 orport=9100 id=EDC46D5E697DBE2C8F2F7C8D8B26EC2FCB3F2F33" +" ipv6=[2a12:a800:1:1:194:26:192:46]:9100" +/* nickname=Quetzalcoatl */ /* extrainfo=0 */ /* ===== */ , -"172.245.23.98 orport=8080 id=0F5A78ECBA449016B00F05A85398D5AD3DC7A895" -/* nickname=YoungBrother */ +"199.241.137.60 orport=9001 id=8D8DAD240CECFE9B48DC5F2C6EA20D042D5B8733" +" ipv6=[2602:ff16:6:0:1:297:0:1]:9001" +/* nickname=ac1dburn */ /* extrainfo=0 */ /* ===== */ , -"91.203.5.118 orport=9001 id=B7326215A9CFB1392618841F23A0D9F7935AB103" -/* nickname=hastyfire */ +"94.100.6.11 orport=443 id=03E107A3663E912664F4A934DFF451262C218357" +/* nickname=Wildtwister */ /* extrainfo=0 */ /* ===== */ , -"185.165.169.239 orport=443 id=CD94752BFBC94EC82F081B86E95241BB71D7CF99" -/* nickname=impishingyserawn */ +"62.210.181.63 orport=18256 id=6DF9B54DF49AEB5992B9AF8D4ECFA7BCC7447A8B" +" ipv6=[2001:bc8:32d7:2006::]:18256" +/* nickname=Belize */ /* extrainfo=0 */ /* ===== */ , -"193.142.147.204 orport=9200 id=EFAABD340122E724FE3A96CEA994240395B6C6D4" -/* nickname=prsv */ +"74.208.11.136 orport=6733 id=8A67C5D1B659355698ADE012AF2C7B0EB3B3F1A9" +/* nickname=NotTheNSA */ /* extrainfo=0 */ /* ===== */ , -"158.69.48.49 orport=443 id=1425934FA39046386C3B2EFC3D8F78E08A731CA6" -" ipv6=[2607:5300:201:3100::3aef]:443" -/* nickname=Superluminal2 */ +"195.176.3.23 orport=443 id=BCF55F865EE6EF17E25EFEAF851BC429F190B85D" +" ipv6=[2001:620:20d0::23]:443" +/* nickname=DigiGesTor5e1 */ /* extrainfo=0 */ /* ===== */ , -"185.220.102.241 orport=993 id=C8B715F96168D414E580A98563C1F86372D3FE26" -" ipv6=[2a0b:f4c1:2::241]:993" -/* nickname=Digitalcourage4ipbb */ +"45.9.156.101 orport=8100 id=E492BA484812A7FED594F2852473876779617E16" +" ipv6=[2a0e:bfc7:0:3::2d83]:8100" +/* nickname=Quetzalcoatl */ /* extrainfo=0 */ /* ===== */ , -"209.44.114.178 orport=34579 id=3A94EFBF4A220B35A92D0A5B4A80D6324C3C306A" -/* nickname=Pasquino3 */ +"45.80.171.18 orport=9001 id=DA71126E1D0B11605533B7AD399DD5A7EC8E2F0E" +" ipv6=[2a10:3781:1f::5]:9001" +/* nickname=blackstar */ /* extrainfo=0 */ /* ===== */ , -"70.32.0.100 orport=9001 id=507B5DD1DB16FCA800B9CDC13CE0A8EDB9A8323D" -/* nickname=gr8eight */ +"45.138.16.230 orport=9700 id=662C083862D68475A41777EC9D9163E51FE90110" +" ipv6=[2a12:a800:2:1:45:138:16:230]:9700" +/* nickname=Aramis */ /* extrainfo=0 */ /* ===== */ , -"185.243.218.110 orport=11443 id=6E6E11155BE3E7F38BA3702AB5BA18C9139D8734" -" ipv6=[2a03:94e0:ffff:185:243:218:0:110]:11443" -/* nickname=bauruine */ +"208.72.67.116 orport=9063 id=19F03506712EBF7F1E791C11C4CA13877F9AB84B" +/* nickname=GlobalEntry */ /* extrainfo=0 */ /* ===== */ , -"64.42.176.50 orport=9001 id=956B0D08024639F9D7F3F333283ED4480B807D8D" -" ipv6=[2605:9f80:2000:83::2]:9001" -/* nickname=SDRHausSEA1 */ +"64.65.1.103 orport=443 id=6562CB938FE7B45629B8AEE4C8478D02A27D4492" +/* nickname=youngdolph */ /* extrainfo=0 */ /* ===== */ , -"62.210.244.146 orport=9001 id=BD4C647508162F59CB44E4DFC1C2B2B8A9387CCA" -" ipv6=[2001:bc8:3680:4242::1]:9001" -/* nickname=regar42 */ +"135.181.67.210 orport=443 id=DC7E7D9AB7AD52F03B856E6DC278E9D92BF19B33" +" ipv6=[2a01:4f9:4b:4e97::6666]:443" +/* nickname=s6tor2 */ /* extrainfo=0 */ /* ===== */ , -"104.244.79.44 orport=9000 id=A1AB134123F9F534C7E09B6841A7ECAFD0282240" -" ipv6=[2605:6400:30:f38b:28b3:cd24:51f3:e412]:9000" -/* nickname=Quetzalcoatl */ +"96.9.98.188 orport=443 id=E68789BC34CFC5B932E827C463E104ECFB9FA060" +/* nickname=liltjay */ /* extrainfo=0 */ /* ===== */ , -"83.136.106.136 orport=443 id=E8466E02C893B9A6602A251CCEA100F252E25B4B" -" ipv6=[2a02:29e0:2:6:1:1:30fe:8547]:443" -/* nickname=BetelgeuseIT */ +"185.73.240.205 orport=443 id=A60AFA6FFB2EEB8E4A4C531FBA6A78AF586AACB7" +/* nickname=adlon */ /* extrainfo=0 */ /* ===== */ , -"5.188.51.30 orport=9001 id=3F7E3BB28DDCE7E4541D19B1D401472B8D5B4C68" -/* nickname=Shorty */ +"181.215.45.194 orport=9001 id=426E5509BEA3CEB670EAB6789872B729C178A7BE" +" ipv6=[2a0e:b107:1ef0:0:181:215:45:194]:9001" +/* nickname=relaytorparacba */ /* extrainfo=0 */ /* ===== */ , -"87.62.96.246 orport=9032 id=E384748293FC4429E2B427360DB4F9D4C3D619D1" -/* nickname=PXArelay02 */ +"84.167.246.41 orport=9002 id=BCB8813996025205A8BDDED17DF0372367207205" +/* nickname=crmh */ /* extrainfo=0 */ /* ===== */ , -"171.25.193.78 orport=80 id=E0665F733B3821CE05A2A7545105371821D25875" -" ipv6=[2001:67c:289c:4::78]:80" -/* nickname=DFRI18 */ +"194.26.192.186 orport=9300 id=53A6473ACE36671C79AB985D3237C179E850FA62" +" ipv6=[2a12:a800:1:1:194:26:192:186]:9300" +/* nickname=prsv */ /* extrainfo=0 */ /* ===== */ , -"199.249.230.106 orport=443 id=9D21F034C3BFF4E7737D08CF775DC1745706801F" -" ipv6=[2620:7:6001::106]:80" -/* nickname=Quintex16 */ +"185.82.127.213 orport=443 id=24E9CFAE081B16E87B490C596C18B00EE6FF8413" +/* nickname=se3andersio */ /* extrainfo=0 */ /* ===== */ , -"77.109.152.87 orport=143 id=0432BEE829FCB155CE92CF418B7280F9849E12D0" -" ipv6=[2a02:168:6426::11]:143" -/* nickname=arbertDelroth */ +"5.254.118.191 orport=9001 id=A7AA32CA10E1BEDA1E976A659FD96CA99C2D86FE" +/* nickname=Dominos */ /* extrainfo=0 */ /* ===== */ , -"194.34.132.169 orport=9001 id=6CB2C00C8374D6968698A57940245249FC5B1769" -/* nickname=code */ +"192.42.116.65 orport=443 id=0055DB090820D7C08999EC1598FD6EA6365861AD" +" ipv6=[2001:67c:e60:c0c:192:42:116:65]:443" +/* nickname=NTH65R1 */ /* extrainfo=0 */ /* ===== */ , -"205.185.124.164 orport=9001 id=7B67A3AD2395536FD15CB97588A0BC1A015AC267" -/* nickname=stubbornoxen */ +"185.233.100.23 orport=19001 id=4A39E7D2C121F664CFD9B5DF80CE9E70BB8B3C16" +" ipv6=[2a0c:e300:b:b::b]:19001" +/* nickname=elenagb4 */ /* extrainfo=0 */ /* ===== */ , -"91.92.109.43 orport=443 id=2BD1936E0B4D5BB615CF99B0CFF74EAF19426888" -/* nickname=0001 */ +"45.80.158.167 orport=7100 id=09257AB36470E686491710153FF9412ACC53F2A0" +" ipv6=[2a12:a800:2:1:45:80:158:167]:7100" +/* nickname=Quetzalcoatl */ /* extrainfo=0 */ /* ===== */ , -"51.159.186.85 orport=9001 id=498CDD3BF9DE59A5678E8488FEA450E1876242A5" -" ipv6=[2001:bc8:1200:fa28::1]:9001" -/* nickname=ColinCogleEU */ +"45.80.158.93 orport=8430 id=F5A47B1E8397139628FA424C1C7A560232E35EB4" +" ipv6=[2a12:a800:2:1:45:80:158:93]:8430" +/* nickname=Quetzalcoatl */ /* extrainfo=0 */ /* ===== */ , -"78.130.174.8 orport=9001 id=CCF520E282B27180EF056A0F389D0846FBB45D7C" -/* nickname=Neo2SHYAlien */ +"212.47.233.86 orport=9001 id=B4CAFD9CBFB34EC5DAAC146920DC7DFAFE91EA20" +" ipv6=[2001:bc8:710:5bcb:dc00:ff:fe5e:e8b5]:9001" +/* nickname=netimanmu */ /* extrainfo=0 */ /* ===== */ , -"198.98.51.189 orport=9001 id=76959901386E8C908F50235D9894007886B67C2E" -" ipv6=[2605:6400:10:58f:8768:8283:1a62:bdc6]:9001" -/* nickname=TorDotTeitelNet */ +"23.191.200.7 orport=443 id=5BC542BEC38E8D373D21C6A79CC9348DC28BD62C" +/* nickname=UnredactedRadack */ /* extrainfo=0 */ /* ===== */ , -"46.182.21.248 orport=443 id=9EAD5B2D3DBD96DBC80DCE423B0C345E920A758D" -" ipv6=[2a02:2970:1001::4b]:443" -/* nickname=Digitalcourage3ip1 */ +"23.108.55.71 orport=443 id=DF885E50651903A212EE519BE5A58397AD2E0975" +/* nickname=hamburger */ /* extrainfo=0 */ /* ===== */ , -"95.216.202.181 orport=9001 id=24893333D304C74CCDD11D99090C0471DCFED589" -/* nickname=eternaljenny */ +"86.54.28.49 orport=443 id=98CDDAF76419C5DBCBCF512D87E3F99BA5F22770" +/* nickname=OMICRON */ /* extrainfo=0 */ /* ===== */ , -"45.138.16.44 orport=143 id=B8D6593D777BB7C6167F23A43F8C74248DBD9FE8" -/* nickname=RDPdotSH */ +"62.210.122.182 orport=9201 id=B91A1EB30E66D52026EFCD1E96BFC0E966C83E6D" +" ipv6=[2001:bc8:32d7:10b::f1fa:9201]:9201" +/* nickname=Assange008fr2 */ /* extrainfo=0 */ /* ===== */ , -"185.220.101.211 orport=8443 id=9423A72BBC8B5C6AC9DE9F57735EB2B08E4156E8" -" ipv6=[2a0b:f4c2:2:1::211]:8443" -/* nickname=ForPrivacyNET */ +"74.140.253.100 orport=9001 id=F84C674E4932768107D6460318CC0F73EF8CF493" +/* nickname=DisrodRelay */ /* extrainfo=0 */ /* ===== */ , -"5.135.199.11 orport=9001 id=CCACC39911230FC95A00A859CBC3E94AD54B52A4" -/* nickname=RobWilliamsGhost */ +"194.180.191.93 orport=9001 id=677347441FDD2AEA22BD364A7174D277E929B255" +/* nickname=abnormalbonus */ /* extrainfo=0 */ /* ===== */ , -"140.78.100.36 orport=5443 id=C0360EB664017B831FF73FE2A41A154CE264FAC4" -/* nickname=INSRelay36at5443 */ +"64.65.2.12 orport=443 id=8D55E78059CB694ABD69DEED64D444862B79D8E1" +/* nickname=hitboy */ /* extrainfo=0 */ /* ===== */ , -"198.98.48.192 orport=9001 id=F7B387348CA9073A3F5D2AC16EA1CD0C80A44C50" -/* nickname=frost */ +"64.65.1.20 orport=443 id=A69AAF75702AB9041A3EDA1918F930377E13F39D" +/* nickname=statquo */ /* extrainfo=0 */ /* ===== */ , -"185.220.101.195 orport=8443 id=FA54BDBF6054B3F52281E993B1C01EBBF9C59873" -" ipv6=[2a0b:f4c2:2:1::195]:8443" -/* nickname=ForPrivacyNET */ +"218.236.76.26 orport=9002 id=0A30E1467618B1AC167D012C9718C57B4E5F68F3" +/* nickname=Unnamed */ /* extrainfo=0 */ /* ===== */ , -"216.73.159.101 orport=9001 id=FF03BE4E8F9E7E41E2C7D9682CE4D6496FEE0621" -/* nickname=DareDevil */ +"96.9.98.27 orport=443 id=C6426F3974070BEBB6F4E019EBC96F4A2A3C8DB7" +/* nickname=yungpinch */ /* extrainfo=0 */ /* ===== */ , -"217.23.8.2 orport=9001 id=B42C797CC8CD63C60FB643E820A11D113DF4F5C8" -/* nickname=firefly */ +"176.65.148.3 orport=443 id=7FF8F83DD10D3E685B6846D5C32593C1B62A9945" +" ipv6=[2a05:b0c7:655b::1]:443" +/* nickname=nix */ /* extrainfo=0 */ /* ===== */ , -"141.145.208.153 orport=9001 id=2F2BCB532689FFEC760E5EC5F6C08E44CBBD50C9" -/* nickname=GourouLubrik */ +"207.90.194.2 orport=443 id=A39D10B59C0614DFFE296DC2C55F7C4C8557D485" +" ipv6=[2602:ffd5:1:29c::1]:443" +/* nickname=fluffypancakes002ca */ /* extrainfo=0 */ /* ===== */ , -"5.255.99.5 orport=9001 id=D698261BC1B4A80E24BD050909552C7FE9464CD2" -" ipv6=[2a04:52c0:104:ad97::1]:9001" -/* nickname=Unnamed */ +"185.220.101.203 orport=443 id=B7E9849D446FC57D4BDED937B8E17F3AACE1FA06" +" ipv6=[2a0b:f4c2:2:1::203]:443" +/* nickname=ForPrivacyNET */ /* extrainfo=0 */ /* ===== */ , -"91.228.52.73 orport=9001 id=9F0B16DD36B8A4D25BBB77CC2BFADEA37B02E7E1" -/* nickname=thedefendingangel */ +"64.65.2.35 orport=443 id=8E663773B6489347EE34C6D3FFCFD9D6FC80A2DE" +/* nickname=timbaland */ /* extrainfo=0 */ /* ===== */ , -"66.206.0.82 orport=9001 id=8404E8B8AAB98208FAEFB1727B637133AD9C6FAF" -/* nickname=8rijgto8 */ +"64.65.62.20 orport=443 id=A92C33AE18D64EEC719FAF3038FD8F52462BA3FD" +/* nickname=hdbearfaced */ /* extrainfo=0 */ /* ===== */ , -"94.16.112.22 orport=9001 id=B4841639CED48C13546F0EBA6FAC0445EB3F1199" -" ipv6=[2a03:4000:28:3e:c4ee:b0ff:fecb:1cde]:9001" -/* nickname=lokit01 */ +"74.123.98.18 orport=443 id=A2C85DB6C3D64D7178D24848FD8A0E59347F2E6D" +/* nickname=tournament */ /* extrainfo=0 */ /* ===== */ , -"95.216.115.85 orport=443 id=22BCD0DFD148209C9860C7F89907AB4DEE974A08" -/* nickname=Fastnet */ +"77.68.20.86 orport=443 id=07C17931AE2E17F95681FA2A91C7F7CDB068BF48" +" ipv6=[2a00:da00:f412:c100::1]:443" +/* nickname=SidNYGiants */ /* extrainfo=0 */ /* ===== */ , -"164.132.226.30 orport=22 id=0AC3C86BC9CA2A50C7762EF42ABC6D37575ACFFB" -" ipv6=[2001:41d0:401:3100::7fda]:22" -/* nickname=PieroV */ +"15.204.103.3 orport=9030 id=4D4748577DC4F963A9BACF51E1D49B86F12CE23E" +" ipv6=[2604:2dc0:200:2903::]:9030" +/* nickname=Solsticist */ /* extrainfo=0 */ /* ===== */ , -"71.19.157.127 orport=993 id=6AD3EA55B87C80971F353EBA710F6550202A9355" -" ipv6=[2605:2700:1:1008:bdcf:70a4:ad52:f4e8]:443" -/* nickname=OrphanOrOften */ +"51.15.243.22 orport=443 id=1C7D71A2581DE79C5CFC4ED1FF75D5BE30F01BB7" +/* nickname=BabyOnion */ /* extrainfo=0 */ /* ===== */ , -"185.241.208.202 orport=9400 id=6F3E7CD6B97E33F6A91824164A1A9085C045E2C0" -/* nickname=Aramis */ +"171.25.193.234 orport=80 id=CF1C1804C33CD69D8A75587FABC63D5D0E2980FA" +" ipv6=[2001:67c:289c:2::234]:80" +/* nickname=DFRI10 */ /* extrainfo=0 */ /* ===== */ , -"185.220.101.201 orport=443 id=EBF648E1CF3FA3AC46AA272857BCAFCCD70D49FC" -" ipv6=[2a0b:f4c2:2:1::201]:443" -/* nickname=ForPrivacyNET */ +"188.214.132.18 orport=9001 id=EA9E042A05E851076A657639CD0C84D8DA86A76F" +/* nickname=blockaide */ /* extrainfo=0 */ /* ===== */ , -"94.46.171.221 orport=9001 id=7819384A3E66F65CB4FA96FB1D56EA44274DB940" -/* nickname=sunandfun02 */ +"185.153.182.11 orport=9001 id=BEBE82BEAB014983F55DD4CA94CE33E3751B1FDA" +/* nickname=Assange044tr */ /* extrainfo=0 */ /* ===== */ , -"135.148.150.100 orport=443 id=950E02DB326D28101E29286044C5714A204F3222" -/* nickname=cello */ +"178.236.254.48 orport=9000 id=121212BF2F3ED5FA26B65CB376394F4EA322FEBE" +" ipv6=[2a0b:4141:820:138::2]:9000" +/* nickname=prsv */ /* extrainfo=0 */ /* ===== */ , -"173.73.134.86 orport=9001 id=6FC8D3B152054906417CB1EE0642265747C7F689" -" ipv6=[2600:4040:20aa:7c01:21b:21ff:fe36:fd2e]:9001" -/* nickname=jubei */ +"86.14.169.71 orport=443 id=417AA3C8D226DDD79A8047D7F217B21D9C63C21F" +" ipv6=[2001:470:681e::dead:c0de]:443" +/* nickname=sudokill */ /* extrainfo=0 */ /* ===== */ , -"185.220.101.199 orport=8443 id=E1AF5373E3240566B598FA481AD3860549F6168B" -" ipv6=[2a0b:f4c2:2:1::199]:8443" -/* nickname=ForPrivacyNET */ +"89.58.17.228 orport=46856 id=593A4431DA2E315883406AECE1D1188E02F23D8F" +" ipv6=[2a0a:4cc0:0:f0a:a45c:7aff:fe13:2781]:46856" +/* nickname=klarheit */ /* extrainfo=0 */ /* ===== */ , -"162.250.191.15 orport=9201 id=D29B31FDB5EDD2D1B94CD31C2F13B5CF411B1268" -/* nickname=Assange020ca2 */ +"196.200.160.95 orport=9001 id=483E50E35E3CFFA1B69F1AC6B452053AEB7C9581" +" ipv6=[2001:4310:f1::95]:9001" +/* nickname=toky0 */ /* extrainfo=0 */ /* ===== */ , -"45.141.215.56 orport=7100 id=92A8C8292F06E18B116DDD50F517040A17D80512" -/* nickname=Quetzalcoatl */ +"147.189.174.139 orport=9001 id=8F229BC977B322E10826E1605386799E5273ED73" +/* nickname=zgato */ /* extrainfo=0 */ /* ===== */ , -"93.95.231.110 orport=9001 id=097D8390A998FBEBDBDA80BAC7D86F8AE606E4A6" -/* nickname=MetalsAU */ +"185.244.194.156 orport=4711 id=B13BF9FB86663B2D587611B5F3369873919AC54F" +" ipv6=[2a03:4000:27:71a:1853:7aff:feaf:449b]:4711" +/* nickname=makeitfoss */ /* extrainfo=0 */ /* ===== */ , -"194.147.140.103 orport=443 id=1F001137C1241321B33A0BC66BD5D3B0B04F46FD" -/* nickname=tor103IPConnectINFO */ +"205.185.113.180 orport=9001 id=80914004BD527CE984A1576CA63AAA77944D9D2B" +" ipv6=[2605:6400:20:482:3920:1829:1839:1293]:9001" +/* nickname=anonymityiscool */ /* extrainfo=0 */ /* ===== */ , -"192.18.128.35 orport=9001 id=474AB014C284803A9604F189777D20CAC112E1CD" -/* nickname=AllHailEdSnowden */ +"140.78.100.37 orport=8443 id=CFB535715442BC0E9F6AF224A794BBFA02D0B343" +/* nickname=INSRelay37at8443 */ /* extrainfo=0 */ /* ===== */ , -"199.195.250.165 orport=9100 id=446E16B00D5131DAC9643AB10136B3CD19B1E9B9" -" ipv6=[2605:6400:10:aa1:2db8:1c14:2191:4aa8]:9100" -/* nickname=Quetzalcoatl */ +"209.250.2.254 orport=443 id=205ED2C309999F0F18767A1ECCD384B580070BA9" +" ipv6=[2001:470:1f19:c2::9090:1]:9090" +/* nickname=RazorsEdge */ /* extrainfo=0 */ /* ===== */ , -"45.141.215.80 orport=8100 id=76BACC90CBA71714918554156CAABE955E7A940F" +"45.9.156.193 orport=7430 id=7C9FC7C99D7F83980E621BA8D4E0D40FCE53104F" +" ipv6=[2a0e:bfc7::216:3cff:feae:41de]:7430" /* nickname=Quetzalcoatl */ /* extrainfo=0 */ /* ===== */ , -"185.181.61.115 orport=8443 id=7A6C085A12D90C56C17A9D1A77D9D1D9B9E592D4" -" ipv6=[2a03:94e0:ffff:185:181:61:0:115]:8443" -/* nickname=bauruine */ +"195.88.75.18 orport=9001 id=3F1B13B101DB4D043D0DA18272B8646D3132EE47" +/* nickname=rarelotus */ /* extrainfo=0 */ /* ===== */ , -"77.48.28.239 orport=443 id=E56F07759E704C4F53334E161066F12FAF7F7C97" -/* nickname=pangea06 */ +"107.174.64.206 orport=9954 id=34C5ECB828A275A472F78CE0BBC0884E17E14B1D" +/* nickname=opencommunity */ /* extrainfo=0 */ /* ===== */ , -"51.158.148.230 orport=993 id=F9E32D4058F7F35E9BC4F1D8C3B2DAA0C4466660" -" ipv6=[2001:bc8:2dd2:2000::a]:993" -/* nickname=KagamineLenApple */ +"64.65.1.72 orport=443 id=6FE1A22BAC0635BA510E2EFE1249D7AA4BECBE67" +/* nickname=xalisoflow */ /* extrainfo=0 */ /* ===== */ , -"83.212.96.97 orport=443 id=BE09D5F931C9240CE5369861CD67A1F66A636C76" -/* nickname=okeanosrelay1 */ +"104.167.241.4 orport=443 id=4625F385CA5364CDD63C791893973B0CAD49C4E0" +" ipv6=[2602:fccf:100:3::14]:9001" +/* nickname=HoustonTexas4Torcom */ /* extrainfo=0 */ /* ===== */ , -"148.252.96.77 orport=4430 id=87086C2BBEC0D49B7A4568F137C127F204C74550" -" ipv6=[2a01:563:e3:701:f8ab:53ff:febd:961c]:4430" -/* nickname=CentralNorwayRelay */ +"64.65.0.33 orport=443 id=7EA091DF4CE4256ED35DC113D4921867CBF03A0E" +/* nickname=megaran */ /* extrainfo=0 */ /* ===== */ , -"217.160.150.88 orport=44323 id=0853576E12BA9CD473254FAFF820BD4699E22077" -/* nickname=theactualNSA */ +"45.141.215.200 orport=7430 id=4BDF25CD6E8482C0E835F6A70918540F4FC4CF22" +" ipv6=[2a12:a800:2:1:45:141:215:200]:7430" +/* nickname=Quetzalcoatl */ /* extrainfo=0 */ /* ===== */ , -"185.220.101.64 orport=9100 id=9785BD5AC04E6112071EA9172591275465FD758D" -/* nickname=CCCStuttgartBer */ +"96.9.98.58 orport=443 id=843E20D60EB7EF118FE8F4F4ACABD1AACE59E9B3" +/* nickname=smokepurpp */ /* extrainfo=0 */ /* ===== */ , -"185.66.91.18 orport=9001 id=95333D86240F6402656D2EB96716255634F6C007" -/* nickname=BuNGOfAr */ +"45.11.248.196 orport=9001 id=60DC7DDDCD659C47D4644EDF97E2ACC3C6B18EEB" +" ipv6=[2a00:6340:2043:5000::1]:9001" +/* nickname=surveyor */ /* extrainfo=0 */ /* ===== */ , -"2.57.122.215 orport=9200 id=1F6869F1C301AAD1EF7FBA926D2A726DFE74BB37" -/* nickname=prsv */ +"37.187.122.8 orport=9001 id=221E976B546E60048A01950250399B8534D4E4B7" +" ipv6=[2001:41d0:a:f308::1]:9001" +/* nickname=malechick */ /* extrainfo=0 */ /* ===== */ , -"135.148.100.90 orport=443 id=728F97D5BCB131698814D8C713C2220C6E7267DE" -/* nickname=CanisLatrans */ +"80.94.92.99 orport=9200 id=D1968B63E1105F5E71CC28026687F3C86A46C46E" +/* nickname=prsv */ /* extrainfo=0 */ /* ===== */ , -"74.91.26.170 orport=80 id=981DF882842207A759FAC8CE57651B8DE8A21CC4" -" ipv6=[2604:4300:a:3e9::170]:80" -/* nickname=jstark1809eff */ +"185.4.134.104 orport=9001 id=C6E3910CBADCA6D2D7E932AB31A038EDD6A6FB79" +" ipv6=[2a02:c500:2:110::8709:9001]:9001" +/* nickname=Assange023gr */ /* extrainfo=0 */ /* ===== */ , -"82.197.182.161 orport=443 id=2B51193205D091CC80B904D65721FF8DCBE51C96" -" ipv6=[2001:1620:51a1:0:8aae:ddff:fe61:8ccc]:443" -/* nickname=thealgorithm */ +"164.215.103.126 orport=9001 id=2144EC311E714F30648F2B62546E2CA28FDBD36B" +/* nickname=caseyjones */ /* extrainfo=0 */ /* ===== */ , -"65.108.136.183 orport=80 id=15291291D81E404FB6BEC16D366608590D2B0247" -" ipv6=[2a01:4f9:6b:3408::4]:80" -/* nickname=arbitraryKenzie5 */ +"217.123.118.44 orport=9001 id=047DFF9DBA6A7DB666626F7F4560A1D7B1135F73" +/* nickname=VegetaSSJ */ /* extrainfo=0 */ /* ===== */ , -"62.210.231.115 orport=9001 id=3AF8390D3F4B8103DA297CFD514B35740781B87D" -/* nickname=Horacienne */ +"64.65.3.35 orport=443 id=5BCA9F58CA3C8C130998C8F853921DD56CEF0C2C" +/* nickname=youngma */ /* extrainfo=0 */ /* ===== */ , -"89.58.45.45 orport=443 id=C6ECCF2AC13921242526AE9444613DD3E7595DA2" -" ipv6=[2a03:4000:67:d1a:c44b:31ff:fea5:7443]:443" -/* nickname=yrl4tjdevde */ +"38.29.158.193 orport=9001 id=269885C61FD6CFCC54BD86B88A82565956A42F55" +/* nickname=fr33domNod3 */ /* extrainfo=0 */ /* ===== */ , -"191.252.111.55 orport=443 id=1D1FA50D605FDC8F6DC39A0A60A7233DD35D0001" -/* nickname=K4M1K4Z3 */ +"198.28.165.248 orport=36325 id=A526EA0B6BB1C7B2B7163E834963FC1884A6914E" +/* nickname=vici */ /* extrainfo=0 */ /* ===== */ , -"174.128.250.164 orport=80 id=5197FC89F7A1623CA90D6E0254ABCCBC6D85A86E" -/* nickname=ready2 */ +"185.194.143.87 orport=35897 id=54625FCF74D8311F3175349A1F879A0A298D5CA8" +" ipv6=[2a03:4000:1c:555::11e8]:43741" +/* nickname=TorNode05 */ /* extrainfo=0 */ /* ===== */ , -"66.165.241.228 orport=9002 id=B2D0823FE5F9047C292B0412603F4801BCCABD07" -" ipv6=[2604:4500:8:14::4]:9002" -/* nickname=skibble */ +"23.141.40.7 orport=443 id=375DCBB2DBD94E5263BC0C015F0C9E756669617E" +" ipv6=[2620:b0:2000:102::7]:443" +/* nickname=nitrogen */ /* extrainfo=0 */ /* ===== */ , -"185.243.218.41 orport=8126 id=E2B7CE01E2086332986EF6D94F6ECC80A0C4FEF6" -" ipv6=[2a03:94e0:ffff:185:243:218:0:41]:8126" -/* nickname=terNOicebeer16 */ +"152.53.252.155 orport=443 id=D19E920B886D664E21EB88AF7D955CA4FC570181" +" ipv6=[2a0a:4cc0:c0:bbbd:4660:c905:736b:bee8]:443" +/* nickname=jilfrg60 */ /* extrainfo=0 */ /* ===== */ , -"45.138.16.107 orport=7430 id=C11A2DABF6103F17B29B29B30D20BBC176633BCE" -/* nickname=Quetzalcoatl */ +"74.108.36.251 orport=9001 id=192B3306D8A064510CE6363D5AFFB563E789D246" +/* nickname=LittleIsland */ /* extrainfo=0 */ /* ===== */ , -"185.220.103.116 orport=443 id=901E39B18CC59BCB18ABC97DD63DC49F3DF7401C" -/* nickname=psychopomp9 */ +"5.45.99.251 orport=8080 id=75C0B7A2650BD317CE0FF4EE37DEA093AAD9019B" +" ipv6=[2a03:4000:5:b1:14bb:a9ff:fe0f:70c3]:8080" +/* nickname=northerndownpour */ /* extrainfo=0 */ /* ===== */ , -"217.163.129.42 orport=9001 id=55A5A764A072177A743765C155036421902B3783" -/* nickname=Valinor */ +"5.180.82.224 orport=443 id=BA36742C1FBA693619E085899AC6970C5D3F2A53" +/* nickname=khajiitthief */ /* extrainfo=0 */ /* ===== */ , -"129.126.111.54 orport=443 id=F7E5CDCFFB87549532473194393E6138571854F1" -/* nickname=landsend88 */ +"91.92.109.23 orport=443 id=81D4A9FB174118AA4809B4EE209982FFF215E8A9" +/* nickname=whatscrackin */ /* extrainfo=0 */ /* ===== */ , -"188.214.30.66 orport=443 id=21A42FD48A60DC8AD30730C88CD815EF5E5D3F33" -/* nickname=pleaseDonateWhonix */ +"192.34.87.86 orport=9001 id=CBC8D277C35BCE9512BA45479CF8141FC6A2CD73" +/* nickname=iamthatdude */ /* extrainfo=0 */ /* ===== */ , -"135.125.89.25 orport=443 id=872108C52C52CC10217A351C883E991AEDF7C470" -/* nickname=myNiceRelay */ +"198.23.133.146 orport=9001 id=B00A2DE75DEB8ABB3058290CE311A3D9D096797A" +/* nickname=DebbieDoesTor2023 */ /* extrainfo=0 */ /* ===== */ , -"66.206.4.26 orport=9001 id=BBD8F4DF8FF5C69A6A989DB8C1EE2CA7ADFE0755" -/* nickname=sprucegoose */ +"92.205.161.164 orport=80 id=65369D044C659CD299E35763914FFD0FC9AD4509" +" ipv6=[2a00:1169:11c:3e00::]:443" +/* nickname=Charybdis5 */ /* extrainfo=0 */ /* ===== */ , -"46.248.165.120 orport=19001 id=0669834C7CEA3BEF77D34B739C3235EFF97A8864" -/* nickname=CoreRelay005 */ +"24.125.17.222 orport=443 id=EB044ED4110BA4A6D546992B457DFD13C52B96E5" +/* nickname=mammoth */ /* extrainfo=0 */ /* ===== */ , -"37.205.8.191 orport=443 id=F7B024DB02C601185C202E26DFFD2AD525C16A36" -/* nickname=relay0vpsfree0cz */ +"193.189.100.197 orport=445 id=3C518040CA63BB9EA6B2BE3F514B7168DCC72A74" +" ipv6=[2a0f:df00:0:255::197]:445" +/* nickname=TORKeFFORG30 */ /* extrainfo=0 */ /* ===== */ , -"107.189.30.60 orport=9001 id=97188863FDFF9D21F7560AED3F037F316CA6AE20" -/* nickname=IronServer */ +"89.106.71.126 orport=9001 id=C588F709A5D9CF37358E456003645CDC74BC8B3C" +" ipv6=[2a02:2fc0:11::71:126]:9001" +/* nickname=DediZoneRelay */ /* extrainfo=0 */ /* ===== */ , -"45.80.158.27 orport=110 id=0A76C0A0A721DDBC324B705ADBFC95FD806AE855" -/* nickname=Quetzalcoatl */ +"23.137.248.69 orport=443 id=A24CB2FAB0B4CC1F1965CC7FA332AB1184617DDA" +" ipv6=[2602:fc24:11:16f9::1]:443" +/* nickname=AntonPann8 */ /* extrainfo=0 */ /* ===== */ , -"93.95.227.226 orport=443 id=9DC6270447B9C354BE2F76C14D83FC93748C4237" -/* nickname=RecapturePrivacy */ +"217.154.188.247 orport=443 id=8B8A8328539BF34221C1F136D6EAA48EFCAD379D" +" ipv6=[2001:ba0:215:f000::1]:443" +/* nickname=0x011 */ /* extrainfo=0 */ /* ===== */ , -"86.14.81.141 orport=443 id=417AA3C8D226DDD79A8047D7F217B21D9C63C21F" -" ipv6=[2001:470:681e::c0f:fee]:443" -/* nickname=Gentoo */ +"51.15.96.2 orport=443 id=56344DEE34D3343090D00AD88CE2D58B50712C81" +" ipv6=[2001:bc8:1640:777:dc00:ff:fe12:d075]:443" +/* nickname=gh5d4h56s468r784s32 */ /* extrainfo=0 */ /* ===== */ , -"145.239.41.102 orport=9100 id=3A04AC8969E55DF51C8D11C49ABF18A0CC847FC0" -/* nickname=Unnamed */ +"185.244.192.184 orport=9100 id=3AD0E099EA0F64B6202BEE3B737A9FE5D554A3CC" +" ipv6=[2a03:4000:27:36:c813:6dff:fe0e:b93e]:9100" +/* nickname=Quetzalcoatl */ /* extrainfo=0 */ /* ===== */ , -"107.189.1.160 orport=443 id=5AA6370205AA611CED967BDB4D8EBCB9D5DB57A9" -" ipv6=[2605:6400:30:ef7a:391a:8c71:a2f1:9506]:443" -/* nickname=AllTheWorldsAStage */ +"23.129.64.140 orport=443 id=C98CD99E2BF5F1D7EFA5ED90646AF809CE8F75DF" +" ipv6=[2620:18c:0:192::e0:140]:443" +/* nickname=kiriakou */ /* extrainfo=0 */ /* ===== */ , -"124.187.101.155 orport=9001 id=C0848CF7A17D49178F70938128521F09BC229843" -/* nickname=PCGG */ +"64.65.2.44 orport=443 id=5CA1EBAC7D56273D719B3405DC361DCFEACC4863" +/* nickname=statikselektah */ /* extrainfo=0 */ /* ===== */ , -"51.89.106.29 orport=8080 id=BEC5DA93729F8ACA043228F057058A90C327AAA3" -/* nickname=voronoy */ +"185.255.122.39 orport=443 id=406A030C4A33800DA8E8CDCA72DAFC446A3787AC" +/* nickname=Unnamed */ /* extrainfo=0 */ /* ===== */ , -"163.172.151.206 orport=9001 id=484F666C491BCDE22B45E0E19D1CEA5ACC5A9611" -/* nickname=WinstonSmith */ +"74.215.154.5 orport=9003 id=1D4F6F26E34E2C571F25E93605EDBC95626760FD" +" ipv6=[2600:2b00:939e:710d:aab8:e0ff:fe00:87f2]:9003" +/* nickname=evequefou3 */ /* extrainfo=0 */ /* ===== */ , -"64.5.123.66 orport=443 id=962843FBF8513F57E1190FD4C2DDF083A00C7867" -" ipv6=[2620:59:a000:9666:216:3eff:fe7d:dae8]:443" -/* nickname=nx1tor */ +"144.126.133.74 orport=143 id=ACB30ED82CA61B49E38E5969505D7E2F29897AA1" +" ipv6=[2605:a140:2262:7686::1]:143" +/* nickname=Quetzalcoatl */ /* extrainfo=0 */ /* ===== */ , -"95.217.39.117 orport=4443 id=EA670AB58CD5E1D5DCAB571D100EA1D36D72CA28" -" ipv6=[2a01:4f9:2b:31a0::2]:4443" -/* nickname=billgates */ +"185.181.60.181 orport=443 id=335E993222204F6B4817134506494A6441DEFB6B" +" ipv6=[2a03:94e0:ffff:185:181:60:0:181]:443" +/* nickname=DowntimePatrol1 */ /* extrainfo=0 */ /* ===== */ , -"178.32.136.221 orport=443 id=A9F8CA97F0DD5F05F368B150CB10ECAB77581FAC" -/* nickname=JustBingIt */ +"185.42.170.203 orport=443 id=5D263037FC175596B3A344132B0B755EB8FB1D1C" +/* nickname=anduinExit01 */ /* extrainfo=0 */ /* ===== */ , -"77.207.22.214 orport=9001 id=8331DAA603F1ABCEBAA2C1C0AD5E4B85BE590DEA" -/* nickname=hyelko */ +"77.20.3.30 orport=433 id=781817A50379EE962CC031A7C059791CEF11ACC4" +/* nickname=DocTor */ /* extrainfo=0 */ /* ===== */ , -"89.191.217.1 orport=9001 id=F2ED5032B52021E7BADBBB82E6594F1A872FFD09" -/* nickname=runninglizard */ +"203.55.81.1 orport=443 id=5D9D80195162D7D77506EAF768F00F70A51CD191" +/* nickname=lunar1 */ /* extrainfo=0 */ /* ===== */ , -"152.86.13.25 orport=420 id=AA55B1F67922A2BCAE9BE491981BC9DA9167CE03" -/* nickname=MrNiceGuy */ +"5.135.68.65 orport=443 id=1580298405E54F02FF6F66637C3FC7077D363CDC" +" ipv6=[2001:41d0:303:9d44::1]:443" +/* nickname=Scalpay */ /* extrainfo=0 */ /* ===== */ , -"185.82.219.109 orport=443 id=2B34099ED2BC598C4745C96C873FD73A445646BD" -/* nickname=RunningOnFumes4 */ +"45.138.16.164 orport=8100 id=2FDB0E08C563AB5D225FDBD553D117C96D1160ED" +" ipv6=[2a12:a800:2:1:45:138:16:164]:8100" +/* nickname=Quetzalcoatl */ /* extrainfo=0 */ /* ===== */ , -"83.44.43.39 orport=80 id=9554FC0CF9A5200542E3375C8AE4E939C4594228" -/* nickname=FiveBoxingWizards */ +"37.187.149.125 orport=9001 id=46BACCCE4BC3CAA63D2FE770DA2AE3CF401B9CF0" +" ipv6=[2001:41d0:a:557d::1]:9001" +/* nickname=SORgaming */ /* extrainfo=0 */ /* ===== */ , -"46.231.93.216 orport=9001 id=F4F605AA21C4633CCB5B8DBBC1CEEE5C590C6DCE" -/* nickname=puertasecreta */ +"64.65.1.210 orport=443 id=08CBCC075BD2511E989823846F8F9505380F2740" +/* nickname=shotgunshane */ /* extrainfo=0 */ /* ===== */ , -"107.172.25.67 orport=443 id=172377C5231A1E25F3A4FA0FA082F09864BE6B71" -/* nickname=0 */ +"64.65.2.26 orport=443 id=556C9A64ED5489352B402ABB784B70CAE243D37C" +/* nickname=marleymarl */ /* extrainfo=0 */ /* ===== */ , -"84.216.26.137 orport=9001 id=DCAA176F75B04287131C6D78B7CFDDAC6F2691D9" -/* nickname=SweRaspiTor3 */ +"96.9.98.88 orport=443 id=E237E9F386F14456E99EED36B1FAC4F9F77B0F80" +/* nickname=stormyz */ /* extrainfo=0 */ /* ===== */ , -"138.201.55.77 orport=8445 id=632779C468355C7F7E55C248BC2F42CE2CA2A184" -" ipv6=[2a01:4f8:172:1045::2]:8445" -/* nickname=bauruine */ +"64.65.62.25 orport=443 id=722C8F1B5ADA4C274F36D7DD8A32DE7F3298242A" +/* nickname=lilwayne1 */ /* extrainfo=0 */ /* ===== */ , -"92.60.36.153 orport=9001 id=2D418A89F79DB4A8E658BA549FBB974D1D22DD1A" -" ipv6=[2a03:4000:33:6e3:1418:12ff:fe82:4abd]:9001" -/* nickname=MyPalEdSnowden */ +"45.84.107.200 orport=9100 id=9E2E162267A5F615AD8942EBAF90DC4297BC3D72" +" ipv6=[2a0d:bbc7::f816:3eff:feec:9f18]:9100" +/* nickname=prsv */ /* extrainfo=0 */ /* ===== */ , -"90.28.193.137 orport=9001 id=E05CAC929E391787077066C29461A9D22ECF0809" -/* nickname=albator */ +"109.69.218.176 orport=443 id=FA7136FD4F8A727810A22ED2096AF60F872C2F41" +/* nickname=vandewoestijne */ /* extrainfo=0 */ /* ===== */ , -"78.194.158.30 orport=9001 id=6189F0691D8AD1CBB373CAD3906E72238AC4364F" -" ipv6=[2a01:e34:ec29:e1e0:baae:edff:fe7d:7bd8]:9001" -/* nickname=seeidideditit */ +"64.65.1.142 orport=443 id=60EC7FF9D1922E8BE72878C15DD85932EE786ACA" +/* nickname=latto */ /* extrainfo=0 */ /* ===== */ , -"198.180.150.9 orport=9001 id=60E4C5E306D2DB22890EE24A09F9B6C30AF396A8" -" ipv6=[2001:418:8006::9]:9001" -/* nickname=rgiad */ +"171.25.193.39 orport=81 id=9A561CA579F0918D4E0C7A8533801B91C56FD605" +" ipv6=[2001:67c:289c:2::40]:81" +/* nickname=DFRI79 */ /* extrainfo=0 */ /* ===== */ , -"193.108.118.209 orport=587 id=B86137AE9681701901C6720E55C16805B46BD8E3" -" ipv6=[2604:86c0:f001:2:9baf:37c2:e99e:cafe]:587" -/* nickname=BeastieJoy60 */ +"66.92.214.63 orport=9001 id=0E33CE0721903F24B5680E1105D19EC4D7D335EB" +/* nickname=forest07 */ /* extrainfo=0 */ /* ===== */ , -"150.230.253.242 orport=36295 id=D7FEE7CF8D8246C3A74A598E48548142657FB7F1" -" ipv6=[2603:c024:1:f088:34::]:34785" -/* nickname=mrchau6 */ +"64.65.2.54 orport=443 id=8A5B9A2D0B37BE2F8ECFB14396EB4D432131D907" +/* nickname=bustarhymes */ /* extrainfo=0 */ /* ===== */ , -"185.220.101.86 orport=9100 id=EC8E0AF0670A443FDBC29806E77E81EE167DE765" -/* nickname=CCCStuttgartBer */ +"78.47.189.21 orport=1984 id=B939F036D9BF7FEA590BE961BFAB4C2E0641AC36" +" ipv6=[2a01:4f8:c0c:358b::1]:1984" +/* nickname=ReDHumus */ /* extrainfo=0 */ /* ===== */ , -"136.24.227.100 orport=9001 id=4E517F46EBED1393ACA6060E64CB2FD16EDC1576" -" ipv6=[2604:5500:c26d:be02:9776:aec7:b90e:526d]:9001" -/* nickname=hBridge */ +"64.65.0.56 orport=443 id=FB6F6C38348F3879C568F7AD7282697E69274E77" +/* nickname=bishoplamont */ /* extrainfo=0 */ /* ===== */ , -"94.16.114.247 orport=9002 id=D1FACB6FCE485D6710E919E08BCF923A6F4D101D" -" ipv6=[2a03:4000:28:174:3838:ceff:fe4b:a166]:9002" -/* nickname=Psi */ +"140.78.100.26 orport=5443 id=70B2D83BFCA9502E37EAF49DC685166718EADEFE" +/* nickname=INSRelay26at5443 */ /* extrainfo=0 */ /* ===== */ , -"107.189.12.101 orport=9001 id=AC9D89E7A99B7F95E115BE6D5D219D4196B09790" -/* nickname=devvulLU */ +"92.27.11.80 orport=9001 id=C7865D58EEFE96B92333E3C8BE3C0AAAA0000EEF" +" ipv6=[2001:470:1f08:4c7::2]:9001" +/* nickname=RealityNews */ /* extrainfo=0 */ /* ===== */ , -"204.8.156.142 orport=443 id=94C4B7B8C50C86A92B6A20107539EE2678CF9A28" -/* nickname=BostonUCompSci */ +"96.9.98.140 orport=443 id=24167CC4D183585A6AA4192B770F611F9D69C043" +/* nickname=famousdex */ /* extrainfo=0 */ /* ===== */ , -"135.181.213.167 orport=9100 id=BB2F9504B41CE4DF1BE3EA22A8A1853CA774BA36" -" ipv6=[2a01:4f9:3a:2b96::2]:9100" -/* nickname=privaterII */ +"50.103.128.207 orport=9006 id=D0B5734B42303C9FEDF5BDA1C2383C6195909A88" +/* nickname=raspberry */ /* extrainfo=0 */ /* ===== */ , -"185.177.229.20 orport=443 id=E697F38B3351FC0EF51A384C88404658D360E8E2" -" ipv6=[2604:86c0:f001:d:4973:1939:28c:b0b0]:443" -/* nickname=Doedelkiste7E */ +"81.16.33.42 orport=443 id=F21DFB7CCD5EEF3E021086EC96EF7CFCAA72F4F3" +/* nickname=pangea07 */ /* extrainfo=0 */ /* ===== */ , -"193.105.134.16 orport=9001 id=CDEAB87D26FC60F35474FEED676EBB13237D9FBC" -/* nickname=Sparker */ +"78.142.18.219 orport=8443 id=C05DCC87D7667D08EE4370D6CDB8CBEB6E0B4313" +/* nickname=bauruine */ /* extrainfo=0 */ /* ===== */ , -"188.94.124.99 orport=9001 id=483AAF032AF596B692FE2EEF03047B07E4B8736B" -" ipv6=[2a12:bec0:430:2::2]:9001" -/* nickname=ITPIPRelay */ +"171.25.193.36 orport=9001 id=F140945C1C795A367B0ACC5F67741857B73FA4B2" +" ipv6=[2001:67c:289c:2::35]:9001" +/* nickname=DFRI57 */ /* extrainfo=0 */ /* ===== */ , -"46.105.91.78 orport=9100 id=1D6528AA190F17B2C055CBD042D672778A265661" -/* nickname=Unnamed */ +"178.17.174.164 orport=443 id=9BAAA9CBA3109C2C807F2E84D5C9C0C8C147DCE6" +" ipv6=[2a00:1dc0:caff:73::a568]:443" +/* nickname=calator */ /* extrainfo=0 */ /* ===== */ , -"45.141.215.110 orport=9100 id=54687D59F8C8D90056CA94849970B362DA385DAD" -/* nickname=Quetzalcoatl */ +"64.65.62.115 orport=443 id=CE77E80343CCF0D68FAE60EC6637EF1829F64805" +/* nickname=jaykae */ /* extrainfo=0 */ /* ===== */ , -"89.163.128.25 orport=9001 id=AE6A8C18E7499B586CD36246AC4BCAFFBBF93AB2" -" ipv6=[2001:4ba0:ffff:237::10cc]:9001" -/* nickname=Doedel21 */ +"185.244.129.163 orport=9001 id=C171B79FF282D3394129D66D83AFEA85548138D1" +/* nickname=Sinker */ /* extrainfo=0 */ /* ===== */ , -"185.129.61.9 orport=443 id=6878541E2613946DCE1E454369190263D473BA73" -" ipv6=[2001:67c:89c:702:1ce:1ce:babe:9]:443" -/* nickname=dotsrcExit9 */ +"82.67.111.215 orport=9001 id=E58D998896E2464A989D4107AB4403C8AD9F32AE" +/* nickname=GigaTorOfHell2 */ /* extrainfo=0 */ /* ===== */ , -"185.73.220.8 orport=443 id=DAC825BBF05D678ABDEA1C3086E8D99CF0BBF112" -/* nickname=malene */ +"216.197.207.48 orport=9001 id=C366391E67A29CE959A15193D0CF2F9ED94F3578" +/* nickname=jorcanada */ /* extrainfo=0 */ /* ===== */ , -"138.197.166.92 orport=443 id=E26635F9ED41CDA8467C2AA992D81074337602EF" -/* nickname=NvorDarkdrop */ +"140.238.97.211 orport=9001 id=0B53297F0BD687103A00A514E7D2AB83C70F3700" +/* nickname=ruffletor */ /* extrainfo=0 */ /* ===== */ , -"68.171.179.124 orport=8234 id=085527CBD6485FD475AC983FA8683A2D9028BAA8" -/* nickname=pastly01 */ +"124.198.131.121 orport=8430 id=8B70848F74BD5A90F6B9E0CB555E7D8C18FF325F" +" ipv6=[2a12:a800:11:1:124:198:131:121]:8430" +/* nickname=Quetzalcoatl */ /* extrainfo=0 */ /* ===== */ , -"135.148.150.99 orport=443 id=A06CDA7922E2522BAD37AABDB51BC953CC41BEB8" -/* nickname=violin */ +"50.65.178.92 orport=9001 id=E690103F3E388A3D9C125936F1AE5C64C1A26D51" +" ipv6=[2604:3d09:667c:9560::9]:9001" +/* nickname=affinezeussv */ /* extrainfo=0 */ /* ===== */ , -"86.125.246.38 orport=9001 id=0A58B825C1159C2778BDA4817F10CB1DA4D6865D" -" ipv6=[2a02:2f0a:e211:8500:dea6:32ff:fef0:5e0d]:9001" -/* nickname=nebula */ +"73.68.62.87 orport=8443 id=CDB2605D2BD28DA31CC91956E8BAD147B7DF8AF9" +/* nickname=2mpdhack */ /* extrainfo=0 */ /* ===== */ , -"141.144.197.7 orport=443 id=908E600C32F9218975295C0BD5204FE84BF4A568" -" ipv6=[2603:c022:c004:feff:3685:a7d0:9baa:7b60]:443" -/* nickname=ColdSnowflake1128 */ +"172.245.106.179 orport=9001 id=C300E4E60EB8A73ED017540B36A3C6CEEBBCD2A9" +" ipv6=[2001:470:1f07:8b9::f7ae]:9001" +/* nickname=breaker39 */ /* extrainfo=0 */ /* ===== */ , -"103.21.3.89 orport=9001 id=819D5BC31172DC2D75488B1AAC66013EB15E459B" -/* nickname=Unnamed */ +"150.230.22.185 orport=9001 id=C42AB0BC0F7B4B7BB660F582B73C6A83AA89D245" +/* nickname=GEamsterdam */ /* extrainfo=0 */ /* ===== */ , -"173.79.7.70 orport=9001 id=48085FD5ECE14454BC7349E484602CB7C1036D82" -/* nickname=tactback1545 */ +"51.38.112.15 orport=9100 id=89F95502BDA81E44B67BADBFFF00DA80CDD4AFB5" +/* nickname=prsv */ /* extrainfo=0 */ /* ===== */ , -"168.70.63.205 orport=443 id=DA04BF208D36182E7BE35E1AA4E3867B5AEDE2DE" -/* nickname=IloveHK */ +"5.39.81.102 orport=9001 id=5500BAEEDC61A6685F687019196E1765171301D5" +" ipv6=[2001:41d0:8:9366::1]:9001" +/* nickname=p1onX01 */ /* extrainfo=0 */ /* ===== */ , -"195.15.242.29 orport=9001 id=74E8B68042A2774884BBF67E43ABEC4D9E5DF59A" -" ipv6=[2001:1600:10:100::3ab]:9001" -/* nickname=StarAppsTrenton */ +"64.65.1.30 orport=443 id=6DE6F463227B87923C12C83157C21ECC8764E9B2" +/* nickname=joegifted */ /* extrainfo=0 */ /* ===== */ , -"51.38.64.149 orport=443 id=BC2804813E63C8D3A88083EE1CAC93C4AABCC110" -" ipv6=[2001:41d0:801:2000::15a]:443" -/* nickname=blue */ +"64.65.2.43 orport=443 id=0842C38D6CDA0C9DA41032A43A4F30BF5264E13B" +/* nickname=pmddawn */ /* extrainfo=0 */ /* ===== */ , -"147.135.31.134 orport=443 id=7460C77412E8C8E65ABE1797C652161FE903EBFB" -/* nickname=AOP */ +"45.138.16.240 orport=7430 id=B85E978AEE73A9604FD9B124E1D834080AFC3FA4" +" ipv6=[2a12:a800:2:1:45:138:16:240]:7430" +/* nickname=Quetzalcoatl */ /* extrainfo=0 */ /* ===== */ , -"185.220.101.80 orport=9100 id=4F53BF996406B74E7DAB3DE1DA7983DE551B0113" -/* nickname=CCCStuttgartBer */ +"195.218.16.136 orport=9001 id=2D8768E3EA8B974ADB69F7FA8140DBEAFC14C8F0" +/* nickname=NotMyMothersRelay */ /* extrainfo=0 */ /* ===== */ , -"185.87.50.180 orport=443 id=26CE0AE5F373CBCBA24471D603BB5BE6A25593C1" -" ipv6=[2a0a:9300:d1::9ab]:443" -/* nickname=LetsDance */ +"5.2.79.190 orport=9001 id=02A8CCB1FB70984226231283596DA734A80E3F6F" +/* nickname=onionDAOrel0aded1 */ /* extrainfo=0 */ /* ===== */ , -"185.243.218.89 orport=12443 id=D034A1475CD6BB68A1F465B231ED90FB045AEBAA" -" ipv6=[2a03:94e0:242c:dead::1]:12443" -/* nickname=bauruine */ +"45.13.104.185 orport=9001 id=234D670EAA794F092F7BD758D5D2AA7F4E3FFBE3" +" ipv6=[2a0b:cbc0:1100:1a::1]:9001" +/* nickname=Ceres */ /* extrainfo=0 */ /* ===== */ , -"185.241.208.206 orport=9200 id=0806B64E53BD3ED2F0BDB5EED8DBF81DF331F45A" -/* nickname=Aramis */ +"124.198.131.62 orport=9000 id=49B422AB305669407516E4A0D4CE5BEACE3E2432" +" ipv6=[2a12:a800:11:1:124:198:131:62]:9000" +/* nickname=Quetzalcoatl */ /* extrainfo=0 */ /* ===== */ , -"91.132.145.245 orport=9001 id=447A24F3402C4774D89E7AAD2D876D0BF64E3267" -" ipv6=[2a03:4000:37:76e:68f6:30ff:fe7c:a4]:9001" -/* nickname=m0rix */ +"192.121.44.27 orport=9001 id=ABC5A7A6D5C609512F5D7CD2B490CE7366F00D60" +" ipv6=[2a09:be40:28ff:50:c4c9:3dff:fea3:f4fa]:9001" +/* nickname=Playstar02 */ /* extrainfo=0 */ /* ===== */ , -"91.203.145.116 orport=443 id=8D1085E818D0473EC693E3B0911FF18741F1F2DF" -/* nickname=Raptor */ +"64.65.1.144 orport=443 id=DEB01655570C9BCB968F6EEA95B2E4F85F6C99CF" +/* nickname=shine1k */ /* extrainfo=0 */ /* ===== */ , -"87.120.237.130 orport=9001 id=CF9BEB3E3554C5C343024641A91CC9AE6B849882" -/* nickname=vunreteqrado */ +"64.65.1.52 orport=443 id=137E23C6BA0863C229D68A64C0E0BD0F2D17D6D2" +/* nickname=greasymiami */ /* extrainfo=0 */ /* ===== */ , -"51.81.56.123 orport=443 id=401651D4C130090D5CA2C9F17C2ECBB0748F30F8" -/* nickname=trash2 */ +"107.189.30.236 orport=9000 id=A4F42AE65F11634C42A3F3952E719F47091BD36F" +" ipv6=[2605:6400:30:f5a3:5bb1:af4e:c969:c73e]:9000" +/* nickname=Quetzalcoatl */ /* extrainfo=0 */ /* ===== */ , -"90.143.213.98 orport=9001 id=372DE4EF044885ABB756E10024A410F50CF222E0" -/* nickname=unryzerRelay */ +"178.20.55.16 orport=19001 id=CFAB19E23290F5BA1F7FF24494D26FBD4E4DF6CE" +" ipv6=[2a00:1b88:4::2]:19001" +/* nickname=marcuse4 */ /* extrainfo=0 */ /* ===== */ , -"104.244.73.136 orport=9001 id=322967A70161145738F6CEB4F5165FDADF9EB27C" -" ipv6=[2605:6400:30:edc3::34]:9001" -/* nickname=4715 */ +"82.223.103.104 orport=53421 id=5F6C321216267A086F6B3634BA4664297C504F5E" +" ipv6=[2001:ba0:214:a800::1]:53421" +/* nickname=TORkedOff */ /* extrainfo=0 */ /* ===== */ , -"157.90.146.188 orport=1337 id=5F96CDCAEED3A18CDBAB2B5AFC85334B12E5FD73" -" ipv6=[2a01:4f8:c012:842e::1]:1337" -/* nickname=GermanCraft11 */ +"108.181.57.251 orport=443 id=AFEAF3A9E0DB1D837BE8FF1983BA0C65A3E71D73" +/* nickname=osterreich */ /* extrainfo=0 */ /* ===== */ , -"172.104.148.219 orport=9001 id=3A4FDF6B88950212E74D4C7BD40E021D4EAA0288" -" ipv6=[2a01:7e01::f03c:91ff:fe39:a130]:9001" -/* nickname=lttao4532 */ +"124.198.131.114 orport=8100 id=52F1B080FB427CEE1D3D190B97776B704879FA08" +" ipv6=[2a12:a800:11:1:124:198:131:114]:8100" +/* nickname=Quetzalcoatl */ /* extrainfo=0 */ /* ===== */ , -"193.35.18.95 orport=9300 id=A2EDA667F3B15E0ADDC7E3FA3DA18667C9AD020F" -" ipv6=[2a05:dfc7:40b8::1]:9300" +"135.125.183.193 orport=9300 id=949838C7EDCBC3AA0FF057935D2E7AD9184389BD" +" ipv6=[2001:41d0:701:1100::9e20]:9300" /* nickname=prsv */ /* extrainfo=0 */ /* ===== */ , -"116.12.180.237 orport=443 id=10805A3833774B812D07EB7D1D75A54021590F56" -/* nickname=tommyboy */ +"37.221.195.103 orport=9001 id=C54AB7F3CCAB01BAF61A6F7337AE1F60D8BB940D" +" ipv6=[2a03:4000:8:61b:85e:b6ff:fefa:8752]:9001" +/* nickname=fedoriansRelayTor */ /* extrainfo=0 */ /* ===== */ , -"193.189.100.194 orport=443 id=6DFEB2BFBFA9DBEDCE2DE932F9D16EE7E0530ED1" -" ipv6=[2a0f:df00:0:255::194]:443" -/* nickname=TORKeFFORG1 */ +"45.89.127.221 orport=9001 id=9CCC3E2BC7FA56F602020AC9D77FE19A3727D0DD" +/* nickname=apalaris */ /* extrainfo=0 */ /* ===== */ , -"185.220.101.77 orport=9000 id=A1AC4E5DEA2D24032BF586A3ADFDE7BD11761857" -/* nickname=CCCStuttgartBer */ +"23.129.64.202 orport=443 id=60904553C1C40F3C503F3F10E2F7F6DEBECD6CBF" +" ipv6=[2620:18c:0:192::e0:202]:443" +/* nickname=eo202 */ /* extrainfo=0 */ /* ===== */ , -"185.21.100.50 orport=4443 id=58ED9C9C35E433EE58764D62892B4FFD518A3CD0" -" ipv6=[2a00:1158:2:cd00:0:74:6f:72]:443" -/* nickname=SamAAdams2 */ +"188.172.228.104 orport=443 id=83C8D4A066522D230D640FE3592A810C59669B25" +" ipv6=[2a0a:4cc0:3:10d::42]:443" +/* nickname=Totoro4220 */ /* extrainfo=0 */ /* ===== */ , -"198.98.48.20 orport=9100 id=6C95E81A86B48DB835AE1431277A301318422A18" -" ipv6=[2605:6400:10:c39:3b1c:a9d9:fb78:d7f1]:9100" -/* nickname=Quetzalcoatl */ +"15.204.140.9 orport=8443 id=3FB88013FAC7AB8F479F33F5B484BE9F444330C3" +/* nickname=Parzival */ /* extrainfo=0 */ /* ===== */ , -"185.220.101.38 orport=10038 id=FF5D538B72DAC854D4C8FE3A637C242F5B54649A" -" ipv6=[2a0b:f4c2:2::38]:10038" -/* nickname=ForPrivacyNET */ +"95.216.145.1 orport=1066 id=B9C8AA1EA320CF1BD3E0D158C3E76705A2CB9D2C" +" ipv6=[2a01:4f9:c010:8fb::bee]:1066" +/* nickname=karnak */ /* extrainfo=0 */ /* ===== */ , -"185.241.208.204 orport=9400 id=26551EE9CF98BEE9E7CCA1954B71CC724B3D1A25" -/* nickname=Aramis */ +"144.217.90.187 orport=9001 id=7040C1F5728746C5FB5E12845101A26EE8636D7E" +" ipv6=[2607:5300:201:3100::5b0d]:9001" +/* nickname=SaruTorUmidanuki */ /* extrainfo=0 */ /* ===== */ , -"138.201.55.77 orport=8443 id=7B5720666CD386AF852F6E2CC94C24F2502BAF15" -" ipv6=[2a01:4f8:172:1045::2]:8443" -/* nickname=bauruine */ +"51.81.222.62 orport=9001 id=7BC8F2680657BE6C51B51FF6EE113E739D85EDDE" +" ipv6=[2604:2dc0:202:300::ed3]:9001" +/* nickname=Tor2DotTeitelNet */ /* extrainfo=0 */ /* ===== */ , -"193.11.114.46 orport=9003 id=B83DC1558F0D34353BB992EF93AFEAFDB226A73E" -" ipv6=[2001:6b0:30:1000::101]:9050" -/* nickname=mdfnet3 */ +"82.153.138.57 orport=9003 id=6C5496CC85F96FF6B4BE0B2952A523BEB84184E6" +/* nickname=obzgs5tbmn4q */ /* extrainfo=0 */ /* ===== */ , -"37.120.190.6 orport=1993 id=CBA653B8678CF7BEF7C2C1BCDCA0807CD449A8AB" -/* nickname=teutates2 */ +"107.189.7.144 orport=9100 id=4EFF3D0C9DE539CF1E27BFC5B3E23BC7CB2D41A9" +" ipv6=[2605:6400:30:f1fa:f57f:d285:3ed9:ee27]:9100" +/* nickname=Quetzalcoatl */ /* extrainfo=0 */ /* ===== */ , -"135.148.100.84 orport=443 id=4A4EFB3E9347189B6AB9453844692CCA1F46A4C7" -/* nickname=netzwerkspaB */ +"78.142.18.219 orport=12444 id=92F187D29A0F0DAEB929511D8870F3E9F0F46D46" +/* nickname=bauruine */ /* extrainfo=0 */ /* ===== */ , diff -Nru tor-0.4.7.16/src/app/config/include.am tor-0.4.9.6/src/app/config/include.am --- tor-0.4.7.16/src/app/config/include.am 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/app/config/include.am 2026-03-25 14:30:34.000000000 +0000 @@ -16,7 +16,6 @@ src/app/config/statefile.h \ src/app/config/tor_cmdline_mode.h - noinst_HEADERS += \ src/app/config/auth_dirs.inc \ src/app/config/fallback_dirs.inc \ diff -Nru tor-0.4.7.16/src/app/config/or_options_st.h tor-0.4.9.6/src/app/config/or_options_st.h --- tor-0.4.7.16/src/app/config/or_options_st.h 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/app/config/or_options_st.h 2026-03-25 14:30:34.000000000 +0000 @@ -89,6 +89,10 @@ char *KeyDirectory; /**< Where to store keys data, as modified. */ int KeyDirectoryGroupReadable; /**< Boolean: Is the KeyDirectory g+r? */ + char *FamilyKeyDirectory_option; /**< Where to look for family ID keys, + * as configured by the user. */ + char *FamilyKeyDirectory; /**< Where to look for family ID keys. */ + char *CacheDirectory_option; /**< Where to store cached data, as * configured by the user. */ char *CacheDirectory; /**< Where to store cached data, as modified. */ @@ -141,6 +145,8 @@ * Includes OutboundBindAddresses and * configured ports. */ int ReducedExitPolicy; /**

  • for processing onionskins in onion.c *
  • for compressing consensuses in consdiffmgr.c, - *
  • and for calculating diffs and compressing them in consdiffmgr.c. + *
  • for calculating diffs and compressing them in consdiffmgr.c. + *
  • and for solving onion service PoW challenges in pow.c. *
**/ #include "core/or/or.h" @@ -73,7 +74,6 @@ worker_state_free_(arg); } -static replyqueue_t *replyqueue = NULL; static threadpool_t *threadpool = NULL; static uint32_t total_pending_tasks = 0; @@ -113,35 +113,42 @@ set_max_pending_tasks(ns); } -/** Initialize the cpuworker subsystem. It is OK to call this more than once - * during Tor's lifetime. - */ -void -cpu_init(void) -{ - if (!replyqueue) { - replyqueue = replyqueue_new(0); - } +/** Initialize the cpuworker subsystem. */ +int +cpuworker_init(void) +{ + /* + In our threadpool implementation, half the threads are permissive and + half are strict (when it comes to running lower-priority tasks). So we + always make sure we have at least two threads, so that there will be at + least one thread of each kind. + */ + const int n_threads = MAX(get_num_cpus(get_options()), 2); + threadpool = threadpool_new(n_threads, + replyqueue_new(0), + worker_state_new, + worker_state_free_void, + NULL); + if (!threadpool) { - /* - In our threadpool implementation, half the threads are permissive and - half are strict (when it comes to running lower-priority tasks). So we - always make sure we have at least two threads, so that there will be at - least one thread of each kind. - */ - const int n_threads = get_num_cpus(get_options()) + 1; - threadpool = threadpool_new(n_threads, - replyqueue, - worker_state_new, - worker_state_free_void, - NULL); + log_err(LD_GENERAL, "Can't create worker thread pool"); + return -1; + } - int r = threadpool_register_reply_event(threadpool, NULL); + int r = threadpool_register_reply_event(threadpool, NULL); - tor_assert(r == 0); - } + tor_assert(r == 0); set_max_pending_tasks(NULL); + + return 0; +} + +/** Free all resources allocated by cpuworker. */ +void +cpuworker_free_all(void) +{ + threadpool_free(threadpool); } /** Return the number of threads configured for our CPU worker. */ @@ -206,7 +213,9 @@ /** The created cell to send back. */ created_cell_t created_cell; /** The keys to use on this circuit. */ - uint8_t keys[CPATH_KEY_MATERIAL_LEN]; + uint8_t keys[MAX_RELAY_KEY_MATERIAL_LEN]; + /** Length of the generated key material. */ + size_t keys_len; /** Input to use for authenticating introduce1 cells. */ uint8_t rend_auth_material[DIGEST_LEN]; /** Negotiated circuit parameters. */ @@ -444,9 +453,12 @@ } } + circ->relay_cell_format = rpl.circ_params.cell_fmt; + if (onionskin_answer(circ, &rpl.created_cell, - (const char*)rpl.keys, sizeof(rpl.keys), + rpl.circ_params.crypto_alg, + (const char*)rpl.keys, rpl.keys_len, rpl.rend_auth_material) < 0) { log_warn(LD_OR,"onionskin_answer failed. Closing."); circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_INTERNAL); @@ -488,15 +500,17 @@ rpl.handshake_type = cc->handshake_type; if (req.timed) tor_gettimeofday(&tv_start); + rpl.keys_len = sizeof(rpl.keys); n = onion_skin_server_handshake(cc->handshake_type, cc->onionskin, cc->handshake_len, onion_keys, &req.circ_ns_params, cell_out->reply, sizeof(cell_out->reply), - rpl.keys, CPATH_KEY_MATERIAL_LEN, + rpl.keys, &rpl.keys_len, rpl.rend_auth_material, &rpl.circ_params); + if (n < 0) { /* failure */ log_debug(LD_OR,"onion_skin_server_handshake failed."); diff -Nru tor-0.4.7.16/src/core/mainloop/cpuworker.h tor-0.4.9.6/src/core/mainloop/cpuworker.h --- tor-0.4.7.16/src/core/mainloop/cpuworker.h 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/core/mainloop/cpuworker.h 2026-03-25 14:30:34.000000000 +0000 @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2021, The Tor Project, Inc. */ + * Copyright (c) 2007-2024, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -12,9 +12,8 @@ #ifndef TOR_CPUWORKER_H #define TOR_CPUWORKER_H -#include "feature/nodelist/networkstatus_st.h" - -void cpu_init(void); +int cpuworker_init(void); +void cpuworker_free_all(void); void cpuworkers_rotate_keyinfo(void); void cpuworker_consensus_has_changed(const networkstatus_t *ns); diff -Nru tor-0.4.7.16/src/core/mainloop/include.am tor-0.4.9.6/src/core/mainloop/include.am --- tor-0.4.7.16/src/core/mainloop/include.am 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/core/mainloop/include.am 2026-03-25 14:30:34.000000000 +0000 @@ -1,6 +1,6 @@ # ADD_C_FILE: INSERT SOURCES HERE. -LIBTOR_APP_A_SOURCES += \ +LIBTOR_APP_A_SOURCES += \ src/core/mainloop/connection.c \ src/core/mainloop/cpuworker.c \ src/core/mainloop/mainloop.c \ @@ -15,8 +15,8 @@ src/core/mainloop/cpuworker.h \ src/core/mainloop/mainloop.h \ src/core/mainloop/mainloop_pubsub.h \ - src/core/mainloop/mainloop_state.inc \ - src/core/mainloop/mainloop_state_st.h \ + src/core/mainloop/mainloop_state.inc \ + src/core/mainloop/mainloop_state_st.h \ src/core/mainloop/mainloop_sys.h \ src/core/mainloop/netstatus.h \ src/core/mainloop/periodic.h diff -Nru tor-0.4.7.16/src/core/mainloop/mainloop.c tor-0.4.9.6/src/core/mainloop/mainloop.c --- tor-0.4.7.16/src/core/mainloop/mainloop.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/core/mainloop/mainloop.c 2026-03-25 14:30:34.000000000 +0000 @@ -21,7 +21,7 @@ *
  • signal_callback(), which handles incoming signals. * * Other events are used for specific purposes, or for building more complex - * control structures. If you search for usage of tor_libevent_new(), you + * control structures. If you search for usage of tor_event_new(), you * will find all the events that we construct in Tor. * * Tor has numerous housekeeping operations that need to happen @@ -274,16 +274,8 @@ void connection_unregister_events(connection_t *conn) { - if (conn->read_event) { - if (event_del(conn->read_event)) - log_warn(LD_BUG, "Error removing read event for %d", (int)conn->s); - tor_free(conn->read_event); - } - if (conn->write_event) { - if (event_del(conn->write_event)) - log_warn(LD_BUG, "Error removing write event for %d", (int)conn->s); - tor_free(conn->write_event); - } + tor_event_free(conn->read_event); + tor_event_free(conn->write_event); if (conn->type == CONN_TYPE_AP_DNS_LISTENER) { dnsserv_close_listener(conn); } @@ -505,7 +497,7 @@ /** Return true iff conn is listening for read events. */ int -connection_is_reading(connection_t *conn) +connection_is_reading(const connection_t *conn) { tor_assert(conn); @@ -653,6 +645,16 @@ "to watched: %s", (int)conn->s, tor_socket_strerror(tor_socket_errno(conn->s))); + + /* Process the inbuf if it is not empty because the only way to empty it is + * through a read event or a SENDME which might not come if the package + * window is proper or if the application has nothing more for us to read. + * + * If this is not done here, we risk having data lingering in the inbuf + * forever. */ + if (conn->inbuf && buf_datalen(conn->inbuf) > 0) { + connection_process_inbuf(conn, 1); + } } } @@ -1269,8 +1271,8 @@ log_fn(LOG_PROTOCOL_WARN,LD_PROTOCOL, "Expiring stuck OR connection to fd %d (%s:%d). (%d bytes to " "flush; %d seconds since last write)", - (int)conn->s, fmt_and_decorate_addr(&conn->addr), conn->port, - (int)connection_get_outbuf_len(conn), + (int)conn->s, safe_str(fmt_and_decorate_addr(&conn->addr)), + conn->port, (int)connection_get_outbuf_len(conn), (int)(now-conn->timestamp_last_write_allowed)); connection_or_close_normally(TO_OR_CONN(conn), 0); } else if (past_keepalive && !connection_get_outbuf_len(conn)) { @@ -2330,6 +2332,7 @@ reset_bandwidth_test(); reset_uptime(); router_reset_reachability(); + pt_update_bridge_lines(); /* All relays include their IP addresses as their ORPort addresses in * their descriptor. * Exit relays also incorporate interface addresses in their exit diff -Nru tor-0.4.7.16/src/core/mainloop/mainloop.h tor-0.4.9.6/src/core/mainloop/mainloop.h --- tor-0.4.7.16/src/core/mainloop/mainloop.h 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/core/mainloop/mainloop.h 2026-03-25 14:30:34.000000000 +0000 @@ -38,7 +38,7 @@ WRITE_EVENT=0x04 /**< We want to know when a connection is writable */ } watchable_events_t; void connection_watch_events(connection_t *conn, watchable_events_t events); -int connection_is_reading(connection_t *conn); +int connection_is_reading(const connection_t *conn); MOCK_DECL(void,connection_stop_reading,(connection_t *conn)); MOCK_DECL(void,connection_start_reading,(connection_t *conn)); diff -Nru tor-0.4.7.16/src/core/or/channel.c tor-0.4.9.6/src/core/or/channel.c --- tor-0.4.7.16/src/core/or/channel.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/core/or/channel.c 2026-03-25 14:30:34.000000000 +0000 @@ -83,6 +83,7 @@ #include "lib/time/compat_time.h" #include "core/or/cell_queue_st.h" +#include "core/or/or_connection_st.h" /* Global lists of channels */ @@ -817,22 +818,26 @@ log_notice(LD_OR, "Your relay has a very large number of connections to other relays. " "Is your outbound address the same as your relay address? " - "Found %d connections to %d relays. Found %d current canonical " - "connections, in %d of which we were a non-canonical peer. " + "Found %d connections to authorities, %d connections to %d relays. " + "Found %d current canonical connections, " + "in %d of which we were a non-canonical peer. " "%d relays had more than 1 connection, %d had more than 2, and " "%d had more than 4 connections.", - total_relay_connections, total_relays, total_canonical, - total_half_canonical, total_gt_one_connection, - total_gt_two_connections, total_gt_four_connections); + total_dirauth_connections, total_relay_connections, + total_relays, total_canonical, total_half_canonical, + total_gt_one_connection, total_gt_two_connections, + total_gt_four_connections); } else { log_info(LD_OR, "Performed connection pruning. " - "Found %d connections to %d relays. Found %d current canonical " - "connections, in %d of which we were a non-canonical peer. " + "Found %d connections to authorities, %d connections to %d relays. " + "Found %d current canonical connections, " + "in %d of which we were a non-canonical peer. " "%d relays had more than 1 connection, %d had more than 2, and " "%d had more than 4 connections.", - total_relay_connections, total_relays, total_canonical, - total_half_canonical, total_gt_one_connection, - total_gt_two_connections, total_gt_four_connections); + total_dirauth_connections, total_relay_connections, + total_relays, total_canonical, total_half_canonical, + total_gt_one_connection, total_gt_two_connections, + total_gt_four_connections); } } @@ -1280,7 +1285,7 @@ /* Inform any pending (not attached) circs that they should * give up. */ if (! chan->has_been_open) - circuit_n_chan_done(chan, 0, 0); + circuit_n_chan_done(chan, 0); /* Now close all the attached circuits on it. */ circuit_unlink_all_from_channel(chan, END_CIRC_REASON_CHANNEL_CLOSED); @@ -1860,8 +1865,6 @@ { tor_addr_t remote_addr; int started_here; - time_t now = time(NULL); - int close_origin_circuits = 0; tor_assert(chan); @@ -1871,22 +1874,25 @@ circuit_build_times_network_is_live(get_circuit_build_times_mutable()); router_set_status(chan->identity_digest, 1); } else { - /* only report it to the geoip module if it's a client */ + /* only report it to the geoip module if it's a client and it hasn't + * already been set up for tracking earlier. (Incoming TLS connections + * are tracked before the handshake.) */ if (channel_is_client(chan)) { if (channel_get_addr_if_possible(chan, &remote_addr)) { - char *transport_name = NULL; channel_tls_t *tlschan = BASE_CHAN_TO_TLS(chan); - if (chan->get_transport_name(chan, &transport_name) < 0) - transport_name = NULL; - - geoip_note_client_seen(GEOIP_CLIENT_CONNECT, - &remote_addr, transport_name, - now); - /* Notify the DoS subsystem of a new client. */ - if (tlschan && tlschan->conn) { - dos_new_client_conn(tlschan->conn, transport_name); + if (!tlschan->conn->tracked_for_dos_mitigation) { + char *transport_name = NULL; + if (chan->get_transport_name(chan, &transport_name) < 0) { + transport_name = NULL; + } + geoip_note_client_seen(GEOIP_CLIENT_CONNECT, + &remote_addr, transport_name, + time(NULL)); + if (tlschan && tlschan->conn) { + dos_new_client_conn(tlschan->conn, transport_name); + } + tor_free(transport_name); } - tor_free(transport_name); } /* Otherwise the underlying transport can't tell us this, so skip it */ } @@ -1911,7 +1917,7 @@ } } - circuit_n_chan_done(chan, 1, close_origin_circuits); + circuit_n_chan_done(chan, 1); } /** diff -Nru tor-0.4.7.16/src/core/or/channel.h tor-0.4.9.6/src/core/or/channel.h --- tor-0.4.7.16/src/core/or/channel.h 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/core/or/channel.h 2026-03-25 14:30:34.000000000 +0000 @@ -97,6 +97,7 @@ * * Permitted transitions from: * - CHANNEL_STATE_MAINT + * - CHANNEL_STATE_OPENING * - CHANNEL_STATE_OPEN * Permitted transitions to: * - CHANNEL_STATE_CLOSED, diff -Nru tor-0.4.7.16/src/core/or/channelpadding.c tor-0.4.9.6/src/core/or/channelpadding.c --- tor-0.4.7.16/src/core/or/channelpadding.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/core/or/channelpadding.c 2026-03-25 14:30:34.000000000 +0000 @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2021, The Tor Project, Inc. */ + * Copyright (c) 2007-2025, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -38,6 +38,13 @@ STATIC int channelpadding_send_disable_command(channel_t *); STATIC int64_t channelpadding_compute_time_until_pad_for_netflow(channel_t *); +/** Total channel padding delay of delays that exceeded the allowed time + * window since last heartbeat or, if no heartbeat yet, since startup */ +static uint64_t channel_padding_delayed_ms = 0; +/** Amount of delays that exceeded the allowed time window since + * last heartbeat or, if no heartbeat yet, since startup */ +static uint64_t channel_padding_delayed_count = 0; + /** The total number of pending channelpadding timers */ static uint64_t total_timers_pending; @@ -565,11 +572,14 @@ * about it entirely.. */ #define NETFLOW_MISSED_WINDOW (150000 - DFLT_NETFLOW_INACTIVE_KEEPALIVE_HIGH) if (ms_till_pad < 0) { - int severity = (ms_till_pad < -NETFLOW_MISSED_WINDOW) - ? LOG_NOTICE : LOG_INFO; - log_fn(severity, LD_OR, - "Channel padding timeout scheduled %"PRId64"ms in the past. ", - (-ms_till_pad)); + if (ms_till_pad < -NETFLOW_MISSED_WINDOW) { + log_info(LD_OR, + "Channel padding delay of %"PRIu64"ms occurred in the past " + "that exceeded the allowed time window.", + (-ms_till_pad)); + channel_padding_delayed_ms -= ms_till_pad; + channel_padding_delayed_count += 1; + } return 0; /* Clock jumped: Send padding now */ } @@ -797,3 +807,28 @@ return CHANNELPADDING_PADLATER; } } + +/* Log a heartbeat message with the average channel padding delay and + * the number of occurred delays (that exceeded the allowed time window) + * since the previous heartbeat or, if we didn't have a heartbeat yet, + * since startup. */ +void +channelpadding_log_heartbeat(void) +{ + /* Whether we had a heartbeat since startup */ + static uint8_t heartbeat = 0; + + if (channel_padding_delayed_count > 0) { + log_notice(LD_OR, + "Average channel padding delay of delays that exceeded " + "the allowed time window since %s: %"PRIu64"ms " + "(Number of delays: %"PRIu64")", + heartbeat ? "previous heartbeat" : "startup", + (uint64_t)((double)channel_padding_delayed_ms / + channel_padding_delayed_count), + channel_padding_delayed_count); + channel_padding_delayed_count = 0; + channel_padding_delayed_ms = 0; + } + heartbeat = 1; +} diff -Nru tor-0.4.7.16/src/core/or/channelpadding.h tor-0.4.9.6/src/core/or/channelpadding.h --- tor-0.4.7.16/src/core/or/channelpadding.h 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/core/or/channelpadding.h 2026-03-25 14:30:34.000000000 +0000 @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2021, The Tor Project, Inc. */ + * Copyright (c) 2007-2025, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -39,4 +39,6 @@ unsigned int channelpadding_get_channel_idle_timeout(const channel_t *, int); void channelpadding_new_consensus_params(const networkstatus_t *ns); +void channelpadding_log_heartbeat(void); + #endif /* !defined(TOR_CHANNELPADDING_H) */ diff -Nru tor-0.4.7.16/src/core/or/channeltls.c tor-0.4.9.6/src/core/or/channeltls.c --- tor-0.4.7.16/src/core/or/channeltls.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/core/or/channeltls.c 2026-03-25 14:30:34.000000000 +0000 @@ -44,6 +44,7 @@ #include "core/or/circuitmux.h" #include "core/or/circuitmux_ewma.h" #include "core/or/command.h" +#include "core/or/dos.h" #include "app/config/config.h" #include "app/config/resolve_addr.h" #include "core/mainloop/connection.h" @@ -54,6 +55,7 @@ #include "trunnel/link_handshake.h" #include "core/or/relay.h" #include "feature/stats/rephist.h" +#include "feature/stats/geoip_stats.h" #include "feature/relay/router.h" #include "feature/relay/routermode.h" #include "feature/nodelist/dirlist.h" @@ -358,6 +360,20 @@ /* Register it */ channel_register(chan); + char *transport_name = NULL; + if (channel_tls_get_transport_name_method(TLS_CHAN_TO_BASE(orconn->chan), + &transport_name) < 0) { + transport_name = NULL; + } + /* Start tracking TLS connections in the DoS subsystem as soon as possible, + * so we can protect against attacks that use partially open connections. + */ + geoip_note_client_seen(GEOIP_CLIENT_CONNECT, + &TO_CONN(orconn)->addr, transport_name, + time(NULL)); + dos_new_client_conn(orconn, transport_name); + tor_free(transport_name); + return chan; } @@ -1222,26 +1238,6 @@ return; switch (TO_CONN(conn)->state) { - case OR_CONN_STATE_OR_HANDSHAKING_V2: - if (var_cell->command != CELL_VERSIONS) { - log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, - "Received a cell with command %d in unexpected " - "orconn state \"%s\" [%d], channel state \"%s\" [%d]; " - "closing the connection.", - (int)(var_cell->command), - conn_state_to_string(CONN_TYPE_OR, TO_CONN(conn)->state), - TO_CONN(conn)->state, - channel_state_to_string(TLS_CHAN_TO_BASE(chan)->state), - (int)(TLS_CHAN_TO_BASE(chan)->state)); - /* - * The code in connection_or.c will tell channel_t to close for - * error; it will go to CHANNEL_STATE_CLOSING, and then to - * CHANNEL_STATE_ERROR when conn is closed. - */ - connection_or_close_for_error(conn, 0); - return; - } - break; case OR_CONN_STATE_TLS_HANDSHAKING: /* If we're using bufferevents, it's entirely possible for us to * notice "hey, data arrived!" before we notice "hey, the handshake @@ -1250,7 +1246,7 @@ /* But that should be happening any longer've disabled bufferevents. */ tor_assert_nonfatal_unreached_once(); FALLTHROUGH_UNLESS_ALL_BUGS_ARE_FATAL; - case OR_CONN_STATE_TLS_SERVER_RENEGOTIATING: + case OR_CONN_STATE_SERVER_VERSIONS_WAIT: if (!(command_allowed_before_handshake(var_cell->command))) { log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "Received a cell with command %d in unexpected " @@ -1420,14 +1416,13 @@ tor_assert(TO_CONN(chan->conn)->state == OR_CONN_STATE_TLS_HANDSHAKING || TO_CONN(chan->conn)->state == - OR_CONN_STATE_TLS_SERVER_RENEGOTIATING); + OR_CONN_STATE_SERVER_VERSIONS_WAIT); if (started_here) { log_fn(LOG_PROTOCOL_WARN, LD_OR, "Received a cell while TLS-handshaking, not in " "OR_HANDSHAKING_V3, on a connection we originated."); } - connection_or_block_renegotiation(chan->conn); connection_or_change_state(chan->conn, OR_CONN_STATE_OR_HANDSHAKING_V3); if (connection_init_or_handshake_state(chan->conn, started_here) < 0) { connection_or_close_for_error(chan->conn, 0); @@ -1478,11 +1473,10 @@ } switch (chan->conn->base_.state) { - case OR_CONN_STATE_OR_HANDSHAKING_V2: case OR_CONN_STATE_OR_HANDSHAKING_V3: break; case OR_CONN_STATE_TLS_HANDSHAKING: - case OR_CONN_STATE_TLS_SERVER_RENEGOTIATING: + case OR_CONN_STATE_SERVER_VERSIONS_WAIT: default: log_fn(LOG_PROTOCOL_WARN, LD_OR, "VERSIONS cell while in unexpected state"); @@ -1521,15 +1515,6 @@ "handshake. Closing connection."); connection_or_close_for_error(chan->conn, 0); return; - } else if (highest_supported_version != 2 && - chan->conn->base_.state == OR_CONN_STATE_OR_HANDSHAKING_V2) { - /* XXXX This should eventually be a log_protocol_warn */ - log_fn(LOG_WARN, LD_OR, - "Negotiated link with non-2 protocol after doing a v2 TLS " - "handshake with %s. Closing connection.", - connection_describe_peer(TO_CONN(chan->conn))); - connection_or_close_for_error(chan->conn, 0); - return; } rep_hist_note_negotiated_link_proto(highest_supported_version, started_here); @@ -1717,8 +1702,7 @@ } /* Can't process a NETINFO cell if the connection is not handshaking. */ - if (chan->conn->base_.state != OR_CONN_STATE_OR_HANDSHAKING_V2 && - chan->conn->base_.state != OR_CONN_STATE_OR_HANDSHAKING_V3) { + if (chan->conn->base_.state != OR_CONN_STATE_OR_HANDSHAKING_V3) { log_fn(LOG_PROTOCOL_WARN, LD_OR, "Received a NETINFO cell on non-handshaking connection; dropping."); return false; @@ -2449,22 +2433,20 @@ ERR("Authenticator was too short"); expected_cell = connection_or_compute_authenticate_cell_body( - chan->conn, authtype, NULL, NULL, 1); + chan->conn, authtype, NULL, 1); if (! expected_cell) ERR("Couldn't compute expected AUTHENTICATE cell body"); - int sig_is_rsa; - if (authtype == AUTHTYPE_RSA_SHA256_TLSSECRET || - authtype == AUTHTYPE_RSA_SHA256_RFC5705) { - bodylen = V3_AUTH_BODY_LEN; - sig_is_rsa = 1; + if (BUG(authtype != AUTHTYPE_ED25519_SHA256_RFC5705)) { + /* We should have detected that we don't support this + * authentication type earlier, when we called + * authchallenge_type_is_supported(). */ + ERR("Unsupported authentication type"); } else { - tor_assert(authtype == AUTHTYPE_ED25519_SHA256_RFC5705); /* Our earlier check had better have made sure we had room * for an ed25519 sig (inadvertently) */ tor_assert(V3_AUTH_BODY_LEN > ED25519_SIG_LEN); bodylen = authlen - ED25519_SIG_LEN; - sig_is_rsa = 0; } if (expected_cell->payload_len != bodylen+4) { ERR("Expected AUTHENTICATE cell body len not as expected."); @@ -2480,47 +2462,7 @@ if (tor_memneq(expected_cell->payload+4, auth, bodylen-24)) ERR("Some field in the AUTHENTICATE cell body was not as expected"); - if (sig_is_rsa) { - if (chan->conn->handshake_state->certs->ed_id_sign != NULL) - ERR("RSA-signed AUTHENTICATE response provided with an ED25519 cert"); - - if (chan->conn->handshake_state->certs->auth_cert == NULL) - ERR("We never got an RSA authentication certificate"); - - crypto_pk_t *pk = tor_tls_cert_get_key( - chan->conn->handshake_state->certs->auth_cert); - char d[DIGEST256_LEN]; - char *signed_data; - size_t keysize; - int signed_len; - - if (! pk) { - ERR("Couldn't get RSA key from AUTH cert."); - } - crypto_digest256(d, (char*)auth, V3_AUTH_BODY_LEN, DIGEST_SHA256); - - keysize = crypto_pk_keysize(pk); - signed_data = tor_malloc(keysize); - signed_len = crypto_pk_public_checksig(pk, signed_data, keysize, - (char*)auth + V3_AUTH_BODY_LEN, - authlen - V3_AUTH_BODY_LEN); - crypto_pk_free(pk); - if (signed_len < 0) { - tor_free(signed_data); - ERR("RSA signature wasn't valid"); - } - if (signed_len < DIGEST256_LEN) { - tor_free(signed_data); - ERR("Not enough data was signed"); - } - /* Note that we deliberately allow *more* than DIGEST256_LEN bytes here, - * in case they're later used to hold a SHA3 digest or something. */ - if (tor_memneq(signed_data, d, DIGEST256_LEN)) { - tor_free(signed_data); - ERR("Signature did not match data to be signed."); - } - tor_free(signed_data); - } else { + { if (chan->conn->handshake_state->certs->ed_id_sign == NULL) ERR("We never got an Ed25519 identity certificate."); if (chan->conn->handshake_state->certs->ed_sign_auth == NULL) @@ -2547,7 +2489,7 @@ const common_digests_t *id_digests = tor_x509_cert_get_id_digests(id_cert); const ed25519_public_key_t *ed_identity_received = NULL; - if (! sig_is_rsa) { + { chan->conn->handshake_state->authenticated_ed25519 = 1; ed_identity_received = &chan->conn->handshake_state->certs->ed_id_sign->signing_key; diff -Nru tor-0.4.7.16/src/core/or/circuit_st.h tor-0.4.9.6/src/core/or/circuit_st.h --- tor-0.4.7.16/src/core/or/circuit_st.h 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/core/or/circuit_st.h 2026-03-25 14:30:34.000000000 +0000 @@ -88,11 +88,11 @@ extend_info_t *n_hop; /** True iff we are waiting for n_chan_cells to become less full before - * allowing p_streams to add any more cells. (Origin circuit only.) */ - unsigned int streams_blocked_on_n_chan : 1; + * allowing any more cells on this circuit. (Origin circuit only.) */ + unsigned int circuit_blocked_on_n_chan : 1; /** True iff we are waiting for p_chan_cells to become less full before - * allowing n_streams to add any more cells. (OR circuit only.) */ - unsigned int streams_blocked_on_p_chan : 1; + * allowing any more cells on this circuit. (OR circuit only.) */ + unsigned int circuit_blocked_on_p_chan : 1; /** True iff we have queued a delete backwards on this circuit, but not put * it on the output buffer. */ @@ -144,7 +144,17 @@ * 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. */ + * At maximum, this list contains 200 bytes plus the smartlist overhead. + * + * The elements in this list are always of length SENDME_TAG_LEN_TOR1 + * (== DIGEST_LEN, == 20). The actual digests stored in those elements + * may be smaller, however, if another relay crypto algorithm is in use. + **/ + /* Note that this is a per-circuit field, although logically it might make + * more sense for it to be a per-hop field. That doesn't matter in C tor, + * since we don't send more than a single window of cells to any given + * relay except for the exit. + */ smartlist_t *sendme_last_digests; /** Temporary field used during circuits_handle_oom. */ @@ -248,6 +258,27 @@ /** Congestion control fields */ struct congestion_control_t *ccontrol; + + /** Conflux linked circuit information. + * + * If this is non-NULL, the circuit is linked and part of a usable set, + * and for origin_circuit_t subtypes, the circuit purpose is + * CIRCUIT_PURPOSE_CONFLUX_LINKED. + * + * If this is NULL, the circuit could still be part of a pending conflux + * object, in which case the conflux_pending_nonce field is set, and for + * origin_circuit_t subtypes, the purpose is + * CIRCUIT_PURPOSE_CONFLUX_UNLINKED. + */ + struct conflux_t *conflux; + + /** If set, this circuit is considered *unlinked* and in the pending pool. + * The nonce value is used to find the other legs. Origin circuits that + * have this set are in the CIRCUIT_PURPOSE_CONFLUX_UNLINKED purpose. + * + * If this is NULL, and conflux object is set, it means this circuit is + * linked and thus part of a usable set. */ + uint8_t *conflux_pending_nonce; }; #endif /* !defined(CIRCUIT_ST_H) */ diff -Nru tor-0.4.7.16/src/core/or/circuitbuild.c tor-0.4.9.6/src/core/or/circuitbuild.c --- tor-0.4.7.16/src/core/or/circuitbuild.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/core/or/circuitbuild.c 2026-03-25 14:30:34.000000000 +0000 @@ -11,7 +11,7 @@ * constructing/sending create/extend cells, and so on). * * On the client side, this module handles launching circuits. Circuit - * launches are srtarted from circuit_establish_circuit(), called from + * launches are started from circuit_establish_circuit(), called from * circuit_launch_by_extend_info()). To choose the path the circuit will * take, onion_extend_cpath() calls into a maze of node selection functions. * @@ -33,7 +33,6 @@ #include "core/crypto/hs_ntor.h" #include "core/crypto/onion_crypto.h" #include "core/crypto/onion_fast.h" -#include "core/crypto/onion_tap.h" #include "core/mainloop/connection.h" #include "core/mainloop/mainloop.h" #include "core/or/channel.h" @@ -45,6 +44,7 @@ #include "core/or/command.h" #include "core/or/connection_edge.h" #include "core/or/connection_or.h" +#include "core/or/conflux_pool.h" #include "core/or/extendinfo.h" #include "core/or/onion.h" #include "core/or/ocirc_event.h" @@ -52,6 +52,7 @@ #include "core/or/relay.h" #include "core/or/trace_probes_circuit.h" #include "core/or/crypt_path.h" +#include "core/or/protover.h" #include "feature/client/bridges.h" #include "feature/client/circpathbias.h" #include "feature/client/entrynodes.h" @@ -84,12 +85,14 @@ #include "trunnel/extension.h" #include "trunnel/congestion_control.h" +#include "trunnel/subproto_request.h" 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, crypt_path_t *hop); -static const node_t *choose_good_middle_server(uint8_t purpose, +static const node_t *choose_good_middle_server(const origin_circuit_t *, + uint8_t purpose, cpath_build_state_t *state, crypt_path_t *head, int cur_len); @@ -410,13 +413,6 @@ /* We would like every path to support ntor, but we have to allow for some * edge cases. */ tor_assert(circuit_get_cpath_len(circ)); - if (circuit_can_use_tap(circ)) { - /* Circuits from clients to intro points, and hidden services to rend - * points do not support ntor, because the hidden service protocol does - * not include ntor onion keys. This is also true for Single Onion - * Services. */ - return 0; - } if (circuit_get_cpath_len(circ) == 1) { /* Allow for bootstrapping: when we're fetching directly from a fallback, @@ -465,6 +461,8 @@ ((flags & CIRCLAUNCH_IS_INTERNAL) ? 1 : 0); circ->build_state->is_ipv6_selftest = ((flags & CIRCLAUNCH_IS_IPV6_SELFTEST) ? 1 : 0); + circ->build_state->need_conflux = + ((flags & CIRCLAUNCH_NEED_CONFLUX) ? 1 : 0); circ->base_.purpose = purpose; return circ; } @@ -482,15 +480,51 @@ { origin_circuit_t *circ; int err_reason = 0; - int is_hs_v3_rp_circuit = 0; - if (flags & CIRCLAUNCH_IS_V3_RP) { - is_hs_v3_rp_circuit = 1; + circ = origin_circuit_init(purpose, flags); + + if (onion_pick_cpath_exit(circ, exit_ei) < 0 || + onion_populate_cpath(circ) < 0) { + circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_NOPATH); + return NULL; + } + + circuit_event_status(circ, CIRC_EVENT_LAUNCHED, 0); + + if ((err_reason = circuit_handle_first_hop(circ)) < 0) { + circuit_mark_for_close(TO_CIRCUIT(circ), -err_reason); + return NULL; } + tor_trace(TR_SUBSYS(circuit), TR_EV(establish), circ); + return circ; +} + +/** + * Build a new conflux circuit for purpose. If exit is defined, + * then use that as your exit router, else choose a suitable exit node. + * The flags argument is a bitfield of CIRCLAUNCH_* flags, see + * circuit_launch_by_extend_info() for more details. + * + * Also launch a connection to the first OR in the chosen path, if + * it's not open already. + */ +MOCK_IMPL(origin_circuit_t *, +circuit_establish_circuit_conflux,(const uint8_t *conflux_nonce, + uint8_t purpose, extend_info_t *exit_ei, + int flags)) +{ + origin_circuit_t *circ; + int err_reason = 0; + + /* Right now, only conflux client circuits use this function */ + tor_assert(purpose == CIRCUIT_PURPOSE_CONFLUX_UNLINKED); + circ = origin_circuit_init(purpose, flags); + TO_CIRCUIT(circ)->conflux_pending_nonce = + tor_memdup(conflux_nonce, DIGEST256_LEN); - if (onion_pick_cpath_exit(circ, exit_ei, is_hs_v3_rp_circuit) < 0 || + if (onion_pick_cpath_exit(circ, exit_ei) < 0 || onion_populate_cpath(circ) < 0) { circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_NOPATH); return NULL; @@ -503,6 +537,12 @@ return NULL; } + /* This can happen if the above triggered the OOM handler which in turn + * closed that very circuit. */ + if (TO_CIRCUIT(circ)->marked_for_close) { + return NULL; + } + tor_trace(TR_SUBSYS(circuit), TR_EV(establish), circ); return circ; } @@ -625,17 +665,13 @@ return 0; } -/** Find any circuits that are waiting on or_conn to become +/** Find any circuits that are waiting on chan to become * open and get them to send their create cells forward. * * Status is 1 if connect succeeded, or 0 if connect failed. - * - * Close_origin_circuits is 1 if we should close all the origin circuits - * through this channel, or 0 otherwise. (This happens when we want to retry - * an older guard.) */ void -circuit_n_chan_done(channel_t *chan, int status, int close_origin_circuits) +circuit_n_chan_done(channel_t *chan, int status) { smartlist_t *pending_circs; int err_reason = 0; @@ -688,11 +724,6 @@ continue; } - if (close_origin_circuits && CIRCUIT_IS_ORIGIN(circ)) { - log_info(LD_CIRC,"Channel deprecated for origin circs; closing circ."); - circuit_mark_for_close(circ, END_CIRC_REASON_CHANNEL_CLOSED); - continue; - } log_debug(LD_CIRC, "Found circ, sending create cell."); /* circuit_deliver_create_cell will set n_circ_id and add us to * chan_circuid_circuit_map, so we don't need to call @@ -771,8 +802,10 @@ circuit_set_n_circid_chan(circ, id, circ->n_chan); cell.circ_id = circ->n_circ_id; - append_cell_to_circuit_queue(circ, circ->n_chan, &cell, - CELL_DIRECTION_OUT, 0); + if (append_cell_to_circuit_queue(circ, circ->n_chan, &cell, + CELL_DIRECTION_OUT, 0) < 0) { + return -1; + } if (CIRCUIT_IS_ORIGIN(circ)) { /* Update began timestamp for circuits starting their first hop */ @@ -843,20 +876,16 @@ { /* torspec says: In general, clients SHOULD use CREATE whenever they are * using the TAP handshake, and CREATE2 otherwise. */ - if (extend_info_supports_ntor(ei)) { - *cell_type_out = CELL_CREATE2; - /* Only use ntor v3 with exits that support congestion control, - * and only when it is enabled. */ - if (ei->exit_supports_congestion_control && - congestion_control_enabled()) - *handshake_type_out = ONION_HANDSHAKE_TYPE_NTOR_V3; - else - *handshake_type_out = ONION_HANDSHAKE_TYPE_NTOR; - } else { - /* XXXX030 Remove support for deciding to use TAP and EXTEND. */ - *cell_type_out = CELL_CREATE; - *handshake_type_out = ONION_HANDSHAKE_TYPE_TAP; - } + *cell_type_out = CELL_CREATE2; + /* Only use ntor v3 with exits that support congestion control, + * and only when it is enabled. */ + if (ei->exit_supports_congestion_control && + congestion_control_enabled()) + *handshake_type_out = ONION_HANDSHAKE_TYPE_NTOR_V3; + else if (ei->enable_cgo) + *handshake_type_out = ONION_HANDSHAKE_TYPE_NTOR_V3; + else + *handshake_type_out = ONION_HANDSHAKE_TYPE_NTOR; } /** Decide whether to use a TAP or ntor handshake for extending to ei @@ -877,16 +906,8 @@ uint8_t t; circuit_pick_create_handshake(&t, handshake_type_out, ei); - /* torspec says: Clients SHOULD use the EXTEND format whenever sending a TAP - * handshake... In other cases, clients SHOULD use EXTEND2. */ - if (*handshake_type_out != ONION_HANDSHAKE_TYPE_TAP) { - *cell_type_out = RELAY_COMMAND_EXTEND2; - *create_cell_type_out = CELL_CREATE2; - } else { - /* XXXX030 Remove support for deciding to use TAP and EXTEND. */ - *cell_type_out = RELAY_COMMAND_EXTEND; - *create_cell_type_out = CELL_CREATE; - } + *cell_type_out = RELAY_COMMAND_EXTEND2; + *create_cell_type_out = CELL_CREATE2; } /** @@ -1165,12 +1186,18 @@ { uint8_t command = 0; uint16_t payload_len=0; - uint8_t payload[RELAY_PAYLOAD_SIZE]; + uint8_t payload[RELAY_PAYLOAD_SIZE_MAX]; if (extend_cell_format(&command, &payload_len, payload, &ec)<0) { log_warn(LD_CIRC,"Couldn't format extend cell"); return -END_CIRC_REASON_INTERNAL; } + if (payload_len > circuit_max_relay_payload( + TO_CIRCUIT(circ), hop->prev, command)) { + log_warn(LD_BUG, "Generated a too-long extend cell"); + return -END_CIRC_REASON_INTERNAL; + } + /* send it to hop->prev, because that relay will transfer * it to a create cell and then send to hop */ if (relay_send_command_from_edge(0, TO_CIRCUIT(circ), @@ -1232,7 +1259,7 @@ circuit_finish_handshake(origin_circuit_t *circ, const created_cell_t *reply) { - char keys[CPATH_KEY_MATERIAL_LEN]; + char keys[MAX_RELAY_KEY_MATERIAL_LEN]; crypt_path_t *hop; int rv; @@ -1253,12 +1280,14 @@ tor_assert(hop->state == CPATH_STATE_AWAITING_KEYS); circuit_params_t params; + size_t keylen = sizeof(keys); { const char *msg = NULL; + if (onion_skin_client_handshake(hop->handshake_state.tag, &hop->handshake_state, reply->reply, reply->handshake_len, - (uint8_t*)keys, sizeof(keys), + (uint8_t*)keys, &keylen, (uint8_t*)hop->rend_circ_nonce, ¶ms, &msg) < 0) { @@ -1269,10 +1298,11 @@ } onion_handshake_state_release(&hop->handshake_state); - - if (cpath_init_circuit_crypto(hop, keys, sizeof(keys), 0, 0)<0) { + if (cpath_init_circuit_crypto(params.crypto_alg, + hop, keys, keylen)<0) { return -END_CIRC_REASON_TORPROTOCOL; } + hop->relay_cell_format = params.cell_fmt; if (params.cc_enabled) { int circ_len = circuit_get_cpath_len(circ); @@ -1296,7 +1326,7 @@ hop->ccontrol = congestion_control_new(¶ms, CC_PATH_EXIT); } else { /* This is likely directory requests, which should block on orconn - * before congestion control, but lets give them the lower sbws + * before congestion control, but let's give them the lower sbws * param set anyway just in case. */ log_info(LD_CIRC, "Unexpected path length %d for exit circuit %d, purpose %d", @@ -1444,6 +1474,7 @@ switch (purpose) { /* These purposes connect to a router that we chose, so DEFAULT_ROUTE_LEN * is safe: */ + case CIRCUIT_PURPOSE_CONFLUX_UNLINKED: case CIRCUIT_PURPOSE_TESTING: /* router reachability testing */ known_purpose = 1; @@ -1631,10 +1662,6 @@ IF_BUG_ONCE(flags & CRN_DIRECT_CONN) return NULL; - /* This isn't the function for picking rendezvous nodes. */ - IF_BUG_ONCE(flags & CRN_RENDEZVOUS_V3) - return NULL; - /* We only want exits to extend if we cannibalize the circuit. * But we don't require IPv6 extends yet. */ IF_BUG_ONCE(flags & CRN_INITIATE_IPV6_EXTEND) @@ -1808,14 +1835,6 @@ return NULL; } -/* Pick a Rendezvous Point for our HS circuits according to flags. */ -static const node_t * -pick_rendezvous_node(router_crn_flags_t flags) -{ - const or_options_t *options = get_options(); - return router_choose_random_node(NULL, options->ExcludeNodes, flags); -} - /* * Helper function to pick a configured restricted middle node * (either HSLayer2Nodes or HSLayer3Nodes). @@ -1923,23 +1942,19 @@ case CIRCUIT_PURPOSE_C_HSDIR_GET: case CIRCUIT_PURPOSE_S_HSDIR_POST: case CIRCUIT_PURPOSE_HS_VANGUARDS: + case CIRCUIT_PURPOSE_C_ESTABLISH_REND: /* For these three, we want to pick the exit like a middle hop, * since it should be random. */ tor_assert_nonfatal(is_internal); + /* We want to avoid picking certain nodes for HS purposes. */ + flags |= CRN_FOR_HS; FALLTHROUGH; + case CIRCUIT_PURPOSE_CONFLUX_UNLINKED: case CIRCUIT_PURPOSE_C_GENERAL: if (is_internal) /* pick it like a middle hop */ return router_choose_random_node(NULL, options->ExcludeNodes, flags); else return choose_good_exit_server_general(flags); - case CIRCUIT_PURPOSE_C_ESTABLISH_REND: - { - /* Pick a new RP */ - const node_t *rendezvous_node = pick_rendezvous_node(flags); - log_info(LD_REND, "Picked new RP: %s", - safe_str_client(node_describe(rendezvous_node))); - return rendezvous_node; - } } log_warn(LD_BUG,"Unhandled purpose %d", TO_CIRCUIT(circ)->purpose); tor_fragile_assert(); @@ -1974,6 +1989,8 @@ case CIRCUIT_PURPOSE_S_HSDIR_POST: case CIRCUIT_PURPOSE_C_HSDIR_GET: case CIRCUIT_PURPOSE_C_GENERAL: + case CIRCUIT_PURPOSE_CONFLUX_UNLINKED: + case CIRCUIT_PURPOSE_CONFLUX_LINKED: if (circ->build_state->is_internal) return; description = "requested exit node"; @@ -2070,8 +2087,7 @@ * * Return 0 if ok, -1 if circuit should be closed. */ STATIC int -onion_pick_cpath_exit(origin_circuit_t *circ, extend_info_t *exit_ei, - int is_hs_v3_rp_circuit) +onion_pick_cpath_exit(origin_circuit_t *circ, extend_info_t *exit_ei) { cpath_build_state_t *state = circ->build_state; @@ -2099,8 +2115,8 @@ * (Guards are always direct, middles are never direct.) */ if (state->onehop_tunnel) flags |= CRN_DIRECT_CONN; - if (is_hs_v3_rp_circuit) - flags |= CRN_RENDEZVOUS_V3; + if (state->need_conflux) + flags |= CRN_CONFLUX; const node_t *node = choose_good_exit_server(circ, flags, state->is_internal); if (!node) { @@ -2109,8 +2125,11 @@ } exit_ei = extend_info_from_node(node, state->onehop_tunnel, /* for_exit_use */ - !state->is_internal && TO_CIRCUIT(circ)->purpose == - CIRCUIT_PURPOSE_C_GENERAL); + !state->is_internal && ( + TO_CIRCUIT(circ)->purpose == + CIRCUIT_PURPOSE_C_GENERAL || + TO_CIRCUIT(circ)->purpose == + CIRCUIT_PURPOSE_CONFLUX_UNLINKED)); if (BUG(exit_ei == NULL)) return -1; } @@ -2261,7 +2280,8 @@ * hop, based on already chosen nodes. */ static smartlist_t * -build_middle_exclude_list(uint8_t purpose, +build_middle_exclude_list(const origin_circuit_t *circ, + uint8_t purpose, cpath_build_state_t *state, crypt_path_t *head, int cur_len) @@ -2278,6 +2298,9 @@ excluded = smartlist_new(); + // Exclude other middles on pending and built conflux circs + conflux_add_middles_to_exclude_list(circ, excluded); + /* For non-vanguard circuits, add the exit and its family to the exclude list * (note that the exit/last hop is always chosen first in * circuit_establish_circuit()). */ @@ -2371,7 +2394,8 @@ * family, and make sure we don't duplicate any previous nodes or their * families. */ static const node_t * -choose_good_middle_server(uint8_t purpose, +choose_good_middle_server(const origin_circuit_t * circ, + uint8_t purpose, cpath_build_state_t *state, crypt_path_t *head, int cur_len) @@ -2386,7 +2410,7 @@ log_debug(LD_CIRC, "Contemplating intermediate hop #%d: random choice.", cur_len+1); - excluded = build_middle_exclude_list(purpose, state, head, cur_len); + excluded = build_middle_exclude_list(circ, purpose, state, head, cur_len); flags |= cpath_build_state_to_crn_flags(state); flags |= cpath_build_state_to_crn_ipv6_extend_flag(state, cur_len); @@ -2431,7 +2455,8 @@ * guard worked or not. */ const node_t * -choose_good_entry_server(uint8_t purpose, cpath_build_state_t *state, +choose_good_entry_server(const origin_circuit_t *circ, + uint8_t purpose, cpath_build_state_t *state, circuit_guard_state_t **guard_state_out) { const node_t *choice; @@ -2453,7 +2478,7 @@ /* This request is for an entry server to use for a regular circuit, * and we use entry guard nodes. Just return one of the guard nodes. */ tor_assert(guard_state_out); - return guards_choose_guard(state, purpose, guard_state_out); + return guards_choose_guard(circ, state, purpose, guard_state_out); } excluded = smartlist_new(); @@ -2499,7 +2524,7 @@ if (cur_len == state->desired_path_len - 1) { /* Picking last node */ info = extend_info_dup(state->chosen_exit); } else if (cur_len == 0) { /* picking first node */ - const node_t *r = choose_good_entry_server(purpose, state, + const node_t *r = choose_good_entry_server(circ, purpose, state, &circ->guard_state); if (r) { /* If we're a client, use the preferred address rather than the @@ -2512,7 +2537,7 @@ } } else { const node_t *r = - choose_good_middle_server(purpose, state, circ->cpath, cur_len); + choose_good_middle_server(circ, purpose, state, circ->cpath, cur_len); if (r) { info = extend_info_from_node(r, 0, false); } @@ -2579,29 +2604,6 @@ return state->chosen_exit->nickname; } -/* Is circuit purpose allowed to use the deprecated TAP encryption protocol? - * The hidden service protocol still uses TAP for some connections, because - * ntor onion keys aren't included in HS descriptors or INTRODUCE cells. */ -static int -circuit_purpose_can_use_tap_impl(uint8_t purpose) -{ - return (purpose == CIRCUIT_PURPOSE_S_CONNECT_REND || - purpose == CIRCUIT_PURPOSE_C_INTRODUCING); -} - -/* Is circ allowed to use the deprecated TAP encryption protocol? - * The hidden service protocol still uses TAP for some connections, because - * ntor onion keys aren't included in HS descriptors or INTRODUCE cells. */ -int -circuit_can_use_tap(const origin_circuit_t *circ) -{ - tor_assert(circ); - tor_assert(circ->cpath); - tor_assert(circ->cpath->extend_info); - return (circuit_purpose_can_use_tap_impl(circ->base_.purpose) && - extend_info_supports_tap(circ->cpath->extend_info)); -} - /* Does circ have an onion key which it's allowed to use? */ int circuit_has_usable_onion_key(const origin_circuit_t *circ) @@ -2609,8 +2611,7 @@ tor_assert(circ); tor_assert(circ->cpath); tor_assert(circ->cpath->extend_info); - return (extend_info_supports_ntor(circ->cpath->extend_info) || - circuit_can_use_tap(circ)); + return extend_info_supports_ntor(circ->cpath->extend_info); } /** Find the circuits that are waiting to find out whether their guards are @@ -2636,6 +2637,80 @@ smartlist_free(to_upgrade); } +// TODO: Find a better place to declare this; it's duplicated in +// onion_crypto.c +#define EXT_TYPE_SUBPROTO 3 + +/** Add a request for the CGO subprotocol capability to ext. + * + * NOTE: If we need to support other subprotocol extensions, + * do not add separate functions! Instead rename this function + * and adapt it as appropriate. + */ +static int +build_cgo_subproto_request(trn_extension_t *ext) +{ + trn_extension_field_t *fld = NULL; + trn_subproto_request_t *req = NULL; + trn_subproto_request_ext_t *req_ext = NULL; + int r = 0; + + fld = trn_extension_field_new(); + req_ext = trn_subproto_request_ext_new(); + + req = trn_subproto_request_new(); + req->protocol_id = PRT_RELAY; + req->proto_cap_number = PROTOVER_RELAY_CRYPT_CGO; + trn_subproto_request_ext_add_reqs(req_ext, req); + req = NULL; // prevent double-free + + // TODO: If we add other capabilities here, we need to make + // sure they are correctly sorted. + + ssize_t len = trn_subproto_request_ext_encoded_len(req_ext); + if (BUG(len<0)) + goto err; + if (BUG(len > UINT8_MAX)) + goto err; + + trn_extension_field_setlen_field(fld, len); + trn_extension_field_set_field_type(fld, EXT_TYPE_SUBPROTO); + trn_extension_field_set_field_len(fld, len); + uint8_t *out = trn_extension_field_getarray_field(fld); + ssize_t len2 = trn_subproto_request_ext_encode(out, len, req_ext); + if (BUG(len != len2)) + goto err; + + trn_extension_add_fields(ext, fld); + fld = NULL; // prevent double-free + + // We succeeded! + r = 0; + + err: + trn_subproto_request_ext_free(req_ext); + trn_subproto_request_free(req); + trn_extension_field_free(fld); + + return r; +} + +/** Helper: Comparison function to sort extensions. */ +static int +ext_cmp(const void *a, const void *b) +{ + const trn_extension_field_t *fa = *(trn_extension_field_t **)a; + const trn_extension_field_t *fb = *(trn_extension_field_t **)b; + uint8_t ta = trn_extension_field_get_field_type(fa); + uint8_t tb = trn_extension_field_get_field_type(fb); + if (ta < tb) + return -1; + else if (ta == tb) + return 0; + else + return 1; +} + /** * Try to generate a circuit-negotiation message for communication with a * given relay. Assumes we are using ntor v3, or some later version that @@ -2647,13 +2722,53 @@ int client_circ_negotiation_message(const extend_info_t *ei, uint8_t **msg_out, - size_t *msg_len_out) + size_t *msg_len_out, + circuit_params_t *params_out) { - tor_assert(ei && msg_out && msg_len_out); + tor_assert(ei && msg_out && msg_len_out && params_out); + bool cc_enabled = false; - if (!ei->exit_supports_congestion_control) { - return -1; + *msg_out = NULL; + + trn_extension_t *ext = trn_extension_new(); + + if (ei->exit_supports_congestion_control && + congestion_control_enabled()) { + if (congestion_control_build_ext_request(ext) < 0) { + goto err; + } + cc_enabled = true; + } + + if (cc_enabled && ei->enable_cgo) { + if (build_cgo_subproto_request(ext) < 0) { + goto err; + } + params_out->cell_fmt = RELAY_CELL_FORMAT_V1; + params_out->crypto_alg = RELAY_CRYPTO_ALG_CGO_CLIENT; + } + + size_t n_fields = trn_extension_getlen_fields(ext); + qsort(trn_extension_getarray_fields(ext), + n_fields, sizeof(trn_extension_field_t *), + ext_cmp); + + trn_extension_set_num(ext, n_fields); + + ssize_t total_len = trn_extension_encoded_len(ext); + if (BUG(total_len < 0)) + goto err; + + *msg_out = tor_malloc_zero(total_len); + *msg_len_out = total_len; + if (BUG(trn_extension_encode(*msg_out, total_len, ext) < 0)) { + goto err; } + trn_extension_free(ext); - return congestion_control_build_ext_request(msg_out, msg_len_out); + return 0; + err: + trn_extension_free(ext); + tor_free(*msg_out); + return -1; } diff -Nru tor-0.4.7.16/src/core/or/circuitbuild.h tor-0.4.9.6/src/core/or/circuitbuild.h --- tor-0.4.7.16/src/core/or/circuitbuild.h 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/core/or/circuitbuild.h 2026-03-25 14:30:34.000000000 +0000 @@ -24,11 +24,16 @@ origin_circuit_t *circuit_establish_circuit(uint8_t purpose, extend_info_t *exit, int flags); +MOCK_DECL(origin_circuit_t *, circuit_establish_circuit_conflux, ( + const uint8_t *nonce, + uint8_t purpose, + extend_info_t *exit, + int flags)); + struct circuit_guard_state_t *origin_circuit_get_guard_state( origin_circuit_t *circ); int circuit_handle_first_hop(origin_circuit_t *circ); -void circuit_n_chan_done(channel_t *chan, int status, - int close_origin_circuits); +void circuit_n_chan_done(channel_t *chan, int status); 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); @@ -42,7 +47,6 @@ 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); -int circuit_can_use_tap(const origin_circuit_t *circ); int circuit_has_usable_onion_key(const origin_circuit_t *circ); const uint8_t *build_state_get_exit_rsa_id(cpath_build_state_t *state); MOCK_DECL(const node_t *, @@ -51,7 +55,8 @@ struct circuit_guard_state_t; -const node_t *choose_good_entry_server(uint8_t purpose, +const node_t *choose_good_entry_server(const origin_circuit_t *circ, + uint8_t purpose, cpath_build_state_t *state, struct circuit_guard_state_t **guard_state_out); void circuit_upgrade_circuits_from_guard_wait(void); @@ -64,9 +69,11 @@ const struct create_cell_t *create_cell, int relayed)); +struct circuit_params_t; int client_circ_negotiation_message(const extend_info_t *ei, uint8_t **msg_out, - size_t *msg_len_out); + size_t *msg_len_out, + struct circuit_params_t *params_out); #ifdef CIRCUITBUILD_PRIVATE STATIC circid_t get_unique_circ_id_by_chan(channel_t *chan); @@ -78,8 +85,7 @@ STATIC int onion_extend_cpath(origin_circuit_t *circ); STATIC int -onion_pick_cpath_exit(origin_circuit_t *circ, extend_info_t *exit_ei, - int is_hs_v3_rp_circuit); +onion_pick_cpath_exit(origin_circuit_t *circ, extend_info_t *exit_ei); STATIC int cpath_build_state_to_crn_flags(const cpath_build_state_t *state); STATIC int cpath_build_state_to_crn_ipv6_extend_flag( const cpath_build_state_t *state, diff -Nru tor-0.4.7.16/src/core/or/circuitlist.c tor-0.4.9.6/src/core/or/circuitlist.c --- tor-0.4.7.16/src/core/or/circuitlist.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/core/or/circuitlist.c 2026-03-25 14:30:34.000000000 +0000 @@ -62,7 +62,10 @@ #include "core/or/circuituse.h" #include "core/or/circuitstats.h" #include "core/or/circuitpadding.h" +#include "core/or/conflux.h" +#include "core/or/conflux_pool.h" #include "core/or/crypt_path.h" +#include "core/or/dos.h" #include "core/or/extendinfo.h" #include "core/or/status.h" #include "core/or/trace_probes_circuit.h" @@ -118,6 +121,7 @@ #include "core/or/or_circuit_st.h" #include "core/or/origin_circuit_st.h" +#include "core/or/conflux_util.h" /********* START VARIABLES **********/ /** A global list of all circuits at this hop. */ @@ -156,6 +160,10 @@ uint64_t cc_stats_circs_closed = 0; +/** Total number of circuit protocol violation. This is incremented when the + * END_CIRC_REASON_TORPROTOCOL is used to close a circuit. */ +uint64_t circ_n_proto_violation = 0; + /********* END VARIABLES ************/ /* Implement circuit handle helpers. */ @@ -841,6 +849,11 @@ case CIRCUIT_PURPOSE_C_CIRCUIT_PADDING: return "CIRCUIT_PADDING"; + case CIRCUIT_PURPOSE_CONFLUX_UNLINKED: + return "CONFLUX_UNLINKED"; + case CIRCUIT_PURPOSE_CONFLUX_LINKED: + return "CONFLUX_LINKED"; + default: tor_snprintf(buf, sizeof(buf), "UNKNOWN_%d", (int)purpose); return buf; @@ -870,6 +883,8 @@ case CIRCUIT_PURPOSE_PATH_BIAS_TESTING: case CIRCUIT_PURPOSE_HS_VANGUARDS: case CIRCUIT_PURPOSE_C_CIRCUIT_PADDING: + case CIRCUIT_PURPOSE_CONFLUX_UNLINKED: + case CIRCUIT_PURPOSE_CONFLUX_LINKED: return NULL; case CIRCUIT_PURPOSE_INTRO_POINT: @@ -973,6 +988,12 @@ case CIRCUIT_PURPOSE_C_CIRCUIT_PADDING: return "Circuit kept open for padding"; + case CIRCUIT_PURPOSE_CONFLUX_UNLINKED: + return "Unlinked conflux circuit"; + + case CIRCUIT_PURPOSE_CONFLUX_LINKED: + return "Linked conflux circuit"; + default: tor_snprintf(buf, sizeof(buf), "UNKNOWN_%d", (int)purpose); return buf; @@ -1114,6 +1135,7 @@ cell_queue_init(&circ->p_chan_cells); init_circuit_base(TO_CIRCUIT(circ)); + dos_stream_init_circ_tbf(circ); tor_trace(TR_SUBSYS(circuit), TR_EV(new_or), circ); return circ; @@ -1806,30 +1828,6 @@ return NULL; } -/** We might cannibalize this circuit: Return true if its last hop can be used - * as a v3 rendezvous point. */ -static int -circuit_can_be_cannibalized_for_v3_rp(const origin_circuit_t *circ) -{ - if (!circ->build_state) { - return 0; - } - - extend_info_t *chosen_exit = circ->build_state->chosen_exit; - if (BUG(!chosen_exit)) { - return 0; - } - - const node_t *rp_node = node_get_by_id(chosen_exit->identity_digest); - if (rp_node) { - if (node_supports_v3_rendezvous_point(rp_node)) { - return 1; - } - } - - return 0; -} - /** We are trying to create a circuit of purpose purpose and we are * looking for cannibalizable circuits. Return the circuit purpose we would be * willing to cannibalize. */ @@ -1841,6 +1839,9 @@ * circuits so that we get the same path construction logic. */ return CIRCUIT_PURPOSE_HS_VANGUARDS; } else { + /* Conflux purposes should never get here */ + tor_assert_nonfatal(purpose != CIRCUIT_PURPOSE_CONFLUX_UNLINKED && + purpose != CIRCUIT_PURPOSE_CONFLUX_LINKED); /* If no vanguards are used just get a general circuit! */ return CIRCUIT_PURPOSE_C_GENERAL; } @@ -1886,6 +1887,10 @@ tor_assert_nonfatal(purpose_to_search_for == CIRCUIT_PURPOSE_C_GENERAL || purpose_to_search_for == CIRCUIT_PURPOSE_HS_VANGUARDS); + tor_assert_nonfatal(purpose_to_search_for != + CIRCUIT_PURPOSE_CONFLUX_UNLINKED); + tor_assert_nonfatal(purpose_to_produce != CIRCUIT_PURPOSE_CONFLUX_UNLINKED); + log_debug(LD_CIRC, "Hunting for a circ to cannibalize: purpose %d, uptime %d, " "capacity %d, internal %d", @@ -1952,13 +1957,6 @@ } while (hop != circ->cpath); } - if ((flags & CIRCLAUNCH_IS_V3_RP) && - !circuit_can_be_cannibalized_for_v3_rp(circ)) { - log_debug(LD_GENERAL, "Skipping uncannibalizable circuit for v3 " - "rendezvous point."); - goto next; - } - if (!best || (best->build_state->need_uptime && !need_uptime)) best = circ; next: ; @@ -2172,6 +2170,10 @@ tor_assert(line); tor_assert(file); + if (reason == END_CIRC_REASON_TORPROTOCOL) { + circ_n_proto_violation++; + } + /* Check whether the circuitpadding subsystem wants to block this close */ if (circpad_marked_circuit_for_padding(circ, reason)) { return; @@ -2234,6 +2236,11 @@ /* Notify the HS subsystem that this circuit is closing. */ hs_circ_cleanup_on_close(circ); + /* Specific actions if this is a conflux related circuit. */ + if (CIRCUIT_IS_CONFLUX(circ)) { + conflux_circuit_has_closed(circ); + } + /* Update stats. */ if (circ->ccontrol) { if (circ->ccontrol->in_slow_start) { @@ -2277,6 +2284,8 @@ static void circuit_about_to_free_atexit(circuit_t *circ) { + /* Cleanup conflux specifics. */ + conflux_circuit_about_to_free(circ); if (circ->n_chan) { circuit_clear_cell_queue(circ, circ->n_chan); @@ -2306,6 +2315,9 @@ int reason = circ->marked_for_close_reason; int orig_reason = circ->marked_for_close_orig_reason; + /* Cleanup conflux specifics. */ + conflux_circuit_about_to_free(circ); + if (circ->state == CIRCUIT_STATE_ONIONSKIN_PENDING) { onion_pending_remove(TO_OR_CIRCUIT(circ)); } @@ -2348,6 +2360,7 @@ if (! CIRCUIT_IS_ORIGIN(circ)) { or_circuit_t *or_circ = TO_OR_CIRCUIT(circ); edge_connection_t *conn; + for (conn=or_circ->n_streams; conn; conn=conn->next_stream) connection_edge_destroy(or_circ->p_circ_id, conn); or_circ->n_streams = NULL; @@ -2709,8 +2722,12 @@ * outbuf due to a malicious destination holding off the read on us. */ if ((conn->type == CONN_TYPE_DIR && conn->linked_conn == NULL) || CONN_IS_EDGE(conn)) { - if (!conn->marked_for_close) + if (!conn->marked_for_close) { + if (CONN_IS_EDGE(conn)) { + TO_EDGE_CONN(conn)->end_reason = END_STREAM_REASON_RESOURCELIMIT; + } connection_mark_for_close(conn); + } mem_recovered += single_conn_free_bytes(conn); if (conn->type == CONN_TYPE_DIR) { @@ -2739,6 +2756,7 @@ mem_recovered += n * packed_cell_mem_cost(); mem_recovered += half_stream_alloc; mem_recovered += freed; + mem_recovered += conflux_get_circ_bytes_allocation(circ); if (mem_recovered >= mem_to_recover) goto done_recovering_mem; @@ -2831,3 +2849,27 @@ tor_assert(!or_circ || !or_circ->rend_splice); } } + +/** Return true iff the circuit queue for the given direction is full that is + * above the high watermark. */ +bool +circuit_is_queue_full(const circuit_t *circ, cell_direction_t direction) +{ + int queue_size; + + tor_assert(circ); + + /* Gather objects we need based on cell direction. */ + if (direction == CELL_DIRECTION_OUT) { + /* Outbound. */ + queue_size = circ->n_chan_cells.n; + } else { + /* Inbound. */ + queue_size = CONST_TO_OR_CIRCUIT(circ)->p_chan_cells.n; + } + + /* Then check if our cell queue has reached its high watermark as in its + * upper limit. This is so we avoid too much memory pressure by queuing a + * large amount of cells. */ + return queue_size >= cell_queue_highwatermark(); +} diff -Nru tor-0.4.7.16/src/core/or/circuitlist.h tor-0.4.9.6/src/core/or/circuitlist.h --- tor-0.4.7.16/src/core/or/circuitlist.h 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/core/or/circuitlist.h 2026-03-25 14:30:34.000000000 +0000 @@ -130,7 +130,14 @@ * actual needed HS purpose. */ #define CIRCUIT_PURPOSE_HS_VANGUARDS 24 -#define CIRCUIT_PURPOSE_MAX_ 24 +/** + * These two purposes are for conflux. The first is for circuits that are + * being built, but not yet linked. The second is for circuits that are + * linked and ready to use for streams. */ +#define CIRCUIT_PURPOSE_CONFLUX_UNLINKED 25 +#define CIRCUIT_PURPOSE_CONFLUX_LINKED 26 + +#define CIRCUIT_PURPOSE_MAX_ 26 /** 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 @@ -165,6 +172,7 @@ extern double cc_stats_circ_close_cwnd_ma; extern double cc_stats_circ_close_ss_cwnd_ma; extern uint64_t cc_stats_circs_closed; +extern uint64_t circ_n_proto_violation; /** Convert a circuit_t* to a pointer to the enclosing or_circuit_t. Assert * if the cast is impossible. */ @@ -247,6 +255,8 @@ smartlist_t *circuit_find_circuits_to_upgrade_from_guard_wait(void); +bool circuit_is_queue_full(const circuit_t *circ, cell_direction_t direction); + /* Declare the handle helpers */ HANDLE_DECL(circuit, circuit_t, ) #define circuit_handle_free(h) \ diff -Nru tor-0.4.7.16/src/core/or/circuitpadding.c tor-0.4.9.6/src/core/or/circuitpadding.c --- tor-0.4.7.16/src/core/or/circuitpadding.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/core/or/circuitpadding.c 2026-03-25 14:30:34.000000000 +0000 @@ -78,6 +78,8 @@ #include "core/crypto/relay_crypto.h" #include "feature/nodelist/nodelist.h" +#include "src/core/or/conflux_util.h" + #include "app/config/config.h" static inline circpad_circuit_state_t circpad_circuit_state( @@ -251,8 +253,11 @@ * 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) + if (!circ->timestamp_dirty) { circ->timestamp_dirty = approx_time(); + if (circ->conflux && CIRCUIT_IS_ORIGIN(circ)) + conflux_sync_circ_fields(circ->conflux, TO_ORIGIN_CIRCUIT(circ)); + } /* Take ownership of the circuit */ circuit_change_purpose(circ, CIRCUIT_PURPOSE_C_CIRCUIT_PADDING); @@ -1841,22 +1846,21 @@ * not need any other consideration, otherwise return 1. */ int -circpad_check_received_cell(cell_t *cell, circuit_t *circ, - crypt_path_t *layer_hint, - const relay_header_t *rh) +circpad_check_received_cell(const relay_msg_t *msg, circuit_t *circ, + crypt_path_t *layer_hint) { /* First handle the padding commands, since we want to ignore any other * commands if this circuit is padding-specific. */ - switch (rh->command) { + switch (msg->command) { case RELAY_COMMAND_DROP: /* Already examined in circpad_deliver_recognized_relay_cell_events */ return 0; case RELAY_COMMAND_PADDING_NEGOTIATE: - circpad_handle_padding_negotiate(circ, cell); + circpad_handle_padding_negotiate(circ, msg); return 0; case RELAY_COMMAND_PADDING_NEGOTIATED: - if (circpad_handle_padding_negotiated(circ, cell, layer_hint) == 0) - circuit_read_valid_data(TO_ORIGIN_CIRCUIT(circ), rh->length); + if (circpad_handle_padding_negotiated(circ, msg, layer_hint) == 0) + circuit_read_valid_data(TO_ORIGIN_CIRCUIT(circ), msg->length); return 0; } @@ -1883,7 +1887,7 @@ if (circ->purpose == CIRCUIT_PURPOSE_C_CIRCUIT_PADDING) { log_fn(LOG_PROTOCOL_WARN, LD_CIRC, "Ignored cell (%d) that arrived in padding circuit " - " %u.", rh->command, CIRCUIT_IS_ORIGIN(circ) ? + " %u.", msg->command, CIRCUIT_IS_ORIGIN(circ) ? TO_ORIGIN_CIRCUIT(circ)->global_identifier : 0); return 0; } @@ -2964,7 +2968,7 @@ * Returns -1 on error, 0 on success. */ signed_error_t -circpad_handle_padding_negotiate(circuit_t *circ, cell_t *cell) +circpad_handle_padding_negotiate(circuit_t *circ, const relay_msg_t *msg) { int retval = 0; /* Should we send back a STOP cell? */ @@ -2978,8 +2982,7 @@ return -1; } - if (circpad_negotiate_parse(&negotiate, cell->payload+RELAY_HEADER_SIZE, - CELL_PAYLOAD_SIZE-RELAY_HEADER_SIZE) < 0) { + if (circpad_negotiate_parse(&negotiate, msg->body, msg->length) < 0) { log_fn(LOG_PROTOCOL_WARN, LD_CIRC, "Received malformed PADDING_NEGOTIATE cell; dropping."); return -1; @@ -3052,7 +3055,7 @@ * Returns -1 on error, 0 on success. */ signed_error_t -circpad_handle_padding_negotiated(circuit_t *circ, cell_t *cell, +circpad_handle_padding_negotiated(circuit_t *circ, const relay_msg_t *msg, crypt_path_t *layer_hint) { circpad_negotiated_t *negotiated; @@ -3071,8 +3074,7 @@ return -1; } - if (circpad_negotiated_parse(&negotiated, cell->payload+RELAY_HEADER_SIZE, - CELL_PAYLOAD_SIZE-RELAY_HEADER_SIZE) < 0) { + if (circpad_negotiated_parse(&negotiated, msg->body, msg->length) < 0) { log_fn(LOG_PROTOCOL_WARN, LD_CIRC, "Received malformed PADDING_NEGOTIATED cell on circuit %u; " "dropping.", TO_ORIGIN_CIRCUIT(circ)->global_identifier); diff -Nru tor-0.4.7.16/src/core/or/circuitpadding.h tor-0.4.9.6/src/core/or/circuitpadding.h --- tor-0.4.7.16/src/core/or/circuitpadding.h 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/core/or/circuitpadding.h 2026-03-25 14:30:34.000000000 +0000 @@ -12,6 +12,7 @@ #include "trunnel/circpad_negotiation.h" #include "lib/evloop/timers.h" +#include "core/or/relay_msg_st.h" struct circuit_t; struct origin_circuit_t; @@ -736,9 +737,9 @@ /* Padding negotiation between client and middle */ signed_error_t circpad_handle_padding_negotiate(struct circuit_t *circ, - struct cell_t *cell); + const relay_msg_t *msg); signed_error_t circpad_handle_padding_negotiated(struct circuit_t *circ, - struct cell_t *cell, + const relay_msg_t *msg, crypt_path_t *layer_hint); signed_error_t circpad_negotiate_padding(struct origin_circuit_t *circ, circpad_machine_num_t machine, @@ -753,9 +754,8 @@ circpad_purpose_mask_t circpad_circ_purpose_to_mask(uint8_t circ_purpose); -int circpad_check_received_cell(cell_t *cell, circuit_t *circ, - crypt_path_t *layer_hint, - const relay_header_t *rh); +int circpad_check_received_cell(const relay_msg_t *msg, circuit_t *circ, + crypt_path_t *layer_hint); MOCK_DECL(circpad_decision_t, circpad_machine_schedule_padding,(circpad_machine_runtime_t *)); diff -Nru tor-0.4.7.16/src/core/or/circuitstats.c tor-0.4.9.6/src/core/or/circuitstats.c --- tor-0.4.7.16/src/core/or/circuitstats.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/core/or/circuitstats.c 2026-03-25 14:30:34.000000000 +0000 @@ -709,7 +709,7 @@ * Switch their purpose and wait. */ if (circ->base_.purpose != CIRCUIT_PURPOSE_C_MEASURE_TIMEOUT) { log_info(LD_CIRC, - "Deciding to timeout circuit %"PRIu32"\n", + "Deciding to timeout circuit %"PRIu32, (circ->global_identifier)); circuit_build_times_mark_circ_as_measurement_only(circ); } @@ -1018,6 +1018,18 @@ return 0; } + /* We had a case where someone removed their TotalBuildTimes from the state + * files while having CircuitBuildAbandonedCount above 0 leading to a + * segfault (#40437). Simply bug on it and return an error so at least the + * user will learn that they broke the state file. */ + if (BUG(state->TotalBuildTimes <= 0 && + state->CircuitBuildAbandonedCount > 0)) { + log_warn(LD_GENERAL, "CircuitBuildAbandonedCount count is above 0 but " + "no TotalBuildTimes have been found. Unable to " + "parse broken state file"); + return -1; + } + /* build_time_t 0 means uninitialized */ loaded_times = tor_calloc(state->TotalBuildTimes, sizeof(build_time_t)); diff -Nru tor-0.4.7.16/src/core/or/circuituse.c tor-0.4.9.6/src/core/or/circuituse.c --- tor-0.4.7.16/src/core/or/circuituse.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/core/or/circuituse.c 2026-03-25 14:30:34.000000000 +0000 @@ -36,6 +36,7 @@ #include "core/or/circuitstats.h" #include "core/or/circuituse.h" #include "core/or/circuitpadding.h" +#include "core/or/conflux_pool.h" #include "core/or/connection_edge.h" #include "core/or/extendinfo.h" #include "core/or/policies.h" @@ -51,6 +52,7 @@ #include "feature/hs/hs_client.h" #include "feature/hs/hs_common.h" #include "feature/hs/hs_ident.h" +#include "feature/hs/hs_metrics.h" #include "feature/hs/hs_stats.h" #include "feature/nodelist/describe.h" #include "feature/nodelist/networkstatus.h" @@ -62,6 +64,8 @@ #include "lib/math/fp.h" #include "lib/time/tvdiff.h" #include "lib/trace/events.h" +#include "src/core/mainloop/mainloop.h" +#include "core/or/conflux.h" #include "core/or/cpath_build_state_st.h" #include "feature/dircommon/dir_connection_st.h" @@ -71,8 +75,12 @@ #include "core/or/origin_circuit_st.h" #include "core/or/socks_request_st.h" +#include "core/or/conflux_util.h" + STATIC void circuit_expire_old_circuits_clientside(void); static void circuit_increment_failure_count(void); +static bool connection_ap_socks_iso_keepalive_enabled( + const entry_connection_t *); /** Check whether the hidden service destination of the stream at * edge_conn is the same as the destination of the circuit at @@ -97,7 +105,7 @@ /** Return 1 if circ could be returned by circuit_get_best(). * Else return 0. */ -static int +int circuit_is_acceptable(const origin_circuit_t *origin_circ, const entry_connection_t *conn, int must_be_open, uint8_t purpose, @@ -137,7 +145,8 @@ purpose == CIRCUIT_PURPOSE_C_HSDIR_GET || purpose == CIRCUIT_PURPOSE_S_HSDIR_POST || purpose == CIRCUIT_PURPOSE_HS_VANGUARDS || - purpose == CIRCUIT_PURPOSE_C_REND_JOINED) { + purpose == CIRCUIT_PURPOSE_C_REND_JOINED || + purpose == CIRCUIT_PURPOSE_CONFLUX_LINKED) { if (circ->timestamp_dirty && circ->timestamp_dirty+get_options()->MaxCircuitDirtiness <= now) return 0; @@ -161,6 +170,8 @@ return 0; if (purpose == CIRCUIT_PURPOSE_C_GENERAL || + purpose == CIRCUIT_PURPOSE_CONFLUX_UNLINKED || + purpose == CIRCUIT_PURPOSE_CONFLUX_LINKED || purpose == CIRCUIT_PURPOSE_S_HSDIR_POST || purpose == CIRCUIT_PURPOSE_C_HSDIR_GET) { tor_addr_t addr; @@ -329,6 +340,7 @@ { origin_circuit_t *best=NULL; struct timeval now; + time_t now_sec; tor_assert(conn); @@ -340,6 +352,14 @@ purpose == CIRCUIT_PURPOSE_C_REND_JOINED); tor_gettimeofday(&now); + now_sec = now.tv_sec; + + // Prefer pre-built conflux circuits here, if available but only for general + // purposes. We don't have onion service conflux support at the moment. + if (purpose == CIRCUIT_PURPOSE_C_GENERAL && + (best = conflux_get_circ_for_conn(conn, now_sec))) { + return best; + } SMARTLIST_FOREACH_BEGIN(circuit_get_global_list(), circuit_t *, circ) { origin_circuit_t *origin_circ; @@ -348,7 +368,7 @@ origin_circ = TO_ORIGIN_CIRCUIT(circ); if (!circuit_is_acceptable(origin_circ,conn,must_be_open,purpose, - need_uptime,need_internal, (time_t)now.tv_sec)) + need_uptime,need_internal, now_sec)) continue; /* now this is an acceptable circ to hand back. but that doesn't @@ -695,7 +715,6 @@ } else { /* circuit not open, consider recording failure as timeout */ int first_hop_succeeded = TO_ORIGIN_CIRCUIT(victim)->cpath && TO_ORIGIN_CIRCUIT(victim)->cpath->state == CPATH_STATE_OPEN; - if (TO_ORIGIN_CIRCUIT(victim)->p_streams != NULL) { log_warn(LD_BUG, "Circuit %d (purpose %d, %s) has timed out, " "yet has attached streams!", @@ -934,7 +953,7 @@ c->marked_for_close, c->hold_open_until_flushed ? "" : "not ", conn->edge_has_sent_end ? "" : "not ", - conn->edge_blocked_on_circ ? "Blocked" : "Not blocked"); + connection_is_reading(c) ? "Not blocked" : "Blocked"); if (! c->linked_conn) continue; @@ -1002,7 +1021,8 @@ SMARTLIST_FOREACH_BEGIN(circuit_get_global_list(), circuit_t *, circ) { if (CIRCUIT_IS_ORIGIN(circ) && !circ->marked_for_close && - circ->purpose == CIRCUIT_PURPOSE_C_GENERAL && + (circ->purpose == CIRCUIT_PURPOSE_C_GENERAL || + circ->purpose == CIRCUIT_PURPOSE_CONFLUX_LINKED) && (!circ->timestamp_dirty || circ->timestamp_dirty + get_options()->MaxCircuitDirtiness > now)) { origin_circuit_t *origin_circ = TO_ORIGIN_CIRCUIT(circ); @@ -1183,6 +1203,15 @@ time_t now = time(NULL); int flags = 0; + /* Attempt to launch predicted conflux circuits. This is outside the HS or + * Exit preemptive circuit set. + * As with the other types of preemptive circuits, we only want to + * launch them if we have predicted ports. (If we haven't needed a + * circuit for a while, maybe we won't need one soon either.) */ + if (predicted_ports_prediction_time_remaining(now)) { + conflux_predict_new(now); + } + /* Count how many of each type of circuit we currently have. */ SMARTLIST_FOREACH_BEGIN(circuit_get_global_list(), circuit_t *, circ) { if (!circuit_is_available_for_use(circ)) @@ -1211,6 +1240,7 @@ log_info(LD_CIRC, "Have %d clean circs (%d internal), need another exit circ.", num, num_internal); + circuit_launch(CIRCUIT_PURPOSE_C_GENERAL, flags); return; } @@ -1329,6 +1359,7 @@ circuit_detach_stream(circuit_t *circ, edge_connection_t *conn) { edge_connection_t *prevconn; + bool update_dirty = false; tor_assert(circ); tor_assert(conn); @@ -1336,6 +1367,9 @@ if (conn->base_.type == CONN_TYPE_AP) { entry_connection_t *entry_conn = EDGE_TO_ENTRY_CONN(conn); entry_conn->may_use_optimistic_data = 0; + // When KeepAliveIsolateSOCKSAuth is in effect, we update the dirty + // time on close as well as on open. + update_dirty = connection_ap_socks_iso_keepalive_enabled(entry_conn); } conn->cpath_layer = NULL; /* don't keep a stale pointer */ conn->on_circuit = NULL; @@ -1345,6 +1379,7 @@ int removed = 0; if (conn == origin_circ->p_streams) { origin_circ->p_streams = conn->next_stream; + conflux_update_p_streams(origin_circ, conn->next_stream); removed = 1; } else { for (prevconn = origin_circ->p_streams; @@ -1360,6 +1395,10 @@ log_debug(LD_APP, "Removing stream %d from circ %u", conn->stream_id, (unsigned)circ->n_circ_id); + if (update_dirty) { + circ->timestamp_dirty = approx_time(); + } + /* If the stream was removed, and it was a rend stream, decrement the * number of streams on the circuit associated with the rend service. */ @@ -1377,10 +1416,12 @@ or_circuit_t *or_circ = TO_OR_CIRCUIT(circ); if (conn == or_circ->n_streams) { or_circ->n_streams = conn->next_stream; + conflux_update_n_streams(or_circ, conn->next_stream); return; } if (conn == or_circ->resolving_streams) { or_circ->resolving_streams = conn->next_stream; + conflux_update_resolving_streams(or_circ, conn->next_stream); return; } @@ -1432,6 +1473,7 @@ if (circ->timestamp_dirty && circ->timestamp_dirty + get_options()->MaxCircuitDirtiness < now.tv_sec && + !connection_half_edges_waiting(TO_ORIGIN_CIRCUIT(circ)) && !TO_ORIGIN_CIRCUIT(circ)->p_streams /* nothing attached */ ) { log_debug(LD_CIRC, "Closing n_circ_id %u (dirty %ld sec ago, " "purpose %d)", @@ -1449,6 +1491,8 @@ if (timercmp(&circ->timestamp_began, &cutoff, OP_LT)) { if (circ->purpose == CIRCUIT_PURPOSE_C_GENERAL || circ->purpose == CIRCUIT_PURPOSE_C_HSDIR_GET || + circ->purpose == CIRCUIT_PURPOSE_CONFLUX_UNLINKED || + circ->purpose == CIRCUIT_PURPOSE_CONFLUX_LINKED || circ->purpose == CIRCUIT_PURPOSE_S_HSDIR_POST || circ->purpose == CIRCUIT_PURPOSE_HS_VANGUARDS || circ->purpose == CIRCUIT_PURPOSE_C_MEASURE_TIMEOUT || @@ -1653,7 +1697,12 @@ case CIRCUIT_PURPOSE_C_INTRODUCING: hs_client_circuit_has_opened(circ); break; + case CIRCUIT_PURPOSE_CONFLUX_UNLINKED: + conflux_circuit_has_opened(circ); + break; case CIRCUIT_PURPOSE_C_GENERAL: + circuit_try_attaching_streams(circ); + break; case CIRCUIT_PURPOSE_C_HSDIR_GET: case CIRCUIT_PURPOSE_S_HSDIR_POST: /* Tell any AP connections that have been waiting for a new @@ -1751,8 +1800,11 @@ circuit_purpose_to_string(TO_CIRCUIT(circ)->purpose)); /* If the path failed on an RP, retry it. */ - if (TO_CIRCUIT(circ)->purpose == CIRCUIT_PURPOSE_S_CONNECT_REND) + if (TO_CIRCUIT(circ)->purpose == CIRCUIT_PURPOSE_S_CONNECT_REND) { + hs_metrics_failed_rdv(&circ->hs_ident->identity_pk, + HS_METRICS_ERR_RDV_PATH); hs_circ_retry_service_rendezvous_point(circ); + } /* In all other cases, just bail. The rest is just failure accounting * that we don't want to do */ @@ -1862,6 +1914,9 @@ "(%s hop failed).", escaped(build_state_get_exit_nickname(circ->build_state)), failed_at_last_hop?"last":"non-last"); + + hs_metrics_failed_rdv(&circ->hs_ident->identity_pk, + HS_METRICS_ERR_RDV_RP_CONN_FAILURE); hs_circ_retry_service_rendezvous_point(circ); break; /* default: @@ -2023,6 +2078,11 @@ return 0; } + /* Do not cannibalize for conflux circuits */ + if (purpose_to_build == CIRCUIT_PURPOSE_CONFLUX_UNLINKED) { + return 0; + } + return 1; } @@ -2428,7 +2488,7 @@ extend_info = extend_info_new(conn->chosen_exit_name+1, digest, NULL, /* Ed25519 ID */ - NULL, NULL, /* onion keys */ + NULL, /* onion keys */ &addr, conn->socks_request->port, NULL, false); @@ -2473,7 +2533,6 @@ if (desired_circuit_purpose == CIRCUIT_PURPOSE_C_REND_JOINED && new_circ_purpose == CIRCUIT_PURPOSE_C_ESTABLISH_REND && ENTRY_TO_EDGE_CONN(conn)->hs_ident) { - flags |= CIRCLAUNCH_IS_V3_RP; log_info(LD_GENERAL, "Getting rendezvous circuit to v3 service!"); } @@ -2507,6 +2566,11 @@ circ->hs_ident = hs_ident_circuit_new(&edge_conn->hs_ident->identity_pk); } + if (desired_circuit_purpose == CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT) { + if (hs_client_setup_intro_circ_auth_key(circ) < 0) { + return 0; + } + } if (circ->base_.purpose == CIRCUIT_PURPOSE_C_ESTABLISH_REND && circ->base_.state == CIRCUIT_STATE_OPEN) circuit_has_opened(circ); @@ -2535,7 +2599,13 @@ } /** Return true iff crypt_path is one of the crypt_paths for - * circ. */ + * circ. + * + * WARNING: This function only validates that the cpath is on the *current* + * circuit, for internal consistency checking. For codepaths involving streams, + * or cpaths or layer_hints that could be from a different circuit due to + * conflux, use edge_uses_cpath() or conflux_validate_source_hop() instead. + */ static int cpath_is_on_circuit(origin_circuit_t *circ, crypt_path_t *crypt_path) { @@ -2573,6 +2643,7 @@ ENTRY_TO_EDGE_CONN(apconn)->on_circuit = TO_CIRCUIT(circ); /* assert_connection_ok(conn, time(NULL)); */ circ->p_streams = ENTRY_TO_EDGE_CONN(apconn); + conflux_update_p_streams(circ, ENTRY_TO_EDGE_CONN(apconn)); if (connection_edge_is_rendezvous_stream(ENTRY_TO_EDGE_CONN(apconn))) { /* We are attaching a stream to a rendezvous circuit. That means @@ -2600,6 +2671,8 @@ exitnode = node_get_by_id(cpath->extend_info->identity_digest); /* See if we can use optimistic data on this circuit */ + // TODO-329-PURPOSE: Can conflux use optimistic data? Does + // anything use optimistic data? Does anything use this? if (circ->base_.purpose == CIRCUIT_PURPOSE_C_GENERAL || circ->base_.purpose == CIRCUIT_PURPOSE_C_HSDIR_GET || circ->base_.purpose == CIRCUIT_PURPOSE_S_HSDIR_POST || @@ -2682,6 +2755,20 @@ ADDRMAPSRC_TRACKEXIT, 0, 0, stream_id); } +/** + * Return true if conn is configured with KeepaliveIsolateSOCKSAuth, + * and it has its socks isolation set. + */ +static bool +connection_ap_socks_iso_keepalive_enabled(const entry_connection_t *conn) +{ + return conn && + conn->socks_request && + (conn->entry_cfg.isolation_flags & ISO_SOCKSAUTH) && + (conn->entry_cfg.socks_iso_keep_alive) && + (conn->socks_request->usernamelen || conn->socks_request->passwordlen); +} + /** Attempt to attach the connection conn to circ, and send a * begin or resolve cell as appropriate. Return values are as for * connection_ap_handshake_attach_circuit. The stream will exit from the hop @@ -2703,13 +2790,13 @@ base_conn->state = AP_CONN_STATE_CIRCUIT_WAIT; if (!circ->base_.timestamp_dirty || - ((conn->entry_cfg.isolation_flags & ISO_SOCKSAUTH) && - (conn->entry_cfg.socks_iso_keep_alive) && - (conn->socks_request->usernamelen || - conn->socks_request->passwordlen))) { + connection_ap_socks_iso_keepalive_enabled(conn)) { /* When stream isolation is in use and controlled by an application * we are willing to keep using the stream. */ circ->base_.timestamp_dirty = approx_time(); + if (TO_CIRCUIT(circ)->conflux) { + conflux_sync_circ_fields(TO_CIRCUIT(circ)->conflux, circ); + } } pathbias_count_use_attempt(circ); @@ -2784,8 +2871,10 @@ conn_age = (int)(time(NULL) - base_conn->timestamp_created); - /* Is this connection so old that we should give up on it? */ - if (conn_age >= get_options()->SocksTimeout) { + /* Is this connection so old that we should give up on it? Don't timeout if + * this is a connection to an HS with PoW enabled because it can take an + * arbitrary amount of time. */ + if (conn_age >= get_options()->SocksTimeout && !conn->hs_with_pow_conn) { int severity = (tor_addr_is_null(&base_conn->addr) && !base_conn->port) ? LOG_INFO : LOG_NOTICE; log_fn(severity, LD_APP, @@ -2945,6 +3034,16 @@ conn, CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT, &introcirc); if (retval < 0) return -1; /* failed */ + if (rendcirc && introcirc) { + /* Let's fill out the hs_ident fully as soon as possible, so that + * unreachability counts can be updated properly even if circuits close + * early. */ + tor_assert_nonfatal(!ed25519_public_key_is_zero( + &introcirc->hs_ident->intro_auth_pk)); + ed25519_pubkey_copy(&rendcirc->hs_ident->intro_auth_pk, + &introcirc->hs_ident->intro_auth_pk); + } + if (retval > 0) { /* one has already sent the intro. keep waiting. */ tor_assert(introcirc); @@ -2976,8 +3075,8 @@ if (introcirc->base_.state == CIRCUIT_STATE_OPEN) { int ret; log_info(LD_REND, "Found open intro circ %u (id: %" PRIu32 "). " - "Rend circuit %u (id: %" PRIu32 "); Sending " - "introduction. (stream %d sec old)", + "Rend circuit %u (id: %" PRIu32 "); Considering " + "sending introduction. (stream %d sec old)", (unsigned) TO_CIRCUIT(introcirc)->n_circ_id, introcirc->global_identifier, (unsigned) TO_CIRCUIT(rendcirc)->n_circ_id, @@ -3027,6 +3126,13 @@ if (circ->purpose == new_purpose) return; + /* If this is a conflux circuit, a purpose change means we have closed */ + if (CIRCUIT_IS_CONFLUX(circ)) { + /* If we're not transitioning to the linked purpose, we're closed. */ + if (new_purpose != CIRCUIT_PURPOSE_CONFLUX_LINKED) + conflux_circuit_has_closed(circ); + } + if (CIRCUIT_IS_ORIGIN(circ)) { char old_purpose_desc[80] = ""; @@ -3080,6 +3186,10 @@ circ->base_.timestamp_dirty -= options->MaxCircuitDirtiness; circ->unusable_for_new_conns = 1; + + if (TO_CIRCUIT(circ)->conflux) { + conflux_sync_circ_fields(TO_CIRCUIT(circ)->conflux, circ); + } } /** @@ -3092,15 +3202,16 @@ { if (!circ) return; - tor_assertf_nonfatal(relay_body_len <= RELAY_PAYLOAD_SIZE, + tor_assertf_nonfatal(relay_body_len <= RELAY_PAYLOAD_SIZE_MAX, "Wrong relay_body_len: %d (should be at most %d)", - relay_body_len, RELAY_PAYLOAD_SIZE); + relay_body_len, RELAY_PAYLOAD_SIZE_MAX); circ->n_delivered_written_circ_bw = tor_add_u32_nowrap(circ->n_delivered_written_circ_bw, relay_body_len); + // TODO CGO: I think this may now be somewhat incorrect. circ->n_overhead_written_circ_bw = tor_add_u32_nowrap(circ->n_overhead_written_circ_bw, - RELAY_PAYLOAD_SIZE-relay_body_len); + RELAY_PAYLOAD_SIZE_MAX-relay_body_len); } /** @@ -3113,11 +3224,12 @@ { if (!circ) return; - tor_assert_nonfatal(relay_body_len <= RELAY_PAYLOAD_SIZE); + tor_assert_nonfatal(relay_body_len <= RELAY_PAYLOAD_SIZE_MAX); circ->n_delivered_read_circ_bw = tor_add_u32_nowrap(circ->n_delivered_read_circ_bw, relay_body_len); + // TODO CGO: I think this may now be somewhat incorrect. circ->n_overhead_read_circ_bw = tor_add_u32_nowrap(circ->n_overhead_read_circ_bw, - RELAY_PAYLOAD_SIZE-relay_body_len); + RELAY_PAYLOAD_SIZE_MAX-relay_body_len); } diff -Nru tor-0.4.7.16/src/core/or/circuituse.h tor-0.4.9.6/src/core/or/circuituse.h --- tor-0.4.7.16/src/core/or/circuituse.h 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/core/or/circuituse.h 2026-03-25 14:30:34.000000000 +0000 @@ -44,14 +44,13 @@ /** Flag to set when the last hop of a circuit doesn't need to be an * exit node. */ #define CIRCLAUNCH_IS_INTERNAL (1<<3) -/** Flag to set when we are trying to launch a v3 rendezvous circuit. We need - * to apply some additional filters on the node picked. */ -#define CIRCLAUNCH_IS_V3_RP (1<<4) /** Flag to set when we are trying to launch a self-testing circuit to our * IPv6 ORPort. We need to apply some additional filters on the second-last * node in the circuit. (We are both the client and the last node in the * circuit.) */ #define CIRCLAUNCH_IS_IPV6_SELFTEST (1<<5) +/** Flag to set when a circuit needs the exit to support conflux. */ +#define CIRCLAUNCH_NEED_CONFLUX (1<<6) origin_circuit_t *circuit_launch_by_extend_info(uint8_t purpose, extend_info_t *info, @@ -77,6 +76,11 @@ bool circuit_purpose_is_hs_vanguards(const uint8_t purpose); bool circuit_is_hs_v3(const circuit_t *circ); +int circuit_is_acceptable(const origin_circuit_t *origin_circ, + const entry_connection_t *conn, + int must_be_open, uint8_t purpose, + int need_uptime, int need_internal, + time_t now); int circuit_should_use_vanguards(uint8_t); void circuit_sent_valid_data(origin_circuit_t *circ, uint16_t relay_body_len); diff -Nru tor-0.4.7.16/src/core/or/command.c tor-0.4.9.6/src/core/or/command.c --- tor-0.4.7.16/src/core/or/command.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/core/or/command.c 2026-03-25 14:30:34.000000000 +0000 @@ -331,6 +331,14 @@ return; } + /* We no longer accept TAP, for any reason. */ + if (create_cell->handshake_type == ONION_HANDSHAKE_TYPE_TAP) { + tor_free(create_cell); + /* TODO: Should we collect statistics here? Should we log? */ + circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_TORPROTOCOL); + return; + } + /* Mark whether this circuit used TAP in case we need to use this * information for onion service statistics later on. */ if (create_cell->handshake_type == ONION_HANDSHAKE_TYPE_FAST || @@ -363,6 +371,7 @@ circuit_params_t params; memset(&created_cell, 0, sizeof(created_cell)); + size_t keylen = sizeof(keys); len = onion_skin_server_handshake(ONION_HANDSHAKE_TYPE_FAST, create_cell->onionskin, create_cell->handshake_len, @@ -370,11 +379,11 @@ NULL, created_cell.reply, sizeof(created_cell.reply), - keys, CPATH_KEY_MATERIAL_LEN, + keys, &keylen, rend_circ_nonce, ¶ms); tor_free(create_cell); - if (len < 0) { + if (len < 0 || keylen != sizeof(keys)) { log_warn(LD_OR,"Failed to generate key material. Closing."); circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_INTERNAL); return; @@ -383,6 +392,7 @@ created_cell.handshake_len = len; if (onionskin_answer(circ, &created_cell, + RELAY_CRYPTO_ALG_TOR1, (const char *)keys, sizeof(keys), rend_circ_nonce)<0) { log_warn(LD_OR,"Failed to reply to CREATE_FAST cell. Closing."); @@ -448,7 +458,7 @@ } else { /* pack it into an extended relay cell, and send it. */ uint8_t command=0; uint16_t len=0; - uint8_t payload[RELAY_PAYLOAD_SIZE]; + uint8_t payload[RELAY_PAYLOAD_SIZE_MAX]; log_debug(LD_OR, "Converting created cell to extended relay cell, sending."); memset(payload, 0, sizeof(payload)); @@ -461,6 +471,11 @@ circuit_mark_for_close(circ, END_CIRC_REASON_TORPROTOCOL); return; } + if (len > circuit_max_relay_payload(circ, NULL, command)) { + log_fn(LOG_PROTOCOL_WARN, LD_OR, "Created cell too big to package."); + circuit_mark_for_close(circ, END_CIRC_REASON_TORPROTOCOL); + return; + } relay_send_command_from_edge(0, circ, command, (const char*)payload, len, NULL); @@ -476,7 +491,7 @@ { const or_options_t *options = get_options(); circuit_t *circ; - int reason, direction; + int direction, reason; uint32_t orig_delivered_bw = 0; uint32_t orig_overhead_bw = 0; diff -Nru tor-0.4.7.16/src/core/or/conflux.c tor-0.4.9.6/src/core/or/conflux.c --- tor-0.4.7.16/src/core/or/conflux.c 1970-01-01 00:00:00.000000000 +0000 +++ tor-0.4.9.6/src/core/or/conflux.c 2026-03-25 14:30:34.000000000 +0000 @@ -0,0 +1,1006 @@ +/* Copyright (c) 2021, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file conflux.c + * \brief Conflux multipath core algorithms + */ + +#include "core/or/relay_msg.h" +#define TOR_CONFLUX_PRIVATE + +#include "core/or/or.h" + +#include "core/or/circuit_st.h" +#include "core/or/sendme.h" +#include "core/or/relay.h" +#include "core/or/congestion_control_common.h" +#include "core/or/congestion_control_st.h" +#include "core/or/origin_circuit_st.h" +#include "core/or/circuitlist.h" +#include "core/or/circuituse.h" +#include "core/or/conflux.h" +#include "core/or/conflux_params.h" +#include "core/or/conflux_util.h" +#include "core/or/conflux_pool.h" +#include "core/or/conflux_st.h" +#include "core/or/conflux_cell.h" +#include "lib/time/compat_time.h" +#include "app/config/config.h" + +/** One million microseconds in a second */ +#define USEC_PER_SEC 1000000 + +static inline uint64_t cwnd_sendable(const circuit_t *on_circ, + uint64_t in_usec, uint64_t our_usec); + +/* Track the total number of bytes used by all ooo_q so it can be used by the + * OOM handler to assess. + * + * When adding or subtracting to this value, use conflux_msg_alloc_cost(). */ +static uint64_t total_ooo_q_bytes = 0; + +/** + * Determine if we should multiplex a specific relay command or not. + * + * TODO: Version of this that is the set of forbidden commands + * on linked circuits + */ +bool +conflux_should_multiplex(int relay_command) +{ + switch (relay_command) { + /* These are all fine to multiplex, and must be + * so that ordering is preserved */ + case RELAY_COMMAND_BEGIN: + case RELAY_COMMAND_DATA: + case RELAY_COMMAND_END: + case RELAY_COMMAND_CONNECTED: + return true; + + /* We can't multiplex these because they are + * circuit-specific */ + case RELAY_COMMAND_SENDME: + case RELAY_COMMAND_EXTEND: + case RELAY_COMMAND_EXTENDED: + case RELAY_COMMAND_TRUNCATE: + case RELAY_COMMAND_TRUNCATED: + case RELAY_COMMAND_DROP: + return false; + + /* We must multiplex RESOLVEs because their ordering + * impacts begin/end. */ + case RELAY_COMMAND_RESOLVE: + case RELAY_COMMAND_RESOLVED: + return true; + + /* These are all circuit-specific */ + case RELAY_COMMAND_BEGIN_DIR: + case RELAY_COMMAND_EXTEND2: + case RELAY_COMMAND_EXTENDED2: + case RELAY_COMMAND_ESTABLISH_INTRO: + case RELAY_COMMAND_ESTABLISH_RENDEZVOUS: + case RELAY_COMMAND_INTRODUCE1: + case RELAY_COMMAND_INTRODUCE2: + case RELAY_COMMAND_RENDEZVOUS1: + case RELAY_COMMAND_RENDEZVOUS2: + case RELAY_COMMAND_INTRO_ESTABLISHED: + case RELAY_COMMAND_RENDEZVOUS_ESTABLISHED: + case RELAY_COMMAND_INTRODUCE_ACK: + case RELAY_COMMAND_PADDING_NEGOTIATE: + case RELAY_COMMAND_PADDING_NEGOTIATED: + return false; + + /* These must be multiplexed because their ordering + * relative to BEGIN/END must be preserved */ + case RELAY_COMMAND_XOFF: + case RELAY_COMMAND_XON: + return true; + + /* These two are not multiplexed, because they must + * be processed immediately to update sequence numbers + * before any other cells are processed on the circuit */ + case RELAY_COMMAND_CONFLUX_SWITCH: + case RELAY_COMMAND_CONFLUX_LINK: + case RELAY_COMMAND_CONFLUX_LINKED: + case RELAY_COMMAND_CONFLUX_LINKED_ACK: + return false; + + default: + log_warn(LD_BUG, "Conflux asked to multiplex unknown relay command %d", + relay_command); + return false; + } +} + +/** Return the leg for a circuit in a conflux set. Return NULL if not found. */ +conflux_leg_t * +conflux_get_leg(conflux_t *cfx, const circuit_t *circ) +{ + conflux_leg_t *leg_found = NULL; + tor_assert(cfx); + tor_assert(cfx->legs); + + // Find the leg that the cell is written on + CONFLUX_FOR_EACH_LEG_BEGIN(cfx, leg) { + if (leg->circ == circ) { + leg_found = leg; + break; + } + } CONFLUX_FOR_EACH_LEG_END(leg); + + return leg_found; +} + +/** + * Gets the maximum last_seq_sent from all legs. + */ +uint64_t +conflux_get_max_seq_sent(const conflux_t *cfx) +{ + uint64_t max_seq_sent = 0; + + CONFLUX_FOR_EACH_LEG_BEGIN(cfx, leg) { + if (leg->last_seq_sent > max_seq_sent) { + max_seq_sent = leg->last_seq_sent; + } + } CONFLUX_FOR_EACH_LEG_END(leg); + + return max_seq_sent; +} + +/** + * Gets the maximum last_seq_recv from all legs. + */ +uint64_t +conflux_get_max_seq_recv(const conflux_t *cfx) +{ + uint64_t max_seq_recv = 0; + + CONFLUX_FOR_EACH_LEG_BEGIN(cfx, leg) { + if (leg->last_seq_recv > max_seq_recv) { + max_seq_recv = leg->last_seq_recv; + } + } CONFLUX_FOR_EACH_LEG_END(leg); + + return max_seq_recv; +} + +/** Return the total memory allocation the circuit is using by conflux. If this + * circuit is not a Conflux circuit, 0 is returned. */ +uint64_t +conflux_get_circ_bytes_allocation(const circuit_t *circ) +{ + if (circ->conflux) { + return smartlist_len(circ->conflux->ooo_q) * sizeof(void*) + + circ->conflux->ooo_q_alloc_cost; + } + return 0; +} + +/** Return the total memory allocation in bytes by the subsystem. + * + * At the moment, only out of order queues are consiered. */ +uint64_t +conflux_get_total_bytes_allocation(void) +{ + return total_ooo_q_bytes; +} + +/** The OOM handler is asking us to try to free at least bytes_to_remove. */ +size_t +conflux_handle_oom(size_t bytes_to_remove) +{ + (void) bytes_to_remove; + + /* We are not doing anything on the sets, the OOM handler will trigger a + * circuit clean up which will affect conflux sets, by pruning oldest + * circuits. */ + + log_info(LD_CIRC, "OOM handler triggered. OOO queus allocation: %" PRIu64, + total_ooo_q_bytes); + return 0; +} + +/** + * Returns true if a circuit has package window space to send, and is + * not blocked locally. + */ +static inline bool +circuit_ready_to_send(const circuit_t *circ) +{ + const congestion_control_t *cc = circuit_ccontrol(circ); + bool cc_sendable = true; + + /* We consider ourselves blocked if we're within 1 sendme of the + * cwnd, because inflight is decremented before this check */ + // TODO-329-TUNING: This subtraction not be right.. It depends + // on call order wrt decisions and sendme arrival + if (cc->inflight >= cc->cwnd) { + cc_sendable = false; + } + + /* Origin circuits use the package window of the last hop, and + * have an outbound cell direction (towards exit). Otherwise, + * there is no cpath and direction is inbound. */ + if (CIRCUIT_IS_ORIGIN(circ)) { + return cc_sendable && !circ->circuit_blocked_on_n_chan; + } else { + return cc_sendable && !circ->circuit_blocked_on_p_chan; + } +} + +/** + * Return the circuit with the minimum RTT. Do not use any + * other circuit. + * + * This algorithm will minimize RTT always, and will not provide + * any throughput benefit. We expect it to be useful for VoIP/UDP + * use cases. Because it only uses one circuit on a leg at a time, + * it can have more than one circuit per guard (ie: to find + * lower-latency middles for the path). + */ +static const circuit_t * +conflux_decide_circ_minrtt(const conflux_t *cfx) +{ + uint64_t min_rtt = UINT64_MAX; + const circuit_t *circ = NULL; + + /* Can't get here without any legs. */ + tor_assert(CONFLUX_NUM_LEGS(cfx)); + + CONFLUX_FOR_EACH_LEG_BEGIN(cfx, leg) { + + /* Ignore circuits with no RTT measurement */ + if (leg->circ_rtts_usec && leg->circ_rtts_usec < min_rtt) { + circ = leg->circ; + min_rtt = leg->circ_rtts_usec; + } + } CONFLUX_FOR_EACH_LEG_END(leg); + + /* If the minRTT circuit can't send, dont send on any circuit. */ + if (!circ || !circuit_ready_to_send(circ)) { + return NULL; + } + return circ; +} + +/** + * Favor the circuit with the lowest RTT that still has space in the + * congestion window. + * + * This algorithm will maximize total throughput at the expense of + * bloating out-of-order queues. + */ +static const circuit_t * +conflux_decide_circ_lowrtt(const conflux_t *cfx) +{ + uint64_t low_rtt = UINT64_MAX; + const circuit_t *circ = NULL; + + /* Can't get here without any legs. */ + tor_assert(CONFLUX_NUM_LEGS(cfx)); + + CONFLUX_FOR_EACH_LEG_BEGIN(cfx, leg) { + /* If the package window is full, skip it */ + if (!circuit_ready_to_send(leg->circ)) { + continue; + } + + /* Ignore circuits with no RTT */ + if (leg->circ_rtts_usec && leg->circ_rtts_usec < low_rtt) { + low_rtt = leg->circ_rtts_usec; + circ = leg->circ; + } + } CONFLUX_FOR_EACH_LEG_END(leg); + + /* At this point, if we found a circuit, we've already validated that its + * congestion window has room. */ + return circ; +} + +/** + * Returns the amount of room in a cwnd on a circuit. + */ +static inline uint64_t +cwnd_available(const circuit_t *on_circ) +{ + const congestion_control_t *cc = circuit_ccontrol(on_circ); + tor_assert(cc); + + if (cc->cwnd < cc->inflight) + return 0; + + return cc->cwnd - cc->inflight; +} + +/** + * Return the amount of congestion window we can send on + * on_circ during in_usec. However, if we're still in + * slow-start, send the whole window to establish the true + * cwnd. + */ +static inline uint64_t +cwnd_sendable(const circuit_t *on_circ, uint64_t in_usec, + uint64_t our_usec) +{ + const congestion_control_t *cc = circuit_ccontrol(on_circ); + tor_assert(cc); + uint64_t cwnd_adjusted = cwnd_available(on_circ); + + if (our_usec == 0 || in_usec == 0) { + log_fn(LOG_PROTOCOL_WARN, LD_CIRC, + "cwnd_sendable: Missing RTT data. in_usec: %" PRIu64 + " our_usec: %" PRIu64, in_usec, our_usec); + return cwnd_adjusted; + } + + if (cc->in_slow_start) { + return cwnd_adjusted; + } else { + /* For any given leg, it has min_rtt/2 time before the 'primary' + * leg's acks start arriving. So, the amount of data this + * 'secondary' leg can send while the min_rtt leg transmits these + * acks is: + * (cwnd_leg/(leg_rtt/2))*min_rtt/2 = cwnd_leg*min_rtt/leg_rtt. + */ + uint64_t sendable = cwnd_adjusted*in_usec/our_usec; + return MIN(cc->cwnd, sendable); + } +} + +/** + * Returns true if we can switch to a new circuit, false otherwise. + * + * This function assumes we're primarily switching between two circuits, + * the current and the prev. If we're using more than two circuits, we + * need to set cfx_drain_pct to 100. + */ +static inline bool +conflux_can_switch(const conflux_t *cfx) +{ + /* If we still expected to send more cells on this circuit, + * we're only allowed to switch if the previous circuit emptied. */ + if (cfx->cells_until_switch > 0) { + /* If there is no prev leg, skip the inflight check. */ + if (!cfx->prev_leg) { + return false; + } + const congestion_control_t *ccontrol = + circuit_ccontrol(cfx->prev_leg->circ); + + /* If the inflight count has drained to below cfx_drain_pct + * of the congestion window, then we can switch. + * We check the sendme_inc because there may be un-ackable + * data in inflight as well, and we can still switch then. */ + // TODO-329-TUNING: Should we try to switch if the prev_leg is + // ready to send, instead of this? + if (ccontrol->inflight < ccontrol->sendme_inc || + 100*ccontrol->inflight <= + conflux_params_get_drain_pct()*ccontrol->cwnd) { + return true; + } + + return false; + } + + return true; +} + +/** + * Favor the circuit with the lowest RTT that still has space in the + * congestion window up to the ratio of RTTs. + * + * This algorithm should only use auxillary legs up to the point + * where their data arrives roughly the same time as the lowest + * RTT leg. It will not utilize the full cwnd of auxillary legs, + * except in slow start. Therefore, out-of-order queue bloat should + * be minimized to just the slow-start phase. + */ +static const circuit_t * +conflux_decide_circ_cwndrtt(const conflux_t *cfx) +{ + uint64_t min_rtt = UINT64_MAX; + const conflux_leg_t *leg = NULL; + + /* Can't get here without any legs. */ + tor_assert(CONFLUX_NUM_LEGS(cfx)); + + /* Find the leg with the minimum RTT.*/ + CONFLUX_FOR_EACH_LEG_BEGIN(cfx, l) { + /* Ignore circuits with invalid RTT */ + if (l->circ_rtts_usec && l->circ_rtts_usec < min_rtt) { + min_rtt = l->circ_rtts_usec; + leg = l; + } + } CONFLUX_FOR_EACH_LEG_END(l); + + /* If the package window is has room, use it */ + if (leg && circuit_ready_to_send(leg->circ)) { + return leg->circ; + } + + leg = NULL; + + CONFLUX_FOR_EACH_LEG_BEGIN(cfx, l) { + if (!circuit_ready_to_send(l->circ)) { + continue; + } + + /* Pick a 'min_leg' with the lowest RTT that still has + * room in the congestion window. Note that this works for + * min_leg itself, up to inflight. */ + if (l->circ_rtts_usec && + cwnd_sendable(l->circ, min_rtt, l->circ_rtts_usec) > 0) { + leg = l; + } + } CONFLUX_FOR_EACH_LEG_END(l); + + /* If the circuit can't send, don't send on any circuit. */ + if (!leg || !circuit_ready_to_send(leg->circ)) { + return NULL; + } + return leg->circ; +} + +/** + * This function is called when we want to send a relay cell on a + * conflux, as well as when we want to compute available space in + * to package from streams. + * + * It determines the circuit that relay command should be sent on, + * and sends a SWITCH cell if necessary. + * + * It returns the circuit we should send on. If no circuits are ready + * to send, it returns NULL. + */ +circuit_t * +conflux_decide_circ_for_send(conflux_t *cfx, + circuit_t *orig_circ, + uint8_t relay_command) +{ + /* If this command should not be multiplexed, send it on the original + * circuit */ + if (!conflux_should_multiplex(relay_command)) { + return orig_circ; + } + + circuit_t *new_circ = conflux_decide_next_circ(cfx); + + /* Because our congestion window only cover relay data command, we can end up + * in a situation where we need to send non data command when all circuits + * are at capacity. For those cases, keep using the *current* leg, + * so these commands arrive in-order. */ + if (!new_circ && relay_command != RELAY_COMMAND_DATA) { + /* Curr leg should be set, because conflux_decide_next_circ() should + * have set it earlier. No BUG() here because the only caller BUG()s. */ + if (!cfx->curr_leg) { + log_warn(LD_BUG, "No current leg for conflux with relay command %d", + relay_command); + return NULL; + } + return cfx->curr_leg->circ; + } + + /* + * If we are switching to a new circuit, we need to send a SWITCH command. + * We also need to compute an estimate of how much data we can send on + * the new circuit before we are allowed to switch again, to rate + * limit the frequency of switching. + */ + if (new_circ) { + conflux_leg_t *new_leg = conflux_get_leg(cfx, new_circ); + tor_assert(cfx->curr_leg); + + if (new_circ != cfx->curr_leg->circ) { + // TODO-329-TUNING: This is one mechanism to rate limit switching, + // which should reduce the OOQ mem. However, we're not going to do that + // until we get some data on if the memory usage is high + cfx->cells_until_switch = 0; + //cwnd_sendable(new_circ,cfx->curr_leg->circ_rtts_usec, + // new_leg->circ_rtts_usec); + + conflux_validate_stream_lists(cfx); + + cfx->prev_leg = cfx->curr_leg; + cfx->curr_leg = new_leg; + + tor_assert(cfx->prev_leg); + tor_assert(cfx->curr_leg); + + if (cfx->curr_leg->last_seq_sent > cfx->prev_leg->last_seq_sent) { + /* Having incoherent sequence numbers, log warn about it but rate limit + * it to every hour so we avoid redundent report. */ + static ratelim_t rlimit = RATELIM_INIT(60 * 60); + log_fn_ratelim(&rlimit, LOG_WARN, LD_BUG, + "Current conflux leg last_seq_sent=%"PRIu64 + " is above previous leg at %" PRIu64 ". Closing set.", + cfx->curr_leg->last_seq_sent, + cfx->prev_leg->last_seq_sent); + conflux_mark_all_for_close(cfx->nonce, CIRCUIT_IS_ORIGIN(new_circ), + END_CIRC_REASON_TORPROTOCOL); + return NULL; + } + + uint64_t relative_seq = cfx->prev_leg->last_seq_sent - + cfx->curr_leg->last_seq_sent; + + /* On failure to send the SWITCH, we close everything. This means we have + * a protocol error or the sending failed and the circuit is closed. */ + if (!conflux_send_switch_command(cfx->curr_leg->circ, relative_seq)) { + conflux_mark_all_for_close(cfx->nonce, CIRCUIT_IS_ORIGIN(new_circ), + END_CIRC_REASON_TORPROTOCOL); + return NULL; + } + cfx->curr_leg->last_seq_sent = cfx->prev_leg->last_seq_sent; + } + } + + return new_circ; +} + +/** Called after conflux actually sent a cell on a circuit. + * This function updates sequence number counters, and + * switch counters. + */ +void +conflux_note_cell_sent(conflux_t *cfx, circuit_t *circ, uint8_t relay_command) +{ + conflux_leg_t *leg = NULL; + + if (!conflux_should_multiplex(relay_command)) { + return; + } + + leg = conflux_get_leg(cfx, circ); + if (leg == NULL) { + log_fn(LOG_PROTOCOL_WARN, LD_BUG, "No Conflux leg after sending a cell"); + return; + } + + leg->last_seq_sent++; + + if (cfx->cells_until_switch > 0) { + cfx->cells_until_switch--; + } +} + +/** Find the leg with lowest non-zero curr_rtt_usec, and + * pick it for our current leg. */ +static inline bool +conflux_pick_first_leg(conflux_t *cfx) +{ + conflux_leg_t *min_leg = NULL; + + CONFLUX_FOR_EACH_LEG_BEGIN(cfx, leg) { + /* We need to skip 0-RTT legs, since this can happen at the exit + * when there is a race between BEGIN and LINKED_ACK, and BEGIN + * wins the race. The good news is that because BEGIN won, + * we don't need to consider those other legs, since they are + * slower. */ + if (leg->circ_rtts_usec > 0) { + if (!min_leg || leg->circ_rtts_usec < min_leg->circ_rtts_usec) { + min_leg = leg; + } + } + } CONFLUX_FOR_EACH_LEG_END(leg); + + if (!min_leg) { + // Get the 0th leg; if it does not exist, log the set. + // Bug 40827 managed to hit this, so let's dump the sets + // in case it happens again. + if (BUG(smartlist_len(cfx->legs) <= 0)) { + // Since we have no legs, we have no idea if this is really a client + // or server set. Try to find any that match: + log_warn(LD_BUG, "Matching client sets:"); + conflux_log_set(LOG_WARN, cfx, true); + log_warn(LD_BUG, "Matching server sets:"); + conflux_log_set(LOG_WARN, cfx, false); + log_warn(LD_BUG, "End conflux set dump"); + return false; + } + + min_leg = smartlist_get(cfx->legs, 0); + tor_assert(min_leg); + if (BUG(min_leg->linked_sent_usec == 0)) { + log_warn(LD_BUG, "Conflux has no legs with non-zero RTT. " + "Using first leg."); + conflux_log_set(LOG_WARN, cfx, CIRCUIT_IS_ORIGIN(min_leg->circ)); + } + } + + // TODO-329-TUNING: We may want to initialize this to a cwnd, to + // minimize early switching? + //cfx->cells_until_switch = circuit_ccontrol(min_leg->circ)->cwnd; + cfx->cells_until_switch = 0; + + cfx->curr_leg = min_leg; + + return true; +} + +/** + * Returns the circuit that conflux would send on next, if + * conflux_decide_circ_for_send were called. This is used to compute + * available space in the package window. + */ +circuit_t * +conflux_decide_next_circ(conflux_t *cfx) +{ + // TODO-329-TUNING: Temporarily validate legs here. We can remove + // this once tuning is complete. + conflux_validate_legs(cfx); + + /* If the conflux set is tearing down and has no current leg, + * bail and give up */ + if (cfx->in_full_teardown) { + return NULL; + } + + /* If we don't have a current leg yet, pick one. + * (This is the only non-const operation in this function). */ + if (!cfx->curr_leg) { + if (!conflux_pick_first_leg(cfx)) + return NULL; + } + + /* First, check if we can switch. */ + if (!conflux_can_switch(cfx)) { + tor_assert(cfx->curr_leg); + circuit_t *curr_circ = cfx->curr_leg->circ; + + /* If we can't switch, and the current circuit can't send, + * then return null. */ + if (circuit_ready_to_send(curr_circ)) { + return curr_circ; + } + log_info(LD_CIRC, "Conflux can't switch; no circuit to send on."); + return NULL; + } + + switch (cfx->params.alg) { + case CONFLUX_ALG_MINRTT: // latency (no ooq) + return (circuit_t*)conflux_decide_circ_minrtt(cfx); + case CONFLUX_ALG_LOWRTT: // high throughput (high oooq) + return (circuit_t*)conflux_decide_circ_lowrtt(cfx); + case CONFLUX_ALG_CWNDRTT: // throughput (low oooq) + return (circuit_t*)conflux_decide_circ_cwndrtt(cfx); + default: + return NULL; + } +} + +/** + * Called when we have a new RTT estimate for a circuit. + */ +void +conflux_update_rtt(conflux_t *cfx, circuit_t *circ, uint64_t rtt_usec) +{ + conflux_leg_t *leg = conflux_get_leg(cfx, circ); + + if (!leg) { + log_warn(LD_BUG, "Got RTT update for circuit not in conflux"); + return; + } + + // Update RTT + leg->circ_rtts_usec = rtt_usec; + + // TODO-329-ARTI: For UDP latency targeting, arti could decide to launch + // new a test leg to potentially replace this one, if a latency target + // was requested and we now exceed it. Since C-Tor client likely + // will not have UDP support, we aren't doing this here. +} + +/** + * Comparison function for ooo_q pqueue. + * + * Ensures that lower sequence numbers are at the head of the pqueue. + */ +static int +conflux_queue_cmp(const void *a, const void *b) +{ + // Compare a and b as conflux_cell_t using the seq field, and return a + // comparison result such that the lowest seq is at the head of the pqueue. + const conflux_msg_t *cell_a = a; + const conflux_msg_t *cell_b = b; + + tor_assert(cell_a); + tor_assert(cell_b); + + if (cell_a->seq < cell_b->seq) { + return -1; + } else if (cell_a->seq > cell_b->seq) { + return 1; + } else { + return 0; + } +} + +/** + * Get the congestion control object for a conflux circuit. + * + * Because conflux can only be negotiated with the last hop, we + * can use the last hop of the cpath to obtain the congestion + * control object for origin circuits. For non-origin circuits, + * we can use the circuit itself. + */ +const congestion_control_t * +circuit_ccontrol(const circuit_t *circ) +{ + const congestion_control_t *ccontrol = NULL; + tor_assert(circ); + + if (CIRCUIT_IS_ORIGIN(circ)) { + tor_assert(CONST_TO_ORIGIN_CIRCUIT(circ)->cpath); + tor_assert(CONST_TO_ORIGIN_CIRCUIT(circ)->cpath->prev); + ccontrol = CONST_TO_ORIGIN_CIRCUIT(circ)->cpath->prev->ccontrol; + } else { + ccontrol = circ->ccontrol; + } + + /* Conflux circuits always have congestion control*/ + tor_assert(ccontrol); + return ccontrol; +} + +// TODO-329-TUNING: For LowRTT, we can at most switch every SENDME, +// but for BLEST, we should switch at most every cwnd.. But +// we do not know the other side's CWND here.. We can at best +// asssume it is above the cwnd_min +#define CONFLUX_MIN_LINK_INCREMENT 31 +/** + * Validate and handle RELAY_COMMAND_CONFLUX_SWITCH. + */ +int +conflux_process_switch_command(circuit_t *in_circ, + crypt_path_t *layer_hint, + const relay_msg_t *msg) +{ + tor_assert(in_circ); + tor_assert(msg); + + conflux_t *cfx = in_circ->conflux; + uint32_t relative_seq; + conflux_leg_t *leg; + + if (!conflux_is_enabled(in_circ)) { + circuit_mark_for_close(in_circ, END_CIRC_REASON_TORPROTOCOL); + return -1; + } + + /* If there is no conflux object negotiated, this is invalid. + * log and close circ */ + if (!cfx) { + log_warn(LD_BUG, "Got a conflux switch command on a circuit without " + "conflux negotiated. Closing circuit."); + + circuit_mark_for_close(in_circ, END_CIRC_REASON_TORPROTOCOL); + return -1; + } + + // TODO-329-TUNING: Temporarily validate that we have all legs. + // After tuning is complete, we can remove this. + conflux_validate_legs(cfx); + + leg = conflux_get_leg(cfx, in_circ); + + /* If we can't find the conflux leg, we got big problems.. + * Close the circuit. */ + if (!leg) { + log_warn(LD_BUG, "Got a conflux switch command on a circuit without " + "conflux leg. Closing circuit."); + circuit_mark_for_close(in_circ, END_CIRC_REASON_INTERNAL); + return -1; + } + + // Check source hop via layer_hint + if (!conflux_validate_source_hop(in_circ, layer_hint)) { + log_warn(LD_BUG, "Got a conflux switch command on a circuit with " + "invalid source hop. Closing circuit."); + circuit_mark_for_close(in_circ, END_CIRC_REASON_TORPROTOCOL); + return -1; + } + + relative_seq = conflux_cell_parse_switch(msg); + + /* + * We have to make sure that the switch command is truely + * incrementing the sequence number, or else it becomes + * a side channel that can be spammed for traffic analysis. + */ + // TODO-329-TUNING: This can happen. Disabling for now.. + //if (relative_seq < CONFLUX_MIN_LINK_INCREMENT) { + // log_warn(LD_CIRC, "Got a conflux switch command with a relative " + // "sequence number less than the minimum increment. Closing " + // "circuit."); + // circuit_mark_for_close(in_circ, END_CIRC_REASON_TORPROTOCOL); + // return -1; + //} + + // TODO-329-UDP: When Prop#340 exits and was negotiated, ensure we're + // in a packed cell, with another cell following, otherwise + // this is a spammed side-channel. + // - We definitely should never get switches back-to-back. + // - We should not get switches across all legs with no data + // But before Prop#340, it doesn't make much sense to do this. + // C-Tor is riddled with side-channels like this anyway, unless + // vanguards is in use. And this feature is not supported by + // onion servicees in C-Tor, so we're good there. + + /* Update the absolute sequence number on this leg by the delta. + * Since this cell is not multiplexed, we do not count it towards + * absolute sequence numbers. We only increment the sequence + * numbers for multiplexed cells. Hence there is no +1 here. */ + leg->last_seq_recv += relative_seq; + + /* Mark this data as validated for controlport and vanguards + * dropped cell handling */ + if (CIRCUIT_IS_ORIGIN(in_circ)) { + circuit_read_valid_data(TO_ORIGIN_CIRCUIT(in_circ), msg->length); + } + + return 0; +} + +/** + * Return the total number of required allocated to store `msg`. + */ +static inline size_t +conflux_msg_alloc_cost(conflux_msg_t *msg) +{ + return msg->msg->length + sizeof(conflux_msg_t) + sizeof(relay_msg_t); +} + +/** + * Process an incoming relay cell for conflux. Called from + * connection_edge_process_relay_cell(). + * + * Returns true if the conflux system now has well-ordered cells to deliver + * to streams, false otherwise. + */ +bool +conflux_process_relay_msg(conflux_t *cfx, circuit_t *in_circ, + crypt_path_t *layer_hint, const relay_msg_t *msg) +{ + // TODO-329-TUNING: Temporarily validate legs here. We can remove + // this after tuning is complete. + conflux_validate_legs(cfx); + + conflux_leg_t *leg = conflux_get_leg(cfx, in_circ); + if (!leg) { + log_warn(LD_BUG, "Got a conflux cell on a circuit without " + "conflux leg. Closing circuit."); + circuit_mark_for_close(in_circ, END_CIRC_REASON_INTERNAL); + return false; + } + + /* We need to make sure this cell came from the expected hop, or + * else it could be a data corruption attack from a middle node. */ + if (!conflux_validate_source_hop(in_circ, layer_hint)) { + circuit_mark_for_close(in_circ, END_CIRC_REASON_TORPROTOCOL); + return false; + } + + /* Update the running absolute sequence number */ + leg->last_seq_recv++; + + /* If this cell is next, fast-path it by processing the cell in-place */ + if (leg->last_seq_recv == cfx->last_seq_delivered + 1) { + /* The cell is now ready to be processed, and rest of the queue should + * now be checked for remaining elements */ + cfx->last_seq_delivered++; + return true; + } else if (leg->last_seq_recv <= cfx->last_seq_delivered) { + /* Anyone can mangle these sequence number. */ + log_fn(LOG_PROTOCOL_WARN, LD_BUG, + "Got a conflux cell with a sequence number " + "less than the last delivered. Closing circuit."); + circuit_mark_for_close(in_circ, END_CIRC_REASON_INTERNAL); + return false; + } else { + /* Both cost and param are in bytes. */ + if (cfx->ooo_q_alloc_cost >= conflux_params_get_max_oooq()) { + /* Log rate limit every hour. In heavy DDoS scenario, this could be + * triggered many times so avoid the spam. */ + static ratelim_t rlimit = RATELIM_INIT(60 * 60); + log_fn_ratelim(&rlimit, LOG_WARN, LD_CIRC, + "Conflux OOO queue is at maximum. Currently at " + "%"TOR_PRIuSZ " bytes, maximum allowed is %u bytes. " + "Closing.", + cfx->ooo_q_alloc_cost, conflux_params_get_max_oooq()); + circuit_mark_for_close(in_circ, END_CIRC_REASON_RESOURCELIMIT); + return false; + } + conflux_msg_t *c_msg = tor_malloc_zero(sizeof(conflux_msg_t)); + c_msg->seq = leg->last_seq_recv; + /* Notice the copy here. Reason is that we don't have ownership of the + * message. If we wanted to pull that off, we would need to change the + * whole calling stack and unit tests on either not touching it after this + * function indicates that it has taken it or never allocate it from the + * stack. This is simpler and less error prone but might show up in our + * profile (maybe?). The Maze is serious. It needs to be respected. */ + c_msg->msg = relay_msg_copy(msg); + size_t cost = conflux_msg_alloc_cost(c_msg); + + smartlist_pqueue_add(cfx->ooo_q, conflux_queue_cmp, + offsetof(conflux_msg_t, heap_idx), c_msg); + + total_ooo_q_bytes += cost; + cfx->ooo_q_alloc_cost += cost; + + /* This cell should not be processed yet, and the queue is not ready + * to process because the next absolute seqnum has not yet arrived */ + return false; + } +} + +/** + * Dequeue the top cell from our queue. + * + * Returns the cell as a conflux_cell_t, or NULL if the queue is empty + * or has a hole. + */ +conflux_msg_t * +conflux_dequeue_relay_msg(circuit_t *circ) +{ + conflux_msg_t *top = NULL; + /* Related to #41162. This is really a consequence of the C-tor maze. + * The function above can close a circuit without returning an error + * due to several return code ignored. Auditting all of the cell code + * path and fixing them to not ignore errors could bring many more + * issues as this behavior has been in tor forever. So do the bandaid + * fix of bailing if the circuit is closed. */ + if (circ->marked_for_close) { + static ratelim_t rlim = RATELIM_INIT(60 * 60); + log_fn_ratelim(&rlim, (circ->conflux == NULL) ? LOG_WARN : LOG_NOTICE, + LD_CIRC, + "Circuit was closed at %s:%u when dequeuing from OOO", + circ->marked_for_close_file, circ->marked_for_close); + return NULL; + } + conflux_t *cfx = circ->conflux; + if (cfx == NULL) { + static ratelim_t rlim = RATELIM_INIT(60 * 60); + log_fn_ratelim(&rlim, LOG_WARN, LD_CIRC, + "Bug: Non marked for close circuit with NULL conflux"); + return NULL; + } + if (cfx->ooo_q == NULL) { + static ratelim_t rlim = RATELIM_INIT(60 * 60); + log_fn_ratelim(&rlim, LOG_WARN, LD_CIRC, + "Bug: Non marked for close circuit with NULL OOO queue"); + return NULL; + } + + if (smartlist_len(cfx->ooo_q) == 0) + return NULL; + + top = smartlist_get(cfx->ooo_q, 0); + + /* If the top cell is the next sequence number we need, then + * pop and return it. */ + if (top->seq == cfx->last_seq_delivered+1) { + smartlist_pqueue_pop(cfx->ooo_q, conflux_queue_cmp, + offsetof(conflux_msg_t, heap_idx)); + + size_t cost = conflux_msg_alloc_cost(top); + total_ooo_q_bytes -= cost; + cfx->ooo_q_alloc_cost -= cost; + + cfx->last_seq_delivered++; + return top; + } else { + return NULL; + } +} + +/** Free a given conflux msg object. */ +void +conflux_relay_msg_free_(conflux_msg_t *msg) +{ + if (msg) { + relay_msg_free(msg->msg); + tor_free(msg); + } +} diff -Nru tor-0.4.7.16/src/core/or/conflux.h tor-0.4.9.6/src/core/or/conflux.h --- tor-0.4.7.16/src/core/or/conflux.h 1970-01-01 00:00:00.000000000 +0000 +++ tor-0.4.9.6/src/core/or/conflux.h 2026-03-25 14:30:34.000000000 +0000 @@ -0,0 +1,87 @@ +/* Copyright (c) 2019-2021, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file conflux.h + * \brief Public APIs for conflux multipath support + **/ + +#ifndef TOR_CONFLUX_H +#define TOR_CONFLUX_H + +#include "core/or/circuit_st.h" +#include "core/or/conflux_st.h" +#include "core/or/relay_msg_st.h" + +typedef struct conflux_t conflux_t; +typedef struct conflux_leg_t conflux_leg_t; + +/** Helpers to iterate over legs with better semantic. */ +#define CONFLUX_FOR_EACH_LEG_BEGIN(cfx, var) \ + SMARTLIST_FOREACH_BEGIN(cfx->legs, conflux_leg_t *, var) +#define CONFLUX_FOR_EACH_LEG_END(var) \ + SMARTLIST_FOREACH_END(var) + +/** Helper: Return the number of legs a conflux object has. */ +#define CONFLUX_NUM_LEGS(cfx) (smartlist_len(cfx->legs)) + +/** A relay message for the out-of-order queue. */ +typedef struct { + /** + * Absolute sequence number of this cell, computed from the + * relative sequence number of the conflux cell. */ + uint64_t seq; + + /** + * Heap index of this cell, for use in in the conflux_t ooo_q heap. + */ + int heap_idx; + + /** The relay message here is always guaranteed to have removed its + * extra conflux sequence number, for ease of processing */ + relay_msg_t *msg; +} conflux_msg_t; + +size_t conflux_handle_oom(size_t bytes_to_remove); +uint64_t conflux_get_total_bytes_allocation(void); +uint64_t conflux_get_circ_bytes_allocation(const circuit_t *circ); + +void conflux_update_rtt(conflux_t *cfx, circuit_t *circ, uint64_t rtt_usec); + +circuit_t *conflux_decide_circ_for_send(conflux_t *cfx, + circuit_t *orig_circ, + uint8_t relay_command); +circuit_t *conflux_decide_next_circ(conflux_t *cfx); + +int conflux_process_switch_command(circuit_t *in_circ, + crypt_path_t *layer_hint, + const relay_msg_t *msg); +bool conflux_should_multiplex(int relay_command); +bool conflux_process_relay_msg(conflux_t *cfx, circuit_t *in_circ, + crypt_path_t *layer_hint, + const relay_msg_t *msg); +conflux_msg_t *conflux_dequeue_relay_msg(circuit_t *circ); +void conflux_note_cell_sent(conflux_t *cfx, circuit_t *circ, + uint8_t relay_command); +void conflux_relay_msg_free_(conflux_msg_t *msg); +#define conflux_relay_msg_free(msg) \ + FREE_AND_NULL(conflux_msg_t, conflux_relay_msg_free_, (msg)) + +/* Private section starts. */ +#ifdef TOR_CONFLUX_PRIVATE + +const struct congestion_control_t *circuit_ccontrol(const circuit_t *); +conflux_leg_t *conflux_get_leg(conflux_t *cfx, const circuit_t *circ); +uint64_t conflux_get_max_seq_recv(const conflux_t *cfx); +uint64_t conflux_get_max_seq_sent(const conflux_t *cfx); + +/* + * Unit tests declaractions. + */ +#ifdef TOR_UNIT_TESTS + +#endif /* defined(TOR_UNIT_TESTS) */ + +#endif /* defined(TOR_CONFLUX_PRIVATE) */ + +#endif /* !defined(TOR_CONFLUX_H) */ diff -Nru tor-0.4.7.16/src/core/or/conflux_cell.c tor-0.4.9.6/src/core/or/conflux_cell.c --- tor-0.4.7.16/src/core/or/conflux_cell.c 1970-01-01 00:00:00.000000000 +0000 +++ tor-0.4.9.6/src/core/or/conflux_cell.c 2026-03-25 14:30:34.000000000 +0000 @@ -0,0 +1,358 @@ +/* Copyright (c) 2023, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file conflux_cell.c + * \brief XXX: Write a brief introduction to this module. + **/ + +#define CONFLUX_CELL_PRIVATE + +#include "app/config/config.h" + +#include "core/or/conflux.h" +#include "core/or/conflux_cell.h" +#include "core/or/relay.h" +#include "core/or/circuitlist.h" + +#include "lib/crypt_ops/crypto_rand.h" + +#include "trunnel/conflux.h" + +#include "core/or/crypt_path_st.h" +#include "core/or/or_circuit_st.h" +#include "core/or/origin_circuit_st.h" + +STATIC ssize_t +build_link_cell(const conflux_cell_link_t *link, uint8_t *cell_out) +{ + ssize_t cell_len = -1; + trn_cell_conflux_link_t *cell = NULL; + trn_cell_conflux_link_payload_v1_t *payload = NULL; + + tor_assert(cell_out); + + cell = trn_cell_conflux_link_new(); + trn_cell_conflux_link_set_version(cell, 0x01); + + payload = trn_cell_conflux_link_payload_v1_new(); + + /* Set the nonce. */ + size_t nonce_len = trn_cell_conflux_link_payload_v1_getlen_nonce(payload); + tor_assert(nonce_len == sizeof(link->nonce)); + memcpy(trn_cell_conflux_link_payload_v1_getarray_nonce(payload), + link->nonce, nonce_len); + + /* Set the sequence number. */ + trn_cell_conflux_link_payload_v1_set_last_seqno_recv(payload, + link->last_seqno_recv); + trn_cell_conflux_link_payload_v1_set_last_seqno_sent(payload, + link->last_seqno_sent); + + /* Set the algorithm */ + trn_cell_conflux_link_payload_v1_set_desired_ux(payload, link->desired_ux); + + /* Encode payload. */ + ssize_t pay_len = trn_cell_conflux_link_payload_v1_encoded_len(payload); + tor_assert(pay_len >= 0); + + trn_cell_conflux_link_setlen_payload(cell, pay_len); + + trn_cell_conflux_link_payload_v1_encode( + trn_cell_conflux_link_getarray_payload(cell), + trn_cell_conflux_link_getlen_payload(cell), payload); + + /* Encode cell. */ + cell_len = trn_cell_conflux_link_encode(cell_out, + RELAY_PAYLOAD_SIZE_MAX, cell); + + trn_cell_conflux_link_payload_v1_free(payload); + trn_cell_conflux_link_free(cell); + return cell_len; +} + +static ssize_t +build_linked_cell(const conflux_cell_link_t *link, uint8_t *cell_out) +{ + /* Same payload. This might not be true in the future but for now, we don't + * need to duplicate the code as it is really the same. */ + return build_link_cell(link, cell_out); +} + +static ssize_t +build_linked_ack_cell(uint8_t *cell_out) +{ + ssize_t cell_len = -1; + trn_cell_conflux_linked_ack_t *cell = NULL; + + tor_assert(cell_out); + + cell = trn_cell_conflux_linked_ack_new(); + cell_len = trn_cell_conflux_linked_ack_encode(cell_out, + RELAY_PAYLOAD_SIZE_MAX, + cell); + + trn_cell_conflux_linked_ack_free(cell); + return cell_len; +} + +bool +conflux_cell_send_link(const conflux_cell_link_t *link, origin_circuit_t *circ) +{ + uint8_t payload[RELAY_PAYLOAD_SIZE_MAX] = {0}; + ssize_t cell_len; + + tor_assert(link); + tor_assert(circ); + + log_info(LD_CIRC, "Sending CONFLUX_LINK cell onto origin circuit"); + + /* Build the CONFLUX_LINK cell. */ + cell_len = build_link_cell(link, payload); + if (BUG(cell_len < 0)) { + log_info(LD_CIRC, "Unable to build CONFLUX_LINK cell."); + circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_INTERNAL); + goto err; + } + + /* Send the cell to the endpoint of the circuit. */ + if (relay_send_command_from_edge(CONTROL_CELL_ID, TO_CIRCUIT(circ), + RELAY_COMMAND_CONFLUX_LINK, + (char *) payload, cell_len, + circ->cpath->prev) < 0) { + log_info(LD_CIRC, "Unable to send CONFLUX_LINK cell."); + goto err; + } + + return true; + + err: + return false; +} + +bool +conflux_cell_send_linked(const conflux_cell_link_t *link, or_circuit_t *circ) +{ + uint8_t payload[RELAY_PAYLOAD_SIZE_MAX] = {0}; + ssize_t cell_len; + + tor_assert(link); + tor_assert(circ); + + log_info(LD_CIRC, "Sending CONFLUX_LINKED cell onto OR circuit"); + + /* Build the CONFLUX_LINK cell. */ + cell_len = build_linked_cell(link, payload); + if (BUG(cell_len < 0)) { + log_info(LD_CIRC, "Unable to build CONFLUX_LINKED cell."); + circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_INTERNAL); + goto err; + } + + /* Send back the LINKED cell. */ + if (relay_send_command_from_edge(CONTROL_CELL_ID, TO_CIRCUIT(circ), + RELAY_COMMAND_CONFLUX_LINKED, + (char *) payload, cell_len, NULL) < 0) { + log_info(LD_CIRC, "Unable to send CONFLUX_LINKED cell."); + goto err; + } + + return true; + + err: + return false; +} + +bool +conflux_cell_send_linked_ack(origin_circuit_t *circ) +{ + uint8_t payload[RELAY_PAYLOAD_SIZE_MAX] = {0}; + ssize_t cell_len; + + tor_assert(circ); + + log_info(LD_CIRC, "Sending CONFLUX_LINKED_ACK cell onto origin circuit"); + + /* Build the CONFLUX_LINKED_ACK cell. */ + cell_len = build_linked_ack_cell(payload); + if (BUG(cell_len < 0)) { + log_info(LD_CIRC, "Unable to build CONFLUX_LINKED_ACK cell."); + circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_INTERNAL); + goto err; + } + + /* Send the cell to the endpoint of the circuit. */ + if (relay_send_command_from_edge(CONTROL_CELL_ID, TO_CIRCUIT(circ), + RELAY_COMMAND_CONFLUX_LINKED_ACK, + (char *) payload, cell_len, + circ->cpath->prev) < 0) { + log_info(LD_CIRC, "Unable to send CONFLUX_LINKED_ACK cell."); + goto err; + } + + return true; + + err: + return false; +} + +static conflux_cell_link_t * +conflux_cell_parse_link_v1(const trn_cell_conflux_link_t *trn_link) +{ + conflux_cell_link_t *link = NULL; + trn_cell_conflux_link_payload_v1_t *payload = NULL; + + if (trn_cell_conflux_link_payload_v1_parse(&payload, + trn_cell_conflux_link_getconstarray_payload(trn_link), + trn_cell_conflux_link_getlen_payload(trn_link)) < 0) { + log_fn(LOG_PROTOCOL_WARN, LD_CIRC, + "Unable to parse CONFLUX_LINK v1 payload."); + goto end; + } + + link = tor_malloc_zero(sizeof(*link)); + link->version = trn_cell_conflux_link_get_version(trn_link); + link->desired_ux = + trn_cell_conflux_link_payload_v1_get_desired_ux(payload); + link->last_seqno_recv = + trn_cell_conflux_link_payload_v1_get_last_seqno_recv(payload); + link->last_seqno_sent = + trn_cell_conflux_link_payload_v1_get_last_seqno_sent(payload); + memcpy(link->nonce, + trn_cell_conflux_link_payload_v1_getconstarray_nonce(payload), + trn_cell_conflux_link_payload_v1_getlen_nonce(payload)); + + end: + trn_cell_conflux_link_payload_v1_free(payload); + return link; +} + +conflux_cell_link_t * +conflux_cell_parse_link(const relay_msg_t *msg) +{ + conflux_cell_link_t *link = NULL; + trn_cell_conflux_link_t *trn_cell = NULL; + + tor_assert(msg); + + if (trn_cell_conflux_link_parse(&trn_cell, msg->body, msg->length) < 0) { + log_fn(LOG_PROTOCOL_WARN, LD_CIRC, + "Unable to parse CONFLUX_LINK cell."); + goto end; + } + + uint8_t version = trn_cell_conflux_link_get_version(trn_cell); + switch (version) { + case 0x01: + link = conflux_cell_parse_link_v1(trn_cell); + break; + default: + log_fn(LOG_PROTOCOL_WARN, LD_CIRC, + "Unsupported version %d in CONFLUX_LINK cell", version); + goto end; + } + + end: + trn_cell_conflux_link_free(trn_cell); + return link; +} + +conflux_cell_link_t * +conflux_cell_parse_linked(const relay_msg_t *msg) +{ + /* At the moment, same exact payload so avoid code duplication. */ + return conflux_cell_parse_link(msg); +} + +conflux_cell_link_t * +conflux_cell_new_link(const uint8_t *nonce, uint64_t last_seqno_sent, + uint64_t last_seqno_recv, uint8_t ux) +{ + conflux_cell_link_t *link = tor_malloc_zero(sizeof(*link)); + + link->version = 0x01; + link->desired_ux = ux; + + link->last_seqno_sent = last_seqno_sent; + link->last_seqno_recv = last_seqno_recv; + memcpy(link->nonce, nonce, sizeof(link->nonce)); + + return link; +} + +/** + * Extracts the sequence number from a switch cell. + */ +uint32_t +conflux_cell_parse_switch(const relay_msg_t *msg) +{ + uint32_t seq = 0; + trn_cell_conflux_switch_t *switch_cell = NULL; + + tor_assert(msg); + + if (trn_cell_conflux_switch_parse(&switch_cell, + msg->body, msg->length) < 0) { + log_warn(LD_BUG, "Failed to parse switch cell"); + // Zero counts as a failure to the validation, since legs should + // not switch after 0 cells. + return 0; + } + + seq = trn_cell_conflux_switch_get_seqnum(switch_cell); + + trn_cell_conflux_switch_free(switch_cell); + + return seq; +} + +/** Send a RELAY_COMMAND_CONFLUX_SWITCH cell on the circuit. */ +bool +conflux_send_switch_command(circuit_t *send_circ, uint64_t relative_seq) +{ + trn_cell_conflux_switch_t *switch_cell = trn_cell_conflux_switch_new(); + uint8_t payload[RELAY_PAYLOAD_SIZE_MAX] = {0}; + bool ret = true; + + tor_assert(send_circ); + + /* This is possible unfortunately because the sequence numbers are 64 bit + * while in the SWITCH it is 32 bit. It would require more than 2.2 TB of + * data to be transfered on a circuit to reach this. Worth avoiding. */ + if (relative_seq >= UINT32_MAX) { + /* Avoid spamming logs with this, every hours should be fine. */ + static ratelim_t rlimit = RATELIM_INIT(60 * 60); + log_fn_ratelim(&rlimit, LOG_WARN, LD_CIRC, + "Relative sequence number is too high. Closing circuit."); + ret = false; + goto end; + } + + trn_cell_conflux_switch_set_seqnum(switch_cell, (uint32_t)relative_seq); + + ssize_t len = trn_cell_conflux_switch_encode( + payload, RELAY_PAYLOAD_SIZE_MAX, + switch_cell); + if (len < 0) { + log_warn(LD_BUG, "Failed to encode conflux switch cell"); + ret = false; + goto end; + } + + /* Send the switch command to the new hop */ + if (CIRCUIT_IS_ORIGIN(send_circ)) { + relay_send_command_from_edge(0, send_circ, + RELAY_COMMAND_CONFLUX_SWITCH, + (const char*)payload, len, + TO_ORIGIN_CIRCUIT(send_circ)->cpath->prev); + } else { + relay_send_command_from_edge(0, send_circ, + RELAY_COMMAND_CONFLUX_SWITCH, + (const char*)payload, len, + NULL); + } + +end: + trn_cell_conflux_switch_free(switch_cell); + return ret; +} diff -Nru tor-0.4.7.16/src/core/or/conflux_cell.h tor-0.4.9.6/src/core/or/conflux_cell.h --- tor-0.4.7.16/src/core/or/conflux_cell.h 1970-01-01 00:00:00.000000000 +0000 +++ tor-0.4.9.6/src/core/or/conflux_cell.h 2026-03-25 14:30:34.000000000 +0000 @@ -0,0 +1,48 @@ +/* Copyright (c) 2023, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file conflux_cell.h + * \brief Header file for conflux_cell.c. + **/ + +#ifndef TOR_CONFLUX_CELL_H +#define TOR_CONFLUX_CELL_H + +#include "core/or/or.h" +#include "core/or/relay_msg_st.h" + +typedef struct conflux_cell_link_t { + uint8_t version; + uint8_t desired_ux; + uint8_t nonce[DIGEST256_LEN]; + + uint64_t last_seqno_sent; + uint64_t last_seqno_recv; +} conflux_cell_link_t; + +conflux_cell_link_t *conflux_cell_new_link(const uint8_t *nonce, + uint64_t last_sent, + uint64_t last_recv, + uint8_t ux); + +conflux_cell_link_t *conflux_cell_parse_link(const relay_msg_t *msg); +conflux_cell_link_t *conflux_cell_parse_linked(const relay_msg_t *msg); +uint32_t conflux_cell_parse_switch(const relay_msg_t *msg); + +bool conflux_cell_send_link(const conflux_cell_link_t *link, + origin_circuit_t *circ); +bool conflux_cell_send_linked(const conflux_cell_link_t *link, + or_circuit_t *circ); +bool conflux_cell_send_linked_ack(origin_circuit_t *circ); +bool conflux_send_switch_command(circuit_t *send_circ, uint64_t relative_seq); + +#ifdef TOR_UNIT_TESTS + +STATIC ssize_t +build_link_cell(const conflux_cell_link_t *link, uint8_t *cell_out); + +#endif /* TOR_UNIT_TESTS */ + +#endif /* TOR_CONFLUX_CELL_H */ + diff -Nru tor-0.4.7.16/src/core/or/conflux_params.c tor-0.4.9.6/src/core/or/conflux_params.c --- tor-0.4.7.16/src/core/or/conflux_params.c 1970-01-01 00:00:00.000000000 +0000 +++ tor-0.4.9.6/src/core/or/conflux_params.c 2026-03-25 14:30:34.000000000 +0000 @@ -0,0 +1,330 @@ +/* Copyright (c) 2023, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file conflux_params.h + * \brief Header file for conflux_params.c. + **/ + +#include "core/or/or.h" + +#include "app/config/config.h" + +#include "core/or/conflux_params.h" +#include "core/or/congestion_control_common.h" +#include "core/or/circuitlist.h" + +#include "feature/nodelist/networkstatus.h" +#include "feature/nodelist/networkstatus_st.h" +#include "feature/nodelist/routerstatus_st.h" +#include "feature/relay/routermode.h" + +#include "core/or/origin_circuit_st.h" + +/** + * Consensus parameters defaults, minimums and maximums. + */ + +/* For "cfx_enabled". */ +#define CONFLUX_ENABLED_MIN (0) +#define CONFLUX_ENABLED_MAX (1) +#define CONFLUX_ENABLED_DEFAULT (1) + +/* For "cfx_low_exit_threshold". This is a percentage scaled to 10000 so we can + * support two decimal points. For example, 65.78% would be 6578. */ +#define LOW_EXIT_THRESHOLD_MIN (0) +#define LOW_EXIT_THRESHOLD_MAX (10000) +#define LOW_EXIT_THRESHOLD_DEFAULT (6000) + +/* For "cfx_max_linked_set". */ +#define MAX_LINKED_SET_MIN (0) +#define MAX_LINKED_SET_MAX (UINT8_MAX) +#define MAX_LINKED_SET_DEFAULT (10) + +/* For "cfx_max_prebuilt_set". */ +#define MAX_PREBUILT_SET_MIN (0) +#define MAX_PREBUILT_SET_MAX (UINT8_MAX) +#define MAX_PREBUILT_SET_DEFAULT (3) + +/* For "cfx_max_leg_retry". */ +#define MAX_UNLINKED_LEG_RETRY_DEFAULT (3) +#define MAX_UNLINKED_LEG_RETRY_MIN (0) +#define MAX_UNLINKED_LEG_RETRY_MAX (UINT8_MAX) + +/* For "cfx_num_legs_set". */ +#define NUM_LEGS_SET_MIN (0) +#define NUM_LEGS_SET_MAX (UINT8_MAX) +#define NUM_LEGS_SET_DEFAULT (2) + +/* For "cfx_max_legs_set" */ +#define MAX_LEGS_SET_MIN (3) +#define MAX_LEGS_SET_MAX (UINT8_MAX) +#define MAX_LEGS_SET_DEFAULT (8) + +/* For "cfx_send_pct". */ +#define CFX_SEND_PCT_MIN (0) +#define CFX_SEND_PCT_MAX (255) +#define CFX_SEND_PCT_DFLT 100 + +/* For "cfx_drain_pct". */ +#define CFX_DRAIN_PCT_MIN (0) +#define CFX_DRAIN_PCT_MAX (255) +#define CFX_DRAIN_PCT_DFLT 0 + +/* For "max_ooo_queue_bytes". */ +#define MAX_OOO_QUEUE_BYTES_MIN (0) +#define MAX_OOO_QUEUE_BYTES_MAX (INT32_MAX) +#define MAX_OOO_QUEUE_BYTES_DEFAULT MAX_OOO_QUEUE_BYTES_MAX + +/* + * Cached consensus parameters. + */ + +/* Indicate if conflux is enabled or disabled. */ +static bool conflux_enabled = CONFLUX_ENABLED_DEFAULT; +/* Maximum number of linked set we are allowed to have (even if in use). */ +static uint8_t max_linked_set = MAX_LINKED_SET_DEFAULT; +/* Maximum number of pre built set. */ +static uint8_t max_prebuilt_set = MAX_PREBUILT_SET_DEFAULT; +/* Maximum number of unlinked leg retry that is how many times are we allowed + * to retry a leg until it successfully links. */ +STATIC uint32_t max_unlinked_leg_retry = MAX_UNLINKED_LEG_RETRY_DEFAULT; +/* Number of legs per set. */ +static uint8_t num_legs_set = NUM_LEGS_SET_DEFAULT; +/* Maximum number of legs per set allowed at exits */ +static uint8_t max_legs_set = MAX_LEGS_SET_DEFAULT; +/* The low Exit relay threshold, as a ratio between 0 and 1, used as a limit to + * decide the amount of pre-built set we build depending on how many Exit relay + * supports conflux in our current consensus. */ +static double low_exit_threshold_ratio = + LOW_EXIT_THRESHOLD_DEFAULT / (double)LOW_EXIT_THRESHOLD_MAX; + +static uint8_t cfx_drain_pct = CFX_DRAIN_PCT_DFLT; +static uint8_t cfx_send_pct = CFX_SEND_PCT_DFLT; + +/* The maximum number of bytes allowed in a single OOO queue. Above this value, + * the conflux set is closed. */ +static uint32_t max_ooo_queue_bytes = MAX_OOO_QUEUE_BYTES_DEFAULT; + +/* Ratio of Exit relays in our consensus supporting conflux. This is computed + * at every consensus and it is between 0 and 1. */ +static double exit_conflux_ratio = 0.0; + +/** Sets num_conflux_exit with the latest count of Exits in the given consensus + * that supports Conflux. */ +static void +count_exit_with_conflux_support(const networkstatus_t *ns) +{ + double supported = 0.0; + int total_exits = 0; + + if (!ns || smartlist_len(ns->routerstatus_list) == 0) { + return; + } + + SMARTLIST_FOREACH_BEGIN(ns->routerstatus_list, const routerstatus_t *, rs) { + if (!rs->is_exit || rs->is_bad_exit) { + continue; + } + if (rs->pv.supports_conflux) { + supported++; + } + total_exits++; + } SMARTLIST_FOREACH_END(rs); + + if (total_exits > 0) { + exit_conflux_ratio = + supported / total_exits; + } else { + exit_conflux_ratio = 0.0; + } + + log_info(LD_GENERAL, "Consensus has %.2f %% Exit relays supporting Conflux", + exit_conflux_ratio * 100.0); +} + +/** + * Return true iff conflux feature is enabled and usable for a given circuit. + * + * Circ may be NULL, in which case we only check the consensus and torrc. */ +bool +conflux_is_enabled(const circuit_t *circ) +{ + const or_options_t *opts = get_options(); + + /* Conflux CAN NOT operate properly without congestion control and so + * automatically disabled conflux if we don't have CC enabled. */ + if (!congestion_control_enabled()) { + return false; + } + + if (circ) { + /* If circuit is non-null, we need to check to see if congestion + * control was successfully negotiated. Conflux depends upon congestion + * control, and consensus checks are not enough because there can be a + * race between those checks and the consensus update to enable + * congestion control. This happens in Shadow, and at relay restart. */ + if (CIRCUIT_IS_ORIGIN(circ)) { + tor_assert(CONST_TO_ORIGIN_CIRCUIT(circ)->cpath); + tor_assert(CONST_TO_ORIGIN_CIRCUIT(circ)->cpath->prev); + if (!CONST_TO_ORIGIN_CIRCUIT(circ)->cpath->prev->ccontrol) + return false; + } else { + if (!circ->ccontrol) + return false; + } + } + + /* For clients, this is mostly for sbws. For relays, this is an emergency + * emergency override, in case a bug is discovered by a relay operator + * and we can't set a consensus param fast enough. Basically gives them + * an option other than downgrading. */ + if (opts->ConfluxEnabled != -1) { + if (server_mode(opts)) { + char *msg; + static ratelim_t rlimit = RATELIM_INIT(60 * 60); /* Hourly */ + if ((msg = rate_limit_log(&rlimit, time(NULL)))) { + log_warn(LD_GENERAL, + "This tor is a relay and ConfluxEnabled is set to 0. " + "We would ask you to please write to us on " + "tor-relays@lists.torproject.org or file a bug explaining " + "why you have disabled this option. Without news from you, " + "we might end up marking your relay as a BadExit."); + tor_free(msg); + } + } + return opts->ConfluxEnabled; + } + + return conflux_enabled; +} + +/** Return the maximum number of linked set we are allowed to have. */ +uint8_t +conflux_params_get_max_linked_set(void) +{ + return max_linked_set; +} + +/** Return the number of maximum pre built sets that is allowed to have. */ +uint8_t +conflux_params_get_max_prebuilt(void) +{ + /* Without any Exit supporting conflux, we won't be able to build a set. The + * float problem here is minimal because exit_conflux_ratio is either a flat + * 0 or else it means we do have at least an exit. */ + if (exit_conflux_ratio <= 0.0) { + return 0; + } + + /* Allow only 1 pre built set if we are lower than the low exit threshold + * parameter from the consensus. */ + if (exit_conflux_ratio < low_exit_threshold_ratio) { + return 1; + } + return max_prebuilt_set; +} + +/** Return the maximum number of retry we can do until a leg links. */ +uint8_t +conflux_params_get_max_unlinked_leg_retry(void) +{ + return max_unlinked_leg_retry; +} + +/** Return the number of legs per set. */ +uint8_t +conflux_params_get_num_legs_set(void) +{ + return num_legs_set; +} + +/** Return the maximum number of legs per set. */ +uint8_t +conflux_params_get_max_legs_set(void) +{ + return max_legs_set; +} + +/** Return the drain percent we must hit before switching */ +uint8_t +conflux_params_get_drain_pct(void) +{ + return cfx_drain_pct; +} + +/** Return the percent of the congestion window to send before switching. */ +uint8_t +conflux_params_get_send_pct(void) +{ + return cfx_send_pct; +} + +/** Return maximum allowed bytes in a single OOO queue. */ +uint32_t +conflux_params_get_max_oooq(void) +{ + return max_ooo_queue_bytes; +} + +/** Update global conflux related consensus parameter values, every consensus + * update. */ +void +conflux_params_new_consensus(const networkstatus_t *ns) +{ + /* Params used by conflux_pool.c */ + conflux_enabled = + networkstatus_get_param(ns, "cfx_enabled", + CONFLUX_ENABLED_DEFAULT, + CONFLUX_ENABLED_MIN, CONFLUX_ENABLED_MAX); + + low_exit_threshold_ratio = + networkstatus_get_param(ns, "cfx_low_exit_threshold", + LOW_EXIT_THRESHOLD_DEFAULT, + LOW_EXIT_THRESHOLD_MIN, LOW_EXIT_THRESHOLD_MAX) / + (double)LOW_EXIT_THRESHOLD_MAX; + + max_linked_set = + networkstatus_get_param(ns, "cfx_max_linked_set", + MAX_LINKED_SET_DEFAULT, + MAX_LINKED_SET_MIN, MAX_LINKED_SET_MAX); + + max_prebuilt_set = + networkstatus_get_param(ns, "cfx_max_prebuilt_set", + MAX_PREBUILT_SET_DEFAULT, + MAX_PREBUILT_SET_MIN, MAX_PREBUILT_SET_MAX); + + max_unlinked_leg_retry = + networkstatus_get_param(ns, "cfx_max_unlinked_leg_retry", + MAX_UNLINKED_LEG_RETRY_DEFAULT, + MAX_UNLINKED_LEG_RETRY_MIN, + MAX_UNLINKED_LEG_RETRY_MAX); + + num_legs_set = + networkstatus_get_param(ns, "cfx_num_legs_set", + NUM_LEGS_SET_DEFAULT, + NUM_LEGS_SET_MIN, NUM_LEGS_SET_MAX); + + max_legs_set = + networkstatus_get_param(ns, "cfx_max_legs_set", + MAX_LEGS_SET_DEFAULT, + MAX_LEGS_SET_MIN, MAX_LEGS_SET_MAX); + + /* Params used by conflux.c */ + cfx_send_pct = networkstatus_get_param(ns, "cfx_send_pct", + CFX_SEND_PCT_DFLT, + CFX_SEND_PCT_MIN, + CFX_SEND_PCT_MAX); + + cfx_drain_pct = networkstatus_get_param(ns, "cfx_drain_pct", + CFX_DRAIN_PCT_DFLT, + CFX_DRAIN_PCT_MIN, + CFX_DRAIN_PCT_MAX); + + max_ooo_queue_bytes = networkstatus_get_param(ns, "cfx_max_oooq_bytes", + MAX_OOO_QUEUE_BYTES_DEFAULT, + MAX_OOO_QUEUE_BYTES_MIN, + MAX_OOO_QUEUE_BYTES_MAX); + + count_exit_with_conflux_support(ns); +} diff -Nru tor-0.4.7.16/src/core/or/conflux_params.h tor-0.4.9.6/src/core/or/conflux_params.h --- tor-0.4.7.16/src/core/or/conflux_params.h 1970-01-01 00:00:00.000000000 +0000 +++ tor-0.4.9.6/src/core/or/conflux_params.h 2026-03-25 14:30:34.000000000 +0000 @@ -0,0 +1,31 @@ +/* Copyright (c) 2023, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file conflux_params.h + * \brief Header file for conflux_params.c. + **/ + +#ifndef TOR_CONFLUX_PARAMS_H +#define TOR_CONFLUX_PARAMS_H + +#include "core/or/or.h" + +bool conflux_is_enabled(const struct circuit_t *circ); +uint8_t conflux_params_get_max_linked_set(void); +uint8_t conflux_params_get_max_prebuilt(void); +uint8_t conflux_params_get_max_unlinked_leg_retry(void); +uint8_t conflux_params_get_num_legs_set(void); +uint8_t conflux_params_get_max_legs_set(void); +uint8_t conflux_params_get_drain_pct(void); +uint8_t conflux_params_get_send_pct(void); +uint32_t conflux_params_get_max_oooq(void); + +void conflux_params_new_consensus(const networkstatus_t *ns); + +#ifdef TOR_UNIT_TESTS +extern uint32_t max_unlinked_leg_retry; +#endif + +#endif /* TOR_CONFLUX_PARAMS_H */ + diff -Nru tor-0.4.7.16/src/core/or/conflux_pool.c tor-0.4.9.6/src/core/or/conflux_pool.c --- tor-0.4.7.16/src/core/or/conflux_pool.c 1970-01-01 00:00:00.000000000 +0000 +++ tor-0.4.9.6/src/core/or/conflux_pool.c 2026-03-25 14:30:34.000000000 +0000 @@ -0,0 +1,2215 @@ +/* Copyright (c) 2021, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file conflux_pool.c + * \brief Conflux circuit pool management + */ + +#define TOR_CONFLUX_PRIVATE +#define CONFLUX_CELL_PRIVATE + +#include "core/or/or.h" + +#include "app/config/config.h" + +#include "core/or/circuitbuild.h" +#include "core/or/circuitlist.h" +#include "core/or/circuitstats.h" +#include "core/or/circuituse.h" +#include "core/or/congestion_control_st.h" +#include "core/or/conflux.h" +#include "core/or/conflux_cell.h" +#include "trunnel/conflux.h" +#include "core/or/conflux_params.h" +#include "core/or/conflux_pool.h" +#include "core/or/conflux_util.h" +#include "core/or/relay.h" +#include "core/or/connection_edge.h" +#include "core/or/edge_connection_st.h" + +#include "core/or/crypt_path_st.h" +#include "core/or/or_circuit_st.h" +#include "core/or/origin_circuit_st.h" +#include "core/or/extend_info_st.h" +#include "core/or/conflux_st.h" + +#include "feature/nodelist/nodelist.h" +#include "feature/client/bridges.h" +#include "app/config/config.h" + +#include "lib/crypt_ops/crypto_rand.h" +#include "lib/crypt_ops/crypto_util.h" + +/* Indicate if we are shutting down. This is used so we avoid recovering a + * conflux set on total shutdown. */ +static bool shutting_down = false; + +/** The pool of client-side conflux_t that are built, linked, and ready + * to be used. Indexed by nonce. */ +static digest256map_t *client_linked_pool; + +/** The pool of origin unlinked_circuits_t indexed by nonce. */ +static digest256map_t *client_unlinked_pool; + +/** The pool of relay conflux_t indexed by nonce. We call these "server" + * because they could be onion-service side too (even though we likely will + * only implement onion service conflux in Arti). The code is littered with + * asserts to ensure there are no origin circuits in here for now, too. */ +static digest256map_t *server_linked_pool; + +/** The pool of relay unlinked_circuits_t indexed by nonce. */ +static digest256map_t *server_unlinked_pool; + +/* A leg is essentially a circuit for a conflux set. We use this object for the + * unlinked pool. */ +typedef struct leg_t { + /* The circuit of the leg. */ + circuit_t *circ; + + /* The LINK cell content which is used to put the information back in the + * conflux_t object once all legs have linked and validate the ack. */ + conflux_cell_link_t *link; + + /* Indicate if the leg has received the LINKED or the LINKED_ACK cell + * depending on its side of the circuit. When all legs are linked, we then + * finalize the conflux_t object and move it to the linked pool. */ + bool linked; + + /* What time did we send the LINK/LINKED (depending on which side) so we can + * calculate the RTT. */ + uint64_t link_sent_usec; + + /* The RTT value in usec takend from the LINK <--> LINKED round trip. */ + uint64_t rtt_usec; +} leg_t; + +/* Object used to track unlinked circuits which are kept in the unlinked pool + * until they are linked and moved to the linked pool and global circuit set. + */ +typedef struct unlinked_circuits_t { + /* If true, indicate that this unlinked set is client side as in the legs are + * origin circuits. Else, it is on the exit side and thus or circuits. */ + bool is_client; + + /* If true, indicate if the conflux_t is related to a linked set. */ + bool is_for_linked_set; + + /* Conflux object that will be set in each leg once all linked. */ + conflux_t *cfx; + + /* Legs. */ + smartlist_t *legs; +} unlinked_circuits_t; + +/** Error code used when linking circuits. Based on those, we decide to + * relaunch or not. */ +typedef enum link_circ_err_t { + /* Linking was successful. */ + ERR_LINK_CIRC_OK = 0, + /* The RTT was not acceptable. */ + ERR_LINK_CIRC_BAD_RTT = 1, + /* The leg can't be found. */ + ERR_LINK_CIRC_MISSING_LEG = 2, + /* The set can't be found. */ + ERR_LINK_CIRC_MISSING_SET = 3, + /* Invalid leg as in not pass validation. */ + ERR_LINK_CIRC_INVALID_LEG = 4, +} link_circ_err_t; + +#ifdef TOR_UNIT_TESTS +digest256map_t * +get_unlinked_pool(bool is_client) +{ + return is_client ? client_unlinked_pool : server_unlinked_pool; +} + +digest256map_t * +get_linked_pool(bool is_client) +{ + return is_client ? client_linked_pool : server_linked_pool; +} +#endif + +/* For unit tests only: please treat these exactly as the defines in the + * code. */ +STATIC uint8_t DEFAULT_CLIENT_UX = CONFLUX_UX_HIGH_THROUGHPUT; +STATIC uint8_t DEFAULT_EXIT_UX = CONFLUX_UX_MIN_LATENCY; + +/** Helper: Format at 8 bytes the nonce for logging. */ +static inline const char * +fmt_nonce(const uint8_t *nonce) +{ + return hex_str((char *) nonce, 8); +} + +/** + * Return the conflux algorithm for a desired UX value. + */ +static uint8_t +conflux_choose_algorithm(uint8_t desired_ux) +{ + switch (desired_ux) { + case CONFLUX_UX_NO_OPINION: + return CONFLUX_ALG_LOWRTT; + case CONFLUX_UX_MIN_LATENCY: + return CONFLUX_ALG_MINRTT; + case CONFLUX_UX_HIGH_THROUGHPUT: + return CONFLUX_ALG_LOWRTT; + /* For now, we have no low mem algs, so use minRTT since it should + * switch less and thus use less mem */ + /* TODO-329-TUNING: Pick better algs here*/ + case CONFLUX_UX_LOW_MEM_THROUGHPUT: + case CONFLUX_UX_LOW_MEM_LATENCY: + return CONFLUX_ALG_MINRTT; + default: + /* Trunnel should protect us from this */ + tor_assert_nonfatal_unreached(); + return CONFLUX_ALG_LOWRTT; + } +} + +/** Return a newly allocated conflux_t object. */ +static conflux_t * +conflux_new(void) +{ + conflux_t *cfx = tor_malloc_zero(sizeof(*cfx)); + + cfx->ooo_q = smartlist_new(); + cfx->legs = smartlist_new(); + + return cfx; +} + +static void +conflux_free_(conflux_t *cfx) +{ + if (!cfx) { + return; + } + tor_assert(cfx->legs); + tor_assert(cfx->ooo_q); + + SMARTLIST_FOREACH_BEGIN(cfx->legs, conflux_leg_t *, leg) { + SMARTLIST_DEL_CURRENT(cfx->legs, leg); + tor_free(leg); + } SMARTLIST_FOREACH_END(leg); + smartlist_free(cfx->legs); + + SMARTLIST_FOREACH(cfx->ooo_q, conflux_msg_t *, cell, + conflux_relay_msg_free(cell)); + smartlist_free(cfx->ooo_q); + + memwipe(cfx->nonce, 0, sizeof(cfx->nonce)); + tor_free(cfx); +} + +/** Wrapper for the free function, set the cfx pointer to NULL after free */ +#define conflux_free(cfx) \ + FREE_AND_NULL(conflux_t, conflux_free_, cfx) + +/** Helper: Free function for the digest256map_free(). */ +static inline void +free_conflux_void_(void *ptr) +{ + conflux_t *cfx = (conflux_t *)ptr; + conflux_free(cfx); +} + +/** Return a newly allocated leg object containing the given circuit and link + * pointer (no copy). */ +static leg_t * +leg_new(circuit_t *circ, conflux_cell_link_t *link) +{ + leg_t *leg = tor_malloc_zero(sizeof(*leg)); + leg->circ = circ; + leg->link = link; + return leg; +} + +/** Free the given leg object. Passing NULL is safe. */ +static void +leg_free(leg_t *leg) +{ + if (!leg) { + return; + } + if (leg->circ) { + tor_free(leg->circ->conflux_pending_nonce); + leg->circ->conflux_pending_nonce = NULL; + } + tor_free(leg->link); + tor_free(leg); +} + +/** Return a newly allocated unlinked set object for the given nonce. A new + * conflux object is also created. */ +static unlinked_circuits_t * +unlinked_new(const uint8_t *nonce, bool is_client) +{ + unlinked_circuits_t *unlinked = tor_malloc_zero(sizeof(*unlinked)); + unlinked->cfx = conflux_new(); + unlinked->legs = smartlist_new(); + unlinked->is_client = is_client; + memcpy(unlinked->cfx->nonce, nonce, sizeof(unlinked->cfx->nonce)); + + return unlinked; +} + +/** Free the given unlinked object. */ +static void +unlinked_free(unlinked_circuits_t *unlinked) +{ + if (!unlinked) { + return; + } + tor_assert(unlinked->legs); + + /* This cfx is pointing to a linked set. */ + if (!unlinked->is_for_linked_set) { + conflux_free(unlinked->cfx); + } + SMARTLIST_FOREACH(unlinked->legs, leg_t *, leg, leg_free(leg)); + smartlist_free(unlinked->legs); + tor_free(unlinked); +} + +/** Add the given unlinked object to the unlinked pool. */ +static void +unlinked_pool_add(unlinked_circuits_t *unlinked, bool is_client) +{ + tor_assert(unlinked); + if (is_client) { + digest256map_set(client_unlinked_pool, unlinked->cfx->nonce, unlinked); + } else { + digest256map_set(server_unlinked_pool, unlinked->cfx->nonce, unlinked); + } +} + +/** Delete the given unlinked object from the unlinked pool. */ +static void +unlinked_pool_del(unlinked_circuits_t *unlinked, bool is_client) +{ + tor_assert(unlinked); + + if (is_client) { + digest256map_remove(client_unlinked_pool, unlinked->cfx->nonce); + } else { + digest256map_remove(server_unlinked_pool, unlinked->cfx->nonce); + } +} + +/** Return an unlinked object for the given nonce else NULL. */ +static unlinked_circuits_t * +unlinked_pool_get(const uint8_t *nonce, bool is_client) +{ + tor_assert(nonce); + if (is_client) { + return digest256map_get(client_unlinked_pool, nonce); + } else { + return digest256map_get(server_unlinked_pool, nonce); + } +} + +/** Delete from the pool and free the given unlinked object. */ +static void +unlinked_pool_del_and_free(unlinked_circuits_t *unlinked, bool is_client) +{ + tor_assert(unlinked); + unlinked_pool_del(unlinked, is_client); + unlinked_free(unlinked); +} + +/** Add the given conflux object to the linked conflux set. */ +static void +linked_pool_add(conflux_t *cfx, bool is_client) +{ + tor_assert(cfx); + if (is_client) { + digest256map_set(client_linked_pool, cfx->nonce, cfx); + } else { + digest256map_set(server_linked_pool, cfx->nonce, cfx); + } +} + +/** Delete from the linked conflux set the given nonce. */ +static void +linked_pool_del(const uint8_t *nonce, bool is_client) +{ + tor_assert(nonce); + if (is_client) { + digest256map_remove(client_linked_pool, nonce); + } else { + digest256map_remove(server_linked_pool, nonce); + } +} + +/** Return a conflux_t object for the given nonce from the linked set. */ +static conflux_t * +linked_pool_get(const uint8_t *nonce, bool is_client) +{ + tor_assert(nonce); + if (is_client) { + return digest256map_get(client_linked_pool, nonce); + } else { + return digest256map_get(server_linked_pool, nonce); + } +} + +/** Add the given leg to the given unlinked object. */ +static inline void +unlinked_leg_add(unlinked_circuits_t *unlinked, leg_t *leg) +{ + tor_assert(unlinked); + tor_assert(leg); + + smartlist_add(unlinked->legs, leg); +} + +/** Return an unlinked leg for the given unlinked object and for the given + * circuit. */ +static inline leg_t * +leg_find(const unlinked_circuits_t *unlinked, const circuit_t *circ) +{ + SMARTLIST_FOREACH_BEGIN(unlinked->legs, leg_t *, leg) { + if (leg->circ == circ) { + return leg; + } + } SMARTLIST_FOREACH_END(leg); + return NULL; +} + +/** Return the given circuit leg from its unlinked set (if any). */ +static leg_t * +unlinked_leg_find(const circuit_t *circ, bool is_client) +{ + unlinked_circuits_t *unlinked = + unlinked_pool_get(circ->conflux_pending_nonce, is_client); + if (!unlinked) { + return NULL; + } + return leg_find(unlinked, circ); +} + +static void +unlinked_leg_del_and_free(unlinked_circuits_t *unlinked, + const circuit_t *circ) +{ + tor_assert(circ); + tor_assert(unlinked); + + SMARTLIST_FOREACH_BEGIN(unlinked->legs, leg_t *, leg) { + if (leg->circ == circ) { + SMARTLIST_DEL_CURRENT(unlinked->legs, leg); + leg_free(leg); + break; + } + } SMARTLIST_FOREACH_END(leg); +} + +/** + * Ensure that the given circuit has no attached streams. + * + * This validation function is called at various stages for + * unlinked circuits, to make sure they have no streams. + */ +static void +validate_circ_has_no_streams(circuit_t *circ) +{ + if (CIRCUIT_IS_ORIGIN(circ)) { + origin_circuit_t *ocirc = TO_ORIGIN_CIRCUIT(circ); + if (BUG(ocirc->p_streams)) { + log_warn(LD_BUG, + "Unlinked Conflux circuit %u has attached streams.", + ocirc->global_identifier); + ocirc->p_streams = NULL; + } + if (BUG(ocirc->half_streams)) { + log_warn(LD_BUG, + "Unlinked conflux circ %u has half streams.", + ocirc->global_identifier); + ocirc->half_streams = NULL; + } + } else { + or_circuit_t *orcirc = TO_OR_CIRCUIT(circ); + if (BUG(orcirc->n_streams)) { + log_warn(LD_BUG, + "Unlinked conflux circuit has attached streams."); + orcirc->n_streams = NULL; + } + if (BUG(orcirc->resolving_streams)) { + log_warn(LD_BUG, + "Unlinked conflux circuit has resolving streams."); + orcirc->resolving_streams = NULL; + } + } +} + +/** Return true iff the legs in the given unlinked set are valid and coherent + * to be a linked set. */ +static bool +validate_unlinked_legs(unlinked_circuits_t *unlinked) +{ + bool valid = true; + uint8_t version; + uint8_t *nonce = NULL; + + tor_assert(unlinked); + + SMARTLIST_FOREACH_BEGIN(unlinked->legs, const leg_t *, leg) { + if (!nonce) { + nonce = leg->link->nonce; + version = leg->link->version; + } else { + /* Version and nonce must match in all legs. */ + valid &= (leg->link->version == version && + tor_memeq(leg->link->nonce, nonce, sizeof(leg->link->nonce))); + } + + // If the other ends last sent sequence number is higher than the + // last sequence number we delivered, we have data loss, and cannot link. + if (leg->link->last_seqno_sent > unlinked->cfx->last_seq_delivered) { + log_fn(unlinked->is_client ? LOG_NOTICE : LOG_PROTOCOL_WARN, LD_CIRC, + "Data loss detected while trying to add a conflux leg."); + valid = false; + + // TODO-329-ARTI: Instead of closing the set here, we could + // immediately send a SWITCH cell and re-send the missing data. + // To do this, though, we would need to constantly buffer at least + // a cwnd worth of sent data to retransmit. We're not going to try + // this in C-Tor, but arti could consider it. + } + validate_circ_has_no_streams(leg->circ); + } SMARTLIST_FOREACH_END(leg); + + /* Note that if no legs, it validates. */ + + return valid; +} + +/** Add up a new leg to the given conflux object. */ +static void +cfx_add_leg(conflux_t *cfx, leg_t *leg) +{ + tor_assert(cfx); + tor_assert(leg); + tor_assert(leg->link); + + /* Big trouble if we add a leg to the wrong set. */ + tor_assert(tor_memeq(cfx->nonce, leg->link->nonce, sizeof(cfx->nonce))); + + conflux_leg_t *cleg = tor_malloc_zero(sizeof(*cleg)); + cleg->circ = leg->circ; + // TODO-329-ARTI: Blindly copying the values from the cell. Is this correct? + // I think no... When adding new legs, switching to this leg is + // likely to break, unless the sender tracks what link cell it sent.. + // Is that the best option? Or should we use the max of our legs, here? + // (It seems the other side will have no idea what our current maxes + /// are, so this option seems better right now) + cleg->last_seq_recv = leg->link->last_seqno_sent; + cleg->last_seq_sent = leg->link->last_seqno_recv; + cleg->circ_rtts_usec = leg->rtt_usec; + cleg->linked_sent_usec = leg->link_sent_usec; + + cfx->params.alg = conflux_choose_algorithm(leg->link->desired_ux); + + /* Add leg to given conflux. */ + smartlist_add(cfx->legs, cleg); + + /* Ensure the new circuit has no streams. */ + validate_circ_has_no_streams(leg->circ); + + /* If this is not the first leg, get the first leg, and get + * the reference streams from it. */ + if (CONFLUX_NUM_LEGS(cfx) > 0) { + conflux_leg_t *first_leg = smartlist_get(cfx->legs, 0); + if (CIRCUIT_IS_ORIGIN(first_leg->circ)) { + origin_circuit_t *old_circ = TO_ORIGIN_CIRCUIT(first_leg->circ); + origin_circuit_t *new_circ = TO_ORIGIN_CIRCUIT(leg->circ); + + new_circ->p_streams = old_circ->p_streams; + new_circ->half_streams = old_circ->half_streams; + /* Sync all legs with the new stream(s). */ + conflux_sync_circ_fields(cfx, old_circ); + } else { + or_circuit_t *old_circ = TO_OR_CIRCUIT(first_leg->circ); + or_circuit_t *new_circ = TO_OR_CIRCUIT(leg->circ); + new_circ->n_streams = old_circ->n_streams; + new_circ->resolving_streams = old_circ->resolving_streams; + } + } + + if (CIRCUIT_IS_ORIGIN(cleg->circ)) { + tor_assert_nonfatal(cleg->circ->purpose == + CIRCUIT_PURPOSE_CONFLUX_UNLINKED); + circuit_change_purpose(cleg->circ, CIRCUIT_PURPOSE_CONFLUX_LINKED); + } + conflux_validate_stream_lists(cfx); +} + +/** + * Clean up a circuit from its conflux_t object. + * + * Return true if closing this circuit should tear down the entire set, + * false otherwise. + */ +static bool +cfx_del_leg(conflux_t *cfx, const circuit_t *circ) +{ + conflux_leg_t *leg; + bool full_teardown = false; + + tor_assert(cfx); + tor_assert(circ); + + leg = conflux_get_leg(cfx, circ); + if (!leg) { + goto end; + } + + // If the circuit still has inflight data, teardown + const struct congestion_control_t *cc = circuit_ccontrol(circ); + tor_assert(cc); + tor_assert(cc->sendme_inc); + if (cc->inflight >= cc->sendme_inc) { + full_teardown = true; + log_info(LD_CIRC, "Conflux current circuit has closed with " + "data in flight, tearing down entire set."); + } + + /* Remove it from the cfx. */ + smartlist_remove(cfx->legs, leg); + + /* After removal, if this leg had the highest sent (or recv) + * sequence number, it was in active use by us (or the other side). + * We need to tear down the entire set. */ + // TODO-329-ARTI: If we support resumption, we don't need this. + if (CONFLUX_NUM_LEGS(cfx) > 0) { + if (conflux_get_max_seq_sent(cfx) < leg->last_seq_sent || + conflux_get_max_seq_recv(cfx) < leg->last_seq_recv) { + full_teardown = true; + log_info(LD_CIRC, "Conflux sequence number check failed, " + "tearing down entire set."); + } + } + + /* Cleanup any reference to leg. */ + if (cfx->curr_leg == leg) { + cfx->curr_leg = NULL; + full_teardown = true; + log_info(LD_CIRC, "Conflux current circuit has closed, " + "tearing down entire set."); + } + if (cfx->prev_leg == leg) { + cfx->prev_leg = NULL; + } + + tor_free(leg); + + end: + return full_teardown; +} + +/** Close the circuit of each legs of the given unlinked object. */ +static void +unlinked_close_all_legs(unlinked_circuits_t *unlinked) +{ + smartlist_t *circ_to_close = NULL; + + tor_assert(unlinked); + + /* Small optimization here, avoid this work if no legs. */ + if (smartlist_len(unlinked->legs) == 0) { + return; + } + + /* We will iterate over all legs and put the circuit in its own list and then + * mark them for close. The unlinked object gets freed opportunistically once + * there is no more legs attached to it and so we can't hold a reference + * while closing circuits. */ + circ_to_close = smartlist_new(); + + SMARTLIST_FOREACH(unlinked->legs, leg_t *, leg, + smartlist_add(circ_to_close, leg->circ)); + unlinked = NULL; + + /* The leg gets cleaned up in the circuit close. */ + SMARTLIST_FOREACH_BEGIN(circ_to_close, circuit_t *, circ) { + if (CIRCUIT_IS_ORIGIN(circ)) { + tor_assert_nonfatal(circ->purpose == CIRCUIT_PURPOSE_CONFLUX_UNLINKED); + } + if (!circ->marked_for_close) { + circuit_mark_for_close(circ, END_CIRC_REASON_INTERNAL); + } + } SMARTLIST_FOREACH_END(circ); + + /* Drop the list and ignore its content, we don't have ownership. */ + smartlist_free(circ_to_close); +} + +/** Either closee all legs of the given unlinked set or delete it from the pool + * and free its memory. + * + * Important: The unlinked object is freed opportunistically when legs are + * removed until the point none remains. And so, it is only safe to free the + * object if no more legs exist. + */ +static void +unlinked_close_or_free(unlinked_circuits_t *unlinked) +{ + if (!unlinked) { + return; + } + + /* If we have legs, the circuit close will trigger the unlinked object to be + * opportunistically freed. Else, we do it explicitly. */ + if (smartlist_len(unlinked->legs) > 0) { + unlinked_close_all_legs(unlinked); + } else { + unlinked_pool_del_and_free(unlinked, unlinked->is_client); + } + /* Either the unlinked object has been freed or the last leg close will free + * it so from this point on, nullify for safety reasons. */ + unlinked = NULL; +} + +/** Upon an error condition or a close of an in-use circuit, we must close all + * linked and unlinked circuits associated with a set. When the last leg of + * each set is closed, the set is removed from the pool. */ +void +conflux_mark_all_for_close(const uint8_t *nonce, bool is_client, int reason) +{ + /* It is possible that for a nonce we have both an unlinked set and a linked + * set. This happens if there is a recovery leg launched for an existing + * linked set. */ + + /* Close the unlinked set. */ + unlinked_circuits_t *unlinked = unlinked_pool_get(nonce, is_client); + if (unlinked) { + unlinked_close_or_free(unlinked); + } + /* In case it gets freed, be safe here. */ + unlinked = NULL; + + /* Close the linked set. It will free itself upon the close of + * the last leg. */ + conflux_t *linked = linked_pool_get(nonce, is_client); + if (linked) { + if (linked->in_full_teardown) { + return; + } + linked->in_full_teardown = true; + + smartlist_t *circ_to_close = smartlist_new(); + + SMARTLIST_FOREACH(linked->legs, conflux_leg_t *, leg, + smartlist_add(circ_to_close, leg->circ)); + + SMARTLIST_FOREACH(circ_to_close, circuit_t *, circ, + circuit_mark_for_close(circ, reason)); + + /* Drop the list and ignore its content, we don't have ownership. */ + smartlist_free(circ_to_close); + } +} + +/** Helper: Free function taking a void pointer for the digest256map_free. */ +static inline void +free_unlinked_void_(void *ptr) +{ + unlinked_circuits_t *unlinked = ptr; + unlinked_pool_del_and_free(unlinked, unlinked->is_client); +} + +/** Attempt to finalize the unlinked set to become a linked set and be put in + * the linked pool. + * + * If this finalized successfully, the given unlinked object is freed. */ +static link_circ_err_t +try_finalize_set(unlinked_circuits_t *unlinked) +{ + link_circ_err_t err = ERR_LINK_CIRC_OK; + bool is_client; + + tor_assert(unlinked); + tor_assert(unlinked->legs); + tor_assert(unlinked->cfx); + tor_assert(unlinked->cfx->legs); + + /* Without legs, this is not ready to become a linked set. */ + if (BUG(smartlist_len(unlinked->legs) == 0)) { + err = ERR_LINK_CIRC_MISSING_LEG; + goto end; + } + + /* If there are too many legs, we can't link. */ + if (smartlist_len(unlinked->legs) + + smartlist_len(unlinked->cfx->legs) > conflux_params_get_max_legs_set()) { + log_fn(LOG_PROTOCOL_WARN, LD_CIRC, + "Conflux set has too many legs to link. " + "Rejecting this circuit."); + conflux_log_set(LOG_PROTOCOL_WARN, unlinked->cfx, unlinked->is_client); + err = ERR_LINK_CIRC_INVALID_LEG; + goto end; + } + + /* Validate that all legs are coherent and parameters match. On failure, we + * teardown the whole unlinked set because this means we either have a code + * flow problem or the Exit is trying to trick us. */ + if (!validate_unlinked_legs(unlinked)) { + log_fn(LOG_PROTOCOL_WARN, LD_CIRC, + "Conflux unlinked set legs are not validating. Tearing it down."); + conflux_mark_all_for_close(unlinked->cfx->nonce, unlinked->is_client, + END_CIRC_REASON_TORPROTOCOL); + err = ERR_LINK_CIRC_INVALID_LEG; + goto end; + } + + /* Check all linked status. All need to be true in order to finalize the set + * and move it to the linked pool. */ + SMARTLIST_FOREACH_BEGIN(unlinked->legs, const leg_t *, leg) { + /* We are still waiting on a leg. */ + if (!leg->linked) { + log_info(LD_CIRC, "Can't finalize conflux set, still waiting on at " + "least one leg to link up."); + + goto end; + } + } SMARTLIST_FOREACH_END(leg); + + /* Finalize the cfx object by adding all legs into it. */ + SMARTLIST_FOREACH_BEGIN(unlinked->legs, leg_t *, leg) { + /* Removing the leg from the list is important so we avoid ending up with a + * leg in the unlinked list that is set with LINKED purpose. */ + SMARTLIST_DEL_CURRENT(unlinked->legs, leg); + + /* We are ready to attach the leg to the cfx object now. */ + cfx_add_leg(unlinked->cfx, leg); + + /* Clean the pending nonce and set the conflux object in the circuit. */ + leg->circ->conflux = unlinked->cfx; + + /* We are done with this leg object. */ + leg_free(leg); + } SMARTLIST_FOREACH_END(leg); + + is_client = unlinked->is_client; + + /* Add the conflux object to the linked pool. For an existing linked cfx + * object, we'll simply replace it with itself. */ + linked_pool_add(unlinked->cfx, is_client); + + /* Remove it from the unlinked pool. */ + unlinked_pool_del(unlinked, is_client); + + /* We don't recover a leg when it is linked but if we would like to support + * session ressumption, this would be very important in order to allow new + * legs to be created/recovered. */ + unlinked->cfx->num_leg_launch = 0; + + /* Nullify because we are about to free the unlinked object and the cfx has + * moved to all circuits. */ + unlinked->cfx = NULL; + unlinked_free(unlinked); + + log_info(LD_CIRC, + "Successfully linked a conflux %s set which is now usable.", + is_client ? "client" : "relay"); + + end: + return err; +} + +/** Record the RTT for this client circuit. + * + * Return the RTT value. UINT64_MAX is returned if we couldn't find the initial + * measurement of when the cell was sent or if the leg is missing. */ +static uint64_t +record_rtt_client(const circuit_t *circ) +{ + tor_assert(circ); + tor_assert(circ->conflux_pending_nonce); + tor_assert(CIRCUIT_IS_ORIGIN(circ)); + + leg_t *leg = unlinked_leg_find(circ, true); + + if (BUG(!leg || leg->link_sent_usec == 0)) { + log_warn(LD_BUG, + "Conflux: Trying to record client RTT without a timestamp"); + goto err; + } + + uint64_t now = monotime_absolute_usec(); + tor_assert_nonfatal(now >= leg->link_sent_usec); + leg->rtt_usec = now - leg->link_sent_usec; + if (leg->rtt_usec == 0) { + log_warn(LD_CIRC, "Clock appears stalled for conflux."); + // TODO-329-TUNING: For now, let's accept this case. We need to do + // tuning and clean up the tests such that they use RTT in order to + // fail here. + //goto err; + } + return leg->rtt_usec; + + err: + // Avoid using this leg until a timestamp comes in + if (leg) + leg->rtt_usec = UINT64_MAX; + return UINT64_MAX; +} + +/** Record the RTT for this Exit circuit. + * + * Return the RTT value. UINT64_MAX is returned if we couldn't find the initial + * measurement of when the cell was sent or if the leg is missing. */ + +static uint64_t +record_rtt_exit(const circuit_t *circ) +{ + tor_assert(circ); + tor_assert(circ->conflux); + tor_assert(CIRCUIT_IS_ORCIRC(circ)); + + conflux_leg_t *leg = conflux_get_leg(circ->conflux, circ); + + if (BUG(!leg || leg->linked_sent_usec == 0)) { + log_warn(LD_BUG, + "Conflux: Trying to record exit RTT without a timestamp"); + goto err; + } + + uint64_t now = monotime_absolute_usec(); + tor_assert_nonfatal(now >= leg->linked_sent_usec); + leg->circ_rtts_usec = now - leg->linked_sent_usec; + + if (leg->circ_rtts_usec == 0) { + log_warn(LD_CIRC, "Clock appears stalled for conflux."); + goto err; + } + return leg->circ_rtts_usec; + + err: + if (leg) + leg->circ_rtts_usec = UINT64_MAX; + return UINT64_MAX; +} + +/** For the given circuit, record the RTT from when the LINK or LINKED cell was + * sent that is this function works for either client or Exit. + * + * Return false if the RTT is too high for our standard else true. */ +static bool +record_rtt(const circuit_t *circ, bool is_client) +{ + uint64_t rtt_usec; + + tor_assert(circ); + + if (is_client) { + rtt_usec = record_rtt_client(circ); + + if (rtt_usec == UINT64_MAX) + return false; + + if (rtt_usec >= get_circuit_build_timeout_ms()*1000) { + log_info(LD_CIRC, "Conflux leg RTT is above circuit build time out " + "currently at %f msec. Relaunching.", + get_circuit_build_timeout_ms()); + return false; + } + } else { + rtt_usec = record_rtt_exit(circ); + } + + return true; +} + +/** Link the given circuit within its unlinked set. This is called when either + * the LINKED or LINKED_ACK is received depending on which side of the circuit + * it is. + * + * It attempts to finalize the unlinked set as well which, if successful, puts + * it in the linked pool. */ +static link_circ_err_t +link_circuit(circuit_t *circ) +{ + link_circ_err_t err = ERR_LINK_CIRC_OK; + unlinked_circuits_t *unlinked = NULL; + bool is_client = false; + + tor_assert(circ); + if (CIRCUIT_IS_ORIGIN(circ)) { + tor_assert_nonfatal(circ->purpose == CIRCUIT_PURPOSE_CONFLUX_UNLINKED); + is_client = true; + } + + unlinked = unlinked_pool_get(circ->conflux_pending_nonce, is_client); + if (BUG(!unlinked)) { + log_warn(LD_BUG, "Failed to find the unlinked set %s when linking. " + "Closing circuit.", + fmt_nonce(circ->conflux_pending_nonce)); + err = ERR_LINK_CIRC_MISSING_SET; + goto end; + } + + leg_t *leg = leg_find(unlinked, circ); + if (BUG(!leg)) { + /* Failure to find the leg when linking a circuit is an important problem + * so log loudly and error. */ + log_warn(LD_BUG, "Failed to find leg for the unlinked set %s when " + "linking. Closing circuit.", + fmt_nonce(unlinked->cfx->nonce)); + err = ERR_LINK_CIRC_MISSING_LEG; + goto end; + } + + /* Successful link. Attempt to finalize the set in case this was the last + * LINKED or LINKED_ACK cell to receive. */ + leg->linked = true; + err = try_finalize_set(unlinked); + + end: + return err; +} + +/** Launch a brand new set. + * + * Return true if all legs successfully launched or false if one failed. */ +STATIC bool +launch_new_set(int num_legs) +{ + uint8_t nonce[DIGEST256_LEN]; + + /* Brand new nonce for this set. */ + crypto_rand((char *) nonce, sizeof(nonce)); + + /* Launch all legs. */ + for (int i = 0; i < num_legs; i++) { + if (!conflux_launch_leg(nonce)) { + /* This function cleans up entirely the unlinked set if a leg is unable + * to be launched. The recovery would be complex here. */ + goto err; + } + } + + return true; + + err: + return false; +} + +static unlinked_circuits_t * +unlinked_get_or_create(const uint8_t *nonce, bool is_client) +{ + unlinked_circuits_t *unlinked; + + tor_assert(nonce); + + unlinked = unlinked_pool_get(nonce, is_client); + if (!unlinked) { + unlinked = unlinked_new(nonce, is_client); + + /* If this is a leg of an existing linked set, use that conflux object + * instead so all legs point to the same. It is put in the leg's circuit + * once the link is confirmed. */ + conflux_t *cfx = linked_pool_get(nonce, is_client); + if (cfx) { + conflux_free(unlinked->cfx); + unlinked->cfx = cfx; + unlinked->is_for_linked_set = true; + } + /* Add this set to the unlinked pool. */ + unlinked_pool_add(unlinked, is_client); + } + + return unlinked; +} + +/** + * On the client side, we need to determine if there is already + * an exit in use for this set, and if so, use that. + * + * Otherwise, we return NULL and the exit is decided by the + * circuitbuild.c code. + */ +static extend_info_t * +get_exit_for_nonce(const uint8_t *nonce) +{ + extend_info_t *exit = NULL; + + tor_assert(nonce); + + // First, check the linked pool for the nonce + const conflux_t *cfx = linked_pool_get(nonce, true); + if (cfx) { + tor_assert(cfx->legs); + /* Get the exit from the first leg */ + conflux_leg_t *leg = smartlist_get(cfx->legs, 0); + tor_assert(leg); + tor_assert(leg->circ); + tor_assert(TO_ORIGIN_CIRCUIT(leg->circ)->cpath); + exit = TO_ORIGIN_CIRCUIT(leg->circ)->cpath->prev->extend_info; + tor_assert(exit); + } else { + unlinked_circuits_t *unlinked = NULL; + unlinked = unlinked_pool_get(nonce, true); + + if (unlinked) { + tor_assert(unlinked->legs); + if (smartlist_len(unlinked->legs) > 0) { + /* Get the exit from the first leg */ + leg_t *leg = smartlist_get(unlinked->legs, 0); + tor_assert(leg); + tor_assert(leg->circ); + tor_assert(TO_ORIGIN_CIRCUIT(leg->circ)->cpath); + exit = TO_ORIGIN_CIRCUIT(leg->circ)->cpath->prev->extend_info; + tor_assert(exit); + } + } + } + + return exit; +} + +/** + * Return the currently configured client UX. + */ +static uint8_t +get_client_ux(void) +{ +#ifdef TOR_UNIT_TESTS + return DEFAULT_CLIENT_UX; +#else + const or_options_t *opt = get_options(); + tor_assert(opt); + (void)DEFAULT_CLIENT_UX; + + /* Return the UX */ + return opt->ConfluxClientUX; +#endif +} + +/** Return true iff the given conflux object is allowed to launch a new leg. If + * the cfx object is NULL, then it is always allowed to launch a new leg. */ +static bool +launch_leg_is_allowed(const conflux_t *cfx) +{ + if (!cfx) { + goto allowed; + } + + /* The maximum number of retry is the minimum number of legs we are allowed + * per set plus the maximum amount of retries we are allowed to do. */ + unsigned int max_num_launch = + conflux_params_get_num_legs_set() + + conflux_params_get_max_unlinked_leg_retry(); + + /* Only log once per nonce if we've reached the maximum. */ + if (cfx->num_leg_launch == max_num_launch) { + log_info(LD_CIRC, "Maximum number of leg launch reached for nonce %s", + fmt_nonce(cfx->nonce)); + } + + if (cfx->num_leg_launch >= max_num_launch) { + return false; + } + + allowed: + return true; +} + +/* + * Public API. + */ + +/** Launch a new conflux leg for the given nonce. + * + * Return true on success else false which teardowns the entire unlinked set if + * any. */ +bool +conflux_launch_leg(const uint8_t *nonce) +{ + int flags = CIRCLAUNCH_NEED_UPTIME | CIRCLAUNCH_NEED_CAPACITY | + CIRCLAUNCH_NEED_CONFLUX; + unlinked_circuits_t *unlinked = NULL; + extend_info_t *exit = NULL; + + tor_assert(nonce); + + /* Get or create a new unlinked object for this leg. */ + unlinked = unlinked_get_or_create(nonce, true); + tor_assert(unlinked); + + /* If we have an existing linked set, validate the number of leg retries + * before attempting the launch. */ + if (!launch_leg_is_allowed(unlinked->cfx)) { + goto err; + } + + exit = get_exit_for_nonce(nonce); + + if (exit) { + log_info(LD_CIRC, "Launching conflux leg for nonce %s.", fmt_nonce(nonce)); + } else { + log_info(LD_CIRC, "Launching new conflux set for nonce %s.", + fmt_nonce(nonce)); + } + + /* Increase the retry count for this conflux object as in this nonce. + * We must do this now, because some of the maze's early failure paths + * call right back into this function for relaunch. */ + unlinked->cfx->num_leg_launch++; + + origin_circuit_t *circ = + circuit_establish_circuit_conflux(nonce, CIRCUIT_PURPOSE_CONFLUX_UNLINKED, + exit, flags); + + /* The above call to establish a circuit can send us back a closed + * circuit if the OOM handler closes this very circuit while in that + * function. OOM handler runs everytime we queue a cell on a circuit which + * the above function does with the CREATE cell. + * + * The BUG() checks after are in the same spirit which is that there are so + * many things that can happen in that establish circuit function that we + * ought to make sure we have a valid nonce and a valid conflux object. */ + if (!circ || TO_CIRCUIT(circ)->marked_for_close) { + goto err; + } + /* We think this won't happen but it might. The maze is powerful. #41155 */ + if (BUG(!TO_CIRCUIT(circ)->conflux_pending_nonce || !unlinked->cfx)) { + goto err; + } + + /* At this point, the unlinked object has either a new conflux_t or the one + * used by a linked set so it is fine to use the cfx from the unlinked object + * from now on. */ + + /* Get the max_seq_sent and recv from the linked pool, if it exists, and pass + * to new link cell. */ + uint64_t last_seq_sent = conflux_get_max_seq_sent(unlinked->cfx); + uint64_t last_seq_recv = unlinked->cfx->last_seq_delivered; + + // TODO-329-ARTI: To support resumption/retransmit, the client should store + // the last_seq_sent now, so that it can know how much data to retransmit to + // the server after link. C-Tor will not be implementing this, but arti and + // arti-relay could (if resumption seems worthwhile; it may not be worth the + // memory storage there, either). + + /* We have a circuit, create the new leg and attach it to the set. */ + leg_t *leg = leg_new(TO_CIRCUIT(circ), + conflux_cell_new_link(nonce, + last_seq_sent, last_seq_recv, + get_client_ux())); + + unlinked_leg_add(unlinked, leg); + return true; + + err: + return false; +} + +/** + * Add the identity digest of the guard nodes of all legs of the conflux + * circuit. + * + * This function checks both pending and linked conflux circuits. + */ +void +conflux_add_guards_to_exclude_list(const origin_circuit_t *orig_circ, + smartlist_t *excluded) +{ + tor_assert(orig_circ); + tor_assert(excluded); + + /* Ease our lives. */ + const circuit_t *circ = TO_CIRCUIT(orig_circ); + + /* Ignore if this is not conflux related. */ + if (!CIRCUIT_IS_CONFLUX(circ)) { + return; + } + + /* When building a circuit, we should not have a conflux object + * ourselves (though one may exist elsewhere). */ + tor_assert(!circ->conflux); + + /* Getting here without a nonce is a code flow issue. */ + if (BUG(!circ->conflux_pending_nonce)) { + return; + } + + /* If there is only one bridge, then only issue a warn once that + * at least two bridges are best for conflux. Exempt Snowflake + * from this warn */ + if (get_options()->UseBridges && !conflux_can_exclude_used_bridges()) { + /* Do not build any exclude lists; not enough bridges */ + return; + } + + /* A linked set exists, use it. */ + const conflux_t *cfx = linked_pool_get(circ->conflux_pending_nonce, true); + if (cfx) { + CONFLUX_FOR_EACH_LEG_BEGIN(cfx, leg) { + const origin_circuit_t *ocirc = CONST_TO_ORIGIN_CIRCUIT(leg->circ); + smartlist_add(excluded, + tor_memdup(ocirc->cpath->extend_info->identity_digest, + DIGEST_LEN)); + } CONFLUX_FOR_EACH_LEG_END(leg); + } + + /* An unlinked set might exist for this nonce, if so, add the second hop of + * the existing legs to the exclusion list. */ + unlinked_circuits_t *unlinked = + unlinked_pool_get(circ->conflux_pending_nonce, true); + if (unlinked) { + tor_assert(unlinked->is_client); + SMARTLIST_FOREACH_BEGIN(unlinked->legs, leg_t *, leg) { + /* Convert to origin circ and get cpath */ + const origin_circuit_t *ocirc = CONST_TO_ORIGIN_CIRCUIT(leg->circ); + smartlist_add(excluded, + tor_memdup(ocirc->cpath->extend_info->identity_digest, + DIGEST_LEN)); + } SMARTLIST_FOREACH_END(leg); + } +} + +/** + * Add the identity digest of the middle nodes of all legs of the conflux + * circuit. + * + * This function checks both pending and linked conflux circuits. + * + * XXX: The add guard and middle could be merged since it is the exact same + * code except for the cpath position and the identity digest vs node_t in + * the list. We could use an extra param indicating guard or middle. */ +void +conflux_add_middles_to_exclude_list(const origin_circuit_t *orig_circ, + smartlist_t *excluded) +{ + tor_assert(orig_circ); + tor_assert(excluded); + + /* Ease our lives. */ + const circuit_t *circ = TO_CIRCUIT(orig_circ); + + /* Ignore if this is not conflux related. */ + if (!CIRCUIT_IS_CONFLUX(circ)) { + return; + } + + /* When building a circuit, we should not have a conflux object + * ourselves (though one may exist elsewhere). */ + tor_assert(!circ->conflux); + + /* Getting here without a nonce is a code flow issue. */ + if (BUG(!circ->conflux_pending_nonce)) { + return; + } + + /* A linked set exists, use it. */ + const conflux_t *cfx = linked_pool_get(circ->conflux_pending_nonce, true); + if (cfx) { + CONFLUX_FOR_EACH_LEG_BEGIN(cfx, leg) { + const origin_circuit_t *ocirc = CONST_TO_ORIGIN_CIRCUIT(leg->circ); + node_t *node = node_get_mutable_by_id( + ocirc->cpath->next->extend_info->identity_digest); + if (node) { + smartlist_add(excluded, node); + } + } CONFLUX_FOR_EACH_LEG_END(leg); + } + + /* An unlinked set might exist for this nonce, if so, add the second hop of + * the existing legs to the exclusion list. */ + unlinked_circuits_t *unlinked = + unlinked_pool_get(circ->conflux_pending_nonce, true); + if (unlinked) { + tor_assert(unlinked->is_client); + SMARTLIST_FOREACH_BEGIN(unlinked->legs, leg_t *, leg) { + /* Convert to origin circ and get cpath */ + const origin_circuit_t *ocirc = CONST_TO_ORIGIN_CIRCUIT(leg->circ); + node_t *node = node_get_mutable_by_id( + ocirc->cpath->next->extend_info->identity_digest); + if (node) { + smartlist_add(excluded, node); + } + } SMARTLIST_FOREACH_END(leg); + } +} + +/** Return the number of unused client linked set. */ +static int +count_client_usable_sets(void) +{ + int count = 0; + + DIGEST256MAP_FOREACH(client_linked_pool, key, conflux_t *, cfx) { + conflux_leg_t *leg = smartlist_get(cfx->legs, 0); + if (BUG(!leg->circ)) { + log_warn(LD_BUG, "Client conflux linked set leg without a circuit"); + continue; + } + + /* The maze marks circuits used several different ways. If any of + * them are marked for this leg, launch a new one. */ + if (!CONST_TO_ORIGIN_CIRCUIT(leg->circ)->unusable_for_new_conns && + !CONST_TO_ORIGIN_CIRCUIT(leg->circ)->isolation_values_set && + !leg->circ->timestamp_dirty) { + count++; + } + } DIGEST256MAP_FOREACH_END; + + return count; +} + +/** Determine if we need to launch new conflux circuits for our preemptive + * pool. + * + * This is called once a second from the mainloop from + * circuit_predict_and_launch_new(). */ +void +conflux_predict_new(time_t now) +{ + (void) now; + + /* If conflux is disabled, or we have insufficient consensus exits, + * don't prebuild. */ + if (!conflux_is_enabled(NULL) || + router_have_consensus_path() != CONSENSUS_PATH_EXIT) { + return; + } + + /* Don't attempt to build a new set if we are above our allowed maximum of + * linked sets. */ + if (digest256map_size(client_linked_pool) >= + conflux_params_get_max_linked_set()) { + return; + } + + /* Count the linked and unlinked to get the total number of sets we have + * (will have). */ + int num_linked = count_client_usable_sets(); + int num_unlinked = digest256map_size(client_unlinked_pool); + int num_set = num_unlinked + num_linked; + int max_prebuilt = conflux_params_get_max_prebuilt(); + + if (num_set >= max_prebuilt) { + return; + } + + log_info(LD_CIRC, "Preemptively launching new conflux circuit set(s). " + "We have %d linked and %d unlinked.", + num_linked, num_unlinked); + + for (int i = 0; i < (max_prebuilt - num_set); i++) { + if (!launch_new_set(conflux_params_get_num_legs_set())) { + /* Failing once likely means we'll fail next attempt so stop for now and + * we'll try later. */ + break; + } + } +} + +/** Return the first circuit from the linked pool that will work with the conn. + * If no such circuit exists, return NULL. */ +origin_circuit_t * +conflux_get_circ_for_conn(const entry_connection_t *conn, time_t now) +{ + /* Use conn to check the exit policy of the first circuit + * of each set in the linked pool. */ + tor_assert(conn); + + DIGEST256MAP_FOREACH(client_linked_pool, key, conflux_t *, cfx) { + /* Get the first circuit of the set. */ + conflux_leg_t *leg = smartlist_get(cfx->legs, 0); + tor_assert(leg); + tor_assert(leg->circ); + + /* Bug on these but we can recover. */ + if (BUG(leg->circ->purpose != CIRCUIT_PURPOSE_CONFLUX_LINKED)) { + continue; + } + if (BUG(!CIRCUIT_IS_ORIGIN(leg->circ))) { + continue; + } + origin_circuit_t *ocirc = TO_ORIGIN_CIRCUIT(leg->circ); + + /* Make sure the connection conforms with the exit policy and the isolation + * flags also allows it. */ + if (!circuit_is_acceptable(ocirc, conn, 1 /* Must be open */, + CIRCUIT_PURPOSE_CONFLUX_LINKED, + 1 /* Need uptime */, + 0 /* No need for internal */, now)) { + continue; + } + + /* Found a circuit that works. */ + return ocirc; + } DIGEST256MAP_FOREACH_END; + + return NULL; +} + +/** The given circuit is conflux pending and has closed. This deletes the leg + * from the set, attempt to finalize it and relaunch a new leg. If the set is + * empty after removing this leg, it is deleted. */ +static void +unlinked_circuit_closed(circuit_t *circ) +{ + uint8_t nonce[DIGEST256_LEN]; + unlinked_circuits_t *unlinked = NULL; + bool is_client = false; + + tor_assert(circ); + tor_assert(circ->conflux_pending_nonce); + + if (CIRCUIT_IS_ORIGIN(circ)) { + tor_assert_nonfatal(circ->purpose == CIRCUIT_PURPOSE_CONFLUX_UNLINKED); + is_client = true; + } + + unlinked = unlinked_pool_get(circ->conflux_pending_nonce, is_client); + + /* This circuit is part of set that has already been removed previously freed + * by another leg closing. */ + if (!unlinked) { + return; + } + + /* We keep the nonce here because we will try to recover if we can and the + * pending nonce will get nullified early. */ + memcpy(nonce, circ->conflux_pending_nonce, sizeof(nonce)); + + log_info(LD_CIRC, "Conflux unlinked circuit with nonce %s has closed", + fmt_nonce(nonce)); + + /* Remove leg from set. */ + unlinked_leg_del_and_free(unlinked, circ); + /* The circuit pending nonce has been nullified at this point. */ + + /* If no more legs, opportunistically free the unlinked set. */ + if (smartlist_len(unlinked->legs) == 0) { + unlinked_pool_del_and_free(unlinked, is_client); + } else if (!shutting_down && !have_been_under_memory_pressure()) { + /* Launch a new leg for this set to recover if we are not shutting down or + * if we are not under memory pressure. We must not launch legs under + * memory pressure else it can just create a feedback loop of being closed + * by the OOM handler and relaunching, rinse and repeat. */ + if (CIRCUIT_IS_ORIGIN(circ)) { + conflux_launch_leg(nonce); + } + } + /* After this, it might have been freed. */ + unlinked = NULL; + + /* Unlinked circuits should not have attached streams, but check + * anyway, because The Maze. */ + validate_circ_has_no_streams(circ); +} + +/** Update all stream pointers to point to this circuit. + * This is used when a linked circuit is closed and we need to update the + * streams to point to the remaining circuit + */ +static void +linked_update_stream_backpointers(circuit_t *circ) +{ + tor_assert(circ); + tor_assert_nonfatal(circ->conflux); + + if (CIRCUIT_IS_ORIGIN(circ)) { + origin_circuit_t *ocirc = TO_ORIGIN_CIRCUIT(circ); + tor_assert_nonfatal(circ->purpose == CIRCUIT_PURPOSE_CONFLUX_LINKED); + /* Iterate over stream list using next_stream pointer, until null */ + for (edge_connection_t *stream = ocirc->p_streams; stream; + stream = stream->next_stream) { + /* Update the circuit pointer of each stream */ + stream->on_circuit = circ; + stream->cpath_layer = ocirc->cpath->prev; + } + } else { + or_circuit_t *orcirc = TO_OR_CIRCUIT(circ); + /* Iterate over stream list using next_stream pointer, until null */ + for (edge_connection_t *stream = orcirc->n_streams; stream; + stream = stream->next_stream) { + /* Update the circuit pointer of each stream */ + stream->on_circuit = circ; + } + /* Iterate over stream list using next_stream pointer, until null */ + for (edge_connection_t *stream = orcirc->resolving_streams; stream; + stream = stream->next_stream) { + /* Update the circuit pointer of each stream */ + stream->on_circuit = circ; + } + } +} + +/** Nullify all streams of the given circuit. */ +static void +linked_nullify_streams(circuit_t *circ) +{ + tor_assert(circ); + + if (CIRCUIT_IS_ORIGIN(circ)) { + origin_circuit_t *ocirc = TO_ORIGIN_CIRCUIT(circ); + ocirc->p_streams = NULL; + ocirc->half_streams = NULL; + } else { + or_circuit_t *orcirc = TO_OR_CIRCUIT(circ); + orcirc->n_streams = NULL; + orcirc->resolving_streams = NULL; + } +} + +/** The given circuit is already linked to a set and has been closed. Remove it + * from the set and free the pool if no more legs. */ +static void +linked_circuit_closed(circuit_t *circ) +{ + bool is_client = false; + bool full_teardown = false; + uint8_t nonce[DIGEST256_LEN] = {0}; + + tor_assert(circ); + tor_assert(circ->conflux); + + if (CIRCUIT_IS_ORIGIN(circ)) { + tor_assert_nonfatal(circ->purpose == CIRCUIT_PURPOSE_CONFLUX_LINKED); + is_client = true; + } + + /* Unlink circuit from its conflux object. */ + full_teardown = cfx_del_leg(circ->conflux, circ); + + if (CONFLUX_NUM_LEGS(circ->conflux) == 0) { + /* Last leg, remove conflux object from linked set. */ + linked_pool_del(circ->conflux->nonce, is_client); + } else { + /* If there are other circuits, update streams backpointers and + * nullify the stream lists. We do not free those streams in circuit_free_. + * (They only get freed when the last circuit is freed). */ + conflux_leg_t *leg = smartlist_get(circ->conflux->legs, 0); + linked_update_stream_backpointers(leg->circ); + linked_nullify_streams(circ); + } + + /* Keep the nonce so we can use it through out the rest of the function in + * case we nullify the conflux object before. Reason is that in the case of a + * full teardown, this function becomes basically recursive and so we must + * nullify the conflux object of this circuit now before the recursiveness + * starts leading to all legs being removed and thus not noticing if we are + * the last or the first. + * + * Not the prettiest but that is the price to pay to live in the C-tor maze + * and protected by ballrogs. */ + memcpy(nonce, circ->conflux->nonce, sizeof(nonce)); + + /* Nullify the conflux object from the circuit being closed iff we have more + * legs. Reason being that the last leg needs to have the conflux object + * attached to the circuit so it can be freed in conflux_circuit_free(). */ + if (CONFLUX_NUM_LEGS(circ->conflux) > 0) { + circ->conflux = NULL; + } + + /* If this was a teardown condition, we need to mark other circuits, + * including any potential unlinked circuits, for close. + * + * This call is recursive in the sense that linked_circuit_closed() will end + * up being called for all legs and so by the time we come back here, the + * linked is likely entirely gone. Thus why this is done last. */ + if (full_teardown) { + conflux_mark_all_for_close(nonce, is_client, END_CIRC_REASON_FINISHED); + } +} + +/** The given circuit is being freed and it is a linked leg. Clean up and free + * anything that has to do with this circuit. + * + * After this call, the circuit should NOT be referenced anymore anywhere. */ +static void +linked_circuit_free(circuit_t *circ, bool is_client) +{ + tor_assert(circ); + tor_assert(circ->conflux); + tor_assert(circ->conflux->legs); + tor_assert(circ->conflux->ooo_q); + + if (is_client) { + tor_assert(circ->purpose == CIRCUIT_PURPOSE_CONFLUX_LINKED); + } + + /* Circuit can be freed without being closed and so we try to delete this leg + * so we can learn if this circuit is the last leg or not. */ + if (cfx_del_leg(circ->conflux, circ)) { + /* Check for instances of bug #40870, which we suspect happen + * during exit. If any happen outside of exit, BUG and warn. */ + if (!circ->conflux->in_full_teardown) { + /* We should bug and warn if we're not in a shutdown process; that + * means we got here somehow without a close. */ + if (BUG(!shutting_down)) { + log_warn(LD_BUG, + "Conflux circuit %p being freed without being marked for " + "full teardown via close, with shutdown state %d. " + "Please report this.", circ, shutting_down); + conflux_log_set(LOG_WARN, circ->conflux, is_client); + } + circ->conflux->in_full_teardown = true; + } + } + + if (CONFLUX_NUM_LEGS(circ->conflux) > 0) { + /* The last leg will free the streams but until then, we nullify to avoid + * use-after-free. */ + linked_nullify_streams(circ); + } else { + /* We are the last leg. */ + + /* Remove from pool in case it is still lingering there else we'll end up + * in a double free situation. */ + linked_pool_del(circ->conflux->nonce, is_client); + + /* If there is an unlinked circuit that was also created for this set, we + * need to look for it, and tell it is no longer part of a linked set + * anymore, so it can be freed properly, or can complete the link if it is + * able to. Effectively, the conflux_t object lifetime is longer than + * either the linked or unlinked sets by themselves. This is a situation we + * could cover with handles, but so far, it is not clear they are an + * obvious benefit for other cases than this one. */ + unlinked_circuits_t *unlinked = + unlinked_pool_get(circ->conflux->nonce, is_client); + if (unlinked) { + tor_assert(unlinked->is_for_linked_set); + unlinked->is_for_linked_set = false; + } else { + /* We are the last one, clear the conflux object. If an unlinked object + * has a reference to it, it won't get freed due to is_for_linked_set + * flag. */ + conflux_free(circ->conflux); + } + } +} + +/** The given circuit is being freed and it is an unlinked leg. Clean up and + * free anything that has to do with this circuit. + * + * After this call, the circuit should NOT be referenced anymore anywhere. */ +static void +unlinked_circuit_free(circuit_t *circ, bool is_client) +{ + tor_assert(circ); + tor_assert(circ->conflux_pending_nonce); + if (is_client) { + tor_assert(circ->purpose == CIRCUIT_PURPOSE_CONFLUX_UNLINKED); + } + + /* Cleanup circuit reference if a leg exists. This is possible if the circuit + * was not marked for close before being freed. */ + leg_t *leg = unlinked_leg_find(circ, is_client); + if (leg) { + leg->circ = NULL; + } + + /* Null pointers are safe here. */ + tor_free(circ->conflux_pending_nonce); +} + +/** Circuit has been marked for close. */ +void +conflux_circuit_has_closed(circuit_t *circ) +{ + /* The unlinked case. If an unlinked set exists, we delete the leg and then + * attempt to finalize it. After that, we'll launch a new leg to recover. */ + if (circ->conflux_pending_nonce) { + unlinked_circuit_closed(circ); + } else if (circ->conflux) { + linked_circuit_closed(circ); + } +} + +/** Circuit with conflux purpose just opened. */ +void +conflux_circuit_has_opened(origin_circuit_t *orig_circ) +{ + circuit_t *circ = NULL; + leg_t *leg = NULL; + + tor_assert(orig_circ); + + circ = TO_CIRCUIT(orig_circ); + + /* Extra safety layer so we never let a circuit opens if conflux is not + * enabled. */ + if (!conflux_is_enabled(circ)) { + circuit_mark_for_close(circ, END_CIRC_REASON_TORPROTOCOL); + static ratelim_t conflux_ratelim = RATELIM_INIT(600); + log_fn_ratelim(&conflux_ratelim, LOG_NOTICE, LD_CIRC, + "Conflux circuit opened without negotiating " + "congestion control"); + return; + } + + /* Unrelated to conflux. */ + if (circ->conflux_pending_nonce == NULL) { + goto end; + } + + log_info(LD_CIRC, "Conflux circuit has opened with nonce %s", + fmt_nonce(circ->conflux_pending_nonce)); + + leg = unlinked_leg_find(circ, true); + if (BUG(!leg)) { + log_warn(LD_CIRC, "Unable to find conflux leg in unlinked set."); + goto end; + } + + /* On failure here, the circuit is closed and thus the leg and unlinked set + * will be cleaned up. */ + if (!conflux_cell_send_link(leg->link, orig_circ)) { + goto end; + } + + /* Mark the leg on when the LINK cell is sent. Used to timeout the circuit + * for a minimum RTT when getting the LINKED. */ + leg->link_sent_usec = monotime_absolute_usec(); + + end: + validate_circ_has_no_streams(circ); + return; +} + +/** Process a CONFLUX_LINK cell which arrived on the given circuit. */ +void +conflux_process_link(circuit_t *circ, const relay_msg_t *msg) +{ + unlinked_circuits_t *unlinked = NULL; + conflux_cell_link_t *link = NULL; + + tor_assert(circ); + tor_assert(msg); + + if (!conflux_is_enabled(circ)) { + circuit_mark_for_close(circ, END_CIRC_REASON_TORPROTOCOL); + goto end; + } + + /* This cell can't be received on an origin circuit because only the endpoint + * creating the circuit sends it. */ + if (CIRCUIT_IS_ORIGIN(circ)) { + log_fn(LOG_PROTOCOL_WARN, LD_CIRC, + "Got a CONFLUX_LINK cell on an origin circuit. Closing circuit."); + circuit_mark_for_close(circ, END_CIRC_REASON_TORPROTOCOL); + goto end; + } + + if (!conflux_validate_source_hop(circ, NULL)) { + log_fn(LOG_PROTOCOL_WARN, LD_CIRC, + "Got a CONFLUX_LINK with further hops. Closing circuit."); + circuit_mark_for_close(circ, END_CIRC_REASON_TORPROTOCOL); + goto end; + } + + if (circ->conflux_pending_nonce) { + log_fn(LOG_PROTOCOL_WARN, LD_CIRC, + "Got a CONFLUX_LINK on a circuit with a pending nonce. " + "Closing circuit."); + circuit_mark_for_close(circ, END_CIRC_REASON_TORPROTOCOL); + goto end; + } + + if (circ->conflux) { + log_fn(LOG_PROTOCOL_WARN, LD_CIRC, + "Got a CONFLUX_LINK on an already linked circuit " + "Closing circuit."); + circuit_mark_for_close(circ, END_CIRC_REASON_TORPROTOCOL); + goto end; + } + + /* On errors, logging is emitted in this parsing function. */ + link = conflux_cell_parse_link(msg); + if (!link) { + log_fn(LOG_PROTOCOL_WARN, LD_CIRC, "Unable to parse " + "CONFLUX_LINK cell. Closing circuit."); + circuit_mark_for_close(circ, END_CIRC_REASON_TORPROTOCOL); + goto end; + } + + log_info(LD_CIRC, "Processing a CONFLUX_LINK for set %s", + fmt_nonce(link->nonce)); + + /* Consider this circuit a new leg. We'll now attempt to attach it to an + * existing set or unlinked one. */ + leg_t *leg = leg_new(circ, link); + unlinked = unlinked_get_or_create(link->nonce, false); + tor_assert(unlinked); + + /* Attach leg to the unlinked set. */ + unlinked_leg_add(unlinked, leg); + + /* Set the circuit in a pending conflux state for the LINKED_ACK. */ + circ->conflux_pending_nonce = tor_memdup(leg->link->nonce, + sizeof(leg->link->nonce)); + + /* Mark when we send the LINKED. */ + leg->link_sent_usec = monotime_absolute_usec(); + + /* Send LINKED. */ + uint64_t last_seq_sent = conflux_get_max_seq_sent(unlinked->cfx); + uint64_t last_seq_recv = unlinked->cfx->last_seq_delivered; + + // TODO-329-ARTI: To support resumption/retransmit, the server should + // store the last_seq_sent now, so that it can know how much data + // to retransmit to the server after link. C-Tor will not be implementing + // this, but arti and arti-relay could (if resumption seems worthwhile; + // it may not be worth the memory storage there, either). + + uint8_t nonce[DIGEST256_LEN]; + memcpy(nonce, circ->conflux_pending_nonce, sizeof(nonce)); + + /* Link the circuit to the a conflux set immediately before the LINKED is + * sent. Reason is that once the client sends the LINKED_ACK, there is a race + * with the BEGIN cell that can be sent immediately after and arrive first. + * And so, we need to sync the streams before that happens that is before we + * receive the LINKED_ACK. */ + if (link_circuit(circ) != ERR_LINK_CIRC_OK) { + circuit_mark_for_close(circ, END_CIRC_REASON_TORPROTOCOL); + goto end; + } + + /* Exits should always request min latency from clients */ + conflux_cell_link_t *linked = conflux_cell_new_link(nonce, last_seq_sent, + last_seq_recv, + DEFAULT_EXIT_UX); + + conflux_cell_send_linked(linked, TO_OR_CIRCUIT(circ)); + tor_free(linked); + + end: + return; +} + +/** Process a CONFLUX_LINKED cell which arrived on the given circuit. */ +void +conflux_process_linked(circuit_t *circ, crypt_path_t *layer_hint, + const relay_msg_t *msg) +{ + conflux_cell_link_t *link = NULL; + + tor_assert(circ); + + /* + * There several ways a malicious exit could create problems when sending + * back this LINKED cell. + * + * 1. Using a different nonce that it knows about from another set. Accepting + * it would mean a confirmation attack of linking sets to the same client. + * To address that, the cell nonce MUST be matched with the circuit nonce. + * + * 2. Re-Sending a LINKED cell on an already linked circuit could create side + * channel attacks or unpredictable issues. Circuit is closed. + * + * 3. Receiving a LINKED cell on a circuit that was not expecting it. Again, + * as (2), can create side channel(s). Circuit is closed. + * + * 4. Receiving a LINKED cell from the another hop other than the last one + * (exit). Same as (2) and (3) in terms of issues. Circuit is closed. + */ + + if (!conflux_is_enabled(circ)) { + circuit_mark_for_close(circ, END_CIRC_REASON_TORPROTOCOL); + goto end; + } + + /* LINKED cell are in response to a LINK cell which are only sent on an + * origin circuit and thus received on such.*/ + if (!CIRCUIT_IS_ORIGIN(circ)) { + log_fn(LOG_PROTOCOL_WARN, LD_CIRC, + "Received CONFLUX_LINKED cell on a non origin circuit."); + goto close; + } + + if (!circ->conflux_pending_nonce) { + log_fn(LOG_PROTOCOL_WARN, LD_CIRC, + "Received a CONFLUX_LINKED cell without having sent a " + "CONFLUX_LINK cell. Closing circuit."); + goto close; + } + + if (circ->conflux) { + log_fn(LOG_PROTOCOL_WARN, LD_CIRC, + "Received a CONFLUX_LINKED cell on a circuit that is already " + "linked. Closing circuit."); + goto close; + } + + if (!conflux_validate_source_hop(circ, layer_hint)) { + log_fn(LOG_PROTOCOL_WARN, LD_CIRC, + "Got a CONFLUX_LINKED from wrong hop on circuit. Closing circuit."); + goto close; + } + + tor_assert_nonfatal(circ->purpose == CIRCUIT_PURPOSE_CONFLUX_UNLINKED); + + /* On errors, logging is emitted in this parsing function. */ + link = conflux_cell_parse_link(msg); + if (!link) { + goto close; + } + + log_info(LD_CIRC, "Processing a CONFLUX_LINKED for set %s", + fmt_nonce(link->nonce)); + + /* Make sure the cell nonce matches the one on the circuit that was + * previously set by the CONFLUX_LINK cell. */ + if (tor_memneq(link->nonce, circ->conflux_pending_nonce, + sizeof(link->nonce))) { + log_fn(LOG_PROTOCOL_WARN, LD_CIRC, + "Received CONFLUX_LINKED but circuit nonce doesn't match " + "cell nonce. Closing circuit."); + goto close; + } + + /* Find the leg from the associated unlinked set. */ + leg_t *leg = unlinked_leg_find(circ, true); + if (BUG(!leg)) { + log_warn(LD_CIRC, "Received CONFLUX_LINKED but can't find " + "associated leg. Closing circuit."); + goto close; + } + + log_info(LD_CIRC, "Successfully processed a CONFLUX_LINKED cell."); + + /* Free the old link, and store the new one. We need to validate + * the one we get during finalize, not the one we sent. */ + tor_free(leg->link); + leg->link = link; + + /* Record the RTT for this circuit. On failure, it means the RTT was too + * high, we relaunch to recover. */ + if (!record_rtt(circ, true)) { + goto close; + } + + /* The following will link the circuit with its set and attempt to finalize + * the set if all expected legs have linked. On error, we close the circuit + * because it means the unlinked set needs to be teardowned. */ + link_circ_err_t err = link_circuit(circ); + switch (err) { + case ERR_LINK_CIRC_OK: + /* Successfully linked. */ + break; + case ERR_LINK_CIRC_INVALID_LEG: + case ERR_LINK_CIRC_MISSING_SET: + /* No relaunch if the leg is invalid or the set is not found as in the + * nonce is unknown. */ + break; + case ERR_LINK_CIRC_BAD_RTT: + case ERR_LINK_CIRC_MISSING_LEG: + goto close; + } + + /* We can send the ack only if we finalize. This will not cause issues, + * because LINKED_ACK is exempted from multiplexing in + * conflux_should_multiplex(). */ + if (!conflux_cell_send_linked_ack(TO_ORIGIN_CIRCUIT(circ))) { + /* On failure, the circuit is closed by the underlying function(s). */ + goto end; + } + + /* If this set is ready to use with a valid conflux set, try any pending + * streams again. */ + if (circ->conflux) { + connection_ap_attach_pending(1); + } + + /* This cell is now considered valid for clients. */ + circuit_read_valid_data(TO_ORIGIN_CIRCUIT(circ), msg->length); + + goto end; + + close: + circuit_mark_for_close(circ, END_CIRC_REASON_TORPROTOCOL); + + end: + return; +} + +/** Process a CONFLUX_LINKED_ACK cell which arrived on the given circuit. */ +void +conflux_process_linked_ack(circuit_t *circ) +{ + tor_assert(circ); + + if (!conflux_is_enabled(circ)) { + goto close; + } + + if (CIRCUIT_IS_ORIGIN(circ)) { + log_fn(LOG_PROTOCOL_WARN, LD_CIRC, + "Received CONFLUX_LINKED_ACK cell on an origin circuit. Closing."); + goto close; + } + + if (!conflux_validate_source_hop(circ, NULL)) { + log_fn(LOG_PROTOCOL_WARN, LD_CIRC, + "Got a CONFLUX_LINKED_ACK with further hops. Closing circuit."); + goto close; + } + + if (BUG(!circ->conflux)) { + log_fn(LOG_PROTOCOL_WARN, LD_CIRC, + "Received a CONFLUX_LINKED_ACK cell on a circuit that is not" + "linked. Closing circuit."); + goto close; + } + + log_info(LD_CIRC, "Processing a CONFLUX_LINKED_ACK for set %s", + fmt_nonce(circ->conflux->nonce)); + + /* Record the RTT for this circuit. This should not fail */ + if (BUG(!record_rtt(circ, false))) { + goto close; + } + + return; + + close: + circuit_mark_for_close(circ, END_CIRC_REASON_TORPROTOCOL); +} + +/** Called when a circuit is freed. + * + * It is possible a conflux circuit gets freed without being closed (for + * instance SIGTERM) and so this callback is needed in order to finalize the + * cleanup. */ +void +conflux_circuit_about_to_free(circuit_t *circ) +{ + tor_assert(circ); + + bool is_client = CIRCUIT_IS_ORIGIN(circ); + + if (circ->conflux) { + linked_circuit_free(circ, is_client); + } else if (circ->conflux_pending_nonce) { + unlinked_circuit_free(circ, is_client); + } + + /* Whatever happens, nullify all conflux related pointers. */ + circ->conflux = NULL; + circ->conflux_pending_nonce = NULL; +} + +/** Initialize the conflux pool subsystem. This is called by the subsys + * manager. */ +void +conflux_pool_init(void) +{ + if (!client_linked_pool) { + client_linked_pool = digest256map_new(); + } + if (!client_unlinked_pool) { + client_unlinked_pool = digest256map_new(); + } + if (!server_linked_pool) { + server_linked_pool = digest256map_new(); + } + if (!server_unlinked_pool) { + server_unlinked_pool = digest256map_new(); + } +} + +/** + * Return a description of all linked and unlinked circuits associated + * with a conflux set. + * + * For use in rare bug cases that are hard to diagnose. + */ +void +conflux_log_set(int loglevel, const conflux_t *cfx, bool is_client) +{ + /* This could be called on a closed circuit. */ + if (cfx == NULL) { + return; + } + + log_fn(loglevel, + LD_BUG, + "Conflux %s: %d linked, %d launched. Delivered: %"PRIu64"; " + "teardown: %d; Current: %p, Previous: %p", + fmt_nonce(cfx->nonce), smartlist_len(cfx->legs), + cfx->num_leg_launch, + cfx->last_seq_delivered, cfx->in_full_teardown, + cfx->curr_leg, cfx->prev_leg); + + // Log all linked legs + int legs = 0; + CONFLUX_FOR_EACH_LEG_BEGIN(cfx, leg) { + const struct congestion_control_t *cc = circuit_ccontrol(leg->circ); + log_fn(loglevel, LD_BUG, + " - Linked Leg %d purpose=%d; RTT %"PRIu64", sent: %"PRIu64 + "; sent: %"PRIu64", recv: %"PRIu64", infl: %"PRIu64", " + "ptr: %p, idx: %d, marked: %d", + legs, leg->circ->purpose, leg->circ_rtts_usec, + leg->linked_sent_usec, leg->last_seq_recv, + leg->last_seq_sent, cc->inflight, leg->circ, + leg->circ->global_circuitlist_idx, + leg->circ->marked_for_close); + legs++; + } CONFLUX_FOR_EACH_LEG_END(leg); + + // Look up the nonce to see if we have any unlinked circuits. + unlinked_circuits_t *unlinked = unlinked_pool_get(cfx->nonce, is_client); + if (unlinked) { + // Log the number of legs and the is_for_linked_set status + log_fn(loglevel, LD_BUG, " - Unlinked set: %d legs, for link: %d", + smartlist_len(unlinked->legs), unlinked->is_for_linked_set); + legs = 0; + SMARTLIST_FOREACH_BEGIN(unlinked->legs, leg_t *, leg) { + log_fn(loglevel, LD_BUG, + " Unlinked Leg: %d purpose=%d; linked: %d, RTT %"PRIu64", " + "sent: %"PRIu64" link ptr %p, circ ptr: %p, idx: %d, marked: %d", + legs, leg->circ->purpose, leg->linked, + leg->rtt_usec, leg->link_sent_usec, + leg->link, leg->circ, + leg->circ->global_circuitlist_idx, + leg->circ->marked_for_close); + legs++; + } SMARTLIST_FOREACH_END(leg); + } +} + +/** + * Conflux needs a notification when tor_shutdown() begins, so that + * when circuits are freed, new legs are not launched. + * + * This needs a separate notification from conflux_pool_free_all(), + * because circuits must be freed before that function. + */ +void +conflux_notify_shutdown(void) +{ + shutting_down = true; +} + +#ifdef TOR_UNIT_TESTS +/** + * For unit tests: Clear the shutting down state so we resume building legs. + */ +void +conflux_clear_shutdown(void) +{ + shutting_down = false; +} +#endif + +/** Free and clean up the conflux pool subsystem. This is called by the subsys + * manager AFTER all circuits have been freed which implies that all objects in + * the pools aren't referenced anymore. */ +void +conflux_pool_free_all(void) +{ + digest256map_free(client_linked_pool, free_conflux_void_); + digest256map_free(server_linked_pool, free_conflux_void_); + digest256map_free(client_unlinked_pool, free_unlinked_void_); + digest256map_free(server_unlinked_pool, free_unlinked_void_); +} diff -Nru tor-0.4.7.16/src/core/or/conflux_pool.h tor-0.4.9.6/src/core/or/conflux_pool.h --- tor-0.4.7.16/src/core/or/conflux_pool.h 1970-01-01 00:00:00.000000000 +0000 +++ tor-0.4.9.6/src/core/or/conflux_pool.h 2026-03-25 14:30:34.000000000 +0000 @@ -0,0 +1,55 @@ +/* Copyright (c) 2023, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file conflux_pool.h + * \brief Header file for conflux_pool.c. + **/ + +#ifndef TOR_CONFLUX_POOL_H +#define TOR_CONFLUX_POOL_H + +#include "core/or/or.h" +#include "core/or/relay_msg_st.h" + +void conflux_pool_init(void); +void conflux_notify_shutdown(void); +void conflux_pool_free_all(void); + +origin_circuit_t *conflux_get_circ_for_conn(const entry_connection_t *conn, + time_t now); +void conflux_mark_all_for_close(const uint8_t *nonce, bool is_client, + int reason); + +void conflux_predict_new(time_t now); + +bool conflux_launch_leg(const uint8_t *nonce); + +void conflux_add_guards_to_exclude_list(const origin_circuit_t *circ, + smartlist_t *excluded); +void conflux_add_middles_to_exclude_list(const origin_circuit_t *circ, + smartlist_t *excluded); + +void conflux_circuit_has_closed(circuit_t *circ); +void conflux_circuit_has_opened(origin_circuit_t *orig_circ); +void conflux_circuit_about_to_free(circuit_t *circ); + +void conflux_process_link(circuit_t *circ, const relay_msg_t *msg); +void conflux_process_linked(circuit_t *circ, crypt_path_t *layer_hint, + const relay_msg_t *msg); +void conflux_process_linked_ack(circuit_t *circ); + +typedef struct conflux_t conflux_t; +void conflux_log_set(int loglevel, const conflux_t *cfx, bool is_client); + +#ifdef TOR_UNIT_TESTS +bool launch_new_set(int num_legs); +void conflux_clear_shutdown(void); +digest256map_t *get_linked_pool(bool is_client); +digest256map_t *get_unlinked_pool(bool is_client); +extern uint8_t DEFAULT_CLIENT_UX; +extern uint8_t DEFAULT_EXIT_UX; +#endif /* defined(UNIT_TESTS) */ + +#endif /* TOR_CONFLUX_POOL_H */ + diff -Nru tor-0.4.7.16/src/core/or/conflux_st.h tor-0.4.9.6/src/core/or/conflux_st.h --- tor-0.4.7.16/src/core/or/conflux_st.h 1970-01-01 00:00:00.000000000 +0000 +++ tor-0.4.9.6/src/core/or/conflux_st.h 2026-03-25 14:30:34.000000000 +0000 @@ -0,0 +1,148 @@ +/* Copyright (c) 2019-2021, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file conflux_st.h + * \brief Structure definitions for conflux multipath + **/ + +#ifndef CONFLUX_ST_H +#define CONFLUX_ST_H + +#include "core/or/circuit_st.h" +#include "core/or/cell_st.h" +#include "lib/defs/digest_sizes.h" + +/** +* Specifies which conflux alg is in use. +*/ +typedef enum { + CONFLUX_ALG_MINRTT = 0, + CONFLUX_ALG_LOWRTT = 1, + CONFLUX_ALG_CWNDRTT = 2, +} conflux_alg_t; + +/** XXX: Cached consensus params+scheduling alg */ +struct conflux_params_t { + conflux_alg_t alg; +}; + +struct conflux_leg_t { + /** + * For computing ooo_q insertion sequence numbers: Highest absolute + * sequence number received on each leg, before delivery. + * + * As a receiver, this allows us to compute the absolute sequence number + * of a cell for delivery or insertion into the ooo_q. When a SWITCH cell + * is received on a leg, the absolute sequence number of that cell is + * the relative sequence number in that cell, plus the absolute sequence + * number of that leg from this array. The leg's sequence number + * is then updated to this value immediately. + * + * In this way, we are able to assign absolute sequence numbers to cells + * immediately, regardless of how many legs or leg switches have occurred, + * and regardless of the delivery status of each cell versus if it must be + * queued. + */ + uint64_t last_seq_recv; + + /** + * For relative sequencing: Highest absolute sequence number sent on each + * circuit. The overall absolute current sent sequence number is the highest + * of these values. + * + * As a sender, this allows us to compute a relative sequence number when + * switching legs. When switching legs, the sender looks up its current + * absolute sequence number as the maximum of all legs. The sender then + * compares that to the current sequence number on the leg it is about to + * send on, and then computes the relative sequence number as the difference + * between the overall absolute sequence number and the sequence number + * from the sending leg. + * + * In this way, we can use much smaller relative sequence numbers on the + * wire, as opposed to larger absolute values, at the expense of this + * bookkeeping overhead on each end. + */ + uint64_t last_seq_sent; + + /** + * Current round-trip of the circuit, in usec. + * + * XXX: In theory, we could use the congestion control RTTs directly off the + * circs, but congestion control code has assumptions about the RTT being 0 + * at the start of the circuit, which will *not* be the case here, because we + * get an RTT off the link circuit. */ + uint64_t circ_rtts_usec; + + /** Exit side only: When was the LINKED cell sent? Used for RTT measurement + * that sets circ_rtts_usec when the LINKED_ACK is received. */ + uint64_t linked_sent_usec; + + /** Circuit of this leg. */ + circuit_t *circ; +}; + +/** Fields for conflux multipath support */ +struct conflux_t { + /** Cached parameters for this circuit */ + struct conflux_params_t params; + + /** + * List of all linked conflux_leg_t for this set. Once a leg is in that list, + * it can be used to transmit data. */ + smartlist_t *legs; + + /** + * Out-of-order priority queue of conflux_cell_t *, heapified + * on conflux_cell_t.seq number (lowest at top of heap). + * + * XXX: We are most likely to insert cells at either the head or the tail. + * Verify that is fast-path wrt smartlist priority queues, and not a memmove + * nightmare. If so, we may need a real linked list, or a packed_cell_t list. + */ + smartlist_t *ooo_q; + + /** + * Approximate allocation cost of the bytes stored in ooo_q + * and the messages that it contains. + */ + size_t ooo_q_alloc_cost; + + /** + * Absolute sequence number of cells delivered to streams since start. + * (ie: this is updated *after* dequeue from the ooo_q priority queue). */ + uint64_t last_seq_delivered; + + /** + * The estimated remaining number of cells we can send on this circuit + * before we are allowed to switch legs. */ + uint64_t cells_until_switch; + + /** Current circuit leg. Only use this with conflux_get_circ_for_leg() for + * bounds checking. */ + struct conflux_leg_t *curr_leg; + + /** Previous circuit leg. Only use this with conflux_get_circ_for_leg() for + * bounds checking. */ + struct conflux_leg_t *prev_leg; + + /** The nonce that joins these */ + uint8_t nonce[DIGEST256_LEN]; + + /** Indicate if this conflux set is in full teardown. We mark it at the first + * close in case of a total teardown so we avoid recursive calls of circuit + * mark for close. */ + bool in_full_teardown; + + /** Number of leg launch that we've done for this set. We keep this value + * because there is a maximum allowed in order to avoid side channel(s). */ + unsigned int num_leg_launch; + + /** + * PolicyHint: Predicted ports/protocol shorthand.. + * + * XXX: This might be redundant to the circuit's exitpolicy. + */ +}; + +#endif /* !defined(CONFLUX_ST_H) */ diff -Nru tor-0.4.7.16/src/core/or/conflux_sys.c tor-0.4.9.6/src/core/or/conflux_sys.c --- tor-0.4.7.16/src/core/or/conflux_sys.c 1970-01-01 00:00:00.000000000 +0000 +++ tor-0.4.9.6/src/core/or/conflux_sys.c 2026-03-25 14:30:34.000000000 +0000 @@ -0,0 +1,37 @@ +/* Copyright (c) 2023, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file conflux_sys.c + * \brief Register the conflux pool for early initialization. + **/ + +#include "core/or/conflux_pool.h" +#include "core/or/conflux_sys.h" + +#include "lib/subsys/subsys.h" + +static int +subsys_conflux_initialize(void) +{ + conflux_pool_init(); + return 0; +} + +static void +subsys_conflux_shutdown(void) +{ + /* The conflux pool free all must be called before the circuit free all and + * so we are not calling it from subsys shutdown. */ +} + +const subsys_fns_t sys_conflux = { + SUBSYS_DECLARE_LOCATION(), + + .name = "conflux", + .supported = true, + .level = CONFLUX_SUBSYS_LEVEL, + + .initialize = subsys_conflux_initialize, + .shutdown = subsys_conflux_shutdown, +}; diff -Nru tor-0.4.7.16/src/core/or/conflux_sys.h tor-0.4.9.6/src/core/or/conflux_sys.h --- tor-0.4.7.16/src/core/or/conflux_sys.h 1970-01-01 00:00:00.000000000 +0000 +++ tor-0.4.9.6/src/core/or/conflux_sys.h 2026-03-25 14:30:34.000000000 +0000 @@ -0,0 +1,23 @@ +/* Copyright (c) 2023, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file conflux_sys.h + * \brief Header file for conflux_sys.c. + **/ + +#ifndef TOR_CONFLUX_SYS_H +#define TOR_CONFLUX_SYS_H + +extern const struct subsys_fns_t sys_conflux; + +/** + * Subsystem level. + * + * Defined here so that it can be shared between the real and stub + * definitions. + **/ +#define CONFLUX_SUBSYS_LEVEL (10) + +#endif /* TOR_CONFLUX_SYS_H */ + diff -Nru tor-0.4.7.16/src/core/or/conflux_util.c tor-0.4.9.6/src/core/or/conflux_util.c --- tor-0.4.7.16/src/core/or/conflux_util.c 1970-01-01 00:00:00.000000000 +0000 +++ tor-0.4.9.6/src/core/or/conflux_util.c 2026-03-25 14:30:34.000000000 +0000 @@ -0,0 +1,474 @@ +/* Copyright (c) 2021, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file conflux_util.c + * \brief Conflux utility functions for stream blocking and management. + */ + +#define TOR_CONFLUX_PRIVATE + +#include "core/or/or.h" + +#include "core/or/circuit_st.h" +#include "core/or/sendme.h" +#include "core/or/congestion_control_common.h" +#include "core/or/congestion_control_st.h" +#include "core/or/circuitlist.h" +#include "core/or/origin_circuit_st.h" +#include "core/or/or_circuit_st.h" +#include "core/or/conflux.h" +#include "core/or/conflux_params.h" +#include "core/or/conflux_util.h" +#include "core/or/conflux_pool.h" +#include "core/or/conflux_st.h" +#include "lib/time/compat_time.h" +#include "app/config/config.h" + +/** + * This is a utility function that returns the package window circuit, + * regardless of if it has a conflux pair or not. + */ +int +circuit_get_package_window(circuit_t *circ, + const crypt_path_t *cpath) +{ + /* We believe it is possible to get a closed circuit related to the + * on_circuit pointer of a connection not being nullified before ending up + * here. Else, this can lead to loud bug like experienced in #40908. */ + if (circ->marked_for_close) { + return 0; + } + + if (circ->conflux) { + if (CIRCUIT_IS_ORIGIN(circ)) { + tor_assert_nonfatal(circ->purpose == + CIRCUIT_PURPOSE_CONFLUX_LINKED); + } + circuit_t *orig_circ = circ; + + /* If conflux is in the process of tearing down the set, + * the package window is 0 -- there is no room. */ + if (circ->conflux->in_full_teardown) + return 0; + + circ = conflux_decide_next_circ(circ->conflux); + + /* If conflux has no circuit to send on, the package window is 0. */ + if (!circ) { + /* Bug #40842: Additional diagnostics for other potential cases */ + if (!orig_circ->conflux->curr_leg) { + if (orig_circ->marked_for_close) { + log_warn(LD_BUG, "Conflux has no circuit to send on. " + "Circuit %p idx %d marked at line %s:%d", + orig_circ, orig_circ->global_circuitlist_idx, + orig_circ->marked_for_close_file, + orig_circ->marked_for_close); + } else { + log_warn(LD_BUG, "Conflux has no circuit to send on. " + "Circuit %p idx %d not marked for close.", + orig_circ, orig_circ->global_circuitlist_idx); + } + } + return 0; + } + + /* If we are the origin, we need to get the last hop's cpath for + * congestion control information. */ + if (CIRCUIT_IS_ORIGIN(circ)) { + cpath = CONST_TO_ORIGIN_CIRCUIT(circ)->cpath->prev; + } else { + if (BUG(cpath != NULL)) { + log_warn(LD_BUG, "cpath is not NULL for non-origin circuit"); + } + } + } + + return congestion_control_get_package_window(circ, cpath); +} + +/** + * Returns true if conflux can send a data cell. + * + * Used to decide if we should block streams or not, for + * proccess_sendme_cell(), circuit_resume_edge_reading(), + * circuit_consider_stop_edge_reading(), circuit_resume_edge_reading_helper(), + * channel_flush_from_first_active_circuit() +*/ +bool +conflux_can_send(conflux_t *cfx) +{ + const circuit_t *send_circ = conflux_decide_next_circ(cfx); + + /* If we have a circuit, we can send */ + if (send_circ) { + return true; + } else { + if (BUG(!cfx->in_full_teardown && !cfx->curr_leg)) { + log_fn(LOG_WARN, + LD_BUG, "Conflux has no current circuit to send on. "); + } + return false; + } +} + +/** + * For a given conflux circuit, return the cpath of the destination. + * + * The cpath destination is the last hop of the circuit, or NULL if + * the circuit is a non-origin circuit. + */ +crypt_path_t * +conflux_get_destination_hop(circuit_t *circ) +{ + if (BUG(!circ)) { + log_warn(LD_BUG, "No circuit to send on for conflux"); + return NULL; + } else { + /* Conflux circuits always send multiplexed relay commands to + * to the last hop. (Non-multiplexed commands go on their + * original circuit and hop). */ + if (CIRCUIT_IS_ORIGIN(circ)) { + return TO_ORIGIN_CIRCUIT(circ)->cpath->prev; + } else { + return NULL; + } + } +} + +/** + * Validates that the source of a cell is from the last hop of the circuit + * for origin circuits, and that there are no further hops for non-origin + * circuits. + */ +bool +conflux_validate_source_hop(circuit_t *in_circ, + crypt_path_t *layer_hint) +{ + crypt_path_t *dest = conflux_get_destination_hop(in_circ); + + if (dest != layer_hint) { + log_warn(LD_CIRC, "Got conflux command from incorrect hop"); + return false; + } + + if (layer_hint == NULL) { + /* We should not have further hops attached to this circuit */ + if (in_circ->n_chan) { + log_warn(LD_BUG, "Got conflux command on circuit with further hops"); + return false; + } + } + return true; +} + +/** + * Returns true if the edge connection uses the given cpath. + * + * If there is a conflux object, we inspect all the last hops of the conflux + * circuits. + */ +bool +edge_uses_cpath(const edge_connection_t *conn, + const crypt_path_t *cpath) +{ + if (!conn->on_circuit) + return false; + + if (CIRCUIT_IS_ORIGIN(conn->on_circuit)) { + if (conn->on_circuit->conflux) { + tor_assert_nonfatal(conn->on_circuit->purpose == + CIRCUIT_PURPOSE_CONFLUX_LINKED); + + /* If the circuit is an origin circuit with a conflux object, the cpath + * is valid if it came from any of the conflux circuit's last hops. */ + CONFLUX_FOR_EACH_LEG_BEGIN(conn->on_circuit->conflux, leg) { + const origin_circuit_t *ocirc = CONST_TO_ORIGIN_CIRCUIT(leg->circ); + if (ocirc->cpath->prev == cpath) { + return true; + } + } CONFLUX_FOR_EACH_LEG_END(leg); + } else { + return cpath == conn->cpath_layer; + } + } else { + /* For non-origin circuits, cpath should be null */ + return cpath == NULL; + } + + return false; +} + +/** + * Returns the max RTT for the circuit that carries this stream, + * as observed by congestion control. For conflux circuits, + * we return the max RTT across all circuits. + */ +uint64_t +edge_get_max_rtt(const edge_connection_t *stream) +{ + if (!stream->on_circuit) + return 0; + + if (stream->on_circuit->conflux) { + tor_assert_nonfatal(stream->on_circuit->purpose == + CIRCUIT_PURPOSE_CONFLUX_LINKED); + + /* Find the max rtt from the ccontrol object of each circuit. */ + uint64_t max_rtt = 0; + CONFLUX_FOR_EACH_LEG_BEGIN(stream->on_circuit->conflux, leg) { + const congestion_control_t *cc = circuit_ccontrol(leg->circ); + if (cc->max_rtt_usec > max_rtt) { + max_rtt = cc->max_rtt_usec; + } + } CONFLUX_FOR_EACH_LEG_END(leg); + + return max_rtt; + } else { + if (stream->on_circuit && stream->on_circuit->ccontrol) + return stream->on_circuit->ccontrol->max_rtt_usec; + else if (stream->cpath_layer && stream->cpath_layer->ccontrol) + return stream->cpath_layer->ccontrol->max_rtt_usec; + } + + return 0; +} + +/** + * Return true iff our decryption layer_hint is from the last hop + * in a circuit. + */ +bool +relay_crypt_from_last_hop(const origin_circuit_t *circ, + const crypt_path_t *layer_hint) +{ + tor_assert(circ); + tor_assert(layer_hint); + tor_assert(circ->cpath); + + if (TO_CIRCUIT(circ)->conflux) { + tor_assert_nonfatal(TO_CIRCUIT(circ)->purpose == + CIRCUIT_PURPOSE_CONFLUX_LINKED); + + /* If we are a conflux circuit, we need to check if the layer_hint + * is from the last hop of any of the conflux circuits. */ + CONFLUX_FOR_EACH_LEG_BEGIN(TO_CIRCUIT(circ)->conflux, leg) { + const origin_circuit_t *ocirc = CONST_TO_ORIGIN_CIRCUIT(leg->circ); + if (layer_hint == ocirc->cpath->prev) { + return true; + } + } CONFLUX_FOR_EACH_LEG_END(leg); + + log_fn(LOG_PROTOCOL_WARN, LD_CIRC, + "Got unexpected relay data from intermediate hop"); + return false; + } else { + if (layer_hint != circ->cpath->prev) { + log_fn(LOG_PROTOCOL_WARN, LD_CIRC, + "Got unexpected relay data from intermediate hop"); + return false; + } + return true; + } +} + +/** + * Update the head of the n_streams list on all circuits in the conflux + * set. + */ +void +conflux_update_p_streams(origin_circuit_t *circ, edge_connection_t *stream) +{ + tor_assert(circ); + + if (TO_CIRCUIT(circ)->conflux) { + tor_assert_nonfatal(TO_CIRCUIT(circ)->purpose == + CIRCUIT_PURPOSE_CONFLUX_LINKED); + CONFLUX_FOR_EACH_LEG_BEGIN(TO_CIRCUIT(circ)->conflux, leg) { + TO_ORIGIN_CIRCUIT(leg->circ)->p_streams = stream; + } CONFLUX_FOR_EACH_LEG_END(leg); + } +} + +/** + * Sync the next_stream_id, timestamp_dirty, and circuit_idle_timeout + * fields of a conflux set to the values in a particular circuit. + * + * This is called upon link, and whenever one of these fields + * changes on ref_circ. The ref_circ values are copied to all + * other circuits in the conflux set. +*/ +void +conflux_sync_circ_fields(conflux_t *cfx, origin_circuit_t *ref_circ) +{ + tor_assert(cfx); + tor_assert(ref_circ); + + CONFLUX_FOR_EACH_LEG_BEGIN(cfx, leg) { + if (leg->circ == TO_CIRCUIT(ref_circ)) { + continue; + } + origin_circuit_t *ocirc = TO_ORIGIN_CIRCUIT(leg->circ); + ocirc->next_stream_id = ref_circ->next_stream_id; + leg->circ->timestamp_dirty = TO_CIRCUIT(ref_circ)->timestamp_dirty; + ocirc->circuit_idle_timeout = ref_circ->circuit_idle_timeout; + ocirc->unusable_for_new_conns = ref_circ->unusable_for_new_conns; + } CONFLUX_FOR_EACH_LEG_END(leg); +} + +/** + * Update the head of the n_streams list on all circuits in the conflux + * set. + */ +void +conflux_update_n_streams(or_circuit_t *circ, edge_connection_t *stream) +{ + tor_assert(circ); + + if (TO_CIRCUIT(circ)->conflux) { + CONFLUX_FOR_EACH_LEG_BEGIN(TO_CIRCUIT(circ)->conflux, leg) { + TO_OR_CIRCUIT(leg->circ)->n_streams = stream; + } CONFLUX_FOR_EACH_LEG_END(leg); + } +} + +/** + * Update the head of the resolving_streams list on all circuits in the conflux + * set. + */ +void +conflux_update_resolving_streams(or_circuit_t *circ, edge_connection_t *stream) +{ + tor_assert(circ); + + if (TO_CIRCUIT(circ)->conflux) { + CONFLUX_FOR_EACH_LEG_BEGIN(TO_CIRCUIT(circ)->conflux, leg) { + TO_OR_CIRCUIT(leg->circ)->resolving_streams = stream; + } CONFLUX_FOR_EACH_LEG_END(leg); + } +} + +/** + * Update the half_streams list on all circuits in the conflux + */ +void +conflux_update_half_streams(origin_circuit_t *circ, smartlist_t *half_streams) +{ + tor_assert(circ); + + if (TO_CIRCUIT(circ)->conflux) { + tor_assert_nonfatal(TO_CIRCUIT(circ)->purpose == + CIRCUIT_PURPOSE_CONFLUX_LINKED); + CONFLUX_FOR_EACH_LEG_BEGIN(TO_CIRCUIT(circ)->conflux, leg) { + TO_ORIGIN_CIRCUIT(leg->circ)->half_streams = half_streams; + } CONFLUX_FOR_EACH_LEG_END(leg); + } +} + +/** + * Helper function that emits non-fatal asserts if the stream lists + * or next_stream_id is out of sync between any of the conflux legs. +*/ +void +conflux_validate_stream_lists(const conflux_t *cfx) +{ + const conflux_leg_t *first_leg = smartlist_get(cfx->legs, 0); + tor_assert(first_leg); + + /* Compare the stream lists of the first leg to all other legs. */ + if (CIRCUIT_IS_ORIGIN(first_leg->circ)) { + const origin_circuit_t *f_circ = + CONST_TO_ORIGIN_CIRCUIT(first_leg->circ); + + CONFLUX_FOR_EACH_LEG_BEGIN(cfx, leg) { + const origin_circuit_t *l_circ = CONST_TO_ORIGIN_CIRCUIT(leg->circ); + tor_assert_nonfatal(l_circ->p_streams == f_circ->p_streams); + tor_assert_nonfatal(l_circ->half_streams == f_circ->half_streams); + tor_assert_nonfatal(l_circ->next_stream_id == f_circ->next_stream_id); + } CONFLUX_FOR_EACH_LEG_END(leg); + } else { + const or_circuit_t *f_circ = CONST_TO_OR_CIRCUIT(first_leg->circ); + CONFLUX_FOR_EACH_LEG_BEGIN(cfx, leg) { + const or_circuit_t *l_circ = CONST_TO_OR_CIRCUIT(leg->circ); + tor_assert_nonfatal(l_circ->n_streams == f_circ->n_streams); + tor_assert_nonfatal(l_circ->resolving_streams == + f_circ->resolving_streams); + } CONFLUX_FOR_EACH_LEG_END(leg); + } +} + +/** + * Validate the conflux set has two legs, and both circuits have + * no nonce, and for origin circuits, the purpose is CONFLUX_PURPOSE_LINKED. + */ +void +conflux_validate_legs(const conflux_t *cfx) +{ + tor_assert(cfx); + bool is_client = false; + int num_legs = 0; + CONFLUX_FOR_EACH_LEG_BEGIN(cfx, leg) { + if (CIRCUIT_IS_ORIGIN(leg->circ)) { + tor_assert_nonfatal(leg->circ->purpose == + CIRCUIT_PURPOSE_CONFLUX_LINKED); + is_client = true; + } + + /* Ensure we have no pending nonce on the circ */ + if (BUG(leg->circ->conflux_pending_nonce != NULL)) { + conflux_log_set(LOG_WARN, cfx, is_client); + continue; + } + + /* Ensure we have a conflux object */ + if (BUG(leg->circ->conflux == NULL)) { + conflux_log_set(LOG_WARN, cfx, is_client); + continue; + } + + /* Only count legs that have a valid RTT */ + if (leg->circ_rtts_usec > 0) { + num_legs++; + } + } CONFLUX_FOR_EACH_LEG_END(leg); + + // TODO-329-UDP: Eventually we want to allow three legs for the + // exit case, to allow reconnection of legs to hit an RTT target. + // For now, this validation helps find bugs. + if (num_legs > conflux_params_get_num_legs_set()) { + log_fn(LOG_PROTOCOL_WARN, + LD_BUG, "Number of legs is above maximum of %d allowed: %d\n", + conflux_params_get_num_legs_set(), smartlist_len(cfx->legs)); + conflux_log_set(LOG_PROTOCOL_WARN, cfx, is_client); + } +} + +/** Return the nonce for a circuit, for use on the control port */ +const uint8_t * +conflux_get_nonce(const circuit_t *circ) +{ + if (circ->conflux_pending_nonce) { + return circ->conflux_pending_nonce; + } else if (circ->conflux) { + return circ->conflux->nonce; + } else { + return NULL; + } +} + +/** Return the conflux RTT for a circuit, for use on the control port */ +uint64_t +conflux_get_circ_rtt(const circuit_t *circ) +{ + if (circ->conflux) { + conflux_leg_t *leg = conflux_get_leg(circ->conflux, circ); + if (BUG(!leg)) { + return 0; + } else { + return leg->circ_rtts_usec; + } + } else { + return 0; + } +} + diff -Nru tor-0.4.7.16/src/core/or/conflux_util.h tor-0.4.9.6/src/core/or/conflux_util.h --- tor-0.4.7.16/src/core/or/conflux_util.h 1970-01-01 00:00:00.000000000 +0000 +++ tor-0.4.9.6/src/core/or/conflux_util.h 2026-03-25 14:30:34.000000000 +0000 @@ -0,0 +1,62 @@ +/* Copyright (c) 2023, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file conflux_util.h + * \brief Header file for conflux_util.c. + **/ + +#ifndef TOR_CONFLUX_UTIL_H +#define TOR_CONFLUX_UTIL_H + +/* Forward decls */ +typedef struct edge_connection_t edge_connection_t; +typedef struct crypt_path_t crypt_path_t; +typedef struct origin_circuit_t origin_circuit_t; +typedef struct conflux_t conflux_t; + +/* True iff the given circuit_t circ is conflux related. */ +static inline bool +CIRCUIT_IS_CONFLUX(const circuit_t *circ) +{ + if (circ->conflux_pending_nonce) { + if (CIRCUIT_IS_ORIGIN(circ)) + tor_assert_nonfatal(circ->purpose == CIRCUIT_PURPOSE_CONFLUX_UNLINKED); + return true; + } else if (circ->conflux) { + if (CIRCUIT_IS_ORIGIN(circ)) + tor_assert_nonfatal(circ->purpose == CIRCUIT_PURPOSE_CONFLUX_LINKED); + return true; + } else { + tor_assert_nonfatal(circ->purpose != CIRCUIT_PURPOSE_CONFLUX_LINKED); + tor_assert_nonfatal(circ->purpose != CIRCUIT_PURPOSE_CONFLUX_UNLINKED); + return false; + } +} + +const uint8_t *conflux_get_nonce(const circuit_t *circ); +uint64_t conflux_get_circ_rtt(const circuit_t *circ); + +int circuit_get_package_window(circuit_t *circ, + const crypt_path_t *cpath); +bool conflux_can_send(conflux_t *cfx); + +bool edge_uses_cpath(const edge_connection_t *conn, + const crypt_path_t *cpath); +crypt_path_t *conflux_get_destination_hop(circuit_t *circ); +bool conflux_validate_source_hop(circuit_t *in_circ, + crypt_path_t *layer_hint); +uint64_t edge_get_max_rtt(const edge_connection_t *stream); +bool relay_crypt_from_last_hop(const origin_circuit_t *circ, + const crypt_path_t *layer_hint); + +void conflux_update_p_streams(origin_circuit_t *, edge_connection_t *); +void conflux_update_half_streams(origin_circuit_t *, smartlist_t *); +void conflux_update_n_streams(or_circuit_t *, edge_connection_t *); +void conflux_update_resolving_streams(or_circuit_t *, edge_connection_t *); +void conflux_sync_circ_fields(conflux_t *cfx, origin_circuit_t *ref_circ); +void conflux_validate_stream_lists(const conflux_t *cfx); +void conflux_validate_legs(const conflux_t *cfx); + +#endif /* TOR_CONFLUX_UTIL_H */ + diff -Nru tor-0.4.7.16/src/core/or/congestion_control_common.c tor-0.4.9.6/src/core/or/congestion_control_common.c --- tor-0.4.7.16/src/core/or/congestion_control_common.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/core/or/congestion_control_common.c 2026-03-25 14:30:34.000000000 +0000 @@ -7,6 +7,7 @@ */ #define TOR_CONGESTION_CONTROL_COMMON_PRIVATE +#define TOR_CONGESTION_CONTROL_PRIVATE #include "core/or/or.h" @@ -18,11 +19,12 @@ #include "core/or/channel.h" #include "core/mainloop/connection.h" #include "core/or/sendme.h" +#include "core/or/congestion_control_st.h" #include "core/or/congestion_control_common.h" #include "core/or/congestion_control_vegas.h" -#include "core/or/congestion_control_nola.h" -#include "core/or/congestion_control_westwood.h" #include "core/or/congestion_control_st.h" +#include "core/or/conflux.h" +#include "core/or/conflux_util.h" #include "core/or/trace_probes_cc.h" #include "lib/time/compat_time.h" #include "feature/nodelist/networkstatus.h" @@ -38,14 +40,14 @@ #define SENDME_INC_DFLT (TLS_RECORD_MAX_CELLS) #define CIRCWINDOW_INIT (4*SENDME_INC_DFLT) -#define CC_ALG_DFLT (CC_ALG_SENDME) +#define CC_ALG_DFLT (CC_ALG_VEGAS) #define CC_ALG_DFLT_ALWAYS (CC_ALG_VEGAS) -#define CWND_INC_DFLT (TLS_RECORD_MAX_CELLS) +#define CWND_INC_DFLT (1) #define CWND_INC_PCT_SS_DFLT (100) -#define CWND_INC_RATE_DFLT (1) +#define CWND_INC_RATE_DFLT (SENDME_INC_DFLT) -#define CWND_MIN_DFLT (2*SENDME_INC_DFLT) +#define CWND_MIN_DFLT (CIRCWINDOW_INIT) #define CWND_MAX_DFLT (INT32_MAX) #define BWE_SENDME_MIN_DFLT (5) @@ -82,15 +84,9 @@ #define CELL_QUEUE_LOW_DFLT (10) #define CELL_QUEUE_HIGH_DFLT (256) -static uint64_t congestion_control_update_circuit_rtt(congestion_control_t *, - uint64_t); static bool congestion_control_update_circuit_bdp(congestion_control_t *, const circuit_t *, - const crypt_path_t *, - uint64_t, uint64_t); -/* For unit tests */ -void congestion_control_set_cc_enabled(void); - + uint64_t); /* Number of times the RTT value was reset. For MetricsPort. */ static uint64_t num_rtt_reset; @@ -104,33 +100,33 @@ uint32_t or_conn_highwater = OR_CONN_HIGHWATER_DFLT; uint32_t or_conn_lowwater = OR_CONN_LOWWATER_DFLT; uint8_t cc_sendme_inc = SENDME_INC_DFLT; -static cc_alg_t cc_alg = CC_ALG_DFLT; +STATIC cc_alg_t cc_alg = CC_ALG_DFLT; /** * Number of cwnd worth of sendme acks to smooth RTT and BDP with, * using N_EWMA */ -static uint8_t n_ewma_cwnd_pct; +static uint8_t n_ewma_cwnd_pct = N_EWMA_CWND_PCT_DFLT; /** * Maximum number N for the N-count EWMA averaging of RTT and BDP. */ -static uint8_t n_ewma_max; +static uint8_t n_ewma_max = N_EWMA_MAX_DFLT; /** * Maximum number N for the N-count EWMA averaging of RTT in Slow Start. */ -static uint8_t n_ewma_ss; +static uint8_t n_ewma_ss = N_EWMA_SS_DFLT; /** * Minimum number of sendmes before we begin BDP estimates */ -static uint8_t bwe_sendme_min; +static uint8_t bwe_sendme_min = BWE_SENDME_MIN_DFLT; /** - * Percentage of the current RTT to use when reseting the minimum RTT + * Percentage of the current RTT to use when resetting the minimum RTT * for a circuit. (RTT is reset when the cwnd hits cwnd_min). */ -static uint8_t rtt_reset_pct; +static uint8_t rtt_reset_pct = RTT_RESET_PCT_DFLT; /** Metric to count the number of congestion control circuits **/ uint64_t cc_stats_circs_created = 0; @@ -203,7 +199,7 @@ RTT_RESET_PCT_MAX); #define SENDME_INC_MIN 1 -#define SENDME_INC_MAX (255) +#define SENDME_INC_MAX (254) cc_sendme_inc = networkstatus_get_param(NULL, "cc_sendme_inc", SENDME_INC_DFLT, @@ -217,6 +213,13 @@ CC_ALG_DFLT, CC_ALG_MIN, CC_ALG_MAX); + if (cc_alg != CC_ALG_SENDME && cc_alg != CC_ALG_VEGAS) { + // Does not need rate limiting because consensus updates + // are at most 1x/hour + log_warn(LD_BUG, "Unsupported congestion control algorithm %d", + cc_alg); + cc_alg = CC_ALG_DFLT; + } #define BWE_SENDME_MIN_MIN 2 #define BWE_SENDME_MIN_MAX (20) @@ -317,37 +320,13 @@ cc->cc_alg = cc_alg; } - bdp_alg_t default_bdp_alg = 0; - - switch (cc->cc_alg) { - case CC_ALG_WESTWOOD: - default_bdp_alg = WESTWOOD_BDP_ALG; - break; - case CC_ALG_VEGAS: - default_bdp_alg = VEGAS_BDP_MIX_ALG; - break; - case CC_ALG_NOLA: - default_bdp_alg = NOLA_BDP_ALG; - break; - case CC_ALG_SENDME: - default: - tor_fragile_assert(); - return; // No alg-specific params - } - - cc->bdp_alg = - networkstatus_get_param(NULL, "cc_bdp_alg", - default_bdp_alg, - 0, - NUM_BDP_ALGS-1); - /* Algorithm-specific parameters */ - if (cc->cc_alg == CC_ALG_WESTWOOD) { - congestion_control_westwood_set_params(cc); - } else if (cc->cc_alg == CC_ALG_VEGAS) { + if (cc->cc_alg == CC_ALG_VEGAS) { congestion_control_vegas_set_params(cc, path); - } else if (cc->cc_alg == CC_ALG_NOLA) { - congestion_control_nola_set_params(cc); + } else { + // This should not happen anymore + log_warn(LD_BUG, "Unknown congestion control algorithm %d", + cc->cc_alg); } } @@ -385,6 +364,7 @@ return cc_alg != CC_ALG_SENDME; } +#ifdef TOR_UNIT_TESTS /** * For unit tests only: set the cached consensus cc alg to * specified value. @@ -396,6 +376,17 @@ } /** + * For unit tests only: set the cached consensus cc alg to + * specified value. + */ +void +congestion_control_set_cc_disabled(void) +{ + cc_alg = CC_ALG_SENDME; +} +#endif + +/** * Allocate and initialize fields in congestion control object. * * cc_alg is the negotiated congestion control algorithm. @@ -409,7 +400,6 @@ cc_path_t path) { cc->sendme_pending_timestamps = smartlist_new(); - cc->sendme_arrival_timestamps = smartlist_new(); cc->in_slow_start = 1; congestion_control_init_params(cc, params, path); @@ -440,9 +430,7 @@ return; SMARTLIST_FOREACH(cc->sendme_pending_timestamps, uint64_t *, t, tor_free(t)); - SMARTLIST_FOREACH(cc->sendme_arrival_timestamps, uint64_t *, t, tor_free(t)); smartlist_free(cc->sendme_pending_timestamps); - smartlist_free(cc->sendme_arrival_timestamps); tor_free(cc); } @@ -450,7 +438,7 @@ /** * Enqueue a u64 timestamp to the end of a queue of timestamps. */ -static inline void +STATIC inline void enqueue_timestamp(smartlist_t *timestamps_u64, uint64_t timestamp_usec) { uint64_t *timestamp_ptr = tor_malloc(sizeof(uint64_t)); @@ -460,22 +448,6 @@ } /** - * Peek at the head of a smartlist queue of u64 timestamps. - */ -static inline uint64_t -peek_timestamp(const smartlist_t *timestamps_u64_usecs) -{ - uint64_t *timestamp_ptr = smartlist_get(timestamps_u64_usecs, 0); - - if (BUG(!timestamp_ptr)) { - log_err(LD_CIRC, "Congestion control timestamp list became empty!"); - return 0; - } - - return *timestamp_ptr; -} - -/** * Dequeue a u64 monotime usec timestamp from the front of a * smartlist of pointers to 64. */ @@ -679,61 +651,6 @@ } /** - * Returns true if any edge connections are active. - * - * We need to know this so that we can stop computing BDP if the - * edges are not sending on the circuit. - */ -static int -circuit_has_active_streams(const circuit_t *circ, - const crypt_path_t *layer_hint) -{ - const edge_connection_t *streams; - - if (CIRCUIT_IS_ORIGIN(circ)) { - streams = CONST_TO_ORIGIN_CIRCUIT(circ)->p_streams; - } else { - streams = CONST_TO_OR_CIRCUIT(circ)->n_streams; - } - - /* Check linked list of streams */ - for (const edge_connection_t *conn = streams; conn != NULL; - conn = conn->next_stream) { - if (conn->base_.marked_for_close) - continue; - - if (!layer_hint || conn->cpath_layer == layer_hint) { - if (connection_get_inbuf_len(TO_CONN(conn)) > 0) { - log_info(LD_CIRC, "CC: More in edge inbuf..."); - return 1; - } - - /* If we did not reach EOF on this read, there's more */ - if (!TO_CONN(conn)->inbuf_reached_eof) { - log_info(LD_CIRC, "CC: More on edge conn..."); - return 1; - } - - if (TO_CONN(conn)->linked_conn) { - if (connection_get_inbuf_len(TO_CONN(conn)->linked_conn) > 0) { - log_info(LD_CIRC, "CC: More in linked inbuf..."); - return 1; - } - - /* If there is a linked conn, and *it* did not each EOF, - * there's more */ - if (!TO_CONN(conn)->linked_conn->inbuf_reached_eof) { - log_info(LD_CIRC, "CC: More on linked conn..."); - return 1; - } - } - } - } - - return 0; -} - -/** * Upon receipt of a SENDME, pop the oldest timestamp off the timestamp * list, and use this to update RTT. * @@ -742,15 +659,13 @@ */ bool congestion_control_update_circuit_estimates(congestion_control_t *cc, - const circuit_t *circ, - const crypt_path_t *layer_hint) + const circuit_t *circ) { uint64_t now_usec = monotime_absolute_usec(); /* Update RTT first, then BDP. BDP needs fresh RTT */ uint64_t curr_rtt_usec = congestion_control_update_circuit_rtt(cc, now_usec); - return congestion_control_update_circuit_bdp(cc, circ, layer_hint, now_usec, - curr_rtt_usec); + return congestion_control_update_circuit_bdp(cc, circ, curr_rtt_usec); } /** @@ -766,18 +681,11 @@ return true; } - /* If we managed to get enough acks to estimate a SENDME BDP, then - * we have enough to estimate clock jumps relative to a baseline, - * too. (This is at least 'cc_bwe_min' acks). */ - if (cc->bdp[BDP_ALG_SENDME_RATE]) { - return true; - } - /* Not enough data to estimate clock jumps */ return false; } -static bool is_monotime_clock_broken = false; +STATIC bool is_monotime_clock_broken = false; /** * Returns true if the monotime delta is 0, or is significantly @@ -788,7 +696,7 @@ * so we can also provide a is_monotime_clock_reliable() function, * used by flow control rate timing. */ -static bool +STATIC bool time_delta_stalled_or_jumped(const congestion_control_t *cc, uint64_t old_delta, uint64_t new_delta) { @@ -870,7 +778,7 @@ * Returns the current circuit RTT in usecs, or 0 if it could not be * measured (due to clock jump, stall, etc). */ -static uint64_t +STATIC uint64_t congestion_control_update_circuit_rtt(congestion_control_t *cc, uint64_t now_usec) { @@ -939,25 +847,21 @@ static bool congestion_control_update_circuit_bdp(congestion_control_t *cc, const circuit_t *circ, - const crypt_path_t *layer_hint, - uint64_t now_usec, uint64_t curr_rtt_usec) { int chan_q = 0; unsigned int blocked_on_chan = 0; - uint64_t timestamp_usec; - uint64_t sendme_rate_bdp = 0; tor_assert(cc); if (CIRCUIT_IS_ORIGIN(circ)) { /* origin circs use n_chan */ chan_q = circ->n_chan_cells.n; - blocked_on_chan = circ->streams_blocked_on_n_chan; + blocked_on_chan = circ->circuit_blocked_on_n_chan; } else { /* Both onion services and exits use or_circuit and p_chan */ chan_q = CONST_TO_OR_CIRCUIT(circ)->p_chan_cells.n; - blocked_on_chan = circ->streams_blocked_on_p_chan; + blocked_on_chan = circ->circuit_blocked_on_p_chan; } /* If we have no EWMA RTT, it is because monotime has been stalled @@ -984,10 +888,7 @@ cc->blocked_chan = 0; } - cc->bdp[BDP_ALG_CWND_RTT] = cwnd; - cc->bdp[BDP_ALG_INFLIGHT_RTT] = cwnd; - cc->bdp[BDP_ALG_SENDME_RATE] = cwnd; - cc->bdp[BDP_ALG_PIECEWISE] = cwnd; + cc->bdp = cwnd; static ratelim_t dec_notice_limit = RATELIM_INIT(300); log_fn_ratelim(&dec_notice_limit, LOG_NOTICE, LD_CIRC, @@ -1006,84 +907,7 @@ * close to ewma RTT. Since all fields are u64, there is plenty of * room here to multiply first. */ - cc->bdp[BDP_ALG_CWND_RTT] = cc->cwnd*cc->min_rtt_usec/cc->ewma_rtt_usec; - - /* - * If we have no pending streams, we do not have enough data to fill - * the BDP, so preserve our old estimates but do not make any more. - */ - if (!blocked_on_chan && !circuit_has_active_streams(circ, layer_hint)) { - log_info(LD_CIRC, - "CC: Streams drained. Spare package window: %"PRIu64 - ", no BDP update", cc->cwnd - cc->inflight); - - /* Clear SENDME timestamps; they will be wrong with intermittent data */ - SMARTLIST_FOREACH(cc->sendme_arrival_timestamps, uint64_t *, t, - tor_free(t)); - smartlist_clear(cc->sendme_arrival_timestamps); - } else if (curr_rtt_usec && is_monotime_clock_reliable()) { - /* Sendme-based BDP will quickly measure BDP in much less than - * a cwnd worth of data when in use (in 2-10 SENDMEs). - * - * But if the link goes idle, it will be vastly lower than true BDP. Hence - * we only compute it if we have either pending stream data, or streams - * are still blocked on the channel queued data. - * - * We also do not compute it if we do not have a current RTT passed in, - * because that means that monotime is currently stalled or just jumped. - */ - enqueue_timestamp(cc->sendme_arrival_timestamps, now_usec); - - if (smartlist_len(cc->sendme_arrival_timestamps) >= bwe_sendme_min) { - /* If we have more sendmes than fit in a cwnd, trim the list. - * Those are not acurrately measuring throughput, if cwnd is - * currently smaller than BDP */ - while (smartlist_len(cc->sendme_arrival_timestamps) > - bwe_sendme_min && - (uint64_t)smartlist_len(cc->sendme_arrival_timestamps) > - n_ewma_count(cc)) { - (void)dequeue_timestamp(cc->sendme_arrival_timestamps); - } - int sendme_cnt = smartlist_len(cc->sendme_arrival_timestamps); - - /* Calculate SENDME_BWE_COUNT pure average */ - timestamp_usec = peek_timestamp(cc->sendme_arrival_timestamps); - uint64_t delta = now_usec - timestamp_usec; - - /* In Shadow, the time delta between acks can be 0 if there is no - * network activity between them. Only update BDP if the delta is - * non-zero. */ - if (delta > 0) { - /* The acked data is in sendme_cnt-1 chunks, because we are counting - * the data that is processed by the other endpoint *between* all of - * these sendmes. There's one less gap between the sendmes than the - * number of sendmes. */ - uint64_t cells = (sendme_cnt-1)*cc->sendme_inc; - - /* The bandwidth estimate is cells/delta, which when multiplied - * by min RTT obtains the BDP. However, we multiply first to - * avoid precision issues with the RTT being close to delta in size. */ - sendme_rate_bdp = cells*cc->min_rtt_usec/delta; - - /* Calculate BDP_EWMA_COUNT N-EWMA */ - cc->bdp[BDP_ALG_SENDME_RATE] = - n_count_ewma(sendme_rate_bdp, cc->bdp[BDP_ALG_SENDME_RATE], - n_ewma_count(cc)); - } - } - - /* In-flight BDP will cause the cwnd to drift down when underutilized. - * It is most useful when the local OR conn is blocked, so we only - * compute it if we're utilized. */ - cc->bdp[BDP_ALG_INFLIGHT_RTT] = - (cc->inflight - chan_q)*cc->min_rtt_usec/ - MAX(cc->ewma_rtt_usec, curr_rtt_usec); - } else { - /* We can still update inflight with just an EWMA RTT, but only - * if there is data flowing */ - cc->bdp[BDP_ALG_INFLIGHT_RTT] = - (cc->inflight - chan_q)*cc->min_rtt_usec/cc->ewma_rtt_usec; - } + cc->bdp = cc->cwnd*cc->min_rtt_usec/cc->ewma_rtt_usec; /* The orconn is blocked; use smaller of inflight vs SENDME */ if (blocked_on_chan) { @@ -1096,13 +920,6 @@ cc->next_cc_event = 0; cc->blocked_chan = 1; } - - if (cc->bdp[BDP_ALG_SENDME_RATE]) { - cc->bdp[BDP_ALG_PIECEWISE] = MIN(cc->bdp[BDP_ALG_INFLIGHT_RTT], - cc->bdp[BDP_ALG_SENDME_RATE]); - } else { - cc->bdp[BDP_ALG_PIECEWISE] = cc->bdp[BDP_ALG_INFLIGHT_RTT]; - } } else { /* If we were previously blocked, emit a new congestion event * now that we are unblocked, to re-evaluate cwnd */ @@ -1112,19 +929,6 @@ log_info(LD_CIRC, "CC: Streams un-blocked on circ channel. Chanq: %d", chan_q); } - - cc->bdp[BDP_ALG_PIECEWISE] = MAX(cc->bdp[BDP_ALG_SENDME_RATE], - cc->bdp[BDP_ALG_CWND_RTT]); - } - - /* We can end up with no piecewise value if we didn't have either - * a SENDME estimate or enough data for an inflight estimate. - * It also happens on the very first sendme, since we need two - * to get a BDP. In these cases, use the cwnd method. */ - if (!cc->bdp[BDP_ALG_PIECEWISE]) { - cc->bdp[BDP_ALG_PIECEWISE] = cc->bdp[BDP_ALG_CWND_RTT]; - log_info(LD_CIRC, "CC: No piecewise BDP. Using %"PRIu64, - cc->bdp[BDP_ALG_PIECEWISE]); } if (cc->next_cc_event == 0) { @@ -1132,44 +936,25 @@ log_info(LD_CIRC, "CC: Circuit %d " "SENDME RTT: %"PRIu64", %"PRIu64", %"PRIu64", %"PRIu64", " - "BDP estimates: " - "%"PRIu64", " - "%"PRIu64", " - "%"PRIu64", " - "%"PRIu64", " - "%"PRIu64". ", + "BDP estimate: %"PRIu64, CONST_TO_ORIGIN_CIRCUIT(circ)->global_identifier, cc->min_rtt_usec/1000, curr_rtt_usec/1000, cc->ewma_rtt_usec/1000, cc->max_rtt_usec/1000, - cc->bdp[BDP_ALG_INFLIGHT_RTT], - cc->bdp[BDP_ALG_CWND_RTT], - sendme_rate_bdp, - cc->bdp[BDP_ALG_SENDME_RATE], - cc->bdp[BDP_ALG_PIECEWISE] - ); + cc->bdp); } else { log_info(LD_CIRC, "CC: Circuit %"PRIu64":%d " "SENDME RTT: %"PRIu64", %"PRIu64", %"PRIu64", %"PRIu64", " - "%"PRIu64", " - "%"PRIu64", " - "%"PRIu64", " - "%"PRIu64", " - "%"PRIu64". ", + "%"PRIu64, CONST_TO_OR_CIRCUIT(circ)->p_chan->global_identifier, CONST_TO_OR_CIRCUIT(circ)->p_circ_id, cc->min_rtt_usec/1000, curr_rtt_usec/1000, cc->ewma_rtt_usec/1000, cc->max_rtt_usec/1000, - cc->bdp[BDP_ALG_INFLIGHT_RTT], - cc->bdp[BDP_ALG_CWND_RTT], - sendme_rate_bdp, - cc->bdp[BDP_ALG_SENDME_RATE], - cc->bdp[BDP_ALG_PIECEWISE] - ); + cc->bdp); } } @@ -1177,8 +962,7 @@ * the curr_rtt_usec was not 0. */ bool ret = (blocked_on_chan || curr_rtt_usec != 0); if (ret) { - tor_trace(TR_SUBSYS(cc), TR_EV(bdp_update), circ, cc, curr_rtt_usec, - sendme_rate_bdp); + tor_trace(TR_SUBSYS(cc), TR_EV(bdp_update), circ, cc, curr_rtt_usec); } return ret; } @@ -1188,27 +972,12 @@ */ int congestion_control_dispatch_cc_alg(congestion_control_t *cc, - const circuit_t *circ, - const crypt_path_t *layer_hint) + circuit_t *circ) { int ret = -END_CIRC_REASON_INTERNAL; - switch (cc->cc_alg) { - case CC_ALG_WESTWOOD: - ret = congestion_control_westwood_process_sendme(cc, circ, layer_hint); - break; - - case CC_ALG_VEGAS: - ret = congestion_control_vegas_process_sendme(cc, circ, layer_hint); - break; - - case CC_ALG_NOLA: - ret = congestion_control_nola_process_sendme(cc, circ, layer_hint); - break; - - case CC_ALG_SENDME: - default: - tor_assert(0); - } + + tor_assert_nonfatal_once(cc->cc_alg == CC_ALG_VEGAS); + ret = congestion_control_vegas_process_sendme(cc, circ); if (cc->cwnd > cwnd_max) { static ratelim_t cwnd_limit = RATELIM_INIT(60); @@ -1218,6 +987,10 @@ cc->cwnd = cwnd_max; } + /* If we have a non-zero RTT measurement, update conflux. */ + if (circ->conflux && cc->ewma_rtt_usec) + conflux_update_rtt(circ->conflux, circ, cc->ewma_rtt_usec); + return ret; } @@ -1225,26 +998,18 @@ * Build an extension field request to negotiate congestion control. * * If congestion control is enabled, field TRUNNEL_EXT_TYPE_CC_FIELD_REQUEST - * is created in msg_out. It is a single 0-length field that signifies that we - * want to use congestion control. The length of msg_out is provided via - * msg_len_out. + * added to ext. It is a single 0-length field that signifies that we + * want to use congestion control. * - * If congestion control is not enabled, a payload with 0 extensions is created - * and returned. + * If congestion control is not enabled, no extension is added. * * If there is a failure building the request, -1 is returned, else 0. - * - * *msg_out must be freed if the return value is 0. */ int -congestion_control_build_ext_request(uint8_t **msg_out, size_t *msg_len_out) +congestion_control_build_ext_request(trn_extension_t *ext) { - uint8_t *request = NULL; - trn_extension_t *ext = NULL; trn_extension_field_t *field = NULL; - ext = trn_extension_new(); - /* With congestion control enabled, add the request, else it is an empty * request in the payload. */ @@ -1259,30 +1024,9 @@ /* Build final extension. */ trn_extension_add_fields(ext, field); - trn_extension_set_num(ext, 1); - } - - /* Encode extension. */ - ssize_t ret = trn_extension_encoded_len(ext); - if (BUG(ret < 0)) { - goto err; } - size_t request_len = ret; - request = tor_malloc_zero(request_len); - ret = trn_extension_encode(request, request_len, ext); - if (BUG(ret < 0)) { - tor_free(request); - goto err; - } - *msg_out = request; - *msg_len_out = request_len; - /* Free everything, we've encoded the request now. */ - ret = 0; - - err: - trn_extension_free(ext); - return (int)ret; + return 0; } /** @@ -1296,44 +1040,19 @@ * WARNING: Called from CPU worker! Must not access any global state. */ int -congestion_control_parse_ext_request(const uint8_t *msg, const size_t msg_len) +congestion_control_parse_ext_request(const trn_extension_t *ext) { ssize_t ret = 0; - trn_extension_t *ext = NULL; - size_t num_fields = 0; - /* Parse extension from payload. */ - ret = trn_extension_parse(&ext, msg, msg_len); - if (ret < 0) { - goto end; - } - - /* No extension implies no support for congestion control. In this case, we - * simply return 0 to indicate CC is disabled. */ - if ((num_fields = trn_extension_get_num(ext)) == 0) { + if (trn_extension_find(ext, TRUNNEL_EXT_TYPE_CC_FIELD_REQUEST) == NULL) { + /* No extension implies no support for congestion control. In this case, we + * simply return 0 to indicate CC is disabled. */ ret = 0; - goto end; - } - - /* Go over all fields. If any field is TRUNNEL_EXT_TYPE_CC_FIELD_REQUEST, - * then congestion control is enabled. Ignore unknown fields. */ - for (size_t f = 0; f < num_fields; f++) { - const trn_extension_field_t *field = trn_extension_get_fields(ext, f); - if (field == NULL) { - ret = -1; - goto end; - } - + } else { /* For congestion control to be enabled, we only need the field type. */ - if (trn_extension_field_get_field_type(field) == - TRUNNEL_EXT_TYPE_CC_FIELD_REQUEST) { - ret = 1; - break; - } + ret = 1; } - end: - trn_extension_free(ext); return (int)ret; } @@ -1437,19 +1156,16 @@ congestion_control_validate_sendme_increment(uint8_t sendme_inc) { /* We will only accept this response (and this circuit) if sendme_inc - * is within a factor of 2 of our consensus value. We should not need + * is within +/- 1 of the current consensus value. We should not need * to change cc_sendme_inc much, and if we do, we can spread out those * changes over smaller increments once every 4 hours. Exits that * violate this range should just not be used. */ -#define MAX_SENDME_INC_NEGOTIATE_FACTOR 2 if (sendme_inc == 0) return false; - if (sendme_inc > - MAX_SENDME_INC_NEGOTIATE_FACTOR * congestion_control_sendme_inc() || - sendme_inc < - congestion_control_sendme_inc() / MAX_SENDME_INC_NEGOTIATE_FACTOR) { + if (sendme_inc > (congestion_control_sendme_inc() + 1) || + sendme_inc < (congestion_control_sendme_inc() - 1)) { return false; } return true; @@ -1458,13 +1174,11 @@ /** Return 1 if CC is enabled which also will set the SENDME increment into our * params_out. Return 0 if CC is disabled. Else, return -1 on error. */ int -congestion_control_parse_ext_response(const uint8_t *msg, - const size_t msg_len, +congestion_control_parse_ext_response(const trn_extension_t *ext, circuit_params_t *params_out) { ssize_t ret = 0; - size_t num_fields = 0; - trn_extension_t *ext = NULL; + const trn_extension_field_t *field = NULL; trn_extension_field_cc_t *cc_field = NULL; /* We will only accept this response (and this circuit) if sendme_inc @@ -1474,30 +1188,11 @@ * violate this range should just not be used. */ #define MAX_SENDME_INC_NEGOTIATE_FACTOR 2 - /* Parse extension from payload. */ - ret = trn_extension_parse(&ext, msg, msg_len); - if (ret < 0) { - goto end; - } + field = trn_extension_find(ext, TRUNNEL_EXT_TYPE_CC_FIELD_RESPONSE); - if ((num_fields = trn_extension_get_num(ext)) == 0) { + if (field == 0) { ret = 0; - goto end; - } - - /* Go over all fields. If any field is TRUNNEL_EXT_TYPE_CC_FIELD_RESPONSE, - * then congestion control is enabled. Ignore unknown fields. */ - for (size_t f = 0; f < num_fields; f++) { - const trn_extension_field_t *field = trn_extension_get_fields(ext, f); - if (field == NULL) { - ret = -1; - goto end; - } - - /* Only examine TRUNNEL_EXT_TYPE_CC_FIELD_RESPONSE; ignore other fields */ - if (trn_extension_field_get_field_type(field) == - TRUNNEL_EXT_TYPE_CC_FIELD_RESPONSE) { - + } else { /* Parse the field into the congestion control field. */ ret = trn_extension_field_cc_parse(&cc_field, trn_extension_field_getconstarray_field(field), @@ -1516,12 +1211,9 @@ /* All good. Get value and break */ params_out->sendme_inc_cells = sendme_inc_cells; ret = 1; - break; - } } end: - trn_extension_free(ext); trn_extension_field_cc_free(cc_field); return (int)ret; diff -Nru tor-0.4.7.16/src/core/or/congestion_control_common.h tor-0.4.9.6/src/core/or/congestion_control_common.h --- tor-0.4.7.16/src/core/or/congestion_control_common.h 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/core/or/congestion_control_common.h 2026-03-25 14:30:34.000000000 +0000 @@ -46,16 +46,14 @@ cc_path_t path); int congestion_control_dispatch_cc_alg(congestion_control_t *cc, - const circuit_t *circ, - const crypt_path_t *layer_hint); + circuit_t *circ); void congestion_control_note_cell_sent(congestion_control_t *cc, const circuit_t *circ, const crypt_path_t *cpath); bool congestion_control_update_circuit_estimates(congestion_control_t *, - const circuit_t *, - const crypt_path_t *); + const circuit_t *); int congestion_control_get_package_window(const circuit_t *, const crypt_path_t *); @@ -68,16 +66,15 @@ bool congestion_control_enabled(void); -int congestion_control_build_ext_request(uint8_t **msg_out, - size_t *msg_len_out); -int congestion_control_parse_ext_request(const uint8_t *msg, - const size_t msg_len); +struct trn_extension_st; +int congestion_control_build_ext_request(struct trn_extension_st *ext); + +int congestion_control_parse_ext_request(const struct trn_extension_st *ext); int congestion_control_build_ext_response(const circuit_params_t *our_params, const circuit_params_t *circ_params, uint8_t **msg_out, size_t *msg_len_out); -int congestion_control_parse_ext_response(const uint8_t *msg, - const size_t msg_len, +int congestion_control_parse_ext_response(const struct trn_extension_st *ext, circuit_params_t *params_out); bool congestion_control_validate_sendme_increment(uint8_t sendme_inc); char *congestion_control_get_control_port_fields(const origin_circuit_t *); @@ -174,14 +171,25 @@ } /* Private section starts. */ -#ifdef TOR_CONGESTION_CONTROL_PRIVATE +#ifdef TOR_CONGESTION_CONTROL_COMMON_PRIVATE +STATIC uint64_t congestion_control_update_circuit_rtt(congestion_control_t *, + uint64_t); + +STATIC bool time_delta_stalled_or_jumped(const congestion_control_t *cc, + uint64_t old_delta, uint64_t new_delta); + +STATIC void enqueue_timestamp(smartlist_t *timestamps_u64, + uint64_t timestamp_usec); /* * Unit tests declaractions. */ #ifdef TOR_UNIT_TESTS +extern bool is_monotime_clock_broken; +extern cc_alg_t cc_alg; void congestion_control_set_cc_enabled(void); +void congestion_control_set_cc_disabled(void); #endif /* defined(TOR_UNIT_TESTS) */ diff -Nru tor-0.4.7.16/src/core/or/congestion_control_flow.c tor-0.4.9.6/src/core/or/congestion_control_flow.c --- tor-0.4.7.16/src/core/or/congestion_control_flow.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/core/or/congestion_control_flow.c 2026-03-25 14:30:34.000000000 +0000 @@ -28,6 +28,7 @@ #include "core/or/connection_st.h" #include "core/or/cell_st.h" #include "app/config/config.h" +#include "core/or/conflux_util.h" /** Cache consensus parameters */ static uint32_t xoff_client; @@ -48,6 +49,33 @@ * and strange logic in connection_bucket_get_share(). */ #define MAX_EXPECTED_CELL_BURST 32 +/* This is the grace period that we use to give the edge connection a chance to + * reduce its outbuf before we send an XOFF. + * + * The congestion control spec says: + * > If the length of an edge outbuf queue exceeds the size provided in the + * > appropriate client or exit XOFF consensus parameter, a + * > RELAY_COMMAND_STREAM_XOFF will be sent + * + * This doesn't directly adapt well to tor, where we process many incoming + * messages at once. We may buffer a lot of stream data before giving the + * mainloop a chance to flush the the edge connection's outbuf, even if the + * edge connection's socket is able to accept more bytes. + * + * Instead if we detect that we should send an XOFF (as described in the cc + * spec), we delay sending an XOFF for `XOFF_GRACE_PERIOD_USEC` microseconds. + * This gives the mainloop a chance to flush the buffer to the edge + * connection's socket. If this flush causes the outbuf queue to shrink under + * our XOFF limit, then we no longer need to send an XOFF. If after + * `XOFF_GRACE_PERIOD_USEC` we receive another message and the outbuf queue + * still exceeds the XOFF limit, we send an XOFF. + * + * The value of 5 milliseconds was chosen arbitrarily. In practice it should be + * enough time for the edge connection to get a chance to flush, but not too + * long to cause excessive buffering. + */ +#define XOFF_GRACE_PERIOD_USEC (5000) + /* The following three are for dropmark rate limiting. They define when we * scale down our XON, XOFF, and xmit byte counts. Early scaling is beneficial * because it limits the ability of spurious XON/XOFF to be sent after large @@ -61,27 +89,6 @@ #define TOTAL_XMIT_SCALE_AT (10 * ONE_MEGABYTE) /** - * Return the congestion control object of the given edge connection. - * - * Returns NULL if the edge connection doesn't have a cpath_layer or not - * attached to a circuit. But also if the cpath_layer or circuit doesn't have a - * congestion control object. - */ -static inline const congestion_control_t * -edge_get_ccontrol(const edge_connection_t *edge) -{ - congestion_control_t *ccontrol = NULL; - - if (edge->on_circuit && edge->on_circuit->ccontrol) { - ccontrol = edge->on_circuit->ccontrol; - } else if (edge->cpath_layer && edge->cpath_layer->ccontrol) { - ccontrol = edge->cpath_layer->ccontrol; - } - - return ccontrol; -} - -/** * Update global congestion control related consensus parameter values, every * consensus update. * @@ -97,7 +104,7 @@ xoff_client = networkstatus_get_param(ns, "cc_xoff_client", CC_XOFF_CLIENT_DFLT, CC_XOFF_CLIENT_MIN, - CC_XOFF_CLIENT_MAX)*RELAY_PAYLOAD_SIZE; + CC_XOFF_CLIENT_MAX)*RELAY_PAYLOAD_SIZE_MIN; #define CC_XOFF_EXIT_DFLT 500 #define CC_XOFF_EXIT_MIN 1 @@ -105,7 +112,7 @@ xoff_exit = networkstatus_get_param(ns, "cc_xoff_exit", CC_XOFF_EXIT_DFLT, CC_XOFF_EXIT_MIN, - CC_XOFF_EXIT_MAX)*RELAY_PAYLOAD_SIZE; + CC_XOFF_EXIT_MAX)*RELAY_PAYLOAD_SIZE_MIN; #define CC_XON_CHANGE_PCT_DFLT 25 #define CC_XON_CHANGE_PCT_MIN 1 @@ -121,7 +128,7 @@ xon_rate_bytes = networkstatus_get_param(ns, "cc_xon_rate", CC_XON_RATE_BYTES_DFLT, CC_XON_RATE_BYTES_MIN, - CC_XON_RATE_BYTES_MAX)*RELAY_PAYLOAD_SIZE; + CC_XON_RATE_BYTES_MAX)*RELAY_PAYLOAD_SIZE_MAX; #define CC_XON_EWMA_CNT_DFLT (2) #define CC_XON_EWMA_CNT_MIN (2) @@ -252,10 +259,8 @@ */ bool circuit_process_stream_xoff(edge_connection_t *conn, - const crypt_path_t *layer_hint, - const cell_t *cell) + const crypt_path_t *layer_hint) { - (void)cell; bool retval = true; if (BUG(!conn)) { @@ -265,13 +270,13 @@ } /* Make sure this XOFF came from the right hop */ - if (layer_hint && layer_hint != conn->cpath_layer) { + if (!edge_uses_cpath(conn, layer_hint)) { log_fn(LOG_PROTOCOL_WARN, LD_EDGE, "Got XOFF from wrong hop."); return false; } - if (edge_get_ccontrol(conn) == NULL) { + if (!edge_uses_flow_control(conn)) { log_fn(LOG_PROTOCOL_WARN, LD_EDGE, "Got XOFF for non-congestion control circuit"); return false; @@ -347,7 +352,7 @@ bool circuit_process_stream_xon(edge_connection_t *conn, const crypt_path_t *layer_hint, - const cell_t *cell) + const relay_msg_t *msg) { xon_cell_t *xon; bool retval = true; @@ -359,20 +364,19 @@ } /* Make sure this XON came from the right hop */ - if (layer_hint && layer_hint != conn->cpath_layer) { + if (!edge_uses_cpath(conn, layer_hint)) { log_fn(LOG_PROTOCOL_WARN, LD_EDGE, "Got XON from wrong hop."); return false; } - if (edge_get_ccontrol(conn) == NULL) { + if (!edge_uses_flow_control(conn)) { log_fn(LOG_PROTOCOL_WARN, LD_EDGE, "Got XON for non-congestion control circuit"); return false; } - if (xon_cell_parse(&xon, cell->payload+RELAY_HEADER_SIZE, - CELL_PAYLOAD_SIZE-RELAY_HEADER_SIZE) < 0) { + if (xon_cell_parse(&xon, msg->body, msg->length) < 0) { log_fn(LOG_PROTOCOL_WARN, LD_EDGE, "Received malformed XON cell."); return false; @@ -464,7 +468,7 @@ size_t total_buffered = connection_get_outbuf_len(TO_CONN(stream)); uint32_t buffer_limit_xoff = 0; - if (BUG(edge_get_ccontrol(stream) == NULL)) { + if (BUG(!edge_uses_flow_control(stream))) { log_err(LD_BUG, "Flow control called for non-congestion control circuit"); return -1; } @@ -479,20 +483,47 @@ if (total_buffered > buffer_limit_xoff) { if (!stream->xoff_sent) { - log_info(LD_EDGE, "Sending XOFF: %"TOR_PRIuSZ" %d", - total_buffered, buffer_limit_xoff); - tor_trace(TR_SUBSYS(cc), TR_EV(flow_decide_xoff_sending), stream); + uint64_t now = monotime_absolute_usec(); - cc_stats_flow_xoff_outbuf_ma = - stats_update_running_avg(cc_stats_flow_xoff_outbuf_ma, - total_buffered); - - circuit_send_stream_xoff(stream); - - /* Clear the drain rate. It is considered wrong if we - * got all the way to XOFF */ - stream->ewma_drain_rate = 0; + if (stream->xoff_grace_period_start_usec == 0) { + /* If unset, we haven't begun the XOFF grace period. We need to start. + */ + log_debug(LD_EDGE, + "Exceeded XOFF limit; Beginning grace period: " + "total-buffered=%" TOR_PRIuSZ " xoff-limit=%d", + total_buffered, buffer_limit_xoff); + + stream->xoff_grace_period_start_usec = now; + } else if (now > stream->xoff_grace_period_start_usec + + XOFF_GRACE_PERIOD_USEC) { + /* If we've exceeded our XOFF grace period, we need to send an XOFF. */ + log_info(LD_EDGE, + "Sending XOFF: total-buffered=%" TOR_PRIuSZ + " xoff-limit=%d grace-period-dur=%" PRIu64 "usec", + total_buffered, buffer_limit_xoff, + now - stream->xoff_grace_period_start_usec); + tor_trace(TR_SUBSYS(cc), TR_EV(flow_decide_xoff_sending), stream); + + cc_stats_flow_xoff_outbuf_ma = + stats_update_running_avg(cc_stats_flow_xoff_outbuf_ma, + total_buffered); + + circuit_send_stream_xoff(stream); + + /* Clear the drain rate. It is considered wrong if we + * got all the way to XOFF */ + stream->ewma_drain_rate = 0; + + /* Unset our grace period. */ + stream->xoff_grace_period_start_usec = 0; + } else { + /* Else we're in the XOFF grace period, so don't do anything. */ + } } + } else { + /* The outbuf length is less than the XOFF limit, so unset our grace + * period. */ + stream->xoff_grace_period_start_usec = 0; } /* If the outbuf has accumulated more than the expected burst limit of @@ -500,7 +531,7 @@ * do this because writes only happen when the socket unblocks, so * may not otherwise notice accumulation of data in the outbuf for * advisory XONs. */ - if (total_buffered > MAX_EXPECTED_CELL_BURST*RELAY_PAYLOAD_SIZE) { + if (total_buffered > MAX_EXPECTED_CELL_BURST*RELAY_PAYLOAD_SIZE_MIN) { flow_control_decide_xon(stream, 0); } @@ -717,21 +748,6 @@ return ret; } -/** - * Returns the max RTT for the circuit that carries this stream, - * as observed by congestion control. - */ -uint64_t -edge_get_max_rtt(const edge_connection_t *stream) -{ - if (stream->on_circuit && stream->on_circuit->ccontrol) - return stream->on_circuit->ccontrol->max_rtt_usec; - else if (stream->cpath_layer && stream->cpath_layer->ccontrol) - return stream->cpath_layer->ccontrol->max_rtt_usec; - - return 0; -} - /** Returns true if a connection is an edge conn that uses flow control */ bool conn_uses_flow_control(connection_t *conn) @@ -748,4 +764,3 @@ return ret; } - diff -Nru tor-0.4.7.16/src/core/or/congestion_control_flow.h tor-0.4.9.6/src/core/or/congestion_control_flow.h --- tor-0.4.7.16/src/core/or/congestion_control_flow.h 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/core/or/congestion_control_flow.h 2026-03-25 14:30:34.000000000 +0000 @@ -13,14 +13,15 @@ #include "core/or/circuit_st.h" #include "core/or/edge_connection_st.h" +struct relay_msg_t; + void flow_control_new_consensus_params(const struct networkstatus_t *); bool circuit_process_stream_xoff(edge_connection_t *conn, - const crypt_path_t *layer_hint, - const cell_t *cell); + const crypt_path_t *layer_hint); bool circuit_process_stream_xon(edge_connection_t *conn, const crypt_path_t *layer_hint, - const cell_t *cell); + const struct relay_msg_t *msg); int flow_control_decide_xoff(edge_connection_t *stream); void flow_control_decide_xon(edge_connection_t *stream, size_t n_written); @@ -31,8 +32,6 @@ bool conn_uses_flow_control(connection_t *stream); -uint64_t edge_get_max_rtt(const edge_connection_t *); - /** Metricsport externs */ extern uint64_t cc_stats_flow_num_xoff_sent; extern uint64_t cc_stats_flow_num_xon_sent; diff -Nru tor-0.4.7.16/src/core/or/congestion_control_nola.c tor-0.4.9.6/src/core/or/congestion_control_nola.c --- tor-0.4.7.16/src/core/or/congestion_control_nola.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/core/or/congestion_control_nola.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,139 +0,0 @@ -/* Copyright (c) 2019-2021, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -/** - * \file congestion_control_nola.c - * \brief Code that implements the TOR_NOLA congestion control algorithm - * from Proposal #324. - */ - -#define TOR_CONGESTION_CONTROL_NOLA_PRIVATE - -#include "core/or/or.h" - -#include "core/or/crypt_path.h" -#include "core/or/or_circuit_st.h" -#include "core/or/sendme.h" -#include "core/or/congestion_control_st.h" -#include "core/or/congestion_control_common.h" -#include "core/or/congestion_control_nola.h" -#include "core/or/circuituse.h" -#include "core/or/circuitlist.h" -#include "core/or/origin_circuit_st.h" -#include "core/or/channel.h" -#include "feature/nodelist/networkstatus.h" -#include "feature/control/control_events.h" - -#define NOLA_BDP_OVERSHOOT 100 - -/** - * Cache NOLA consensus parameters. - */ -void -congestion_control_nola_set_params(congestion_control_t *cc) -{ - tor_assert(cc->cc_alg == CC_ALG_NOLA); - - cc->nola_params.bdp_overshoot = - networkstatus_get_param(NULL, "cc_nola_overshoot", - NOLA_BDP_OVERSHOOT, - 0, - 1000); -} - -/** -* Process a SENDME and update the congestion window according to the -* rules specified in TOR_NOLA of Proposal #324. -* -* TOR_NOLA updates the congestion window to match the current -* BDP estimate, every sendme. Because this can result in downward -* drift, a fixed overhead is added to the BDP estimate. This will -* cause some queuing, but ensures that the algorithm always uses -* the full BDP. -* -* To handle the case where the local orconn blocks, TOR_NOLA uses -* the 'piecewise' BDP estimate, which uses more a conservative BDP -* estimate method when blocking occurs, but a more aggressive BDP -* estimate when there is no local blocking. This minimizes local -* client queues. -*/ -int -congestion_control_nola_process_sendme(congestion_control_t *cc, - const circuit_t *circ, - const crypt_path_t *layer_hint) -{ - tor_assert(cc && cc->cc_alg == CC_ALG_NOLA); - tor_assert(circ); - - if (cc->next_cc_event) - cc->next_cc_event--; - - /* If we get a congestion event, the only thing NOLA - * does is note this as if we exited slow-start - * (which for NOLA just means we finished our ICW). */ - if (cc->next_cc_event == 0) { - if (cc->in_slow_start) { - cc->in_slow_start = 0; - - /* We need to report that slow start has exited ASAP, - * for sbws bandwidth measurement. */ - if (CIRCUIT_IS_ORIGIN(circ)) { - /* We must discard const here because the event modifies fields :/ */ - control_event_circ_bandwidth_used_for_circ( - TO_ORIGIN_CIRCUIT((circuit_t*)circ)); - } - } - } - - /* If we did not successfully update BDP, we must return. Otherwise, - * NOLA can drift downwards */ - if (!congestion_control_update_circuit_estimates(cc, circ, layer_hint)) { - cc->inflight = cc->inflight - cc->sendme_inc; - return 0; - } - - /* We overshoot the BDP by the cwnd_inc param amount, because BDP - * may otherwise drift down. This helps us probe for more capacity. - * But there is no sense to do it if the local channel is blocked. */ - if (cc->blocked_chan) - cc->cwnd = cc->bdp[cc->bdp_alg]; - else - cc->cwnd = cc->bdp[cc->bdp_alg] + cc->nola_params.bdp_overshoot; - - /* cwnd can never fall below 1 increment */ - cc->cwnd = MAX(cc->cwnd, cc->cwnd_min); - - if (CIRCUIT_IS_ORIGIN(circ)) { - log_info(LD_CIRC, - "CC TOR_NOLA: Circuit %d " - "CWND: %"PRIu64", " - "INFL: %"PRIu64", " - "NCCE: %"PRIu16", " - "SS: %d", - CONST_TO_ORIGIN_CIRCUIT(circ)->global_identifier, - cc->cwnd, - cc->inflight, - cc->next_cc_event, - cc->in_slow_start - ); - } else { - log_info(LD_CIRC, - "CC TOR_NOLA: Circuit %"PRIu64":%d " - "CWND: %"PRIu64", " - "INFL: %"PRIu64", " - "NCCE: %"PRIu16", " - "SS: %d", - CONST_TO_OR_CIRCUIT(circ)->p_chan->global_identifier, - CONST_TO_OR_CIRCUIT(circ)->p_circ_id, - cc->cwnd, - cc->inflight, - cc->next_cc_event, - cc->in_slow_start - ); - } - - /* Update inflight with ack */ - cc->inflight = cc->inflight - cc->sendme_inc; - - return 0; -} diff -Nru tor-0.4.7.16/src/core/or/congestion_control_nola.h tor-0.4.9.6/src/core/or/congestion_control_nola.h --- tor-0.4.7.16/src/core/or/congestion_control_nola.h 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/core/or/congestion_control_nola.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,33 +0,0 @@ -/* Copyright (c) 2019-2021, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -/** - * \file congestion_control_nola.h - * \brief Private-ish APIs for the TOR_NOLA congestion control algorithm - **/ - -#ifndef TOR_CONGESTION_CONTROL_NOLA_H -#define TOR_CONGESTION_CONTROL_NOLA_H - -#include "core/or/crypt_path_st.h" -#include "core/or/circuit_st.h" - -/* Processing SENDME cell. */ -int congestion_control_nola_process_sendme(struct congestion_control_t *cc, - const circuit_t *circ, - const crypt_path_t *layer_hint); -void congestion_control_nola_set_params(struct congestion_control_t *cc); - -/* Private section starts. */ -#ifdef TOR_CONGESTION_CONTROL_NOLA_PRIVATE - -/* - * Unit tests declaractions. - */ -#ifdef TOR_UNIT_TESTS - -#endif /* defined(TOR_UNIT_TESTS) */ - -#endif /* defined(TOR_CONGESTION_CONTROL_NOLA_PRIVATE) */ - -#endif /* !defined(TOR_CONGESTION_CONTROL_NOLA_H) */ diff -Nru tor-0.4.7.16/src/core/or/congestion_control_st.h tor-0.4.9.6/src/core/or/congestion_control_st.h --- tor-0.4.7.16/src/core/or/congestion_control_st.h 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/core/or/congestion_control_st.h 2026-03-25 14:30:34.000000000 +0000 @@ -41,8 +41,8 @@ * Prop#324: TOR_NOLA - NOLA looks the BDP right in the eye and uses it * immediately as CWND. No slow start, no other congestion signals, no delay, * no bullshit. Like TOR_VEGAS, it also uses aggressive BDP estimates, to - * avoid out-competition. It seems a bit better throughput than Vegas, - * but its agressive BDP and rapid updates may lead to more queue latency. */ + * avoid out-competition. It seems a bit better throughput than Vegas, but + * its aggressive BDP and rapid updates may lead to more queue latency. */ CC_ALG_NOLA = 3, } cc_alg_t; @@ -79,22 +79,6 @@ /** Total number of BDP algs in bdp_alg_t enum */ #define NUM_BDP_ALGS (BDP_ALG_PIECEWISE+1) -/** Westwood algorithm parameters */ -struct westwood_params_t { - /** Cwnd backoff multiplier upon congestion (as percent) */ - uint8_t cwnd_backoff_m; - /** Max RTT backoff multiplier upon congestion (as percent) */ - uint8_t rtt_backoff_m; - - /** Threshold between min and max RTT, to signal congestion (percent) */ - uint8_t rtt_thresh; - - /** - * If true, use minimum of BDP and backoff multiplication in backoff. - * If false, use maximum of BDP and backoff multiplication in backoff. */ - bool min_backoff; -}; - /** Vegas algorithm parameters. */ struct vegas_params_t { /** The slow-start cwnd cap for RFC3742 */ @@ -114,12 +98,6 @@ uint8_t bdp_mix_pct; }; -/** NOLA consensus params */ -struct nola_params_t { - /** How many cells to add to BDP estimate to obtain cwnd */ - uint16_t bdp_overshoot; -}; - /** Fields common to all congestion control algorithms */ struct congestion_control_t { /** @@ -128,19 +106,13 @@ * sendme_last_digests. */ smartlist_t *sendme_pending_timestamps; - /** - * Smartlist of uint64_t monotime timestamp of when sendme's arrived. - * FIFO queue that is managed similar to sendme_last_digests. - * Used to estimate circuitbandwidth and BDP. */ - smartlist_t *sendme_arrival_timestamps; - /** RTT time data for congestion control. */ uint64_t ewma_rtt_usec; uint64_t min_rtt_usec; uint64_t max_rtt_usec; - /* BDP estimates by algorithm */ - uint64_t bdp[NUM_BDP_ALGS]; + /* Vegas BDP estimate */ + uint64_t bdp; /** Congestion window */ uint64_t cwnd; @@ -203,15 +175,9 @@ * consensus parameter during circuit setup. */ bdp_alg_t bdp_alg; - /** Algorithm-specific parameters. The specific struct that is used - * depends upon the algorithm selected by the cc_alg parameter. - * These should not be accessed anywhere other than the algorithm-specific - * files. */ - union { - struct westwood_params_t westwood_params; - struct vegas_params_t vegas_params; - struct nola_params_t nola_params; - }; + /** Vegas-specific parameters. These should not be accessed anywhere + * other than the congestion_control_vegas.c file. */ + struct vegas_params_t vegas_params; }; /** diff -Nru tor-0.4.7.16/src/core/or/congestion_control_vegas.c tor-0.4.9.6/src/core/or/congestion_control_vegas.c --- tor-0.4.7.16/src/core/or/congestion_control_vegas.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/core/or/congestion_control_vegas.c 2026-03-25 14:30:34.000000000 +0000 @@ -37,30 +37,30 @@ #define VEGAS_SSCAP_SBWS_DFLT (400) /* Exits are three hops, so params are based on 3 outbufs of cells */ -#define VEGAS_ALPHA_EXIT_DFLT (2*OUTBUF_CELLS) +#define VEGAS_ALPHA_EXIT_DFLT (3*OUTBUF_CELLS) #define VEGAS_BETA_EXIT_DFLT (4*OUTBUF_CELLS) #define VEGAS_GAMMA_EXIT_DFLT (3*OUTBUF_CELLS) -#define VEGAS_DELTA_EXIT_DFLT (6*OUTBUF_CELLS) -#define VEGAS_SSCAP_EXIT_DFLT (500) +#define VEGAS_DELTA_EXIT_DFLT (5*OUTBUF_CELLS) +#define VEGAS_SSCAP_EXIT_DFLT (600) /* Onion rends are six hops, so params are based on 6 outbufs of cells */ #define VEGAS_ALPHA_ONION_DFLT (3*OUTBUF_CELLS) -#define VEGAS_BETA_ONION_DFLT (7*OUTBUF_CELLS) -#define VEGAS_GAMMA_ONION_DFLT (5*OUTBUF_CELLS) -#define VEGAS_DELTA_ONION_DFLT (9*OUTBUF_CELLS) -#define VEGAS_SSCAP_ONION_DFLT (600) +#define VEGAS_BETA_ONION_DFLT (6*OUTBUF_CELLS) +#define VEGAS_GAMMA_ONION_DFLT (4*OUTBUF_CELLS) +#define VEGAS_DELTA_ONION_DFLT (7*OUTBUF_CELLS) +#define VEGAS_SSCAP_ONION_DFLT (475) /** * Number of sendme_incs between cwnd and inflight for cwnd to be * still considered full */ -#define VEGAS_CWND_FULL_GAP_DFLT (1) +#define VEGAS_CWND_FULL_GAP_DFLT (4) static int cc_vegas_cwnd_full_gap = VEGAS_CWND_FULL_GAP_DFLT; /** * If the cwnd becomes less than this percent full at any point, * we declare it not full immediately. */ -#define VEGAS_CWND_FULL_MINPCT_DFLT (75) +#define VEGAS_CWND_FULL_MINPCT_DFLT (25) static int cc_vegas_cwnd_full_minpct = VEGAS_CWND_FULL_MINPCT_DFLT; /** @@ -98,7 +98,7 @@ static inline uint64_t vegas_bdp(const congestion_control_t *cc) { - return cc->bdp[BDP_ALG_CWND_RTT]; + return cc->bdp; } /** @@ -405,8 +405,7 @@ */ int congestion_control_vegas_process_sendme(congestion_control_t *cc, - const circuit_t *circ, - const crypt_path_t *layer_hint) + const circuit_t *circ) { uint64_t queue_use; @@ -422,7 +421,7 @@ cc->next_cwnd_event--; /* Compute BDP and RTT. If we did not update, don't run the alg */ - if (!congestion_control_update_circuit_estimates(cc, circ, layer_hint)) { + if (!congestion_control_update_circuit_estimates(cc, circ)) { cc->inflight = cc->inflight - cc->sendme_inc; return 0; } @@ -467,7 +466,7 @@ } else { uint64_t old_cwnd = cc->cwnd; - /* Congestion signal: Set cwnd to gamma threshhold */ + /* Congestion signal: Set cwnd to gamma threshold */ cc->cwnd = vegas_bdp(cc) + cc->vegas_params.gamma; /* Compute the percentage we experience a blocked csig vs RTT sig */ @@ -506,8 +505,8 @@ uint64_t old_cwnd = cc->cwnd; uint64_t cwnd_diff; - /* If we are above the delta threshhold, drop cwnd down to the - * delta threshhold. */ + /* If we are above the delta threshold, drop cwnd down to the + * delta threshold. */ cc->cwnd = vegas_bdp(cc) + cc->vegas_params.delta - CWND_INC(cc); /* Account the amount we reduced the cwnd by for the gamma cutoff */ diff -Nru tor-0.4.7.16/src/core/or/congestion_control_vegas.h tor-0.4.9.6/src/core/or/congestion_control_vegas.h --- tor-0.4.7.16/src/core/or/congestion_control_vegas.h 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/core/or/congestion_control_vegas.h 2026-03-25 14:30:34.000000000 +0000 @@ -35,8 +35,7 @@ /* Processing SENDME cell. */ int congestion_control_vegas_process_sendme(struct congestion_control_t *cc, - const circuit_t *circ, - const crypt_path_t *layer_hint); + const circuit_t *circ); void congestion_control_vegas_set_params(struct congestion_control_t *cc, cc_path_t path); diff -Nru tor-0.4.7.16/src/core/or/congestion_control_westwood.c tor-0.4.9.6/src/core/or/congestion_control_westwood.c --- tor-0.4.7.16/src/core/or/congestion_control_westwood.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/core/or/congestion_control_westwood.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,241 +0,0 @@ -/* Copyright (c) 2019-2021, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -/** - * \file congestion_control_westwood.c - * \brief Code that implements the TOR_WESTWOOD congestion control algorithm - * from Proposal #324. - */ - -#define TOR_CONGESTION_CONTROL_WESTWOOD_PRIVATE - -#include "core/or/or.h" - -#include "core/or/crypt_path.h" -#include "core/or/or_circuit_st.h" -#include "core/or/sendme.h" -#include "core/or/congestion_control_st.h" -#include "core/or/congestion_control_common.h" -#include "core/or/congestion_control_westwood.h" -#include "core/or/circuitlist.h" -#include "core/or/circuituse.h" -#include "core/or/origin_circuit_st.h" -#include "core/or/channel.h" -#include "feature/nodelist/networkstatus.h" -#include "feature/control/control_events.h" - -#define USEC_ONE_MS (1000) - -#define WESTWOOD_CWND_BACKOFF_M 75 -#define WESTWOOD_RTT_BACKOFF_M 100 -#define WESTWOOD_RTT_THRESH 33 -#define WESTWOOD_MIN_BACKOFF 0 - -/** - * Cache westwood consensus parameters. - */ -void -congestion_control_westwood_set_params(congestion_control_t *cc) -{ - tor_assert(cc->cc_alg == CC_ALG_WESTWOOD); - - cc->westwood_params.cwnd_backoff_m = - networkstatus_get_param(NULL, "cc_westwood_cwnd_m", - WESTWOOD_CWND_BACKOFF_M, - 0, - 100); - - cc->westwood_params.rtt_backoff_m = - networkstatus_get_param(NULL, "cc_westwood_rtt_m", - WESTWOOD_RTT_BACKOFF_M, - 50, - 100); - - cc->westwood_params.rtt_thresh = - networkstatus_get_param(NULL, "cc_westwood_rtt_thresh", - WESTWOOD_RTT_THRESH, - 0, - 100); - - cc->westwood_params.min_backoff = - networkstatus_get_param(NULL, "cc_westwood_min_backoff", - WESTWOOD_MIN_BACKOFF, - 0, - 1); -} - -/** - * Return the RTT threshold that signals congestion. - * - * Computed from the threshold parameter that specifies a - * percent between the min and max RTT observed so far. - */ -static inline uint64_t -westwood_rtt_signal(const congestion_control_t *cc) -{ - return ((100 - cc->westwood_params.rtt_thresh)*cc->min_rtt_usec + - cc->westwood_params.rtt_thresh*(cc)->max_rtt_usec)/100; -} - -/** - * Compute a backoff to reduce the max RTT. - * - * This may be necessary to ensure that westwood does not have - * a runaway condition where congestion inflates the max RTT, which - * inflates the congestion threshold. That cannot happen with one - * Westwood instance, but it may happen in aggregate. Hence, this is - * a safety parameter, in case we need it. - */ -static inline uint64_t -westwood_rtt_max_backoff(const congestion_control_t *cc) -{ - return cc->min_rtt_usec + - (cc->westwood_params.rtt_backoff_m * - (cc->max_rtt_usec - cc->min_rtt_usec))/100; -} - -/** - * Returns true if the circuit is experiencing congestion, as per - * TOR_WESTWOOD rules. - */ -static inline bool -westwood_is_congested(const congestion_control_t *cc) -{ - /* If the local channel is blocked, that is always congestion */ - if (cc->blocked_chan) - return true; - - /* If the min RTT is within 1ms of the signal, then there is not enough - * range in RTTs to signify congestion. Treat that as not congested. */ - if (westwood_rtt_signal(cc) < cc->min_rtt_usec || - westwood_rtt_signal(cc) - cc->min_rtt_usec < USEC_ONE_MS) - return false; - - /* If the EWMA-smoothed RTT exceeds the westwood RTT threshold, - * then it is congestion. */ - if (cc->ewma_rtt_usec > westwood_rtt_signal(cc)) - return true; - - return false; -} - -/** - * Process a SENDME and update the congestion window according to the - * rules specified in TOR_WESTWOOD of Proposal #324. - * - * Essentially, this algorithm uses a threshold of 'rtt_thresh', which - * is a midpoint between the min and max RTT. If the RTT exceeds this - * threshold, then queue delay due to congestion is assumed to be present, - * and the algorithm reduces the congestion window. If the RTT is below the - * threshold, the circuit is not congested (ie: queue delay is low), and we - * increase the congestion window. - * - * The congestion window is updated only once every congestion window worth of - * packets, even if the signal persists. It is also updated whenever the - * upstream orcon blocks, or unblocks. This minimizes local client queues. - */ -int -congestion_control_westwood_process_sendme(congestion_control_t *cc, - const circuit_t *circ, - const crypt_path_t *layer_hint) -{ - tor_assert(cc && cc->cc_alg == CC_ALG_WESTWOOD); - tor_assert(circ); - - /* Update ack counter until next congestion signal event is allowed */ - if (cc->next_cc_event) - cc->next_cc_event--; - - /* If we were unable to update our circuit estimates, Westwood must - * *not* update its cwnd, otherwise it could run to infinity, or to 0. - * Just update inflight from the sendme and return. */ - if (!congestion_control_update_circuit_estimates(cc, circ, layer_hint)) { - cc->inflight = cc->inflight - cc->sendme_inc; - return 0; - } - - /* We only update anything once per window */ - if (cc->next_cc_event == 0) { - if (!westwood_is_congested(cc)) { - if (cc->in_slow_start) { - cc->cwnd = MAX(cc->cwnd + CWND_INC_SS(cc), - cc->bdp[cc->bdp_alg]); - } else { - cc->cwnd = cc->cwnd + CWND_INC(cc); - } - } else { - if (cc->westwood_params.min_backoff) - cc->cwnd = MIN(cc->cwnd*cc->westwood_params.cwnd_backoff_m/100, - cc->bdp[cc->bdp_alg]); - else - cc->cwnd = MAX(cc->cwnd*cc->westwood_params.cwnd_backoff_m/100, - cc->bdp[cc->bdp_alg]); - - cc->in_slow_start = 0; - - // Because Westwood's congestion can runaway and boost max rtt, - // which increases its congestion signal, we backoff the max rtt - // too. - cc->max_rtt_usec = westwood_rtt_max_backoff(cc); - - log_info(LD_CIRC, "CC: TOR_WESTWOOD congestion. New max RTT: %"PRIu64, - cc->max_rtt_usec/1000); - - /* We need to report that slow start has exited ASAP, - * for sbws bandwidth measurement. */ - if (CIRCUIT_IS_ORIGIN(circ)) { - /* We must discard const here because the event modifies fields :/ */ - control_event_circ_bandwidth_used_for_circ( - TO_ORIGIN_CIRCUIT((circuit_t*)circ)); - } - } - - /* cwnd can never fall below 1 increment */ - cc->cwnd = MAX(cc->cwnd, cc->cwnd_min); - - /* Schedule next update */ - cc->next_cc_event = CWND_UPDATE_RATE(cc); - - if (CIRCUIT_IS_ORIGIN(circ)) { - log_info(LD_CIRC, - "CC: TOR_WESTWOOD Circuit %d " - "CWND: %"PRIu64", " - "INFL: %"PRIu64", " - "NCCE: %"PRIu16", " - "WRTT: %"PRIu64", " - "WSIG: %"PRIu64", " - "SS: %d", - CONST_TO_ORIGIN_CIRCUIT(circ)->global_identifier, - cc->cwnd, - cc->inflight, - cc->next_cc_event, - cc->ewma_rtt_usec/1000, - westwood_rtt_signal(cc)/1000, - cc->in_slow_start - ); - } else { - log_info(LD_CIRC, - "CC: TOR_WESTWOOD Circuit %"PRIu64":%d " - "CWND: %"PRIu64", " - "INFL: %"PRIu64", " - "NCCE: %"PRIu16", " - "WRTT: %"PRIu64", " - "WSIG: %"PRIu64", " - "SS: %d", - CONST_TO_OR_CIRCUIT(circ)->p_chan->global_identifier, - CONST_TO_OR_CIRCUIT(circ)->p_circ_id, - cc->cwnd, - cc->inflight, - cc->next_cc_event, - cc->ewma_rtt_usec/1000, - westwood_rtt_signal(cc)/1000, - cc->in_slow_start - ); - } - } - - /* Update inflight with ack */ - cc->inflight = cc->inflight - cc->sendme_inc; - - return 0; -} diff -Nru tor-0.4.7.16/src/core/or/congestion_control_westwood.h tor-0.4.9.6/src/core/or/congestion_control_westwood.h --- tor-0.4.7.16/src/core/or/congestion_control_westwood.h 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/core/or/congestion_control_westwood.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,33 +0,0 @@ -/* Copyright (c) 2019-2021, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -/** - * \file congestion_control_westwood.h - * \brief Private-ish APIs for the TOR_WESTWOOD congestion control algorithm - **/ - -#ifndef TOR_CONGESTION_CONTROL_WESTWOOD_H -#define TOR_CONGESTION_CONTROL_WESTWOOD_H - -#include "core/or/crypt_path_st.h" -#include "core/or/circuit_st.h" - -/* Processing SENDME cell. */ -int congestion_control_westwood_process_sendme(struct congestion_control_t *cc, - const circuit_t *circ, - const crypt_path_t *layer_hint); -void congestion_control_westwood_set_params(struct congestion_control_t *cc); - -/* Private section starts. */ -#ifdef TOR_CONGESTION_CONTROL_WESTWOOD_PRIVATE - -/* - * Unit tests declaractions. - */ -#ifdef TOR_UNIT_TESTS - -#endif /* defined(TOR_UNIT_TESTS) */ - -#endif /* defined(TOR_CONGESTION_CONTROL_WESTWOOD_PRIVATE) */ - -#endif /* !defined(TOR_CONGESTION_CONTROL_WESTWOOD_H) */ diff -Nru tor-0.4.7.16/src/core/or/connection_edge.c tor-0.4.9.6/src/core/or/connection_edge.c --- tor-0.4.7.16/src/core/or/connection_edge.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/core/or/connection_edge.c 2026-03-25 14:30:34.000000000 +0000 @@ -70,8 +70,10 @@ #include "core/or/circuitpadding.h" #include "core/or/connection_edge.h" #include "core/or/congestion_control_flow.h" +#include "core/or/conflux_util.h" #include "core/or/circuitstats.h" #include "core/or/connection_or.h" +#include "core/or/dos.h" #include "core/or/extendinfo.h" #include "core/or/policies.h" #include "core/or/reasons.h" @@ -104,6 +106,7 @@ #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 "core/or/cell_st.h" #include "core/or/cpath_build_state_st.h" @@ -510,7 +513,7 @@ int connection_edge_end(edge_connection_t *conn, uint8_t reason) { - char payload[RELAY_PAYLOAD_SIZE]; + char payload[RELAY_PAYLOAD_SIZE_MAX]; size_t payload_len=1; circuit_t *circ; uint8_t control_reason = reason; @@ -628,6 +631,7 @@ if (!circ->half_streams) { circ->half_streams = smartlist_new(); + conflux_update_half_streams(circ, circ->half_streams); } half_conn->stream_id = conn->stream_id; @@ -673,6 +677,25 @@ smartlist_insert(circ->half_streams, insert_at, half_conn); } +/** + * Return true if the circuit has any half-closed connections + * that are still within the end_ack_expected_usec timestamp + * from now. + */ +bool +connection_half_edges_waiting(const origin_circuit_t *circ) +{ + if (!circ->half_streams) + return false; + + SMARTLIST_FOREACH_BEGIN(circ->half_streams, const half_edge_t *, half_conn) { + if (half_conn->end_ack_expected_usec > monotime_absolute_usec()) + return true; + } SMARTLIST_FOREACH_END(half_conn); + + return false; +} + /** Release space held by he */ void half_edge_free_(half_edge_t *he) @@ -1057,7 +1080,9 @@ static void connection_edge_about_to_close(edge_connection_t *edge_conn) { - if (!edge_conn->edge_has_sent_end) { + /* Under memory pressure, the OOM handler can close connections without + * sending END cell. If we are NOT in that scenario, log loudly. */ + if (!edge_conn->edge_has_sent_end && !have_been_under_memory_pressure()) { connection_t *conn = TO_CONN(edge_conn); log_warn(LD_BUG, "(Harmless.) Edge connection (marked at %s:%d) " "hasn't sent end yet?", @@ -1192,7 +1217,10 @@ * it here too because controllers that put streams in controller_wait * state never ask Tor to attach the circuit. */ if (AP_CONN_STATE_IS_UNATTACHED(base_conn->state)) { - if (seconds_since_born >= options->SocksTimeout) { + /* If this is a connection to an HS with PoW defenses enabled, we need to + * wait longer than the usual Socks timeout. */ + if (seconds_since_born >= options->SocksTimeout && + !entry_conn->hs_with_pow_conn) { log_fn(severity, LD_APP, "Tried for %d seconds to get a connection to %s:%d. " "Giving up. (%s)", @@ -1236,6 +1264,7 @@ } if (circ->purpose != CIRCUIT_PURPOSE_C_GENERAL && + circ->purpose != CIRCUIT_PURPOSE_CONFLUX_LINKED && circ->purpose != CIRCUIT_PURPOSE_CONTROLLER && circ->purpose != CIRCUIT_PURPOSE_C_HSDIR_GET && circ->purpose != CIRCUIT_PURPOSE_S_HSDIR_POST && @@ -2029,6 +2058,19 @@ descriptor_is_usable = hs_client_any_intro_points_usable(&hs_conn_ident->identity_pk, cached_desc); + /* Check if PoW parameters have expired. If yes, the descriptor is + * unusable. */ + if (cached_desc->encrypted_data.pow_params) { + if (cached_desc->encrypted_data.pow_params->expiration_time < + approx_time()) { + log_info(LD_REND, "Descriptor PoW parameters have expired."); + descriptor_is_usable = 0; + } else { + /* Mark that the connection is to an HS with PoW defenses on. */ + conn->hs_with_pow_conn = 1; + } + } + log_info(LD_GENERAL, "Found %s descriptor in cache for %s. %s.", (descriptor_is_usable) ? "usable" : "unusable", safe_str_client(socks->address), @@ -2163,7 +2205,7 @@ /* Whoops; this one is stale. It must have gotten added earlier? * (Probably this is not possible, since AllowDotExit no longer * exists.) */ - log_warn(LD_APP,"Stale automapped address for '%s.exit'. Refusing.", + log_warn(LD_APP,"Stale automapped address for '%s.$fp.exit'. Refusing.", safe_str_client(socks->address)); control_event_client_status(LOG_WARN, "SOCKS_BAD_HOSTNAME HOSTNAME=%s", escaped(socks->address)); @@ -2177,7 +2219,7 @@ if (exit_source == ADDRMAPSRC_DNS || exit_source == ADDRMAPSRC_NONE) { /* It shouldn't be possible to get a .exit address from any of these * sources. */ - log_warn(LD_BUG,"Address '%s.exit', with impossible source for the " + log_warn(LD_BUG,"Address '%s.$fp.exit', with impossible source for the " ".exit part. Refusing.", safe_str_client(socks->address)); control_event_client_status(LOG_WARN, "SOCKS_BAD_HOSTNAME HOSTNAME=%s", @@ -2230,7 +2272,7 @@ /* Now make sure that the chosen exit exists... */ if (!node) { log_warn(LD_APP, - "Unrecognized relay in exit address '%s.exit'. Refusing.", + "Unrecognized relay in exit address '%s.$fp.exit'. Refusing.", safe_str_client(socks->address)); connection_mark_unattached_ap(conn, END_STREAM_REASON_TORPROTOCOL); return -1; @@ -2238,7 +2280,7 @@ /* ...and make sure that it isn't excluded. */ if (routerset_contains_node(excludeset, node)) { log_warn(LD_APP, - "Excluded relay in exit address '%s.exit'. Refusing.", + "Excluded relay in exit address '%s.$fp.exit'. Refusing.", safe_str_client(socks->address)); connection_mark_unattached_ap(conn, END_STREAM_REASON_TORPROTOCOL); return -1; @@ -2944,9 +2986,28 @@ return connection_ap_rewrite_and_attach_if_allowed(conn, NULL, NULL); } +#define TOR_CAPABILITIES_HEADER \ + "Tor-Capabilities: \r\n" + +#define HTTP_CONNECT_FIXED_HEADERS \ + TOR_CAPABILITIES_HEADER \ + "Via: tor/1.0 tor-network (tor "VERSION")\r\n" + +#define HTTP_OTHER_FIXED_HEADERS \ + TOR_CAPABILITIES_HEADER \ + "Server: tor/1.0 (tor "VERSION")\r\n" + +static const char HTTP_OPTIONS_REPLY[] = + "HTTP/1.0 200 OK\r\n" + "Allow: OPTIONS, CONNECT\r\n" + HTTP_OTHER_FIXED_HEADERS + "\r\n"; + 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" + "Content-Type: text/html; charset=iso-8859-1\r\n" + HTTP_OTHER_FIXED_HEADERS + "\r\n" "\n" "\n" "This is an HTTP CONNECT tunnel, not a full HTTP Proxy\n" @@ -2969,6 +3030,64 @@ "\n" "\n"; +/** Return true iff `host` is a valid host header value indicating localhost. + */ +static bool +host_header_is_localhost(const char *host_value) +{ + char *host = NULL; + uint16_t port = 0; + tor_addr_t addr; + bool result; + + // Note that this does not _require_ that a port was set, + // which is what we want. + if (tor_addr_port_split(LOG_DEBUG, host_value, &host, &port) < 0) { + return false; + } + tor_assert(host); + + if (tor_addr_parse(&addr, host) == 0) { + result = tor_addr_is_loopback(&addr); + } else { + result = ! strcasecmp(host, "localhost"); + } + + tor_free(host); + return result; +} + +/** Return true if the Proxy-Authorization header present in auth + * isn't using the "modern" format introduced by proposal 365, + * with "basic" auth and username "tor". */ +STATIC bool +using_old_proxy_auth(const char *auth) +{ + auth = eat_whitespace(auth); + if (strcasecmpstart(auth, "Basic ")) { + // Not Basic. + return true; + } + auth += strlen("Basic "); + auth = eat_whitespace(auth); + + ssize_t clen = base64_decode_maxsize(strlen(auth)) + 1; + char *credential = tor_malloc_zero(clen); + ssize_t n = base64_decode(credential, clen, auth, strlen(auth)); + if (n < 0 || BUG(n >= clen)) { + // not base64, or somehow too long. + tor_free(credential); + return true; + } + // nul-terminate. + credential[n] = 0; + + bool username_is_modern = ! strcmpstart(credential, "tor:"); + tor_free(credential); + + return ! username_is_modern; +} + /** 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 @@ -2985,16 +3104,26 @@ char *command = NULL, *addrport = NULL; char *addr = NULL; size_t bodylen = 0; + const char *fixed_reply_headers = HTTP_OTHER_FIXED_HEADERS; const char *errmsg = NULL; + bool close_without_message = false; int rv = 0; + bool host_is_localhost = false; + + // If true, we already have a full reply, so we shouldn't add + // fixed headers and CRLF. + bool errmsg_is_complete = false; + // If true, we're sending a fixed reply as an errmsg, + // but technically this isn't an error so we shouldn't log. + bool skip_error_log = false; const int http_status = fetch_from_buf_http(ENTRY_TO_CONN(conn)->inbuf, &headers, 8192, &body, &bodylen, 1024, 0); if (http_status < 0) { - /* Bad http status */ - errmsg = "HTTP/1.0 400 Bad Request\r\n\r\n"; + /* Unparseable http message. Don't send a reply. */ + close_without_message = true; goto err; } else if (http_status == 0) { /* no HTTP request yet. */ @@ -3003,25 +3132,68 @@ const int cmd_status = parse_http_command(headers, &command, &addrport); if (cmd_status < 0) { - errmsg = "HTTP/1.0 400 Bad Request\r\n\r\n"; + /* Unparseable command. Don't reply. */ + close_without_message = true; goto err; } tor_assert(command); tor_assert(addrport); + { + // Find out whether the host is localhost. If it isn't, + // then either this is a connect request (which is okay) + // or a webpage is using DNS rebinding to try to bypass + // browser security (which isn't). + char *host = http_get_header(headers, "Host: "); + if (host) { + host_is_localhost = host_header_is_localhost(host); + } + tor_free(host); + } + if (!strcasecmp(command, "options") && host_is_localhost) { + errmsg = HTTP_OPTIONS_REPLY; + errmsg_is_complete = true; + + // TODO: We could in theory make sure that the target + // is a host or is *. + // TODO: We could in theory make sure that the body is empty. + // (And we would have to, if we ever support HTTP/1.1.) + + // This is not actually an error, but the error handling + // does the right operations here (send the reply, + // mark the connection). + skip_error_log = true; + + goto err; + } if (strcasecmp(command, "connect")) { - errmsg = HTTP_CONNECT_IS_NOT_AN_HTTP_PROXY_MSG; + if (host_is_localhost) { + errmsg = HTTP_CONNECT_IS_NOT_AN_HTTP_PROXY_MSG; + errmsg_is_complete = true; + } else { + close_without_message = true; + } goto err; } + fixed_reply_headers = HTTP_CONNECT_FIXED_HEADERS; + tor_assert(conn->socks_request); socks_request_t *socks = conn->socks_request; uint16_t port; if (tor_addr_port_split(LOG_WARN, addrport, &addr, &port) < 0) { - errmsg = "HTTP/1.0 400 Bad Request\r\n\r\n"; + errmsg = "HTTP/1.0 400 Bad Request\r\n"; goto err; } if (strlen(addr) >= MAX_SOCKS_ADDR_LEN) { - errmsg = "HTTP/1.0 414 Request-URI Too Long\r\n\r\n"; + errmsg = "HTTP/1.0 414 Request-URI Too Long\r\n"; + goto err; + } + + /* Reject the request if it's trying to interact with Arti RPC. */ + char *rpc_hdr = http_get_header(headers, "Tor-RPC-Target: "); + if (rpc_hdr) { + tor_free(rpc_hdr); + errmsg = "HTTP/1.0 501 Not implemented (No RPC Support)\r\n"; goto err; } @@ -3030,13 +3202,30 @@ { char *authorization = http_get_header(headers, "Proxy-Authorization: "); if (authorization) { + if (using_old_proxy_auth(authorization)) { + log_warn(LD_GENERAL, "Proxy-Authorization header in legacy format. " + "With modern Tor, use Basic auth with username=tor."); + } socks->username = authorization; // steal reference socks->usernamelen = strlen(authorization); } - char *isolation = http_get_header(headers, "X-Tor-Stream-Isolation: "); - if (isolation) { - socks->password = isolation; // steal reference - socks->passwordlen = strlen(isolation); + char *isolation = http_get_header(headers, "Tor-Stream-Isolation: "); + char *x_isolation = http_get_header(headers, "X-Tor-Stream-Isolation: "); + if (isolation || x_isolation) { + // We need to cram both of these headers into a single + // password field. Using a delimiter like this is a bit ugly, + // but the only ones who can confuse it are the applications, + // whom we are trusting to get their own isolation right. + const char DELIM[] = "\x01\xff\x01\xff"; + tor_asprintf(&socks->password, + "%s%s%s", + isolation?isolation:"", + DELIM, + x_isolation?x_isolation:""); + tor_free(isolation); + tor_free(x_isolation); + + socks->passwordlen = strlen(socks->password); } } @@ -3054,10 +3243,21 @@ goto done; err: - if (BUG(errmsg == NULL)) - errmsg = "HTTP/1.0 400 Bad Request\r\n\r\n"; - log_info(LD_EDGE, "HTTP tunnel error: saying %s", escaped(errmsg)); - connection_buf_add(errmsg, strlen(errmsg), ENTRY_TO_CONN(conn)); + if (! close_without_message && BUG(errmsg == NULL)) + errmsg = "HTTP/1.0 400 Bad Request\r\n"; + if (errmsg) { + if (!skip_error_log) + log_info(LD_EDGE, "HTTP tunnel error: saying %s", escaped(errmsg)); + connection_buf_add(errmsg, strlen(errmsg), ENTRY_TO_CONN(conn)); + if (!errmsg_is_complete) { + connection_buf_add(fixed_reply_headers, strlen(fixed_reply_headers), + ENTRY_TO_CONN(conn)); + connection_buf_add("\r\n", 2, ENTRY_TO_CONN(conn)); + } + } else { + if (!skip_error_log) + log_info(LD_EDGE, "HTTP tunnel error: closing silently"); + } /* Mark it as "has_finished" so that we don't try to send an extra socks * reply. */ conn->socks_request->has_finished = 1; @@ -3101,6 +3301,10 @@ test_stream_id)) goto again; + if (TO_CIRCUIT(circ)->conflux) { + conflux_sync_circ_fields(TO_CIRCUIT(circ)->conflux, circ); + } + return test_stream_id; } @@ -3112,6 +3316,8 @@ const edge_connection_t *edge_conn = ENTRY_TO_EDGE_CONN(conn); /* We can only send optimistic data if we're connected to an open general circuit. */ + // TODO-329-PURPOSE: Can conflux circuits use optimistic data? + // Does anything use optimistic data? if (edge_conn->on_circuit == NULL || edge_conn->on_circuit->state != CIRCUIT_STATE_OPEN || (edge_conn->on_circuit->purpose != CIRCUIT_PURPOSE_C_GENERAL && @@ -3138,7 +3344,8 @@ return 0; /* No flags for hidden services. */ - if (edge_conn->on_circuit->purpose != CIRCUIT_PURPOSE_C_GENERAL) + if (edge_conn->on_circuit->purpose != CIRCUIT_PURPOSE_C_GENERAL && + edge_conn->on_circuit->purpose != CIRCUIT_PURPOSE_CONFLUX_LINKED) return 0; /* If only IPv4 is supported, no flags */ @@ -3191,8 +3398,8 @@ MOCK_IMPL(int, connection_ap_handshake_send_begin,(entry_connection_t *ap_conn)) { - char payload[CELL_PAYLOAD_SIZE]; - int payload_len; + char payload[RELAY_PAYLOAD_SIZE_MAX]; + size_t payload_len; int begin_type; const or_options_t *options = get_options(); origin_circuit_t *circ; @@ -3217,16 +3424,20 @@ return -1; } + size_t payload_max = circuit_max_relay_payload( + edge_conn->on_circuit, edge_conn->cpath_layer, + RELAY_COMMAND_BEGIN); /* Set up begin cell flags. */ edge_conn->begincell_flags = connection_ap_get_begincell_flags(ap_conn); - tor_snprintf(payload,RELAY_PAYLOAD_SIZE, "%s:%d", + tor_snprintf(payload,payload_max, "%s:%d", (circ->base_.purpose == CIRCUIT_PURPOSE_C_GENERAL || + circ->base_.purpose == CIRCUIT_PURPOSE_CONFLUX_LINKED || circ->base_.purpose == CIRCUIT_PURPOSE_CONTROLLER) ? ap_conn->socks_request->address : "", ap_conn->socks_request->port); - payload_len = (int)strlen(payload)+1; - if (payload_len <= RELAY_PAYLOAD_SIZE - 4 && edge_conn->begincell_flags) { + payload_len = strlen(payload)+1; + if (payload_len <= payload_max - 4 && edge_conn->begincell_flags) { set_uint32(payload + payload_len, htonl(edge_conn->begincell_flags)); payload_len += 4; } @@ -3323,7 +3534,8 @@ tor_assert(base_conn->type == CONN_TYPE_AP); tor_assert(base_conn->state == AP_CONN_STATE_CIRCUIT_WAIT); tor_assert(ap_conn->socks_request); - tor_assert(circ->base_.purpose == CIRCUIT_PURPOSE_C_GENERAL); + tor_assert(circ->base_.purpose == CIRCUIT_PURPOSE_C_GENERAL || + circ->base_.purpose == CIRCUIT_PURPOSE_CONFLUX_LINKED); command = ap_conn->socks_request->command; tor_assert(SOCKS_COMMAND_IS_RESOLVE(command)); @@ -3724,9 +3936,24 @@ CONN_TYPE_AP_HTTP_CONNECT_LISTENER) { const char *response = end_reason_to_http_connect_response_line(endreason); if (!response) { - response = "HTTP/1.0 400 Bad Request\r\n\r\n"; + response = "HTTP/1.0 400 Bad Request\r\n"; } connection_buf_add(response, strlen(response), ENTRY_TO_CONN(conn)); + connection_buf_add(HTTP_CONNECT_FIXED_HEADERS, + strlen(HTTP_CONNECT_FIXED_HEADERS), + ENTRY_TO_CONN(conn)); + if (endreason) { + bool reason_is_remote = (endreason & END_STREAM_REASON_MASK) < 256; + const char *reason = stream_end_reason_to_control_string(endreason); + if (reason) { + const char *prefix = reason_is_remote ? "end" : "c-tor"; + tor_snprintf(buf, sizeof(buf), + "Tor-Request-Failed: %s/%s\r\n", + prefix, reason); + connection_buf_add(buf, strlen(buf), ENTRY_TO_CONN(conn)); + } + } + connection_buf_add("\r\n", 2, ENTRY_TO_CONN(conn)); } else if (conn->socks_request->socks_version == 4) { memset(buf,0,SOCKS4_NETWORK_LEN); buf[1] = (status==SOCKS5_SUCCEEDED ? SOCKS4_GRANTED : SOCKS4_REJECT); @@ -3767,33 +3994,27 @@ * we don't. **/ STATIC int -begin_cell_parse(const cell_t *cell, begin_cell_t *bcell, +begin_cell_parse(const relay_msg_t *msg, begin_cell_t *bcell, uint8_t *end_reason_out) { - relay_header_t rh; const uint8_t *body, *nul; memset(bcell, 0, sizeof(*bcell)); *end_reason_out = END_STREAM_REASON_MISC; - relay_header_unpack(&rh, cell->payload); - if (rh.length > RELAY_PAYLOAD_SIZE) { - return -2; /*XXXX why not TORPROTOCOL? */ - } - - bcell->stream_id = rh.stream_id; + bcell->stream_id = msg->stream_id; - if (rh.command == RELAY_COMMAND_BEGIN_DIR) { + if (msg->command == RELAY_COMMAND_BEGIN_DIR) { bcell->is_begindir = 1; return 0; - } else if (rh.command != RELAY_COMMAND_BEGIN) { - log_warn(LD_BUG, "Got an unexpected command %d", (int)rh.command); + } else if (msg->command != RELAY_COMMAND_BEGIN) { + log_warn(LD_BUG, "Got an unexpected command %u", msg->command); *end_reason_out = END_STREAM_REASON_INTERNAL; return -1; } - body = cell->payload + RELAY_HEADER_SIZE; - nul = memchr(body, 0, rh.length); + body = msg->body; + nul = memchr(body, 0, msg->length); if (! nul) { log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "Relay begin cell has no \\0. Closing."); @@ -3816,7 +4037,7 @@ *end_reason_out = END_STREAM_REASON_TORPROTOCOL; return -1; } - if (body + rh.length >= nul + 4) + if (body + msg->length >= nul + 4) bcell->flags = ntohl(get_uint32(nul+1)); return 0; @@ -3929,10 +4150,9 @@ * Else return 0. */ int -connection_exit_begin_conn(cell_t *cell, circuit_t *circ) +connection_exit_begin_conn(const relay_msg_t *msg, circuit_t *circ) { edge_connection_t *n_stream; - relay_header_t rh; char *address = NULL; uint16_t port = 0; or_circuit_t *or_circ = NULL; @@ -3942,6 +4162,7 @@ begin_cell_t bcell; int rv; uint8_t end_reason=0; + dos_stream_defense_type_t dos_defense_type; assert_circuit_ok(circ); if (!CIRCUIT_IS_ORIGIN(circ)) { @@ -3952,25 +4173,22 @@ layer_hint = origin_circ->cpath->prev; } - relay_header_unpack(&rh, cell->payload); - if (rh.length > RELAY_PAYLOAD_SIZE) - return -END_CIRC_REASON_TORPROTOCOL; - if (!server_mode(options) && circ->purpose != CIRCUIT_PURPOSE_S_REND_JOINED) { log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "Relay begin cell at non-server. Closing."); - relay_send_end_cell_from_edge(rh.stream_id, circ, + relay_send_end_cell_from_edge(msg->stream_id, circ, END_STREAM_REASON_EXITPOLICY, NULL); return 0; } - rv = begin_cell_parse(cell, &bcell, &end_reason); + rv = begin_cell_parse(msg, &bcell, &end_reason); if (rv < -1) { return -END_CIRC_REASON_TORPROTOCOL; } else if (rv == -1) { tor_free(bcell.address); - relay_send_end_cell_from_edge(rh.stream_id, circ, end_reason, layer_hint); + relay_send_end_cell_from_edge(msg->stream_id, circ, end_reason, + layer_hint); return 0; } @@ -3994,7 +4212,7 @@ safe_str(channel_describe_peer(or_circ->p_chan)), client_chan ? "on first hop of circuit" : "from unknown relay"); - relay_send_end_cell_from_edge(rh.stream_id, circ, + relay_send_end_cell_from_edge(msg->stream_id, circ, client_chan ? END_STREAM_REASON_TORPROTOCOL : END_STREAM_REASON_MISC, @@ -4003,11 +4221,12 @@ return 0; } } - } else if (rh.command == RELAY_COMMAND_BEGIN_DIR) { + } else if (msg->command == RELAY_COMMAND_BEGIN_DIR) { if (!directory_permits_begindir_requests(options) || circ->purpose != CIRCUIT_PURPOSE_OR) { - relay_send_end_cell_from_edge(rh.stream_id, circ, - END_STREAM_REASON_NOTDIRECTORY, layer_hint); + relay_send_end_cell_from_edge(msg->stream_id, circ, + END_STREAM_REASON_NOTDIRECTORY, + layer_hint); return 0; } /* Make sure to get the 'real' address of the previous hop: the @@ -4025,8 +4244,8 @@ * isn't "really" a connection here. But we * need to set it to something nonzero. */ } else { - log_warn(LD_BUG, "Got an unexpected command %d", (int)rh.command); - relay_send_end_cell_from_edge(rh.stream_id, circ, + log_warn(LD_BUG, "Got an unexpected command %u", msg->command); + relay_send_end_cell_from_edge(msg->stream_id, circ, END_STREAM_REASON_INTERNAL, layer_hint); return 0; } @@ -4037,7 +4256,7 @@ /* If you don't want IPv4, I can't help. */ if (bcell.flags & BEGIN_FLAG_IPV4_NOT_OK) { tor_free(address); - relay_send_end_cell_from_edge(rh.stream_id, circ, + relay_send_end_cell_from_edge(msg->stream_id, circ, END_STREAM_REASON_EXITPOLICY, layer_hint); return 0; } @@ -4054,7 +4273,7 @@ n_stream->base_.purpose = EXIT_PURPOSE_CONNECT; n_stream->begincell_flags = bcell.flags; - n_stream->stream_id = rh.stream_id; + n_stream->stream_id = msg->stream_id; n_stream->base_.port = port; /* leave n_stream->s at -1, because it's not yet valid */ n_stream->package_window = STREAMWINDOW_START; @@ -4069,7 +4288,7 @@ if (ret == 0) { /* This was a valid cell. Count it as delivered + overhead. */ - circuit_read_valid_data(origin_circ, rh.length); + circuit_read_valid_data(origin_circ, msg->length); } return ret; } @@ -4080,7 +4299,7 @@ /* If we're hibernating or shutting down, we refuse to open new streams. */ if (we_are_hibernating()) { - relay_send_end_cell_from_edge(rh.stream_id, circ, + relay_send_end_cell_from_edge(msg->stream_id, circ, END_STREAM_REASON_HIBERNATING, NULL); connection_free_(TO_CONN(n_stream)); return 0; @@ -4088,7 +4307,7 @@ n_stream->on_circuit = circ; - if (rh.command == RELAY_COMMAND_BEGIN_DIR) { + if (msg->command == RELAY_COMMAND_BEGIN_DIR) { tor_addr_t tmp_addr; tor_assert(or_circ); if (or_circ->p_chan && @@ -4100,6 +4319,24 @@ log_debug(LD_EXIT,"about to start the dns_resolve()."); + // in the future we may want to have a similar defense for BEGIN_DIR and + // BEGIN sent to OS. + dos_defense_type = dos_stream_new_begin_or_resolve_cell(or_circ); + switch (dos_defense_type) { + case DOS_STREAM_DEFENSE_NONE: + break; + case DOS_STREAM_DEFENSE_REFUSE_STREAM: + // we don't use END_STREAM_REASON_RESOURCELIMIT because it would make a + // client mark us as non-functional until they get a new consensus. + relay_send_end_cell_from_edge(msg->stream_id, circ, + END_STREAM_REASON_MISC, layer_hint); + connection_free_(TO_CONN(n_stream)); + return 0; + case DOS_STREAM_DEFENSE_CLOSE_CIRCUIT: + connection_free_(TO_CONN(n_stream)); + return -END_CIRC_REASON_RESOURCELIMIT; + } + /* send it off to the gethostbyname farm */ switch (dns_resolve(n_stream)) { case 1: /* resolve worked; now n_stream is attached to circ. */ @@ -4108,7 +4345,7 @@ connection_exit_connect(n_stream); return 0; case -1: /* resolve failed */ - relay_send_end_cell_from_edge(rh.stream_id, circ, + relay_send_end_cell_from_edge(msg->stream_id, circ, END_STREAM_REASON_RESOLVEFAILED, NULL); /* n_stream got freed. don't touch it. */ break; @@ -4123,17 +4360,17 @@ * Called when we receive a RELAY_COMMAND_RESOLVE cell 'cell' along the * circuit circ; * begin resolving the hostname, and (eventually) reply with a RESOLVED cell. + * + * Return -(some circuit end reason) if we want to tear down circ. + * Else return 0. */ int -connection_exit_begin_resolve(cell_t *cell, or_circuit_t *circ) +connection_exit_begin_resolve(const relay_msg_t *msg, or_circuit_t *circ) { edge_connection_t *dummy_conn; - relay_header_t rh; + dos_stream_defense_type_t dos_defense_type; assert_circuit_ok(TO_CIRCUIT(circ)); - relay_header_unpack(&rh, cell->payload); - if (rh.length > RELAY_PAYLOAD_SIZE) - return -1; /* Note the RESOLVE stream as seen. */ rep_hist_note_exit_stream(RELAY_COMMAND_RESOLVE); @@ -4146,16 +4383,27 @@ * the housekeeping in dns.c would get way more complicated.) */ dummy_conn = edge_connection_new(CONN_TYPE_EXIT, AF_INET); - dummy_conn->stream_id = rh.stream_id; - dummy_conn->base_.address = tor_strndup( - (char*)cell->payload+RELAY_HEADER_SIZE, - rh.length); + dummy_conn->stream_id = msg->stream_id; + dummy_conn->base_.address = tor_strndup((char *) msg->body, msg->length); dummy_conn->base_.port = 0; dummy_conn->base_.state = EXIT_CONN_STATE_RESOLVEFAILED; dummy_conn->base_.purpose = EXIT_PURPOSE_RESOLVE; dummy_conn->on_circuit = TO_CIRCUIT(circ); + dos_defense_type = dos_stream_new_begin_or_resolve_cell(circ); + switch (dos_defense_type) { + case DOS_STREAM_DEFENSE_NONE: + break; + case DOS_STREAM_DEFENSE_REFUSE_STREAM: + dns_send_resolved_error_cell(dummy_conn, RESOLVED_TYPE_ERROR_TRANSIENT); + connection_free_(TO_CONN(dummy_conn)); + return 0; + case DOS_STREAM_DEFENSE_CLOSE_CIRCUIT: + connection_free_(TO_CONN(dummy_conn)); + return -END_CIRC_REASON_RESOURCELIMIT; + } + /* send it off to the gethostbyname farm */ switch (dns_resolve(dummy_conn)) { case -1: /* Impossible to resolve; a resolved cell was sent. */ @@ -4190,6 +4438,76 @@ return 0; } +/* Reapply exit policy to existing connections, possibly terminating + * connections + * no longer allowed by the policy. + */ +void +connection_reapply_exit_policy(config_line_t *changes) +{ + int marked_for_close = 0; + smartlist_t *conn_list = NULL; + smartlist_t *policy = NULL; + int config_change_relevant = 0; + + if (get_options()->ReevaluateExitPolicy == 0) { + return; + } + + for (const config_line_t *line = changes; + line && !config_change_relevant; + line = line->next) { + const char* exit_policy_options[] = { + "ExitRelay", + "ExitPolicy", + "ReducedExitPolicy", + "ReevaluateExitPolicy", + "IPv6Exit", + NULL + }; + for (unsigned int i = 0; exit_policy_options[i] != NULL; ++i) { + if (strcmp(line->key, exit_policy_options[i]) == 0) { + config_change_relevant = 1; + break; + } + } + } + + if (!config_change_relevant) { + /* Policy did not change: no need to iterate over connections */ + return; + } + + // we can't use router_compare_to_my_exit_policy as it depend on the + // descriptor, which is regenerated asynchronously, so we have to parse the + // policy ourselves. + // We don't verify for our own IP, it's not part of the configuration. + if (BUG(policies_parse_exit_policy_from_options(get_options(), NULL, NULL, + &policy) != 0)) { + return; + } + + conn_list = connection_list_by_type_purpose(CONN_TYPE_EXIT, + EXIT_PURPOSE_CONNECT); + + SMARTLIST_FOREACH_BEGIN(conn_list, connection_t *, conn) { + addr_policy_result_t verdict = compare_tor_addr_to_addr_policy(&conn->addr, + conn->port, + policy); + if (verdict != ADDR_POLICY_ACCEPTED) { + connection_edge_end(TO_EDGE_CONN(conn), END_STREAM_REASON_EXITPOLICY); + connection_mark_for_close(conn); + ++marked_for_close; + } + } SMARTLIST_FOREACH_END(conn); + + smartlist_free(conn_list); + smartlist_free(policy); + + log_info(LD_GENERAL, "Marked %d connections to be closed as no longer " + "allowed per ExitPolicy", marked_for_close); +} + /** Return true iff the consensus allows network reentry. The default value is * false if the parameter is not found. */ static bool diff -Nru tor-0.4.7.16/src/core/or/connection_edge.h tor-0.4.9.6/src/core/or/connection_edge.h --- tor-0.4.7.16/src/core/or/connection_edge.h 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/core/or/connection_edge.h 2026-03-25 14:30:34.000000000 +0000 @@ -12,7 +12,10 @@ #ifndef TOR_CONNECTION_EDGE_H #define TOR_CONNECTION_EDGE_H +#include "core/or/relay_msg_st.h" + #include "lib/testsupport/testsupport.h" +#include "lib/encoding/confline.h" #include "feature/hs/hs_service.h" @@ -101,6 +104,7 @@ void connection_ap_about_to_close(entry_connection_t *edge_conn); void connection_exit_about_to_close(edge_connection_t *edge_conn); +void connection_reapply_exit_policy(config_line_t *changes); MOCK_DECL(int, connection_ap_handshake_send_begin,(entry_connection_t *ap_conn)); @@ -127,8 +131,8 @@ int ttl, time_t expires); -int connection_exit_begin_conn(cell_t *cell, circuit_t *circ); -int connection_exit_begin_resolve(cell_t *cell, or_circuit_t *circ); +int connection_exit_begin_conn(const relay_msg_t *msg, circuit_t *circ); +int connection_exit_begin_resolve(const relay_msg_t *msg, or_circuit_t *circ); void connection_exit_connect(edge_connection_t *conn); int connection_edge_is_rendezvous_stream(const edge_connection_t *conn); int connection_ap_can_use_exit(const entry_connection_t *conn, @@ -218,6 +222,7 @@ streamid_t stream_id); int connection_half_edge_is_valid_resolved(smartlist_t *half_conns, streamid_t stream_id); +bool connection_half_edges_waiting(const origin_circuit_t *circ); size_t half_streams_get_total_allocation(void); struct half_edge_t; @@ -265,8 +270,8 @@ unsigned is_begindir : 1; } begin_cell_t; -STATIC int begin_cell_parse(const cell_t *cell, begin_cell_t *bcell, - uint8_t *end_reason_out); +STATIC int begin_cell_parse(const relay_msg_t *msg, begin_cell_t *bcell, + uint8_t *end_reason_out); STATIC int connected_cell_format_payload(uint8_t *payload_out, const tor_addr_t *addr, uint32_t ttl); @@ -305,6 +310,7 @@ STATIC struct half_edge_t *connection_half_edge_find_stream_id( const smartlist_t *half_conns, streamid_t stream_id); +STATIC bool using_old_proxy_auth(const char *auth); #endif /* defined(CONNECTION_EDGE_PRIVATE) */ #endif /* !defined(TOR_CONNECTION_EDGE_H) */ diff -Nru tor-0.4.7.16/src/core/or/connection_or.c tor-0.4.9.6/src/core/or/connection_or.c --- tor-0.4.7.16/src/core/or/connection_or.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/core/or/connection_or.c 2026-03-25 14:30:34.000000000 +0000 @@ -83,14 +83,8 @@ #include "core/or/orconn_event.h" -static int connection_tls_finish_handshake(or_connection_t *conn); static int connection_or_launch_v3_or_handshake(or_connection_t *conn); static int connection_or_process_cells_from_inbuf(or_connection_t *conn); -static int connection_or_check_valid_tls_handshake(or_connection_t *conn, - int started_here, - char *digest_rcvd_out); - -static void connection_or_tls_renegotiated_cb(tor_tls_t *tls, void *_conn); static unsigned int connection_or_is_bad_for_new_circs(or_connection_t *or_conn); @@ -104,7 +98,7 @@ /** * Cast a `connection_t *` to an `or_connection_t *`. * - * Exit with an assertion failure if the input is not an `or_connnection_t`. + * Exit with an assertion failure if the input is not an `or_connection_t`. **/ or_connection_t * TO_OR_CONN(connection_t *c) @@ -116,7 +110,7 @@ /** * Cast a `const connection_t *` to a `const or_connection_t *`. * - * Exit with an assertion failure if the input is not an `or_connnection_t`. + * Exit with an assertion failure if the input is not an `or_connection_t`. **/ const or_connection_t * CONST_TO_OR_CONN(const connection_t *c) @@ -419,7 +413,6 @@ /** Call this to change or_connection_t states, so the owning channel_tls_t can * be notified. */ - MOCK_IMPL(void, connection_or_change_state,(or_connection_t *conn, uint8_t state)) { @@ -435,7 +428,6 @@ /** Return the number of circuits using an or_connection_t; this used to * be an or_connection_t field, but it got moved to channel_t and we * shouldn't maintain two copies. */ - MOCK_IMPL(int, connection_or_get_num_circuits, (or_connection_t *conn)) { @@ -526,7 +518,6 @@ /** * Copy a var_cell_t */ - var_cell_t * var_cell_copy(const var_cell_t *src) { @@ -602,9 +593,8 @@ } return ret; - case OR_CONN_STATE_TLS_SERVER_RENEGOTIATING: case OR_CONN_STATE_OPEN: - case OR_CONN_STATE_OR_HANDSHAKING_V2: + case OR_CONN_STATE_SERVER_VERSIONS_WAIT: case OR_CONN_STATE_OR_HANDSHAKING_V3: return connection_or_process_cells_from_inbuf(conn); default: @@ -708,7 +698,6 @@ } break; case OR_CONN_STATE_OPEN: - case OR_CONN_STATE_OR_HANDSHAKING_V2: case OR_CONN_STATE_OR_HANDSHAKING_V3: break; default: @@ -1080,7 +1069,7 @@ * XXXX connections. */ or_connection_t *best = NULL; - int n_old = 0, n_inprogress = 0, n_canonical = 0, n_other = 0; + int n_canonical = 0; time_t now = time(NULL); /* Pass 1: expire everything that's old, and see what the status of @@ -1089,14 +1078,8 @@ if (connection_or_single_set_badness_(now, or_conn, force)) continue; - if (connection_or_is_bad_for_new_circs(or_conn)) { - ++n_old; - } else if (or_conn->base_.state != OR_CONN_STATE_OPEN) { - ++n_inprogress; - } else if (or_conn->is_canonical) { + if (or_conn->is_canonical) { ++n_canonical; - } else { - ++n_other; } } SMARTLIST_FOREACH_END(or_conn); @@ -1462,7 +1445,6 @@ * * Return the launched conn, or NULL if it failed. */ - MOCK_IMPL(or_connection_t *, connection_or_connect, (const tor_addr_t *_addr, uint16_t port, const char *id_digest, @@ -1609,7 +1591,6 @@ * rather than connections, use channel_mark_for_close(); see also * the comment on that function in channel.c. */ - void connection_or_close_normally(or_connection_t *orconn, int flush) { @@ -1630,7 +1611,6 @@ /** Mark orconn for close and transition the associated channel, if any, to * the error state. */ - MOCK_IMPL(void, connection_or_close_for_error,(or_connection_t *orconn, int flush)) { @@ -1696,35 +1676,6 @@ return 0; } -/** Block all future attempts to renegotiate on 'conn' */ -void -connection_or_block_renegotiation(or_connection_t *conn) -{ - tor_tls_t *tls = conn->tls; - if (!tls) - return; - tor_tls_set_renegotiate_callback(tls, NULL, NULL); - tor_tls_block_renegotiation(tls); -} - -/** Invoked on the server side from inside tor_tls_read() when the server - * gets a successful TLS renegotiation from the client. */ -static void -connection_or_tls_renegotiated_cb(tor_tls_t *tls, void *_conn) -{ - or_connection_t *conn = _conn; - (void)tls; - - /* Don't invoke this again. */ - connection_or_block_renegotiation(conn); - - if (connection_tls_finish_handshake(conn) < 0) { - /* XXXX_TLS double-check that it's ok to do this from inside read. */ - /* XXXX_TLS double-check that this verifies certificates. */ - connection_or_close_for_error(conn, 0); - } -} - /** Move forward with the tls handshake. If it finishes, hand * conn to connection_tls_finish_handshake(). * @@ -1748,26 +1699,24 @@ tor_tls_err_to_string(result)); return -1; case TOR_TLS_DONE: - if (! tor_tls_used_v1_handshake(conn->tls)) { + { if (!tor_tls_is_server(conn->tls)) { tor_assert(conn->base_.state == OR_CONN_STATE_TLS_HANDSHAKING); return connection_or_launch_v3_or_handshake(conn); } else { - /* v2/v3 handshake, but we are not a client. */ + /* v3+ handshake, but we are not a client. */ log_debug(LD_OR, "Done with initial SSL handshake (server-side). " - "Expecting renegotiation or VERSIONS cell"); - tor_tls_set_renegotiate_callback(conn->tls, - connection_or_tls_renegotiated_cb, - conn); + "Expecting VERSIONS cell"); + /* Note: We could instead just send a VERSIONS cell now, + * since the V2 handshake is no longer a thing. + * But that would require re-plumbing this state machine. */ connection_or_change_state(conn, - OR_CONN_STATE_TLS_SERVER_RENEGOTIATING); + OR_CONN_STATE_SERVER_VERSIONS_WAIT); connection_stop_writing(TO_CONN(conn)); connection_start_reading(TO_CONN(conn)); return 0; } } - tor_assert(tor_tls_is_server(conn->tls)); - return connection_tls_finish_handshake(conn); case TOR_TLS_WANTWRITE: connection_start_writing(TO_CONN(conn)); log_debug(LD_OR,"wanted write"); @@ -1798,102 +1747,6 @@ return !tor_tls_is_server(conn->tls); } -/** Conn just completed its handshake. Return 0 if all is well, and - * return -1 if they are lying, broken, or otherwise something is wrong. - * - * If we initiated this connection (started_here is true), make sure - * the other side sent a correctly formed certificate. If I initiated the - * connection, make sure it's the right relay by checking the certificate. - * - * Otherwise (if we _didn't_ initiate this connection), it's okay for - * the certificate to be weird or absent. - * - * If we return 0, and the certificate is as expected, write a hash of the - * identity key into digest_rcvd_out, which must have DIGEST_LEN - * space in it. - * If the certificate is invalid or missing on an incoming connection, - * we return 0 and set digest_rcvd_out to DIGEST_LEN NUL bytes. - * (If we return -1, the contents of this buffer are undefined.) - * - * As side effects, - * 1) Set conn->circ_id_type according to tor-spec.txt. - * 2) If we're an authdirserver and we initiated the connection: drop all - * descriptors that claim to be on that IP/port but that aren't - * this relay; and note that this relay is reachable. - * 3) If this is a bridge and we didn't configure its identity - * fingerprint, remember the keyid we just learned. - */ -static int -connection_or_check_valid_tls_handshake(or_connection_t *conn, - int started_here, - char *digest_rcvd_out) -{ - crypto_pk_t *identity_rcvd=NULL; - const or_options_t *options = get_options(); - int severity = server_mode(options) ? LOG_PROTOCOL_WARN : LOG_WARN; - const char *conn_type = started_here ? "outgoing" : "incoming"; - int has_cert = 0; - - check_no_tls_errors(); - has_cert = tor_tls_peer_has_cert(conn->tls); - if (started_here && !has_cert) { - log_info(LD_HANDSHAKE,"Tried connecting to router at %s, but it didn't " - "send a cert! Closing.", - connection_describe_peer(TO_CONN(conn))); - return -1; - } else if (!has_cert) { - log_debug(LD_HANDSHAKE,"Got incoming connection with no certificate. " - "That's ok."); - } - check_no_tls_errors(); - - if (has_cert) { - int v = tor_tls_verify(started_here?severity:LOG_INFO, - conn->tls, &identity_rcvd); - if (started_here && v<0) { - log_fn(severity,LD_HANDSHAKE,"Tried connecting to router at %s: It" - " has a cert but it's invalid. Closing.", - connection_describe_peer(TO_CONN(conn))); - return -1; - } else if (v<0) { - log_info(LD_HANDSHAKE,"Incoming connection gave us an invalid cert " - "chain; ignoring."); - } else { - log_debug(LD_HANDSHAKE, - "The certificate seems to be valid on %s connection " - "with %s", conn_type, - connection_describe_peer(TO_CONN(conn))); - } - check_no_tls_errors(); - } - - if (identity_rcvd) { - if (crypto_pk_get_digest(identity_rcvd, digest_rcvd_out) < 0) { - crypto_pk_free(identity_rcvd); - return -1; - } - } else { - memset(digest_rcvd_out, 0, DIGEST_LEN); - } - - tor_assert(conn->chan); - channel_set_circid_type(TLS_CHAN_TO_BASE(conn->chan), identity_rcvd, 1); - - crypto_pk_free(identity_rcvd); - - if (started_here) { - /* A TLS handshake can't teach us an Ed25519 ID, so we set it to NULL - * here. */ - log_debug(LD_HANDSHAKE, "Calling client_learned_peer_id from " - "check_valid_tls_handshake"); - return connection_or_client_learned_peer_id(conn, - (const uint8_t*)digest_rcvd_out, - NULL); - } - - return 0; -} - /** Called when we (as a connection initiator) have definitively, * authenticatedly, learned that ID of the Tor instance on the other * side of conn is rsa_peer_id and optionally ed_peer_id. @@ -2074,7 +1927,6 @@ /** Return when we last used this channel for client activity (origin * circuits). This is called from connection.c, since client_used is now one * of the timestamps in channel_t */ - time_t connection_or_client_used(or_connection_t *conn) { @@ -2085,58 +1937,6 @@ } else return 0; } -/** The v1/v2 TLS handshake is finished. - * - * Make sure we are happy with the peer we just handshaked with. - * - * If they initiated the connection, make sure they're not already connected, - * then initialize conn from the information in router. - * - * If all is successful, call circuit_n_conn_done() to handle events - * that have been pending on the tls)); - - if (connection_or_check_valid_tls_handshake(conn, started_here, - digest_rcvd) < 0) - return -1; - - circuit_build_times_network_is_live(get_circuit_build_times_mutable()); - - if (tor_tls_used_v1_handshake(conn->tls)) { - conn->link_proto = 1; - connection_or_init_conn_from_address(conn, &conn->base_.addr, - conn->base_.port, digest_rcvd, - NULL, 0); - tor_tls_block_renegotiation(conn->tls); - rep_hist_note_negotiated_link_proto(1, started_here); - return connection_or_set_state_open(conn); - } else { - connection_or_change_state(conn, OR_CONN_STATE_OR_HANDSHAKING_V2); - if (connection_init_or_handshake_state(conn, started_here) < 0) - return -1; - connection_or_init_conn_from_address(conn, &conn->base_.addr, - conn->base_.port, digest_rcvd, - NULL, 0); - return connection_or_send_versions(conn, 0); - } -} - /** * Called as client when initial TLS handshake is done, and we notice * that we got a v3-handshake signalling certificate from the server. @@ -2433,8 +2233,8 @@ } } -/** Array of recognized link protocol versions. */ -static const uint16_t or_protocol_versions[] = { 1, 2, 3, 4, 5 }; +/** Array of supported link protocol versions. */ +static const uint16_t or_protocol_versions[] = { 3, 4, 5 }; /** Number of versions in or_protocol_versions. */ static const int n_or_protocol_versions = (int)( sizeof(or_protocol_versions)/sizeof(uint16_t) ); diff -Nru tor-0.4.7.16/src/core/or/connection_or.h tor-0.4.9.6/src/core/or/connection_or.h --- tor-0.4.7.16/src/core/or/connection_or.h 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/core/or/connection_or.h 2026-03-25 14:30:34.000000000 +0000 @@ -24,7 +24,6 @@ void connection_or_clear_identity_map(void); void clear_broken_connection_map(int disable); -void connection_or_block_renegotiation(or_connection_t *conn); int connection_or_reached_eof(or_connection_t *conn); int connection_or_process_inbuf(or_connection_t *conn); ssize_t connection_or_num_cells_writeable(or_connection_t *conn); @@ -129,8 +128,4 @@ MOCK_DECL(void, connection_or_change_state, (or_connection_t *conn, uint8_t state)); -#ifdef TOR_UNIT_TESTS -extern int testing__connection_or_pretend_TLSSECRET_is_supported; -#endif - #endif /* !defined(TOR_CONNECTION_OR_H) */ diff -Nru tor-0.4.7.16/src/core/or/connection_st.h tor-0.4.9.6/src/core/or/connection_st.h --- tor-0.4.7.16/src/core/or/connection_st.h 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/core/or/connection_st.h 2026-03-25 14:30:34.000000000 +0000 @@ -88,7 +88,7 @@ * connection. */ unsigned int linked_conn_is_closed:1; /** True iff this connection was opened from a listener and thus we've - * recevied this connection. Else, it means we've initiated an outbound + * received this connection. Else, it means we've initiated an outbound * connection. */ unsigned int from_listener:1; diff -Nru tor-0.4.7.16/src/core/or/cpath_build_state_st.h tor-0.4.9.6/src/core/or/cpath_build_state_st.h --- tor-0.4.7.16/src/core/or/cpath_build_state_st.h 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/core/or/cpath_build_state_st.h 2026-03-25 14:30:34.000000000 +0000 @@ -30,6 +30,8 @@ * These are for encrypted dir conns that exit to this router, not * for arbitrary exits from the circuit. */ unsigned int onehop_tunnel : 1; + /** Indicating the exit needs to support Conflux. */ + unsigned int need_conflux: 1; /** How many times has building a circuit for this task failed? */ int failure_count; /** At what time should we give up on this task? */ diff -Nru tor-0.4.7.16/src/core/or/crypt_path.c tor-0.4.9.6/src/core/or/crypt_path.c --- tor-0.4.7.16/src/core/or/crypt_path.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/core/or/crypt_path.c 2026-03-25 14:30:34.000000000 +0000 @@ -71,6 +71,9 @@ hop->package_window = circuit_initial_package_window(); hop->deliver_window = CIRCWINDOW_START; + // This can get changed later on by circuit negotiation. + hop->relay_cell_format = RELAY_CELL_FORMAT_V0; + return 0; } @@ -113,11 +116,8 @@ relay_crypto_assert_ok(&cp->pvt_crypto); FALLTHROUGH; 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); @@ -145,14 +145,13 @@ * 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) +cpath_init_circuit_crypto(relay_crypto_alg_t alg, + crypt_path_t *cpath, + const char *key_data, size_t key_data_len) { tor_assert(cpath); - return relay_crypto_init(&cpath->pvt_crypto, key_data, key_data_len, - reverse, is_hs_v3); + return relay_crypto_init(alg, &cpath->pvt_crypto, key_data, key_data_len); } /** Deallocate space associated with the cpath node victim. */ @@ -164,7 +163,6 @@ 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); congestion_control_free(victim->ccontrol); @@ -172,51 +170,14 @@ 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 the sendme tag of this cpath, + * along with its length. */ +const uint8_t * +cpath_get_sendme_tag(crypt_path_t *cpath, size_t *len_out) { - 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); + return relay_crypto_get_sendme_tag(&cpath->pvt_crypto, len_out); } /************ other cpath functions ***************************/ diff -Nru tor-0.4.7.16/src/core/or/crypt_path.h tor-0.4.9.6/src/core/or/crypt_path.h --- tor-0.4.7.16/src/core/or/crypt_path.h 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/core/or/crypt_path.h 2026-03-25 14:30:34.000000000 +0000 @@ -6,38 +6,28 @@ #ifndef CRYPT_PATH_H #define CRYPT_PATH_H +#include "core/crypto/relay_crypto.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); +int cpath_init_circuit_crypto(relay_crypto_alg_t alg, + crypt_path_t *cpath, + const char *key_data, size_t key_data_len); 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); +const uint8_t *cpath_get_sendme_tag(crypt_path_t *cpath, size_t *len_out); #if defined(TOR_UNIT_TESTS) unsigned int cpath_get_n_hops(crypt_path_t **head_ptr); diff -Nru tor-0.4.7.16/src/core/or/crypt_path_st.h tor-0.4.9.6/src/core/or/crypt_path_st.h --- tor-0.4.7.16/src/core/or/crypt_path_st.h 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/core/or/crypt_path_st.h 2026-03-25 14:30:34.000000000 +0000 @@ -12,21 +12,22 @@ #ifndef CRYPT_PATH_ST_H #define CRYPT_PATH_ST_H -#include "core/or/relay_crypto_st.h" -struct crypto_dh_t; +#include "core/crypto/relay_crypto_st.h" +#include "core/crypto/onion_crypto.h" #define CRYPT_PATH_MAGIC 0x70127012u struct fast_handshake_state_t; struct ntor_handshake_state_t; -struct crypto_dh_t; struct onion_handshake_state_t { /** One of `ONION_HANDSHAKE_TYPE_*`. Determines which member of the union * is accessible. */ uint16_t tag; + /** Initial circuit parameters (selected during first stage of negotiation; + * may be changed based on response from relay). */ + circuit_params_t chosen_params; union { struct fast_handshake_state_t *fast; - struct crypto_dh_t *tap; struct ntor_handshake_state_t *ntor; struct ntor3_handshake_state_t *ntor3; } u; @@ -55,9 +56,6 @@ /** Current state of the handshake as performed with the OR at this * step. */ onion_handshake_state_t handshake_state; - /** Diffie-hellman handshake state for performing an introduction - * operations */ - struct crypto_dh_t *rend_dh_handshake_state; /** Negotiated key material shared with the OR at this step. */ char rend_circ_nonce[DIGEST_LEN];/* KH in tor-spec.txt */ @@ -88,6 +86,9 @@ /** Congestion control info */ struct congestion_control_t *ccontrol; + /** Format to use when exchanging relay cells with this relay. */ + relay_cell_fmt_t relay_cell_format; + /*********************** Private members ****************************/ /** Private member: Cryptographic state used for encrypting and diff -Nru tor-0.4.7.16/src/core/or/dos.c tor-0.4.9.6/src/core/or/dos.c --- tor-0.4.7.16/src/core/or/dos.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/core/or/dos.c 2026-03-25 14:30:34.000000000 +0000 @@ -21,6 +21,7 @@ #include "feature/relay/routermode.h" #include "feature/stats/geoip_stats.h" #include "lib/crypt_ops/crypto_rand.h" +#include "lib/time/compat_time.h" #include "core/or/dos.h" #include "core/or/dos_sys.h" @@ -78,6 +79,24 @@ static uint32_t dos_num_circ_max_outq; /* + * Stream denial of service mitigation. + * + * Namespace used for this mitigation framework is "dos_stream_". + */ + +/* Is the connection DoS mitigation enabled? */ +static unsigned int dos_stream_enabled = 0; + +/* Consensus parameters. They can be changed when a new consensus arrives. + * They are initialized with the hardcoded default values. */ +static dos_stream_defense_type_t dos_stream_defense_type; +static uint32_t dos_stream_rate = DOS_STREAM_RATE_DEFAULT; +static uint32_t dos_stream_burst = DOS_STREAM_BURST_DEFAULT; + +/* Keep some stats for the heartbeat so we can report out. */ +static uint64_t stream_num_rejected; + +/* * General interface of the denial of service mitigation subsystem. */ @@ -257,6 +276,59 @@ INT32_MAX); } +/* Return true iff the stream creation mitigation is enabled. We look at the + * consensus for this else a default value is returned. */ +MOCK_IMPL(STATIC unsigned int, +get_param_stream_enabled, (const networkstatus_t *ns)) +{ + if (dos_get_options()->DoSStreamCreationEnabled != -1) { + return dos_get_options()->DoSStreamCreationEnabled; + } + + return !!networkstatus_get_param(ns, "DoSStreamCreationEnabled", + DOS_STREAM_ENABLED_DEFAULT, 0, 1); +} + +/* Return the parameter for the time rate that is how many stream per circuit + * over this time span. */ +static uint32_t +get_param_stream_rate(const networkstatus_t *ns) +{ + /* This is in seconds. */ + if (dos_get_options()->DoSStreamCreationRate) { + return dos_get_options()->DoSStreamCreationRate; + } + return networkstatus_get_param(ns, "DoSStreamCreationRate", + DOS_STREAM_RATE_DEFAULT, + 1, INT32_MAX); +} + +/* Return the parameter for the maximum circuit count for the circuit time + * rate. */ +static uint32_t +get_param_stream_burst(const networkstatus_t *ns) +{ + if (dos_get_options()->DoSStreamCreationBurst) { + return dos_get_options()->DoSStreamCreationBurst; + } + return networkstatus_get_param(ns, "DoSStreamCreationBurst", + DOS_STREAM_BURST_DEFAULT, + 1, INT32_MAX); +} + +/* Return the consensus parameter of the circuit creation defense type. */ +static uint32_t +get_param_stream_defense_type(const networkstatus_t *ns) +{ + if (dos_get_options()->DoSStreamCreationDefenseType) { + return dos_get_options()->DoSStreamCreationDefenseType; + } + return networkstatus_get_param(ns, "DoSStreamCreationDefenseType", + DOS_STREAM_DEFENSE_TYPE_DEFAULT, + DOS_STREAM_DEFENSE_NONE, + DOS_STREAM_DEFENSE_MAX); +} + /* Set circuit creation parameters located in the consensus or their default * if none are present. Called at initialization or when the consensus * changes. */ @@ -282,6 +354,12 @@ /* Circuit. */ dos_num_circ_max_outq = get_param_dos_num_circ_max_outq(ns); + + /* Stream. */ + dos_stream_enabled = get_param_stream_enabled(ns); + dos_stream_defense_type = get_param_stream_defense_type(ns); + dos_stream_rate = get_param_stream_rate(ns); + dos_stream_burst = get_param_stream_burst(ns); } /* Free everything for the circuit creation DoS mitigation subsystem. */ @@ -528,7 +606,8 @@ stats->concurrent_count++; /* Refill connect connection count. */ - token_bucket_ctr_refill(&stats->connect_count, (uint32_t) approx_time()); + token_bucket_ctr_refill(&stats->connect_count, + (uint32_t) monotime_coarse_absolute_sec()); /* Decrement counter for this new connection. */ if (token_bucket_ctr_get(&stats->connect_count) > 0) { @@ -558,7 +637,7 @@ { /* Extra super duper safety. Going below 0 means an underflow which could * lead to most likely a false positive. In theory, this should never happen - * but lets be extra safe. */ + * but let's be extra safe. */ if (BUG(stats->concurrent_count == 0)) { return; } @@ -673,7 +752,7 @@ /* This is the detection. Assess at every CREATE cell if the client should * get marked as malicious. This should be kept as fast as possible. */ if (cc_has_exhausted_circuits(&entry->dos_stats)) { - /* If this is the first time we mark this entry, log it a info level. + /* If this is the first time we mark this entry, log it. * Under heavy DDoS, logging each time we mark would results in lots and * lots of logs. */ if (entry->dos_stats.cc_stats.marked_until_ts == 0) { @@ -758,6 +837,48 @@ return DOS_CONN_DEFENSE_NONE; } +/* Stream creation public API. */ + +/** Return the number of rejected stream and resolve. */ +uint64_t +dos_get_num_stream_rejected(void) +{ + return stream_num_rejected; +} + +/* Return the action to take against a BEGIN or RESOLVE cell. Return + * DOS_STREAM_DEFENSE_NONE when no action should be taken. + * Increment the appropriate counter when the cell was found to go over a + * limit. */ +dos_stream_defense_type_t +dos_stream_new_begin_or_resolve_cell(or_circuit_t *circ) +{ + if (!dos_stream_enabled || circ == NULL) + return DOS_STREAM_DEFENSE_NONE; + + token_bucket_ctr_refill(&circ->stream_limiter, + (uint32_t) monotime_coarse_absolute_sec()); + + if (token_bucket_ctr_get(&circ->stream_limiter) > 0) { + token_bucket_ctr_dec(&circ->stream_limiter, 1); + return DOS_STREAM_DEFENSE_NONE; + } + /* if defense type is DOS_STREAM_DEFENSE_NONE but DoSStreamEnabled is true, + * we count offending cells as rejected, despite them being actually + * accepted. */ + ++stream_num_rejected; + return dos_stream_defense_type; +} + +/* Initialize the token bucket for stream rate limit on a circuit. */ +void +dos_stream_init_circ_tbf(or_circuit_t *circ) +{ + token_bucket_ctr_init(&circ->stream_limiter, dos_stream_rate, + dos_stream_burst, + (uint32_t) monotime_coarse_absolute_sec()); +} + /* General API */ /* Take any appropriate actions for the given geoip entry that is about to get @@ -808,7 +929,7 @@ * can be enabled at runtime and these counters need to be valid. */ token_bucket_ctr_init(&geoip_ent->dos_stats.conn_stats.connect_count, dos_conn_connect_rate, dos_conn_connect_burst, - (uint32_t) approx_time()); + (uint32_t) monotime_coarse_absolute_sec()); } /** Note that the given channel has sent outbound the maximum amount of cell @@ -943,6 +1064,14 @@ "[DoSRefuseSingleHopClientRendezvous disabled]"); } + if (dos_stream_enabled) { + smartlist_add_asprintf(elems, + "%" PRIu64 " stream rejected", + stream_num_rejected); + } else { + smartlist_add_asprintf(elems, "[DoSStreamCreationEnabled disabled]"); + } + /* HS DoS stats. */ smartlist_add_asprintf(elems, "%" PRIu64 " INTRODUCE2 rejected", @@ -966,6 +1095,7 @@ clientmap_entry_t *entry; tor_assert(or_conn); + tor_assert_nonfatal(!or_conn->tracked_for_dos_mitigation); /* Past that point, we know we have at least one DoS detection subsystem * enabled so we'll start allocating stuff. */ @@ -973,14 +1103,6 @@ goto end; } - /* We ignore any known address meaning an address of a known relay. The - * reason to do so is because network reentry is possible where a client - * connection comes from an Exit node. Even when we'll fix reentry, this is - * a robust defense to keep in place. */ - if (nodelist_probably_contains_address(&TO_CONN(or_conn)->addr)) { - goto end; - } - /* We are only interested in client connection from the geoip cache. */ entry = geoip_lookup_client(&TO_CONN(or_conn)->addr, transport_name, GEOIP_CLIENT_CONNECT); diff -Nru tor-0.4.7.16/src/core/or/dos.h tor-0.4.9.6/src/core/or/dos.h --- tor-0.4.7.16/src/core/or/dos.h 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/core/or/dos.h 2026-03-25 14:30:34.000000000 +0000 @@ -90,6 +90,7 @@ uint64_t dos_get_num_conn_addr_rejected(void); uint64_t dos_get_num_conn_addr_connect_rejected(void); uint64_t dos_get_num_single_hop_refused(void); +uint64_t dos_get_num_stream_rejected(void); /* * Circuit creation DoS mitigation subsystemn interface. @@ -159,6 +160,37 @@ dos_conn_defense_type_t dos_conn_addr_get_defense_type(const tor_addr_t *addr); +/* + * Stream creation DoS mitigation subsystem interface. + */ + +/* DoSStreamCreationEnabled default. Disabled by deault. */ +#define DOS_STREAM_ENABLED_DEFAULT 0 +/* DoSStreamCreationDefenseType maps to the dos_stream_defense_type_t enum */ +#define DOS_STREAM_DEFENSE_TYPE_DEFAULT DOS_STREAM_DEFENSE_REFUSE_STREAM +/* DosStreamCreationRate is 100 per seconds. */ +#define DOS_STREAM_RATE_DEFAULT 100 +/* DosStreamCreationBurst default. */ +#define DOS_STREAM_BURST_DEFAULT 300 + +/* Type of defense that we can use for the stream creation DoS mitigation. */ +typedef enum dos_stream_defense_type_t { + /* No defense used. */ + DOS_STREAM_DEFENSE_NONE = 1, + /* Reject the stream */ + DOS_STREAM_DEFENSE_REFUSE_STREAM = 2, + /* Close the circuit */ + DOS_STREAM_DEFENSE_CLOSE_CIRCUIT = 3, + + /* Maximum value that can be used. Useful for the boundaries of the + * consensus parameter. */ + DOS_STREAM_DEFENSE_MAX = 3, +} dos_stream_defense_type_t; + +dos_stream_defense_type_t dos_stream_new_begin_or_resolve_cell( + or_circuit_t *circ); +void dos_stream_init_circ_tbf(or_circuit_t *circ); + #ifdef DOS_PRIVATE STATIC uint32_t get_param_conn_max_concurrent_count( @@ -176,6 +208,8 @@ (const networkstatus_t *ns)); MOCK_DECL(STATIC unsigned int, get_param_conn_enabled, (const networkstatus_t *ns)); +MOCK_DECL(STATIC unsigned int, get_param_stream_enabled, + (const networkstatus_t *ns)); #endif /* defined(DOS_PRIVATE) */ diff -Nru tor-0.4.7.16/src/core/or/dos_options.inc tor-0.4.9.6/src/core/or/dos_options.inc --- tor-0.4.7.16/src/core/or/dos_options.inc 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/core/or/dos_options.inc 2026-03-25 14:30:34.000000000 +0000 @@ -50,6 +50,19 @@ /** Allowed rate of client connection allowed per address. */ CONF_VAR(DoSConnectionConnectRate, POSINT, 0, "0") +/** Autobool: Is the stream creation DoS mitigation subsystem enabled? */ +CONF_VAR(DoSStreamCreationEnabled, AUTOBOOL, 0, "auto") + +/** Stream rate used to refill the token bucket. */ +CONF_VAR(DoSStreamCreationRate, POSINT, 0, "0") + +/** Maximum allowed burst of stream. */ +CONF_VAR(DoSStreamCreationBurst, POSINT, 0, "0") + +/** When an circuit is detected as malicious, what defense should be used + * against it. See the dos_stream_defense_type_t enum. */ +CONF_VAR(DoSStreamCreationDefenseType, INT, 0, "0") + /** For how much time (in seconds) the connection connect rate defense is * applicable for a malicious address. A random time delta is added to the * defense time of an address which will be between 1 second and half of this diff -Nru tor-0.4.7.16/src/core/or/edge_connection_st.h tor-0.4.9.6/src/core/or/edge_connection_st.h --- tor-0.4.7.16/src/core/or/edge_connection_st.h 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/core/or/edge_connection_st.h 2026-03-25 14:30:34.000000000 +0000 @@ -28,11 +28,15 @@ * circuit? */ int deliver_window; /**< How many more relay cells can end at me? */ - struct circuit_t *on_circuit; /**< The circuit (if any) that this edge - * connection is using. */ + /** The circuit (if any) that this edge connection is using. + * Note that edges that use conflux should use the helpers + * in conflux_util.c instead of accessing this directly. */ + struct circuit_t *on_circuit; /** A pointer to which node in the circ this conn exits at. Set for AP - * connections and for hidden service exit connections. */ + * connections and for hidden service exit connections. + * Note that edges that use conflux should use the helpers + * in conflux_util.c instead of accessing this directly. */ struct crypt_path_t *cpath_layer; /* Hidden service connection identifier for edge connections. Used by the HS @@ -66,9 +70,6 @@ * connections. Set once we've set the stream end, * and check in connection_about_to_close_connection(). */ - /** True iff we've blocked reading until the circuit has fewer queued - * cells. */ - unsigned int edge_blocked_on_circ:1; /** Unique ID for directory requests; this used to be in connection_t, but * that's going away and being used on channels instead. We still tag @@ -88,6 +89,18 @@ uint64_t drain_start_usec; /** + * Monotime timestamp of when we started the XOFF grace period for this edge. + * + * See the comments on `XOFF_GRACE_PERIOD_USEC` for an explanation on how + * this is used. + * + * A value of 0 is considered "unset". This isn't great, but we set this + * field as the output from `monotime_absolute_usec()` which should only ever + * be 0 within the first 1 microsecond of initializing the monotonic timer + * subsystem. */ + uint64_t xoff_grace_period_start_usec; + + /** * Number of bytes written since we either emptied our buffers, * or sent an advisory drate rate. Can wrap, buf if so, * we must reset the usec timestamp above. (Or make this u64, idk). diff -Nru tor-0.4.7.16/src/core/or/entry_connection_st.h tor-0.4.9.6/src/core/or/entry_connection_st.h --- tor-0.4.7.16/src/core/or/entry_connection_st.h 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/core/or/entry_connection_st.h 2026-03-25 14:30:34.000000000 +0000 @@ -96,6 +96,10 @@ * the exit has sent a CONNECTED cell) and we have chosen to use it. */ unsigned int may_use_optimistic_data : 1; + + /** True iff this is a connection to a HS that has PoW defenses enabled, + * so we know not to apply the usual SOCKS timeout. */ + unsigned int hs_with_pow_conn : 1; }; /** Cast a entry_connection_t subtype pointer to a edge_connection_t **/ diff -Nru tor-0.4.7.16/src/core/or/extend_info_st.h tor-0.4.9.6/src/core/or/extend_info_st.h --- tor-0.4.7.16/src/core/or/extend_info_st.h 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/core/or/extend_info_st.h 2026-03-25 14:30:34.000000000 +0000 @@ -34,14 +34,19 @@ /** IP/Port values for this hop's ORPort(s). Any unused values are set * to a null address. */ tor_addr_port_t orports[EXTEND_INFO_MAX_ADDRS]; - /** TAP onion key for this hop. */ - crypto_pk_t *onion_key; /** Ntor onion key for this hop. */ curve25519_public_key_t curve25519_onion_key; + /** True if this hop supports ntor v3. */ + bool supports_ntor_v3; /** True if this hop is to be used as an _exit_, * and it also supports supports NtorV3 _and_ negotiation * of congestion control parameters */ bool exit_supports_congestion_control; + /** + * True if this hop supports CGO relay message enryption, + * and we intend to use it. + */ + bool enable_cgo; }; #endif /* !defined(EXTEND_INFO_ST_H) */ diff -Nru tor-0.4.7.16/src/core/or/extendinfo.c tor-0.4.9.6/src/core/or/extendinfo.c --- tor-0.4.7.16/src/core/or/extendinfo.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/core/or/extendinfo.c 2026-03-25 14:30:34.000000000 +0000 @@ -33,7 +33,6 @@ extend_info_new(const char *nickname, const char *rsa_id_digest, const ed25519_public_key_t *ed_id, - crypto_pk_t *onion_key, const curve25519_public_key_t *ntor_key, const tor_addr_t *addr, uint16_t port, const protover_summary_flags_t *pv, @@ -46,8 +45,6 @@ memcpy(&info->ed_identity, ed_id, sizeof(ed25519_public_key_t)); if (nickname) strlcpy(info->nickname, nickname, sizeof(info->nickname)); - if (onion_key) - info->onion_key = crypto_pk_dup_key(onion_key); if (ntor_key) memcpy(&info->curve25519_onion_key, ntor_key, sizeof(curve25519_public_key_t)); @@ -64,6 +61,11 @@ pv->supports_congestion_control; } + if (pv) { + info->supports_ntor_v3 = pv->supports_ntor_v3; + info->enable_cgo = pv->supports_cgo; + } + return info; } @@ -100,7 +102,6 @@ extend_info_from_node(const node_t *node, int for_direct_connect, bool for_exit) { - crypto_pk_t *rsa_pubkey = NULL; extend_info_t *info = NULL; tor_addr_port_t ap; int valid_addr = 0; @@ -149,13 +150,11 @@ /* Retrieve the curve25519 pubkey. */ const curve25519_public_key_t *curve_pubkey = node_get_curve25519_onion_key(node); - rsa_pubkey = node_get_rsa_onion_key(node); if (valid_addr && node->ri) { info = extend_info_new(node->ri->nickname, node->identity, ed_pubkey, - rsa_pubkey, curve_pubkey, &ap.addr, ap.port, @@ -165,7 +164,6 @@ info = extend_info_new(node->rs->nickname, node->identity, ed_pubkey, - rsa_pubkey, curve_pubkey, &ap.addr, ap.port, @@ -173,7 +171,6 @@ for_exit); } - crypto_pk_free(rsa_pubkey); return info; } @@ -183,7 +180,6 @@ { if (!info) return; - crypto_pk_free(info->onion_key); tor_free(info); } @@ -196,22 +192,9 @@ tor_assert(info); newinfo = tor_malloc(sizeof(extend_info_t)); memcpy(newinfo, info, sizeof(extend_info_t)); - if (info->onion_key) - newinfo->onion_key = crypto_pk_dup_key(info->onion_key); - else - newinfo->onion_key = NULL; return newinfo; } -/* Does ei have a valid TAP key? */ -int -extend_info_supports_tap(const extend_info_t* ei) -{ - tor_assert(ei); - /* Valid TAP keys are not NULL */ - return ei->onion_key != NULL; -} - /* Does ei have a valid ntor key? */ int extend_info_supports_ntor(const extend_info_t* ei) @@ -228,8 +211,7 @@ extend_info_supports_ntor_v3(const extend_info_t *ei) { tor_assert(ei); - return extend_info_supports_ntor(ei) && - ei->exit_supports_congestion_control; + return ei->supports_ntor_v3; } /* Does ei have an onion key which it would prefer to use? diff -Nru tor-0.4.7.16/src/core/or/extendinfo.h tor-0.4.9.6/src/core/or/extendinfo.h --- tor-0.4.7.16/src/core/or/extendinfo.h 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/core/or/extendinfo.h 2026-03-25 14:30:34.000000000 +0000 @@ -15,7 +15,6 @@ extend_info_t *extend_info_new(const char *nickname, const char *rsa_id_digest, const struct ed25519_public_key_t *ed_id, - crypto_pk_t *onion_key, const struct curve25519_public_key_t *ntor_key, const tor_addr_t *addr, uint16_t port, const struct protover_summary_flags_t *pv, @@ -27,7 +26,6 @@ #define extend_info_free(info) \ FREE_AND_NULL(extend_info_t, extend_info_free_, (info)) int extend_info_addr_is_allowed(const tor_addr_t *addr); -int extend_info_supports_tap(const extend_info_t* ei); int extend_info_supports_ntor(const extend_info_t* ei); int extend_info_supports_ntor_v3(const extend_info_t *ei); int extend_info_has_preferred_onion_key(const extend_info_t* ei); diff -Nru tor-0.4.7.16/src/core/or/half_edge_st.h tor-0.4.9.6/src/core/or/half_edge_st.h --- tor-0.4.7.16/src/core/or/half_edge_st.h 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/core/or/half_edge_st.h 2026-03-25 14:30:34.000000000 +0000 @@ -41,10 +41,10 @@ /** * Did this edge use congestion control? If so, use * timer instead of pending data approach */ - int used_ccontrol : 1; + unsigned int used_ccontrol : 1; /** Is there a connected cell pending? */ - int connected_pending : 1; + unsigned int connected_pending : 1; } half_edge_t; #endif /* !defined(HALF_EDGE_ST_H) */ diff -Nru tor-0.4.7.16/src/core/or/include.am tor-0.4.9.6/src/core/or/include.am --- tor-0.4.7.16/src/core/or/include.am 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/core/or/include.am 2026-03-25 14:30:34.000000000 +0000 @@ -1,6 +1,6 @@ # ADD_C_FILE: INSERT SOURCES HERE. -LIBTOR_APP_A_SOURCES += \ +LIBTOR_APP_A_SOURCES += \ src/core/or/address_set.c \ src/core/or/channel.c \ src/core/or/channelpadding.c \ @@ -18,9 +18,9 @@ src/core/or/connection_edge.c \ src/core/or/connection_or.c \ src/core/or/dos.c \ - src/core/or/dos_config.c \ + src/core/or/dos_config.c \ src/core/or/dos_sys.c \ - src/core/or/extendinfo.c \ + src/core/or/extendinfo.c \ src/core/or/onion.c \ src/core/or/ocirc_event.c \ src/core/or/or_periodic.c \ @@ -30,15 +30,20 @@ src/core/or/protover.c \ src/core/or/reasons.c \ src/core/or/relay.c \ + src/core/or/relay_msg.c \ 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/congestion_control_common.c \ - src/core/or/congestion_control_vegas.c \ - src/core/or/congestion_control_nola.c \ - src/core/or/congestion_control_westwood.c \ - src/core/or/congestion_control_flow.c \ + src/core/or/congestion_control_common.c \ + src/core/or/congestion_control_vegas.c \ + src/core/or/congestion_control_flow.c \ + src/core/or/conflux.c \ + src/core/or/conflux_cell.c \ + src/core/or/conflux_params.c \ + src/core/or/conflux_pool.c \ + src/core/or/conflux_sys.c \ + src/core/or/conflux_util.c \ src/core/or/status.c \ src/core/or/versions.c @@ -61,7 +66,7 @@ src/core/or/circuitpadding_machines.h \ src/core/or/circuituse.h \ src/core/or/command.h \ - src/core/or/congestion_control_st.h \ + src/core/or/congestion_control_st.h \ src/core/or/connection_edge.h \ src/core/or/connection_or.h \ src/core/or/connection_st.h \ @@ -71,9 +76,9 @@ src/core/or/crypt_path_st.h \ src/core/or/destroy_cell_queue_st.h \ src/core/or/dos.h \ - src/core/or/dos_config.h \ - src/core/or/dos_options.inc \ - src/core/or/dos_options_st.h \ + src/core/or/dos_config.h \ + src/core/or/dos_options.inc \ + src/core/or/dos_options_st.h \ src/core/or/dos_sys.h \ src/core/or/edge_connection_st.h \ src/core/or/extendinfo.h \ @@ -100,14 +105,20 @@ src/core/or/protover.h \ src/core/or/reasons.h \ src/core/or/relay.h \ - src/core/or/relay_crypto_st.h \ + src/core/or/relay_msg.h \ + src/core/or/relay_msg_st.h \ src/core/or/scheduler.h \ src/core/or/sendme.h \ - src/core/or/congestion_control_flow.h \ - src/core/or/congestion_control_common.h \ - src/core/or/congestion_control_vegas.h \ - src/core/or/congestion_control_nola.h \ - src/core/or/congestion_control_westwood.h \ + src/core/or/congestion_control_flow.h \ + src/core/or/congestion_control_common.h \ + src/core/or/congestion_control_vegas.h \ + src/core/or/conflux.h \ + src/core/or/conflux_cell.h \ + src/core/or/conflux_params.h \ + src/core/or/conflux_pool.h \ + src/core/or/conflux_st.h \ + src/core/or/conflux_sys.h \ + src/core/or/conflux_util.h \ src/core/or/server_port_cfg_st.h \ src/core/or/socks_request_st.h \ src/core/or/status.h \ @@ -117,9 +128,9 @@ if USE_TRACING_INSTRUMENTATION_LTTNG LIBTOR_APP_A_SOURCES += \ - src/core/or/trace_probes_cc.c \ + src/core/or/trace_probes_cc.c \ src/core/or/trace_probes_circuit.c noinst_HEADERS += \ - src/core/or/trace_probes_cc.h \ + src/core/or/trace_probes_cc.h \ src/core/or/trace_probes_circuit.h endif diff -Nru tor-0.4.7.16/src/core/or/lttng_cc.inc tor-0.4.9.6/src/core/or/lttng_cc.inc --- tor-0.4.7.16/src/core/or/lttng_cc.inc 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/core/or/lttng_cc.inc 2026-03-25 14:30:34.000000000 +0000 @@ -142,7 +142,7 @@ /* Emitted when the BDP value has been updated. */ TRACEPOINT_EVENT(tor_cc, bdp_update, TP_ARGS(const circuit_t *, circ, const congestion_control_t *, cc, - uint64_t, curr_rtt_usec, uint64_t, sendme_rate_bdp), + uint64_t, curr_rtt_usec), TP_FIELDS( ctf_integer(uint64_t, circuit_ptr, circ) ctf_integer(uint32_t, n_circ_id, circ->n_circ_id) @@ -150,11 +150,7 @@ ctf_integer(uint64_t, curr_rtt_usec, curr_rtt_usec) ctf_integer(uint64_t, ewma_rtt_usec, cc->ewma_rtt_usec) ctf_integer(uint64_t, max_rtt_usec, cc->max_rtt_usec) - ctf_integer(uint64_t, bdp_inflight_rtt, cc->bdp[BDP_ALG_INFLIGHT_RTT]) - ctf_integer(uint64_t, bdp_cwnd_rtt, cc->bdp[BDP_ALG_CWND_RTT]) - ctf_integer(uint64_t, bdp_sendme_rate, cc->bdp[BDP_ALG_SENDME_RATE]) - ctf_integer(uint64_t, bdp_piecewise, cc->bdp[BDP_ALG_PIECEWISE]) - ctf_integer(uint64_t, sendme_rate_bdp, sendme_rate_bdp) + ctf_integer(uint64_t, bdp_cwnd_rtt, cc->bdp) ) ) diff -Nru tor-0.4.7.16/src/core/or/onion.c tor-0.4.9.6/src/core/or/onion.c --- tor-0.4.7.16/src/core/or/onion.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/core/or/onion.c 2026-03-25 14:30:34.000000000 +0000 @@ -44,7 +44,6 @@ #include "core/crypto/onion_crypto.h" #include "core/crypto/onion_fast.h" #include "core/crypto/onion_ntor.h" -#include "core/crypto/onion_tap.h" #include "core/or/onion.h" #include "feature/nodelist/networkstatus.h" @@ -61,10 +60,7 @@ { switch (cell->cell_type) { case CELL_CREATE: - if (cell->handshake_type != ONION_HANDSHAKE_TYPE_TAP && - cell->handshake_type != ONION_HANDSHAKE_TYPE_NTOR) - return -1; - break; + return -1; case CELL_CREATE_FAST: if (cell->handshake_type != ONION_HANDSHAKE_TYPE_FAST) return -1; @@ -77,9 +73,7 @@ switch (cell->handshake_type) { case ONION_HANDSHAKE_TYPE_TAP: - if (cell->handshake_len != TAP_ONIONSKIN_CHALLENGE_LEN) - return -1; - break; + return -1; case ONION_HANDSHAKE_TYPE_FAST: if (cell->handshake_len != CREATE_FAST_LEN) return -1; @@ -134,7 +128,7 @@ handshake_type = ntohs(get_uint16(p)); handshake_len = ntohs(get_uint16(p+2)); - if (handshake_len > CELL_PAYLOAD_SIZE - 4 || handshake_len > p_len - 4) + if (handshake_len > MAX_CREATE_LEN || handshake_len > p_len - 4) return -1; if (handshake_type == ONION_HANDSHAKE_TYPE_FAST) return -1; @@ -160,14 +154,7 @@ { switch (cell_in->command) { case CELL_CREATE: - if (tor_memeq(cell_in->payload, NTOR_CREATE_MAGIC, 16)) { - create_cell_init(cell_out, CELL_CREATE, ONION_HANDSHAKE_TYPE_NTOR, - NTOR_ONIONSKIN_LEN, cell_in->payload+16); - } else { - create_cell_init(cell_out, CELL_CREATE, ONION_HANDSHAKE_TYPE_TAP, - TAP_ONIONSKIN_CHALLENGE_LEN, cell_in->payload); - } - break; + return -1; case CELL_CREATE_FAST: create_cell_init(cell_out, CELL_CREATE_FAST, ONION_HANDSHAKE_TYPE_FAST, CREATE_FAST_LEN, cell_in->payload); @@ -190,16 +177,15 @@ { switch (cell->cell_type) { case CELL_CREATED: - if (cell->handshake_len != TAP_ONIONSKIN_REPLY_LEN && - cell->handshake_len != NTOR_REPLY_LEN) - return -1; - break; + return -1; case CELL_CREATED_FAST: if (cell->handshake_len != CREATED_FAST_LEN) return -1; break; case CELL_CREATED2: - if (cell->handshake_len > RELAY_PAYLOAD_SIZE-2) + /* Need to remove 2 bytes because first 2 bytes of the payload is the + * handshake_len value and then the payload. */ + if (cell->handshake_len > (RELAY_PAYLOAD_SIZE_MAX - 2)) return -1; break; } @@ -216,10 +202,7 @@ switch (cell_in->command) { case CELL_CREATED: - cell_out->cell_type = CELL_CREATED; - cell_out->handshake_len = TAP_ONIONSKIN_REPLY_LEN; - memcpy(cell_out->reply, cell_in->payload, TAP_ONIONSKIN_REPLY_LEN); - break; + return -1; case CELL_CREATED_FAST: cell_out->cell_type = CELL_CREATED_FAST; cell_out->handshake_len = CREATED_FAST_LEN; @@ -230,7 +213,7 @@ const uint8_t *p = cell_in->payload; cell_out->cell_type = CELL_CREATED2; cell_out->handshake_len = ntohs(get_uint16(p)); - if (cell_out->handshake_len > CELL_PAYLOAD_SIZE - 2) + if (cell_out->handshake_len > MAX_CREATED_LEN) return -1; memcpy(cell_out->reply, p+2, cell_out->handshake_len); break; @@ -260,53 +243,22 @@ } } if (cell->create_cell.cell_type == CELL_CREATE) { - if (cell->cell_type != RELAY_COMMAND_EXTEND) - return -1; + return -1; } else if (cell->create_cell.cell_type == CELL_CREATE2) { - if (cell->cell_type != RELAY_COMMAND_EXTEND2 && - cell->cell_type != RELAY_COMMAND_EXTEND) + if (cell->cell_type != RELAY_COMMAND_EXTEND2) return -1; } else { /* In particular, no CREATE_FAST cells are allowed */ return -1; } - if (cell->create_cell.handshake_type == ONION_HANDSHAKE_TYPE_FAST) + if (cell->create_cell.handshake_type == ONION_HANDSHAKE_TYPE_FAST || + cell->create_cell.handshake_type == ONION_HANDSHAKE_TYPE_TAP) return -1; return check_create_cell(&cell->create_cell, 1); } static int -extend_cell_from_extend1_cell_body(extend_cell_t *cell_out, - const extend1_cell_body_t *cell) -{ - tor_assert(cell_out); - tor_assert(cell); - memset(cell_out, 0, sizeof(*cell_out)); - tor_addr_make_unspec(&cell_out->orport_ipv4.addr); - tor_addr_make_unspec(&cell_out->orport_ipv6.addr); - - cell_out->cell_type = RELAY_COMMAND_EXTEND; - tor_addr_from_ipv4h(&cell_out->orport_ipv4.addr, cell->ipv4addr); - cell_out->orport_ipv4.port = cell->port; - if (tor_memeq(cell->onionskin, NTOR_CREATE_MAGIC, 16)) { - cell_out->create_cell.cell_type = CELL_CREATE2; - cell_out->create_cell.handshake_type = ONION_HANDSHAKE_TYPE_NTOR; - cell_out->create_cell.handshake_len = NTOR_ONIONSKIN_LEN; - memcpy(cell_out->create_cell.onionskin, cell->onionskin + 16, - NTOR_ONIONSKIN_LEN); - } else { - cell_out->create_cell.cell_type = CELL_CREATE; - cell_out->create_cell.handshake_type = ONION_HANDSHAKE_TYPE_TAP; - cell_out->create_cell.handshake_len = TAP_ONIONSKIN_CHALLENGE_LEN; - memcpy(cell_out->create_cell.onionskin, cell->onionskin, - TAP_ONIONSKIN_CHALLENGE_LEN); - } - memcpy(cell_out->node_id, cell->identity, DIGEST_LEN); - return 0; -} - -static int create_cell_from_create2_cell_body(create_cell_t *cell_out, const create2_cell_body_t *cell) { @@ -403,24 +355,12 @@ tor_assert(cell_out); tor_assert(payload); - if (payload_length > RELAY_PAYLOAD_SIZE) + if (payload_length > RELAY_PAYLOAD_SIZE_MAX) return -1; switch (command) { case RELAY_COMMAND_EXTEND: - { - extend1_cell_body_t *cell = NULL; - if (extend1_cell_body_parse(&cell, payload, payload_length)<0 || - cell == NULL) { - if (cell) - extend1_cell_body_free(cell); - return -1; - } - int r = extend_cell_from_extend1_cell_body(cell_out, cell); - extend1_cell_body_free(cell); - if (r < 0) - return r; - } + return -1; break; case RELAY_COMMAND_EXTEND2: { @@ -463,7 +403,7 @@ } /** Parse an EXTENDED or EXTENDED2 cell (according to command) from the - * payload_length bytes of payload into cell_out. Return + * payload_len bytes of payload into cell_out. Return * 0 on success, -1 on failure. */ int extended_cell_parse(extended_cell_t *cell_out, @@ -474,24 +414,22 @@ tor_assert(payload); memset(cell_out, 0, sizeof(*cell_out)); - if (payload_len > RELAY_PAYLOAD_SIZE) + if (payload_len > RELAY_PAYLOAD_SIZE_MAX) return -1; switch (command) { case RELAY_COMMAND_EXTENDED: - if (payload_len != TAP_ONIONSKIN_REPLY_LEN) - return -1; - cell_out->cell_type = RELAY_COMMAND_EXTENDED; - cell_out->created_cell.cell_type = CELL_CREATED; - cell_out->created_cell.handshake_len = TAP_ONIONSKIN_REPLY_LEN; - memcpy(cell_out->created_cell.reply, payload, TAP_ONIONSKIN_REPLY_LEN); - break; + return -1; case RELAY_COMMAND_EXTENDED2: { + if (payload_len < 2) { + // Prevent underflow below. + return -1; + } cell_out->cell_type = RELAY_COMMAND_EXTENDED2; cell_out->created_cell.cell_type = CELL_CREATED2; cell_out->created_cell.handshake_len = ntohs(get_uint16(payload)); - if (cell_out->created_cell.handshake_len > RELAY_PAYLOAD_SIZE - 2 || + if (cell_out->created_cell.handshake_len > RELAY_PAYLOAD_SIZE_MAX - 2 || cell_out->created_cell.handshake_len > payload_len - 2) return -1; memcpy(cell_out->created_cell.reply, payload+2, @@ -612,7 +550,9 @@ /** Format the EXTEND{,2} cell in cell_in, storing its relay payload in * payload_out, the number of bytes used in *len_out, and the * relay command in *command_out. The payload_out must have - * RELAY_PAYLOAD_SIZE bytes available. Return 0 on success, -1 on failure. */ + * RELAY_PAYLOAD_SIZE_MAX bytes available. + * + * Return 0 on success, -1 on failure. */ int extend_cell_format(uint8_t *command_out, uint16_t *len_out, uint8_t *payload_out, const extend_cell_t *cell_in) @@ -623,30 +563,11 @@ p = payload_out; - memset(p, 0, RELAY_PAYLOAD_SIZE); + memset(p, 0, RELAY_PAYLOAD_SIZE_MAX); switch (cell_in->cell_type) { case RELAY_COMMAND_EXTEND: - { - if (BUG(cell_in->create_cell.handshake_type == - ONION_HANDSHAKE_TYPE_NTOR_V3)) { - log_warn(LD_BUG, "Extend cells cannot contain ntorv3!"); - return -1; - } - *command_out = RELAY_COMMAND_EXTEND; - *len_out = 6 + TAP_ONIONSKIN_CHALLENGE_LEN + DIGEST_LEN; - set_uint32(p, tor_addr_to_ipv4n(&cell_in->orport_ipv4.addr)); - set_uint16(p+4, htons(cell_in->orport_ipv4.port)); - if (cell_in->create_cell.handshake_type == ONION_HANDSHAKE_TYPE_NTOR) { - memcpy(p+6, NTOR_CREATE_MAGIC, 16); - memcpy(p+22, cell_in->create_cell.onionskin, NTOR_ONIONSKIN_LEN); - } else { - memcpy(p+6, cell_in->create_cell.onionskin, - TAP_ONIONSKIN_CHALLENGE_LEN); - } - memcpy(p+6+TAP_ONIONSKIN_CHALLENGE_LEN, cell_in->node_id, DIGEST_LEN); - } - break; + return -1; case RELAY_COMMAND_EXTEND2: { uint8_t n_specifiers = 1; @@ -705,7 +626,7 @@ cell_in->create_cell.handshake_len); ssize_t len_encoded = extend2_cell_body_encode( - payload_out, RELAY_PAYLOAD_SIZE, + payload_out, RELAY_PAYLOAD_SIZE_MAX, cell); extend2_cell_body_free(cell); if (len_encoded < 0 || len_encoded > UINT16_MAX) @@ -723,7 +644,9 @@ /** Format the EXTENDED{,2} cell in cell_in, storing its relay payload * in payload_out, the number of bytes used in *len_out, and the * relay command in *command_out. The payload_out must have - * RELAY_PAYLOAD_SIZE bytes available. Return 0 on success, -1 on failure. */ + * RELAY_PAYLOAD_SIZE_MAX bytes available. + * + * Return 0 on success, -1 on failure. */ int extended_cell_format(uint8_t *command_out, uint16_t *len_out, uint8_t *payload_out, const extended_cell_t *cell_in) @@ -733,24 +656,21 @@ return -1; p = payload_out; - memset(p, 0, RELAY_PAYLOAD_SIZE); + memset(p, 0, RELAY_PAYLOAD_SIZE_MAX); switch (cell_in->cell_type) { case RELAY_COMMAND_EXTENDED: - { - *command_out = RELAY_COMMAND_EXTENDED; - *len_out = TAP_ONIONSKIN_REPLY_LEN; - memcpy(payload_out, cell_in->created_cell.reply, - TAP_ONIONSKIN_REPLY_LEN); - } - break; + return -1; case RELAY_COMMAND_EXTENDED2: { *command_out = RELAY_COMMAND_EXTENDED2; *len_out = 2 + cell_in->created_cell.handshake_len; set_uint16(payload_out, htons(cell_in->created_cell.handshake_len)); - if (2+cell_in->created_cell.handshake_len > RELAY_PAYLOAD_SIZE) + /* We are about to write the handshake payload into the cell which is + * RELAY_PAYLOAD_SIZE_MAX minus the two bytes of the HLEN value. */ + if (cell_in->created_cell.handshake_len > (RELAY_PAYLOAD_SIZE_MAX - 2)) { return -1; + } memcpy(payload_out+2, cell_in->created_cell.reply, cell_in->created_cell.handshake_len); } diff -Nru tor-0.4.7.16/src/core/or/onion.h tor-0.4.9.6/src/core/or/onion.h --- tor-0.4.7.16/src/core/or/onion.h 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/core/or/onion.h 2026-03-25 14:30:34.000000000 +0000 @@ -20,6 +20,9 @@ #define MAX_ONIONSKIN_CHALLENGE_LEN 255 #define MAX_ONIONSKIN_REPLY_LEN 255 +#define MAX_CREATE_LEN (CELL_PAYLOAD_SIZE - 4) +#define MAX_CREATED_LEN (CELL_PAYLOAD_SIZE - 2) + /** A parsed CREATE, CREATE_FAST, or CREATE2 cell. */ typedef struct create_cell_t { /** The cell command. One of CREATE{,_FAST,2} */ @@ -29,7 +32,7 @@ /** The number of bytes used in onionskin. */ uint16_t handshake_len; /** The client-side message for the circuit creation handshake. */ - uint8_t onionskin[CELL_PAYLOAD_SIZE - 4]; + uint8_t onionskin[MAX_CREATE_LEN]; } create_cell_t; /** A parsed CREATED, CREATED_FAST, or CREATED2 cell. */ @@ -39,7 +42,7 @@ /** The number of bytes used in reply. */ uint16_t handshake_len; /** The server-side message for the circuit creation handshake. */ - uint8_t reply[CELL_PAYLOAD_SIZE - 2]; + uint8_t reply[MAX_CREATED_LEN]; } created_cell_t; /** A parsed RELAY_EXTEND or RELAY_EXTEND2 cell */ diff -Nru tor-0.4.7.16/src/core/or/or.h tor-0.4.9.6/src/core/or/or.h --- tor-0.4.7.16/src/core/or/or.h 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/core/or/or.h 2026-03-25 14:30:34.000000000 +0000 @@ -185,18 +185,27 @@ #define RELAY_COMMAND_DATA 2 #define RELAY_COMMAND_END 3 #define RELAY_COMMAND_CONNECTED 4 + #define RELAY_COMMAND_SENDME 5 #define RELAY_COMMAND_EXTEND 6 #define RELAY_COMMAND_EXTENDED 7 #define RELAY_COMMAND_TRUNCATE 8 #define RELAY_COMMAND_TRUNCATED 9 #define RELAY_COMMAND_DROP 10 + #define RELAY_COMMAND_RESOLVE 11 #define RELAY_COMMAND_RESOLVED 12 + #define RELAY_COMMAND_BEGIN_DIR 13 #define RELAY_COMMAND_EXTEND2 14 #define RELAY_COMMAND_EXTENDED2 15 +/* Conflux */ +#define RELAY_COMMAND_CONFLUX_LINK 19 +#define RELAY_COMMAND_CONFLUX_LINKED 20 +#define RELAY_COMMAND_CONFLUX_LINKED_ACK 21 +#define RELAY_COMMAND_CONFLUX_SWITCH 22 + #define RELAY_COMMAND_ESTABLISH_INTRO 32 #define RELAY_COMMAND_ESTABLISH_RENDEZVOUS 33 #define RELAY_COMMAND_INTRODUCE1 34 @@ -213,6 +222,52 @@ #define RELAY_COMMAND_XOFF 43 #define RELAY_COMMAND_XON 44 +/* NOTE: Any new command from above MUST be added to this function. */ +/** Helper to learn if we know the relay command. Unfortuantely, they are not + * contigous and so we need this kind of big switch. We could do better but for + * now, we'll run with this. */ +static inline bool +is_known_relay_command(const uint8_t cmd) +{ + switch (cmd) { + case RELAY_COMMAND_BEGIN: + case RELAY_COMMAND_BEGIN_DIR: + case RELAY_COMMAND_CONFLUX_LINK: + case RELAY_COMMAND_CONFLUX_LINKED: + case RELAY_COMMAND_CONFLUX_LINKED_ACK: + case RELAY_COMMAND_CONFLUX_SWITCH: + case RELAY_COMMAND_CONNECTED: + case RELAY_COMMAND_DATA: + case RELAY_COMMAND_DROP: + case RELAY_COMMAND_END: + case RELAY_COMMAND_ESTABLISH_INTRO: + case RELAY_COMMAND_ESTABLISH_RENDEZVOUS: + case RELAY_COMMAND_EXTEND2: + case RELAY_COMMAND_EXTEND: + case RELAY_COMMAND_EXTENDED2: + case RELAY_COMMAND_EXTENDED: + case RELAY_COMMAND_INTRODUCE1: + case RELAY_COMMAND_INTRODUCE2: + case RELAY_COMMAND_INTRODUCE_ACK: + case RELAY_COMMAND_INTRO_ESTABLISHED: + case RELAY_COMMAND_PADDING_NEGOTIATE: + case RELAY_COMMAND_PADDING_NEGOTIATED: + case RELAY_COMMAND_RENDEZVOUS1: + case RELAY_COMMAND_RENDEZVOUS2: + case RELAY_COMMAND_RENDEZVOUS_ESTABLISHED: + case RELAY_COMMAND_RESOLVE: + case RELAY_COMMAND_RESOLVED: + case RELAY_COMMAND_SENDME: + case RELAY_COMMAND_TRUNCATE: + case RELAY_COMMAND_TRUNCATED: + case RELAY_COMMAND_XOFF: + case RELAY_COMMAND_XON: + return true; + default: + return false; + } +} + /* Reasons why an OR connection is closed. */ #define END_OR_CONN_REASON_DONE 1 #define END_OR_CONN_REASON_REFUSED 2 /* connection refused */ @@ -242,7 +297,6 @@ #define END_STREAM_REASON_CONNRESET 12 #define END_STREAM_REASON_TORPROTOCOL 13 #define END_STREAM_REASON_NOTDIRECTORY 14 -#define END_STREAM_REASON_ENTRYPOLICY 15 /* These high-numbered end reasons are not part of the official spec, * and are not intended to be put in relay end cells. They are here @@ -271,6 +325,11 @@ * way we can't handle. */ #define END_STREAM_REASON_HTTPPROTOCOL 263 +/** + * The user has asked us to do something that we reject + * (Like connecting to a plaintext port, or violating OnionTrafficOnly.) + **/ +#define END_STREAM_REASON_ENTRYPOLICY 264 /** Bitwise-and this value with endreason to mask out all flags. */ #define END_STREAM_REASON_MASK 511 @@ -292,6 +351,8 @@ #define RESOLVED_TYPE_IPV6 6 #define RESOLVED_TYPE_ERROR_TRANSIENT 0xF0 #define RESOLVED_TYPE_ERROR 0xF1 +/* C Tor internal error code to handle empty dns reply */ +#define RESOLVED_TYPE_NOERROR 0x01F2 /* Negative reasons are internal: we never send them in a DESTROY or TRUNCATE * call; they only go to the controller for tracking */ @@ -394,6 +455,11 @@ /** Amount to increment a stream window when we get a stream SENDME. */ #define STREAMWINDOW_INCREMENT 50 +/** Length for authenticated sendme tag with tor1 encryption. */ +#define SENDME_TAG_LEN_TOR1 20 +/** Length for authenticated sendme tag with cgo encryption. */ +#define SENDME_TAG_LEN_CGO 16 + /** Maximum number of queued cells on a circuit for which we are the * midpoint before we give up and kill it. This must be >= circwindow * to avoid killing innocent circuits, and >= circwindow*2 to give @@ -436,10 +502,6 @@ #define LEGAL_NICKNAME_CHARACTERS \ "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" -/** Name to use in client TLS certificates if no nickname is given. Once - * Tor 0.1.2.x is obsolete, we can remove this. */ -#define DEFAULT_CLIENT_NICKNAME "client" - /** Name chosen by routers that don't configure nicknames */ #define UNNAMED_ROUTER_NICKNAME "Unnamed" @@ -447,13 +509,20 @@ #define SOCKS4_NETWORK_LEN 8 /* - * Relay payload: + * Relay cell body (V0): * Relay command [1 byte] * Recognized [2 bytes] * Stream ID [2 bytes] * Partial SHA-1 [4 bytes] * Length [2 bytes] * Relay payload [498 bytes] + * + * Relay cell body (V1): + * Tag [16 bytes] + * Command [1 byte] + * Length [2 bytes] + * Stream ID [2 bytes, Optional, depends on command] + * Relay payload [488 bytes _or_ 490 bytes] */ /** Number of bytes in a cell, minus cell header. */ @@ -465,6 +534,14 @@ /** Maximum length of a header on a variable-length cell. */ #define VAR_CELL_MAX_HEADER_SIZE 7 +/** Which format should we use for relay cells? */ +typedef enum relay_cell_fmt_t { + /** Our original format, with 2 byte recognized field and a 4-byte digest */ + RELAY_CELL_FORMAT_V0, + /** New format introduced for CGO, with 16 byte tag. */ + RELAY_CELL_FORMAT_V1, +} relay_cell_fmt_t; + static int get_cell_network_size(int wide_circ_ids); static inline int get_cell_network_size(int wide_circ_ids) { @@ -482,11 +559,30 @@ return wide_circ_ids ? 4 : 2; } -/** Number of bytes in a relay cell's header (not including general cell - * header). */ -#define RELAY_HEADER_SIZE (1+2+2+4+2) -/** Largest number of bytes that can fit in a relay cell payload. */ -#define RELAY_PAYLOAD_SIZE (CELL_PAYLOAD_SIZE-RELAY_HEADER_SIZE) +/** Number of bytes used for a relay cell's header, in the v0 format. */ +#define RELAY_HEADER_SIZE_V0 (1+2+2+4+2) +/** Number of bytes used for a relay cell's header, in the v1 format, + * if no StreamID is used. */ +#define RELAY_HEADER_SIZE_V1_NO_STREAM_ID (16+1+2) +/** Number of bytes used for a relay cell's header, in the v1 format, + * if a StreamID is used. */ +#define RELAY_HEADER_SIZE_V1_WITH_STREAM_ID (16+1+2+2) + +/** Largest number of bytes that can fit in any relay cell payload. + * + * Note that the actual maximum may be smaller if the V1 cell format + * is in use; see relay_cell_max_payload_size() for the real maximum. + */ +#define RELAY_PAYLOAD_SIZE_MAX (CELL_PAYLOAD_SIZE - RELAY_HEADER_SIZE_V0) + +/** Smallest capacity of any relay cell payload. */ +#define RELAY_PAYLOAD_SIZE_MIN \ + (CELL_PAYLOAD_SIZE - RELAY_HEADER_SIZE_V1_WITH_STREAM_ID) + +#ifdef TOR_UNIT_TESTS +// This name is for testing only. +#define RELAY_PAYLOAD_SIZE RELAY_PAYLOAD_SIZE_MAX +#endif /** Identifies a circuit on an or_connection */ typedef uint32_t circid_t; @@ -517,6 +613,11 @@ typedef struct destroy_cell_queue_t destroy_cell_queue_t; typedef struct ext_or_cmd_t ext_or_cmd_t; +#ifdef TOR_UNIT_TESTS +/* This is a vestigial type used only for testing. + * All current code should instead use relay_msg_t and related accessors. + */ + /** Beginning of a RELAY cell payload. */ typedef struct { uint8_t command; /**< The end-to-end relay command. */ @@ -525,6 +626,7 @@ char integrity[4]; /**< Used to tell whether cell is corrupted. */ uint16_t length; /**< How long is the payload body? */ } relay_header_t; +#endif typedef struct socks_request_t socks_request_t; typedef struct entry_port_cfg_t entry_port_cfg_t; @@ -735,6 +837,15 @@ /** True iff this router supports congestion control. * Requires both FlowCtrl=2 *and* Relay=4 */ unsigned int supports_congestion_control : 1; + + /** True iff this router supports conflux. */ + unsigned int supports_conflux : 1; + + /** True iff this router supports CGO. */ + unsigned int supports_cgo : 1; + + /** True iff this router supports ntorv3 */ + unsigned int supports_ntor_v3 : 1; } protover_summary_flags_t; typedef struct routerinfo_t routerinfo_t; diff -Nru tor-0.4.7.16/src/core/or/or_circuit_st.h tor-0.4.9.6/src/core/or/or_circuit_st.h --- tor-0.4.7.16/src/core/or/or_circuit_st.h 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/core/or/or_circuit_st.h 2026-03-25 14:30:34.000000000 +0000 @@ -35,10 +35,18 @@ cell_queue_t p_chan_cells; /** The channel that is previous in this circuit. */ channel_t *p_chan; - /** Linked list of Exit streams associated with this circuit. */ + /** Linked list of Exit streams associated with this circuit. + * + * Note that any updates to this pointer must be followed with + * conflux_update_n_streams() to keep the other legs n_streams + * in sync. */ edge_connection_t *n_streams; /** Linked list of Exit streams associated with this circuit that are - * still being resolved. */ + * still being resolved. + * + * Just like with n_streams, any updates to this pointer must + * be followed with conflux_update_resolving_streams(). + */ edge_connection_t *resolving_streams; /** Cryptographic state used for encrypting and authenticating relay @@ -73,6 +81,11 @@ * circuit. */ bool used_legacy_circuit_handshake; + /** True if we received a version 0 sendme on this circuit, and it came + * on a legacy (CREATE_FAST) circuit so we allowed it. We track this + * state so we can avoid counting those directory requests for geoip. */ + bool used_obsolete_sendme; + /** Number of cells that were removed from circuit queue; reset every * time when writing buffer stats to disk. */ uint32_t processed_cells; @@ -94,6 +107,14 @@ * used if this is a service introduction circuit at the intro point * (purpose = CIRCUIT_PURPOSE_INTRO_POINT). */ token_bucket_ctr_t introduce2_bucket; + + /** RELAY_BEGIN and RELAY_RESOLVE cell bucket controlling how much can go on + * this circuit. Only used if this is the end of a circuit on an exit node.*/ + token_bucket_ctr_t stream_limiter; + + /** Format to use when exchanging relay cells with the client + * who built this circuit. */ + relay_cell_fmt_t relay_cell_format; }; #endif /* !defined(OR_CIRCUIT_ST_H) */ diff -Nru tor-0.4.7.16/src/core/or/or_connection_st.h tor-0.4.9.6/src/core/or/or_connection_st.h --- tor-0.4.7.16/src/core/or/or_connection_st.h 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/core/or/or_connection_st.h 2026-03-25 14:30:34.000000000 +0000 @@ -28,7 +28,7 @@ /** This is the ClientHash value we expect to receive from the * client during the Extended ORPort authentication protocol. We - * compute it upon receiving the ClientNoce from the client, and we + * compute it upon receiving the ClientNonce from the client, and we * compare it with the actual ClientHash value sent by the * client. */ char *ext_or_auth_correct_client_hash; diff -Nru tor-0.4.7.16/src/core/or/orconn_event.h tor-0.4.9.6/src/core/or/orconn_event.h --- tor-0.4.7.16/src/core/or/orconn_event.h 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/core/or/orconn_event.h 2026-03-25 14:30:34.000000000 +0000 @@ -34,24 +34,16 @@ /** State for an OR connection client: SSL is handshaking, not done * yet. */ #define OR_CONN_STATE_TLS_HANDSHAKING 3 -/** State for a connection to an OR: We're doing a second SSL handshake for - * renegotiation purposes. (V2 handshake only.) */ -#define OR_CONN_STATE_TLS_CLIENT_RENEGOTIATING 4 /** State for a connection at an OR: We're waiting for the client to - * renegotiate (to indicate a v2 handshake) or send a versions cell (to - * indicate a v3 handshake) */ -#define OR_CONN_STATE_TLS_SERVER_RENEGOTIATING 5 -/** State for an OR connection: We're done with our SSL handshake, we've done - * renegotiation, but we haven't yet negotiated link protocol versions and - * sent a netinfo cell. */ -#define OR_CONN_STATE_OR_HANDSHAKING_V2 6 + * send a versions cell (to indicate a v3+ handshake) */ +#define OR_CONN_STATE_SERVER_VERSIONS_WAIT 4 /** State for an OR connection: We're done with our SSL handshake, but we * haven't yet negotiated link protocol versions, done a V3 handshake, and * sent a netinfo cell. */ -#define OR_CONN_STATE_OR_HANDSHAKING_V3 7 +#define OR_CONN_STATE_OR_HANDSHAKING_V3 5 /** State for an OR connection: Ready to send/receive cells. */ -#define OR_CONN_STATE_OPEN 8 -#define OR_CONN_STATE_MAX_ 8 +#define OR_CONN_STATE_OPEN 6 +#define OR_CONN_STATE_MAX_ 6 /** @} */ /** Used to indicate the type of an OR connection event passed to the diff -Nru tor-0.4.7.16/src/core/or/origin_circuit_st.h tor-0.4.9.6/src/core/or/origin_circuit_st.h --- tor-0.4.7.16/src/core/or/origin_circuit_st.h 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/core/or/origin_circuit_st.h 2026-03-25 14:30:34.000000000 +0000 @@ -80,11 +80,18 @@ circuit_t base_; /** Linked list of AP streams (or EXIT streams if hidden service) - * associated with this circuit. */ + * associated with this circuit. + * + * Any updates to this pointer must be followed with + * conflux_update_p_streams(). */ edge_connection_t *p_streams; /** Smartlist of half-closed streams (half_edge_t*) that still - * have pending activity */ + * have pending activity. + * + * Any updates to this pointer must be followed with + * conflux_update_half_streams(). + */ smartlist_t *half_streams; /** Bytes read on this circuit since last call to @@ -205,6 +212,20 @@ * (in host byte order) for response comparison. */ uint32_t pathbias_probe_nonce; + /** This is nonzero iff hs_with_pow_circ is set and there was a valid proof + * of work solution associated with this circuit. */ + uint32_t hs_pow_effort; + + /** Set iff this is a hidden-service circuit for a HS with PoW defenses + * enabled, so that we know to be more lenient with timing out the + * circuit-build to allow the service time to work through the queue of + * requests. */ + unsigned int hs_with_pow_circ : 1; + + /** Set iff this intro circ required a pow, and it has already queued + * the pow with the cpuworker and is awaiting a reply. */ + unsigned int hs_currently_solving_pow : 1; + /** Set iff this circuit has been given a relaxed timeout because * no circuits have opened. Used to prevent spamming logs. */ unsigned int relaxed_timeout : 1; diff -Nru tor-0.4.7.16/src/core/or/policies.c tor-0.4.9.6/src/core/or/policies.c --- tor-0.4.7.16/src/core/or/policies.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/core/or/policies.c 2026-03-25 14:30:34.000000000 +0000 @@ -1066,7 +1066,7 @@ } /** Return 1 if addr is permitted to connect to our metrics port, - * based on socks_policy. Else return 0. + * based on metrics_policy. Else return 0. */ int metrics_policy_permits_address(const tor_addr_t *addr) @@ -1138,7 +1138,7 @@ /** 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 +int policy_using_default_exit_options(const or_options_t *or_options) { return (or_options->ExitPolicy == NULL && or_options->ExitRelay == -1 && @@ -1938,8 +1938,10 @@ "accept *:6679,accept *:6697,accept *:8000,accept *:8008,accept *:8074," \ "accept *:8080,accept *:8082,accept *:8087-8088,accept *:8232-8233," \ "accept *:8332-8333,accept *:8443,accept *:8888,accept *:9418," \ - "accept *:9999,accept *:10000,accept *:11371,accept *:19294," \ - "accept *:19638,accept *:50002,accept *:64738,reject *:*" + "accept *:9999,accept *:10000,accept *:11371," \ + "accept *:18080-18081,accept *:18089," \ + "accept *:19294,accept *:19638,accept *:50002,accept *:64738," \ + "reject *:*" /** Parse the exit policy cfg into the linked list *dest. * diff -Nru tor-0.4.7.16/src/core/or/policies.h tor-0.4.9.6/src/core/or/policies.h --- tor-0.4.7.16/src/core/or/policies.h 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/core/or/policies.h 2026-03-25 14:30:34.000000000 +0000 @@ -108,6 +108,7 @@ int authdir_policy_badexit_address(const tor_addr_t *addr, uint16_t port); int authdir_policy_middleonly_address(const tor_addr_t *addr, uint16_t port); +int policy_using_default_exit_options(const or_options_t *or_options); int validate_addr_policies(const or_options_t *options, char **msg); void policy_expand_private(smartlist_t **policy); void policy_expand_unspec(smartlist_t **policy); diff -Nru tor-0.4.7.16/src/core/or/protover.c tor-0.4.9.6/src/core/or/protover.c --- tor-0.4.7.16/src/core/or/protover.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/core/or/protover.c 2026-03-25 14:30:34.000000000 +0000 @@ -55,6 +55,7 @@ { PRT_PADDING, "Padding"}, { PRT_CONS, "Cons" }, { PRT_FLOWCTRL, "FlowCtrl"}, + { PRT_CONFLUX, "Conflux"}, }; #define N_PROTOCOL_NAMES ARRAY_LENGTH(PROTOCOL_NAMES) @@ -385,23 +386,20 @@ /* * XXX START OF HAZARDOUS ZONE XXX */ -/* All protocol version that this relay version supports. */ +/* All protocol version that this version of tor supports. */ +#define PR_CONFLUX_V "1" #define PR_CONS_V "1-2" -#define PR_DESC_V "1-2" +#define PR_DESC_V "1-4" #define PR_DIRCACHE_V "2" #define PR_FLOWCTRL_V "1-2" #define PR_HSDIR_V "2" #define PR_HSINTRO_V "4-5" #define PR_HSREND_V "1-2" -#define PR_LINK_V "1-5" -#ifdef HAVE_WORKING_TOR_TLS_GET_TLSSECRETS -#define PR_LINKAUTH_V "1,3" -#else +#define PR_LINK_V "3-5" #define PR_LINKAUTH_V "3" -#endif -#define PR_MICRODESC_V "1-2" +#define PR_MICRODESC_V "1-3" #define PR_PADDING_V "2" -#define PR_RELAY_V "1-4" +#define PR_RELAY_V "2-6" /** Return the string containing the supported version for the given protocol * type. */ @@ -409,6 +407,7 @@ protover_get_supported(const protocol_type_t type) { switch (type) { + case PRT_CONFLUX: return PR_CONFLUX_V; case PRT_CONS: return PR_CONS_V; case PRT_DESC: return PR_DESC_V; case PRT_DIRCACHE: return PR_DIRCACHE_V; @@ -471,6 +470,7 @@ */ return + "Conflux=" PR_CONFLUX_V " " "Cons=" PR_CONS_V " " "Desc=" PR_DESC_V " " "DirCache=" PR_DIRCACHE_V " " @@ -517,8 +517,8 @@ const char * protover_get_recommended_client_protocols(void) { - return "Cons=2 Desc=2 DirCache=2 HSDir=2 HSIntro=4 HSRend=2 " - "Link=4-5 Microdesc=2 Relay=2"; + return "Cons=2 Desc=2 DirCache=2 FlowCtrl=1-2 HSDir=2 HSIntro=4 HSRend=2 " + "Link=4-5 Microdesc=2 Relay=2-4"; } /** Return the recommended relay protocols list that directory authorities @@ -526,8 +526,8 @@ const char * protover_get_recommended_relay_protocols(void) { - return "Cons=2 Desc=2 DirCache=2 HSDir=2 HSIntro=4 HSRend=2 " - "Link=4-5 LinkAuth=3 Microdesc=2 Relay=2"; + return "Cons=2 Desc=2 DirCache=2 FlowCtrl=1-2 HSDir=2 HSIntro=4-5 HSRend=2 " + "Link=4-5 LinkAuth=3 Microdesc=2 Relay=2-4"; } /** Return the required client protocols list that directory authorities @@ -535,7 +535,7 @@ const char * protover_get_required_client_protocols(void) { - return "Cons=2 Desc=2 Link=4 Microdesc=2 Relay=2"; + return "Cons=2 Desc=2 FlowCtrl=1 Link=4 Microdesc=2 Relay=2"; } /** Return the required relay protocols list that directory authorities @@ -543,8 +543,8 @@ const char * protover_get_required_relay_protocols(void) { - return "Cons=2 Desc=2 DirCache=2 HSDir=2 HSIntro=4 HSRend=2 " - "Link=4-5 LinkAuth=3 Microdesc=2 Relay=2"; + return "Cons=2 Desc=2 DirCache=2 FlowCtrl=1-2 HSDir=2 HSIntro=4-5 HSRend=2 " + "Link=4-5 LinkAuth=3 Microdesc=2 Relay=2-4"; } /* diff -Nru tor-0.4.7.16/src/core/or/protover.h tor-0.4.9.6/src/core/or/protover.h --- tor-0.4.7.16/src/core/or/protover.h 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/core/or/protover.h 2026-03-25 14:30:34.000000000 +0000 @@ -37,6 +37,8 @@ #define PROTOVER_RELAY_CANONICAL_IPV6 3 /** The protover version number where relays can accept ntorv3 */ #define PROTOVER_RELAY_NTOR_V3 4 +/** The protover that signals conflux support. */ +#define PROTOVER_CONFLUX_V1 1 /** The protover version number that signifies HSv3 intro point support */ #define PROTOVER_HS_INTRO_V3 4 @@ -56,6 +58,14 @@ /** The protover that signals support for congestion control */ #define PROTOVER_FLOWCTRL_CC 2 +/** The protover required for negotiating protovers as part of the circuit + * extension handshake. */ +#define PROTOVER_RELAY_NEGOTIATE_SUBPROTO 5 + +/** The protover required for negotiating protovers as part of the circuit + * extension handshake. */ +#define PROTOVER_RELAY_CRYPT_CGO 6 + /** List of recognized subprotocols. */ /// C_RUST_COUPLED: src/rust/protover/ffi.rs `translate_to_rust` /// C_RUST_COUPLED: src/rust/protover/protover.rs `Proto` @@ -72,6 +82,7 @@ PRT_CONS = 9, PRT_PADDING = 10, PRT_FLOWCTRL = 11, + PRT_CONFLUX = 12, } protocol_type_t; bool protover_list_is_invalid(const char *s); diff -Nru tor-0.4.7.16/src/core/or/reasons.c tor-0.4.9.6/src/core/or/reasons.c --- tor-0.4.7.16/src/core/or/reasons.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/core/or/reasons.c 2026-03-25 14:30:34.000000000 +0000 @@ -23,7 +23,11 @@ /***************************** Edge (stream) reasons **********************/ /** Convert the reason for ending a stream reason into the format used - * in STREAM events. Return NULL if the reason is unrecognized. */ + * in STREAM events. Return NULL if the reason is unrecognized. + * + * Note: For all specified remote reasons that can occur in a Relay END + * message, these are the same as the specified name of the END reason. + */ const char * stream_end_reason_to_control_string(int reason) { @@ -464,38 +468,38 @@ /* XXXX these are probably all wrong. Should they all be 502? */ switch (endreason) { case 0: - return "HTTP/1.0 200 OK\r\n\r\n"; + return "HTTP/1.0 200 OK\r\n"; case END_STREAM_REASON_MISC: - return "HTTP/1.0 500 Internal Server Error\r\n\r\n"; + return "HTTP/1.0 500 Internal Server Error\r\n"; case END_STREAM_REASON_RESOLVEFAILED: - return "HTTP/1.0 404 Not Found (resolve failed)\r\n\r\n"; + return "HTTP/1.0 503 Service Unavailable (resolve failed)\r\n"; case END_STREAM_REASON_NOROUTE: - return "HTTP/1.0 404 Not Found (no route)\r\n\r\n"; + return "HTTP/1.0 503 Service Unavailable (no route)\r\n"; case END_STREAM_REASON_CONNECTREFUSED: - return "HTTP/1.0 403 Forbidden (connection refused)\r\n\r\n"; + return "HTTP/1.0 403 Forbidden (connection refused)\r\n"; case END_STREAM_REASON_EXITPOLICY: - return "HTTP/1.0 403 Forbidden (exit policy)\r\n\r\n"; + return "HTTP/1.0 403 Forbidden (exit policy)\r\n"; case END_STREAM_REASON_DESTROY: - return "HTTP/1.0 502 Bad Gateway (destroy cell received)\r\n\r\n"; + return "HTTP/1.0 502 Bad Gateway (destroy cell received)\r\n"; case END_STREAM_REASON_DONE: - return "HTTP/1.0 502 Bad Gateway (unexpected close)\r\n\r\n"; + return "HTTP/1.0 502 Bad Gateway (unexpected close)\r\n"; case END_STREAM_REASON_TIMEOUT: - return "HTTP/1.0 504 Gateway Timeout\r\n\r\n"; + return "HTTP/1.0 504 Gateway Timeout\r\n"; case END_STREAM_REASON_HIBERNATING: - return "HTTP/1.0 502 Bad Gateway (hibernating server)\r\n\r\n"; + return "HTTP/1.0 502 Bad Gateway (hibernating server)\r\n"; case END_STREAM_REASON_INTERNAL: - return "HTTP/1.0 502 Bad Gateway (internal error)\r\n\r\n"; + return "HTTP/1.0 502 Bad Gateway (internal error)\r\n"; case END_STREAM_REASON_RESOURCELIMIT: - return "HTTP/1.0 502 Bad Gateway (resource limit)\r\n\r\n"; + return "HTTP/1.0 502 Bad Gateway (resource limit)\r\n"; case END_STREAM_REASON_CONNRESET: - return "HTTP/1.0 403 Forbidden (connection reset)\r\n\r\n"; + return "HTTP/1.0 403 Forbidden (connection reset)\r\n"; case END_STREAM_REASON_TORPROTOCOL: - return "HTTP/1.0 502 Bad Gateway (tor protocol violation)\r\n\r\n"; + return "HTTP/1.0 502 Bad Gateway (tor protocol violation)\r\n"; case END_STREAM_REASON_ENTRYPOLICY: - return "HTTP/1.0 403 Forbidden (entry policy violation)\r\n\r\n"; + return "HTTP/1.0 403 Forbidden (entry policy violation)\r\n"; case END_STREAM_REASON_NOTDIRECTORY: FALLTHROUGH; default: tor_assert_nonfatal_unreached(); - return "HTTP/1.0 500 Internal Server Error (weird end reason)\r\n\r\n"; + return "HTTP/1.0 500 Internal Server Error (weird end reason)\r\n"; } } diff -Nru tor-0.4.7.16/src/core/or/relay.c tor-0.4.9.6/src/core/or/relay.c --- tor-0.4.7.16/src/core/or/relay.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/core/or/relay.c 2026-03-25 14:30:34.000000000 +0000 @@ -45,6 +45,7 @@ * types of relay cells, launching requests or transmitting data as needed. **/ +#include "lib/log/log.h" #define RELAY_PRIVATE #include "core/or/or.h" #include "feature/client/addressmap.h" @@ -84,6 +85,7 @@ #include "core/or/scheduler.h" #include "feature/hs/hs_metrics.h" #include "feature/stats/rephist.h" +#include "core/or/relay_msg.h" #include "core/or/cell_st.h" #include "core/or/cell_queue_st.h" @@ -99,8 +101,13 @@ #include "core/or/sendme.h" #include "core/or/congestion_control_common.h" #include "core/or/congestion_control_flow.h" +#include "core/or/conflux.h" +#include "core/or/conflux_util.h" +#include "core/or/conflux_pool.h" +#include "core/or/relay_msg_st.h" -static edge_connection_t *relay_lookup_conn(circuit_t *circ, cell_t *cell, +static edge_connection_t *relay_lookup_conn(circuit_t *circ, + const relay_msg_t *msg, cell_direction_t cell_direction, crypt_path_t *layer_hint); @@ -116,6 +123,13 @@ entry_connection_t *conn, node_t *node, const tor_addr_t *addr); +static int connection_edge_process_ordered_relay_cell(const relay_msg_t *msg, + circuit_t *circ, + edge_connection_t *conn, + crypt_path_t *layer_hint); +static void set_block_state_for_streams(circuit_t *circ, + edge_connection_t *stream_list, + int block, streamid_t stream_id); /** Stats: how many relay cells have originated at this hop, or have * been relayed onward (not recognized at this hop)? @@ -216,7 +230,7 @@ * - If not recognized, then we need to relay it: append it to the appropriate * cell_queue on circ. * - * Return -reason on failure. + * Return -reason on failure, else 0. */ int circuit_receive_relay_cell(cell_t *cell, circuit_t *circ, @@ -245,14 +259,19 @@ if (recognized) { edge_connection_t *conn = NULL; + relay_cell_fmt_t format = circuit_get_relay_format(circ, layer_hint); - /* 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); + relay_msg_t msg_buf; + if (relay_msg_decode_cell_in_place(format, cell, &msg_buf) < 0) { + log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, + "Received undecodable relay cell"); + return -END_CIRC_REASON_TORPROTOCOL; + } + const relay_msg_t *msg = &msg_buf; if (circ->purpose == CIRCUIT_PURPOSE_PATH_BIAS_TESTING) { - if (pathbias_check_probe_response(circ, cell) == -1) { - pathbias_count_valid_cells(circ, cell); + if (pathbias_check_probe_response(circ, msg) == -1) { + pathbias_count_valid_cells(circ, msg); } /* We need to drop this cell no matter what to avoid code that expects @@ -260,22 +279,21 @@ return 0; } - conn = relay_lookup_conn(circ, cell, cell_direction, layer_hint); + conn = relay_lookup_conn(circ, msg, cell_direction, layer_hint); if (cell_direction == CELL_DIRECTION_OUT) { ++stats_n_relay_cells_delivered; log_debug(LD_OR,"Sending away from origin."); - reason = connection_edge_process_relay_cell(cell, circ, conn, NULL); + reason = connection_edge_process_relay_cell(msg, circ, conn, NULL); if (reason < 0) { log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "connection_edge_process_relay_cell (away from origin) " "failed."); return reason; } - } - if (cell_direction == CELL_DIRECTION_IN) { + } else if (cell_direction == CELL_DIRECTION_IN) { ++stats_n_relay_cells_delivered; log_debug(LD_OR,"Sending to origin."); - reason = connection_edge_process_relay_cell(cell, circ, conn, + reason = connection_edge_process_relay_cell(msg, circ, conn, layer_hint); if (reason < 0) { /* If a client is trying to connect to unknown hidden service port, @@ -326,10 +344,8 @@ cell->command = CELL_RELAY; /* can't be relay_early anyway */ if ((reason = circuit_receive_relay_cell(cell, TO_CIRCUIT(splice_), CELL_DIRECTION_IN)) < 0) { - log_warn(LD_REND, "Error relaying cell across rendezvous; closing " + log_info(LD_REND, "Error relaying cell across rendezvous; closing " "circuits"); - /* XXXX Do this here, or just return -1? */ - circuit_mark_for_close(circ, -reason); return reason; } return 0; @@ -354,14 +370,19 @@ * we might kill the circ before we relay * the cells. */ - append_cell_to_circuit_queue(circ, chan, cell, cell_direction, 0); + if (append_cell_to_circuit_queue(circ, chan, cell, cell_direction, 0) < 0) { + return -END_CIRC_REASON_RESOURCELIMIT; + } return 0; } /** Package a relay cell from an edge: * - Encrypt it to the right layer * - Append it to the appropriate cell_queue on circ. - */ + * + * Return 1 if the cell was successfully sent as in queued on the circuit. + * Return 0 if the cell needs to be dropped as in ignored. + * Return -1 on error for which the circuit should be marked for close. */ MOCK_IMPL(int, circuit_package_relay_cell, (cell_t *cell, circuit_t *circ, cell_direction_t cell_direction, @@ -419,45 +440,41 @@ } ++stats_n_relay_cells_relayed; - append_cell_to_circuit_queue(circ, chan, cell, cell_direction, on_stream); - return 0; + return append_cell_to_circuit_queue(circ, chan, cell, + cell_direction, on_stream); } /** If cell's stream_id matches the stream_id of any conn that's * attached to circ, return that conn, else return NULL. */ static edge_connection_t * -relay_lookup_conn(circuit_t *circ, cell_t *cell, +relay_lookup_conn(circuit_t *circ, const relay_msg_t *msg, cell_direction_t cell_direction, crypt_path_t *layer_hint) { edge_connection_t *tmpconn; - relay_header_t rh; - - relay_header_unpack(&rh, cell->payload); - if (!rh.stream_id) + if (!msg->stream_id) return NULL; /* IN or OUT cells could have come from either direction, now * that we allow rendezvous *to* an OP. */ - if (CIRCUIT_IS_ORIGIN(circ)) { for (tmpconn = TO_ORIGIN_CIRCUIT(circ)->p_streams; tmpconn; tmpconn=tmpconn->next_stream) { - if (rh.stream_id == tmpconn->stream_id && + if (msg->stream_id == tmpconn->stream_id && !tmpconn->base_.marked_for_close && - tmpconn->cpath_layer == layer_hint) { - log_debug(LD_APP,"found conn for stream %d.", rh.stream_id); + edge_uses_cpath(tmpconn, layer_hint)) { + log_debug(LD_APP,"found conn for stream %d.", msg->stream_id); return tmpconn; } } } else { for (tmpconn = TO_OR_CIRCUIT(circ)->n_streams; tmpconn; tmpconn=tmpconn->next_stream) { - if (rh.stream_id == tmpconn->stream_id && + if (msg->stream_id == tmpconn->stream_id && !tmpconn->base_.marked_for_close) { - log_debug(LD_EXIT,"found conn for stream %d.", rh.stream_id); + log_debug(LD_EXIT,"found conn for stream %d.", msg->stream_id); if (cell_direction == CELL_DIRECTION_OUT || connection_edge_is_rendezvous_stream(tmpconn)) return tmpconn; @@ -465,9 +482,9 @@ } for (tmpconn = TO_OR_CIRCUIT(circ)->resolving_streams; tmpconn; tmpconn=tmpconn->next_stream) { - if (rh.stream_id == tmpconn->stream_id && + if (msg->stream_id == tmpconn->stream_id && !tmpconn->base_.marked_for_close) { - log_debug(LD_EXIT,"found conn for stream %d.", rh.stream_id); + log_debug(LD_EXIT,"found conn for stream %d.", msg->stream_id); return tmpconn; } } @@ -475,6 +492,7 @@ return NULL; /* probably a begin relay cell */ } +#ifdef TOR_UNIT_TESTS /** Pack the relay_header_t host-order structure src into * network-order in the buffer dest. See tor-spec.txt for details * about the wire format. @@ -501,6 +519,7 @@ memcpy(dest->integrity, src+5, 4); dest->length = ntohs(get_uint16(src+9)); } +#endif /** Convert the relay command into a human-readable string. */ const char * @@ -535,6 +554,10 @@ case RELAY_COMMAND_EXTENDED2: return "EXTENDED2"; case RELAY_COMMAND_PADDING_NEGOTIATE: return "PADDING_NEGOTIATE"; case RELAY_COMMAND_PADDING_NEGOTIATED: return "PADDING_NEGOTIATED"; + case RELAY_COMMAND_CONFLUX_LINK: return "CONFLUX_LINK"; + case RELAY_COMMAND_CONFLUX_LINKED: return "CONFLUX_LINKED"; + case RELAY_COMMAND_CONFLUX_LINKED_ACK: return "CONFLUX_LINKED_ACK"; + case RELAY_COMMAND_CONFLUX_SWITCH: return "CONFLUX_SWITCH"; default: tor_snprintf(buf, sizeof(buf), "Unrecognized relay command %u", (unsigned)command); @@ -542,64 +565,6 @@ } } -/** 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 @@ -610,20 +575,70 @@ * return 0. */ MOCK_IMPL(int, -relay_send_command_from_edge_,(streamid_t stream_id, circuit_t *circ, +relay_send_command_from_edge_,(streamid_t stream_id, circuit_t *orig_circ, uint8_t relay_command, const char *payload, size_t payload_len, crypt_path_t *cpath_layer, const char *filename, int lineno)) { cell_t cell; - relay_header_t rh; cell_direction_t cell_direction; + circuit_t *circ = orig_circ; + + /* If conflux is enabled, decide which leg to send on, and use that */ + if (orig_circ->conflux && conflux_should_multiplex(relay_command)) { + circ = conflux_decide_circ_for_send(orig_circ->conflux, orig_circ, + relay_command); + if (!circ) { + /* Something is wrong with the conflux set. We are done. */ + return -1; + } + /* Conflux circuits always send multiplexed relay commands to + * to the last hop. (Non-multiplexed commands go on their + * original circuit and hop). */ + cpath_layer = conflux_get_destination_hop(circ); + } + + /* This is possible because we have protocol error paths when deciding the + * next circuit to send which can close the whole set. Bail out early. */ + if (circ->marked_for_close) { + return -1; + } + /* XXXX NM Split this function into a separate versions per circuit type? */ tor_assert(circ); - tor_assert(payload_len <= RELAY_PAYLOAD_SIZE); - memset(&cell, 0, sizeof(cell_t)); + size_t msg_body_len; + { + relay_cell_fmt_t cell_format = circuit_get_relay_format(circ, cpath_layer); + relay_msg_t msg = {0}; + if (payload_len > + relay_cell_max_payload_size(cell_format, relay_command)) { + // TODO CGO: Rate-limit this? + log_warn(LD_BUG, "Tried to send a command %d of length %d in " + "a v%d cell, from %s:%d", + (int)relay_command, (int)payload_len, (int)cell_format, + filename, lineno); + circuit_mark_for_close(circ, END_CIRC_REASON_INTERNAL); + return -1; + } + + msg.command = relay_command; + msg.stream_id = stream_id; + msg.length = payload_len; + msg.body = (const uint8_t *) payload; + msg_body_len = msg.length; + // If this cell should be RELAY_EARLY, we'll change the type + // later in this function. + msg.is_relay_early = false; + + if (relay_msg_encode_cell(cell_format, &msg, &cell) < 0) { + // We already called IF_BUG_ONCE in relay_msg_encode_cell. + circuit_mark_for_close(circ, END_CIRC_REASON_INTERNAL); + return -1; + } + } + cell.command = CELL_RELAY; if (CIRCUIT_IS_ORIGIN(circ)) { tor_assert(cpath_layer); @@ -635,17 +650,6 @@ cell_direction = CELL_DIRECTION_IN; } - memset(&rh, 0, sizeof(rh)); - rh.command = relay_command; - rh.stream_id = stream_id; - rh.length = payload_len; - relay_header_pack(cell.payload, &rh); - 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"); @@ -704,14 +708,28 @@ /* Let's assume we're well-behaved: Anything that we decide to send is * valid, delivered data. */ - circuit_sent_valid_data(origin_circ, rh.length); + circuit_sent_valid_data(origin_circ, msg_body_len); } - if (circuit_package_relay_cell(&cell, circ, cell_direction, cpath_layer, - stream_id, filename, lineno) < 0) { - log_warn(LD_BUG,"circuit_package_relay_cell failed. Closing."); + int ret = circuit_package_relay_cell(&cell, circ, cell_direction, + cpath_layer, stream_id, filename, + lineno); + if (ret < 0) { circuit_mark_for_close(circ, END_CIRC_REASON_INTERNAL); return -1; + } else if (ret == 0) { + /* This means we should drop the cell or that the circuit was already + * marked for close. At this point in time, we do NOT close the circuit if + * the cell is dropped. It is not the case with arti where each circuit + * protocol violation will lead to closing the circuit. */ + return 0; + } + + /* At this point, we are certain that the cell was queued on the circuit and + * thus will be sent on the wire. */ + + if (circ->conflux) { + conflux_note_cell_sent(circ->conflux, circ, relay_command); } /* If applicable, note the cell digest for the SENDME version 1 purpose if @@ -719,6 +737,15 @@ * because the cell digest is set within that function. */ if (relay_command == RELAY_COMMAND_DATA) { sendme_record_cell_digest_on_circ(circ, cpath_layer); + + /* 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."); + circuit_mark_for_close(circ, END_CIRC_REASON_TORPROTOCOL); + return -1; + } } return 0; @@ -742,6 +769,7 @@ circuit_t *circ; crypt_path_t *cpath_layer = fromconn->cpath_layer; tor_assert(fromconn); + circ = fromconn->on_circuit; if (fromconn->base_.marked_for_close) { @@ -811,16 +839,16 @@ */ static int connection_ap_process_end_not_open( - relay_header_t *rh, cell_t *cell, origin_circuit_t *circ, + const relay_msg_t *msg, origin_circuit_t *circ, entry_connection_t *conn, crypt_path_t *layer_hint) { node_t *exitrouter; - int reason = *(cell->payload+RELAY_HEADER_SIZE); + int reason = get_uint8(msg->body); int control_reason; edge_connection_t *edge_conn = ENTRY_TO_EDGE_CONN(conn); (void) layer_hint; /* unused */ - if (rh->length > 0) { + if (msg->length > 0) { if (reason == END_STREAM_REASON_TORPROTOCOL || reason == END_STREAM_REASON_DESTROY) { /* Both of these reasons could mean a failed tag @@ -843,9 +871,9 @@ } /* This end cell is now valid. */ - circuit_read_valid_data(circ, rh->length); + circuit_read_valid_data(circ, msg->length); - if (rh->length == 0) { + if (msg->length == 0) { reason = END_STREAM_REASON_MISC; } @@ -864,19 +892,17 @@ case END_STREAM_REASON_EXITPOLICY: { tor_addr_t addr; tor_addr_make_unspec(&addr); - if (rh->length >= 5) { + if (msg->length >= 5) { int ttl = -1; tor_addr_make_unspec(&addr); - if (rh->length == 5 || rh->length == 9) { - tor_addr_from_ipv4n(&addr, - get_uint32(cell->payload+RELAY_HEADER_SIZE+1)); - if (rh->length == 9) - ttl = (int)ntohl(get_uint32(cell->payload+RELAY_HEADER_SIZE+5)); - } else if (rh->length == 17 || rh->length == 21) { - tor_addr_from_ipv6_bytes(&addr, - (cell->payload+RELAY_HEADER_SIZE+1)); - if (rh->length == 21) - ttl = (int)ntohl(get_uint32(cell->payload+RELAY_HEADER_SIZE+17)); + if (msg->length == 5 || msg->length == 9) { + tor_addr_from_ipv4n(&addr, get_uint32(msg->body + 1)); + if (msg->length == 9) + ttl = (int)ntohl(get_uint32(msg->body + 5)); + } else if (msg->length == 17 || msg->length == 21) { + tor_addr_from_ipv6_bytes(&addr, msg->body + 1); + if (msg->length == 21) + ttl = (int)ntohl(get_uint32(msg->body + 17)); } if (tor_addr_is_null(&addr)) { log_info(LD_APP,"Address '%s' resolved to 0.0.0.0. Closing,", @@ -998,7 +1024,7 @@ log_info(LD_APP, "Edge got end (%s) before we're connected. Marking for close.", - stream_end_reason_to_string(rh->length > 0 ? reason : -1)); + stream_end_reason_to_string(msg->length > 0 ? reason : -1)); circuit_log_path(LOG_INFO,LD_APP,circ); /* need to test because of detach_retriable */ if (!ENTRY_TO_CONN(conn)->marked_for_close) @@ -1071,17 +1097,17 @@ * connection), and that the ttl can be absent (in which case ttl_out * is set to -1). */ STATIC int -connected_cell_parse(const relay_header_t *rh, const cell_t *cell, - tor_addr_t *addr_out, int *ttl_out) +connected_cell_parse(const relay_msg_t *msg, tor_addr_t *addr_out, + int *ttl_out) { uint32_t bytes; - const uint8_t *payload = cell->payload + RELAY_HEADER_SIZE; + const uint8_t *payload = msg->body; tor_addr_make_unspec(addr_out); *ttl_out = -1; - if (rh->length == 0) + if (msg->length == 0) return 0; - if (rh->length < 4) + if (msg->length < 4) return -1; bytes = ntohl(get_uint32(payload)); @@ -1089,13 +1115,13 @@ if (bytes != 0) { /* v4 address */ tor_addr_from_ipv4h(addr_out, bytes); - if (rh->length >= 8) { + if (msg->length >= 8) { bytes = ntohl(get_uint32(payload + 4)); if (bytes <= INT32_MAX) *ttl_out = bytes; } } else { - if (rh->length < 25) /* 4 bytes of 0s, 1 addr, 16 ipv4, 4 ttl. */ + if (msg->length < 25) /* 4 bytes of 0s, 1 addr, 16 ipv4, 4 ttl. */ return -1; if (get_uint8(payload + 4) != 6) return -1; @@ -1123,8 +1149,8 @@ * one of 0, RESOLVED_TYPE_ERROR, or RESOLVED_TYPE_ERROR_TRANSIENT, and * return 0. */ STATIC int -resolved_cell_parse(const cell_t *cell, const relay_header_t *rh, - smartlist_t *addresses_out, int *errcode_out) +resolved_cell_parse(const relay_msg_t *msg, smartlist_t *addresses_out, + int *errcode_out) { const uint8_t *cp; uint8_t answer_type; @@ -1134,21 +1160,20 @@ int errcode = 0; smartlist_t *addrs; - tor_assert(cell); - tor_assert(rh); + tor_assert(msg); tor_assert(addresses_out); tor_assert(errcode_out); *errcode_out = 0; - if (rh->length > RELAY_PAYLOAD_SIZE) + if (msg->length > RELAY_PAYLOAD_SIZE_MAX) return -1; addrs = smartlist_new(); - cp = cell->payload + RELAY_HEADER_SIZE; + cp = msg->body; - remaining = rh->length; + remaining = msg->length; while (remaining) { const uint8_t *cp_orig = cp; if (remaining < 2) @@ -1279,7 +1304,7 @@ /* Now convert it to the ugly old interface */ if (! addr_best) { connection_ap_handshake_socks_resolved(conn, - RESOLVED_TYPE_ERROR,0,NULL,-1,-1); + RESOLVED_TYPE_NOERROR,0,NULL,-1,-1); return; } @@ -1295,8 +1320,7 @@ * stream. */ STATIC int connection_edge_process_resolved_cell(edge_connection_t *conn, - const cell_t *cell, - const relay_header_t *rh) + const relay_msg_t *msg) { entry_connection_t *entry_conn = EDGE_TO_ENTRY_CONN(conn); smartlist_t *resolved_addresses = NULL; @@ -1310,7 +1334,7 @@ tor_assert(SOCKS_COMMAND_IS_RESOLVE(entry_conn->socks_request->command)); resolved_addresses = smartlist_new(); - if (resolved_cell_parse(cell, rh, resolved_addresses, &errcode)) { + if (resolved_cell_parse(msg, resolved_addresses, &errcode)) { log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "Dropping malformed 'resolved' cell"); connection_mark_unattached_ap(entry_conn, END_STREAM_REASON_TORPROTOCOL); @@ -1343,7 +1367,7 @@ /* This is valid data at this point. Count it */ if (conn->on_circuit && CIRCUIT_IS_ORIGIN(conn->on_circuit)) { circuit_read_valid_data(TO_ORIGIN_CIRCUIT(conn->on_circuit), - rh->length); + msg->length); } connection_ap_handshake_socks_got_resolved_cell(entry_conn, @@ -1370,27 +1394,26 @@ */ static int connection_edge_process_relay_cell_not_open( - relay_header_t *rh, cell_t *cell, circuit_t *circ, + const relay_msg_t *msg, circuit_t *circ, edge_connection_t *conn, crypt_path_t *layer_hint) { - if (rh->command == RELAY_COMMAND_END) { + if (msg->command == RELAY_COMMAND_END) { if (CIRCUIT_IS_ORIGIN(circ) && conn->base_.type == CONN_TYPE_AP) { - return connection_ap_process_end_not_open(rh, cell, + return connection_ap_process_end_not_open(msg, TO_ORIGIN_CIRCUIT(circ), EDGE_TO_ENTRY_CONN(conn), layer_hint); } else { /* we just got an 'end', don't need to send one */ conn->edge_has_sent_end = 1; - conn->end_reason = *(cell->payload+RELAY_HEADER_SIZE) | - END_STREAM_REASON_FLAG_REMOTE; + conn->end_reason = get_uint8(msg->body) | END_STREAM_REASON_FLAG_REMOTE; connection_mark_for_close(TO_CONN(conn)); return 0; } } if (conn->base_.type == CONN_TYPE_AP && - rh->command == RELAY_COMMAND_CONNECTED) { + msg->command == RELAY_COMMAND_CONNECTED) { tor_addr_t addr; int ttl; entry_connection_t *entry_conn = EDGE_TO_ENTRY_CONN(conn); @@ -1405,9 +1428,9 @@ log_info(LD_APP,"'connected' received for circid %u streamid %d " "after %d seconds.", (unsigned)circ->n_circ_id, - rh->stream_id, + msg->stream_id, (int)(time(NULL) - conn->base_.timestamp_last_read_allowed)); - if (connected_cell_parse(rh, cell, &addr, &ttl) < 0) { + if (connected_cell_parse(msg, &addr, &ttl) < 0) { log_fn(LOG_PROTOCOL_WARN, LD_APP, "Got a badly formatted connected cell. Closing."); connection_edge_end(conn, END_STREAM_REASON_TORPROTOCOL); @@ -1423,7 +1446,7 @@ (get_options()->ClientDNSRejectInternalAddresses && tor_addr_is_internal(&addr, 0))) { log_info(LD_APP, "...but it claims the IP address was %s. Closing.", - fmt_addr(&addr)); + safe_str(fmt_addr(&addr))); connection_edge_end(conn, END_STREAM_REASON_TORPROTOCOL); connection_mark_unattached_ap(entry_conn, END_STREAM_REASON_TORPROTOCOL); @@ -1434,7 +1457,7 @@ (family == AF_INET6 && ! entry_conn->entry_cfg.ipv6_traffic)) { log_fn(LOG_PROTOCOL_WARN, LD_APP, "Got a connected cell to %s with unsupported address family." - " Closing.", fmt_addr(&addr)); + " Closing.", safe_str(fmt_addr(&addr))); connection_edge_end(conn, END_STREAM_REASON_TORPROTOCOL); connection_mark_unattached_ap(entry_conn, END_STREAM_REASON_TORPROTOCOL); @@ -1485,7 +1508,7 @@ } /* This is valid data at this point. Count it */ - circuit_read_valid_data(TO_ORIGIN_CIRCUIT(circ), rh->length); + circuit_read_valid_data(TO_ORIGIN_CIRCUIT(circ), msg->length); /* handle anything that might have queued */ if (connection_edge_package_raw_inbuf(conn, 1, NULL) < 0) { @@ -1496,13 +1519,13 @@ return 0; } if (conn->base_.type == CONN_TYPE_AP && - rh->command == RELAY_COMMAND_RESOLVED) { - return connection_edge_process_resolved_cell(conn, cell, rh); + msg->command == RELAY_COMMAND_RESOLVED) { + return connection_edge_process_resolved_cell(conn, msg); } log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "Got an unexpected relay command %d, in state %d (%s). Dropping.", - rh->command, conn->base_.state, + msg->command, conn->base_.state, conn_state_to_string(conn->base_.type, conn->base_.state)); return 0; /* for forward compatibility, don't kill the circuit */ // connection_edge_end(conn, END_STREAM_REASON_TORPROTOCOL); @@ -1510,25 +1533,6 @@ // return -1; } -/** - * Return true iff our decryption layer_hint is from the last hop - * in a circuit. - */ -static bool -relay_crypt_from_last_hop(origin_circuit_t *circ, crypt_path_t *layer_hint) -{ - tor_assert(circ); - tor_assert(layer_hint); - tor_assert(circ->cpath); - - if (layer_hint != circ->cpath->prev) { - log_fn(LOG_PROTOCOL_WARN, LD_CIRC, - "Got unexpected relay data from intermediate hop"); - return false; - } - return true; -} - /** 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 @@ -1537,19 +1541,18 @@ * 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) +process_sendme_cell(const relay_msg_t *msg, circuit_t *circ, + edge_connection_t *conn, crypt_path_t *layer_hint, + int domain) { int ret; - tor_assert(rh); + tor_assert(msg); - if (!rh->stream_id) { + if (!msg->stream_id) { /* Circuit level SENDME cell. */ - ret = sendme_process_circuit_level(layer_hint, circ, - cell->payload + RELAY_HEADER_SIZE, - rh->length); + ret = sendme_process_circuit_level(layer_hint, circ, msg->body, + msg->length); if (ret < 0) { return ret; } @@ -1565,22 +1568,22 @@ 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); + msg->stream_id)) { + circuit_read_valid_data(ocirc, msg->length); log_info(domain, "Sendme cell on circ %u valid on half-closed " "stream id %d", - ocirc->global_identifier, rh->stream_id); + ocirc->global_identifier, msg->stream_id); } } log_info(domain, "SENDME cell dropped, unknown stream (streamid %d).", - rh->stream_id); + msg->stream_id); return 0; } /* Stream level SENDME cell. */ // TODO: Turn this off for cc_alg=1,2,3; use XON/XOFF instead - ret = sendme_process_stream_level(conn, circ, rh->length); + ret = sendme_process_stream_level(conn, circ, msg->length); if (ret < 0) { /* Means we need to close the circuit with reason ret. */ return ret; @@ -1614,24 +1617,35 @@ * parent function. */ STATIC int -handle_relay_cell_command(cell_t *cell, circuit_t *circ, - edge_connection_t *conn, crypt_path_t *layer_hint, - relay_header_t *rh, int optimistic_data) +handle_relay_msg(const relay_msg_t *msg, circuit_t *circ, + edge_connection_t *conn, crypt_path_t *layer_hint, + int optimistic_data) { unsigned domain = layer_hint?LD_APP:LD_EXIT; int reason; - tor_assert(rh); + tor_assert(msg); /* First pass the cell to the circuit padding subsystem, in case it's a * padding cell or circuit that should be handled there. */ - if (circpad_check_received_cell(cell, circ, layer_hint, rh) == 0) { + if (circpad_check_received_cell(msg, circ, layer_hint) == 0) { log_debug(domain, "Cell handled as circuit padding"); return 0; } /* Now handle all the other commands */ - switch (rh->command) { + switch (msg->command) { + case RELAY_COMMAND_CONFLUX_LINK: + conflux_process_link(circ, msg); + return 0; + case RELAY_COMMAND_CONFLUX_LINKED: + conflux_process_linked(circ, layer_hint, msg); + return 0; + case RELAY_COMMAND_CONFLUX_LINKED_ACK: + conflux_process_linked_ack(circ); + return 0; + case RELAY_COMMAND_CONFLUX_SWITCH: + return conflux_process_switch_command(circ, layer_hint, msg); case RELAY_COMMAND_BEGIN: case RELAY_COMMAND_BEGIN_DIR: if (layer_hint && @@ -1652,7 +1666,7 @@ "Begin cell for known stream. Dropping."); return 0; } - if (rh->command == RELAY_COMMAND_BEGIN_DIR && + if (msg->command == RELAY_COMMAND_BEGIN_DIR && circ->purpose != CIRCUIT_PURPOSE_S_REND_JOINED) { /* Assign this circuit and its app-ward OR connection a unique ID, * so that we can measure download times. The local edge and dir @@ -1662,24 +1676,11 @@ circ->dirreq_id = ++next_id; TO_OR_CIRCUIT(circ)->p_chan->dirreq_id = circ->dirreq_id; } - return connection_exit_begin_conn(cell, circ); + return connection_exit_begin_conn(msg, circ); case RELAY_COMMAND_DATA: ++stats_n_data_cells_received; - /* 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."); - connection_edge_end_close(conn, END_STREAM_REASON_TORPROTOCOL); - return -END_CIRC_REASON_TORPROTOCOL; - } - - /* Consider sending a circuit-level SENDME cell. */ - sendme_circuit_consider_sending(circ, layer_hint); - - if (rh->stream_id == 0) { + if (msg->stream_id == 0) { log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "Relay data cell with zero " "stream_id. Dropping."); return 0; @@ -1687,23 +1688,22 @@ if (CIRCUIT_IS_ORIGIN(circ)) { origin_circuit_t *ocirc = TO_ORIGIN_CIRCUIT(circ); if (connection_half_edge_is_valid_data(ocirc->half_streams, - rh->stream_id)) { - circuit_read_valid_data(ocirc, rh->length); + msg->stream_id)) { + circuit_read_valid_data(ocirc, msg->length); log_info(domain, "data cell on circ %u valid on half-closed " - "stream id %d", ocirc->global_identifier, rh->stream_id); + "stream id %d", ocirc->global_identifier, msg->stream_id); } } log_info(domain,"data cell dropped, unknown stream (streamid %d).", - rh->stream_id); + msg->stream_id); return 0; } /* 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."); @@ -1711,20 +1711,19 @@ return -END_CIRC_REASON_TORPROTOCOL; } /* Total all valid application bytes delivered */ - if (CIRCUIT_IS_ORIGIN(circ) && rh->length > 0) { - circuit_read_valid_data(TO_ORIGIN_CIRCUIT(circ), rh->length); + if (CIRCUIT_IS_ORIGIN(circ) && msg->length > 0) { + circuit_read_valid_data(TO_ORIGIN_CIRCUIT(circ), msg->length); } /* For onion service connection, update the metrics. */ if (conn->hs_ident) { hs_metrics_app_write_bytes(&conn->hs_ident->identity_pk, conn->hs_ident->orig_virtual_port, - rh->length); + msg->length); } - stats_n_data_bytes_received += rh->length; - connection_buf_add((char*)(cell->payload + RELAY_HEADER_SIZE), - rh->length, TO_CONN(conn)); + stats_n_data_bytes_received += msg->length; + connection_buf_add((char*) msg->body, msg->length, TO_CONN(conn)); #ifdef MEASUREMENTS_21206 /* Count number of RELAY_DATA cells received on a linked directory @@ -1750,16 +1749,16 @@ origin_circuit_t *ocirc = TO_ORIGIN_CIRCUIT(circ); if (relay_crypt_from_last_hop(ocirc, layer_hint) && connection_half_edge_is_valid_data(ocirc->half_streams, - rh->stream_id)) { - circuit_read_valid_data(ocirc, rh->length); + msg->stream_id)) { + circuit_read_valid_data(ocirc, msg->length); } } return 0; } - if (circuit_process_stream_xoff(conn, layer_hint, cell)) { + if (circuit_process_stream_xoff(conn, layer_hint)) { if (CIRCUIT_IS_ORIGIN(circ)) { - circuit_read_valid_data(TO_ORIGIN_CIRCUIT(circ), rh->length); + circuit_read_valid_data(TO_ORIGIN_CIRCUIT(circ), msg->length); } } return 0; @@ -1769,35 +1768,34 @@ origin_circuit_t *ocirc = TO_ORIGIN_CIRCUIT(circ); if (relay_crypt_from_last_hop(ocirc, layer_hint) && connection_half_edge_is_valid_data(ocirc->half_streams, - rh->stream_id)) { - circuit_read_valid_data(ocirc, rh->length); + msg->stream_id)) { + circuit_read_valid_data(ocirc, msg->length); } } return 0; } - if (circuit_process_stream_xon(conn, layer_hint, cell)) { + if (circuit_process_stream_xon(conn, layer_hint, msg)) { if (CIRCUIT_IS_ORIGIN(circ)) { - circuit_read_valid_data(TO_ORIGIN_CIRCUIT(circ), rh->length); + circuit_read_valid_data(TO_ORIGIN_CIRCUIT(circ), msg->length); } } return 0; case RELAY_COMMAND_END: - reason = rh->length > 0 ? - get_uint8(cell->payload+RELAY_HEADER_SIZE) : END_STREAM_REASON_MISC; + reason = msg->length > 0 ? get_uint8(msg->body) : END_STREAM_REASON_MISC; if (!conn) { if (CIRCUIT_IS_ORIGIN(circ)) { origin_circuit_t *ocirc = TO_ORIGIN_CIRCUIT(circ); if (relay_crypt_from_last_hop(ocirc, layer_hint) && connection_half_edge_is_valid_end(ocirc->half_streams, - rh->stream_id)) { + msg->stream_id)) { - circuit_read_valid_data(ocirc, rh->length); + circuit_read_valid_data(ocirc, msg->length); log_info(domain, "end cell (%s) on circ %u valid on half-closed " "stream id %d", stream_end_reason_to_string(reason), - ocirc->global_identifier, rh->stream_id); + ocirc->global_identifier, msg->stream_id); return 0; } } @@ -1829,7 +1827,7 @@ /* Total all valid application bytes delivered */ if (CIRCUIT_IS_ORIGIN(circ)) { - circuit_read_valid_data(TO_ORIGIN_CIRCUIT(circ), rh->length); + circuit_read_valid_data(TO_ORIGIN_CIRCUIT(circ), msg->length); } } return 0; @@ -1837,18 +1835,18 @@ case RELAY_COMMAND_EXTEND2: { static uint64_t total_n_extend=0, total_nonearly=0; total_n_extend++; - if (rh->stream_id) { + if (msg->stream_id) { log_fn(LOG_PROTOCOL_WARN, domain, "'extend' cell received for non-zero stream. Dropping."); return 0; } - if (cell->command != CELL_RELAY_EARLY && + if (!msg->is_relay_early && !networkstatus_get_param(NULL,"AllowNonearlyExtend",0,0,1)) { #define EARLY_WARNING_INTERVAL 3600 static ratelim_t early_warning_limit = RATELIM_INIT(EARLY_WARNING_INTERVAL); char *m; - if (cell->command == CELL_RELAY) { + if (!msg->is_relay_early) { ++total_nonearly; if ((m = rate_limit_log(&early_warning_limit, approx_time()))) { double percentage = ((double)total_nonearly)/total_n_extend; @@ -1862,11 +1860,11 @@ } else { log_fn(LOG_WARN, domain, "EXTEND cell received, in a cell with type %d! Dropping.", - cell->command); + msg->command); } return 0; } - return circuit_extend(cell, circ); + return circuit_extend(msg, circ); } case RELAY_COMMAND_EXTENDED: case RELAY_COMMAND_EXTENDED2: @@ -1878,9 +1876,8 @@ log_debug(domain,"Got an extended cell! Yay."); { extended_cell_t extended_cell; - if (extended_cell_parse(&extended_cell, rh->command, - (const uint8_t*)cell->payload+RELAY_HEADER_SIZE, - rh->length)<0) { + if (extended_cell_parse(&extended_cell, msg->command, + msg->body, msg->length) < 0) { log_warn(LD_PROTOCOL, "Can't parse EXTENDED cell; killing circuit."); return -END_CIRC_REASON_TORPROTOCOL; @@ -1898,7 +1895,7 @@ } /* Total all valid bytes delivered. */ if (CIRCUIT_IS_ORIGIN(circ)) { - circuit_read_valid_data(TO_ORIGIN_CIRCUIT(circ), rh->length); + circuit_read_valid_data(TO_ORIGIN_CIRCUIT(circ), msg->length); } return 0; case RELAY_COMMAND_TRUNCATE: @@ -1916,7 +1913,7 @@ circuit_set_state(circ, CIRCUIT_STATE_OPEN); } if (circ->n_chan) { - uint8_t trunc_reason = get_uint8(cell->payload + RELAY_HEADER_SIZE); + uint8_t trunc_reason = get_uint8(msg->body); circuit_synchronize_written_or_bandwidth(circ, CIRCUIT_N_CHAN); circuit_clear_cell_queue(circ, circ->n_chan); channel_send_destroy(circ->n_circ_id, circ->n_chan, @@ -1941,11 +1938,9 @@ /* Count the truncated as valid, for completeness. The * circuit is being torn down anyway, though. */ if (CIRCUIT_IS_ORIGIN(circ)) { - circuit_read_valid_data(TO_ORIGIN_CIRCUIT(circ), - rh->length); + circuit_read_valid_data(TO_ORIGIN_CIRCUIT(circ), msg->length); } - circuit_truncated(TO_ORIGIN_CIRCUIT(circ), - get_uint8(cell->payload + RELAY_HEADER_SIZE)); + circuit_truncated(TO_ORIGIN_CIRCUIT(circ), get_uint8(msg->body)); return 0; case RELAY_COMMAND_CONNECTED: if (conn) { @@ -1957,11 +1952,11 @@ if (CIRCUIT_IS_ORIGIN(circ)) { origin_circuit_t *ocirc = TO_ORIGIN_CIRCUIT(circ); if (connection_half_edge_is_valid_connected(ocirc->half_streams, - rh->stream_id)) { - circuit_read_valid_data(ocirc, rh->length); + msg->stream_id)) { + circuit_read_valid_data(ocirc, msg->length); log_info(domain, "connected cell on circ %u valid on half-closed " - "stream id %d", ocirc->global_identifier, rh->stream_id); + "stream id %d", ocirc->global_identifier, msg->stream_id); return 0; } } @@ -1969,10 +1964,10 @@ log_info(domain, "'connected' received on circid %u for streamid %d, " "no conn attached anymore. Ignoring.", - (unsigned)circ->n_circ_id, rh->stream_id); + (unsigned)circ->n_circ_id, msg->stream_id); return 0; case RELAY_COMMAND_SENDME: - return process_sendme_cell(rh, cell, circ, conn, layer_hint, domain); + return process_sendme_cell(msg, circ, conn, layer_hint, domain); case RELAY_COMMAND_RESOLVE: if (layer_hint) { log_fn(LOG_PROTOCOL_WARN, LD_APP, @@ -1988,8 +1983,7 @@ circ->purpose); return 0; } - connection_exit_begin_resolve(cell, TO_OR_CIRCUIT(circ)); - return 0; + return connection_exit_begin_resolve(msg, TO_OR_CIRCUIT(circ)); case RELAY_COMMAND_RESOLVED: if (conn) { log_fn(LOG_PROTOCOL_WARN, domain, @@ -2001,11 +1995,11 @@ origin_circuit_t *ocirc = TO_ORIGIN_CIRCUIT(circ); if (relay_crypt_from_last_hop(ocirc, layer_hint) && connection_half_edge_is_valid_resolved(ocirc->half_streams, - rh->stream_id)) { - circuit_read_valid_data(ocirc, rh->length); + msg->stream_id)) { + circuit_read_valid_data(ocirc, msg->length); log_info(domain, "resolved cell on circ %u valid on half-closed " - "stream id %d", ocirc->global_identifier, rh->stream_id); + "stream id %d", ocirc->global_identifier, msg->stream_id); return 0; } } @@ -2023,14 +2017,13 @@ case RELAY_COMMAND_INTRO_ESTABLISHED: case RELAY_COMMAND_RENDEZVOUS_ESTABLISHED: rend_process_relay_cell(circ, layer_hint, - rh->command, rh->length, - cell->payload+RELAY_HEADER_SIZE); + msg->command, msg->length, msg->body); return 0; } log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "Received unknown relay command %d. Perhaps the other side is using " "a newer version of Tor? Dropping.", - rh->command); + msg->command); return 0; /* for forward compatibility, don't kill the circuit */ } @@ -2044,50 +2037,118 @@ * Return -reason if you want to warn and tear down the circuit, else 0. */ STATIC int -connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ, +connection_edge_process_relay_cell(const relay_msg_t *msg, circuit_t *circ, edge_connection_t *conn, crypt_path_t *layer_hint) { static int num_seen=0; - relay_header_t rh; unsigned domain = layer_hint?LD_APP:LD_EXIT; - int optimistic_data = 0; /* Set to 1 if we receive data on a stream - * that's in the EXIT_CONN_STATE_RESOLVING - * or EXIT_CONN_STATE_CONNECTING states. */ - tor_assert(cell); + tor_assert(msg); tor_assert(circ); - relay_header_unpack(&rh, cell->payload); // log_fn(LOG_DEBUG,"command %d stream %d", rh.command, rh.stream_id); num_seen++; log_debug(domain, "Now seen %d relay cells here (command %d, stream %d).", - num_seen, rh.command, rh.stream_id); + num_seen, msg->command, msg->stream_id); - if (rh.length > RELAY_PAYLOAD_SIZE) { - log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, - "Relay cell length field too long. Closing circuit."); - return - END_CIRC_REASON_TORPROTOCOL; - } - - if (rh.stream_id == 0) { - switch (rh.command) { + if (msg->stream_id == 0) { + switch (msg->command) { case RELAY_COMMAND_BEGIN: case RELAY_COMMAND_CONNECTED: case RELAY_COMMAND_END: case RELAY_COMMAND_RESOLVE: case RELAY_COMMAND_RESOLVED: case RELAY_COMMAND_BEGIN_DIR: - log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "Relay command %d with zero " - "stream_id. Dropping.", (int)rh.command); + log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "Relay command %u with zero " + "stream_id. Dropping.", msg->command); return 0; default: ; } } + /* Regardless of conflux or not, we always decide to send a SENDME + * for RELAY_DATA immediately + */ + if (msg->command == RELAY_COMMAND_DATA) { + /* 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."); + connection_edge_end_close(conn, END_STREAM_REASON_TORPROTOCOL); + return -END_CIRC_REASON_TORPROTOCOL; + } + + /* Consider sending a circuit-level SENDME cell. */ + sendme_circuit_consider_sending(circ, layer_hint); + + /* Continue on to process the data cell via conflux or not */ + } + + /* Conflux handling: If conflux is disabled, or the relay command is not + * multiplexed across circuits, then process it immediately. + * + * Otherwise, we need to process the relay cell against our conflux + * queues, and if doing so results in ordered cells to deliver, we + * dequeue and process those in-order until there are no more. + */ + if (!circ->conflux || !conflux_should_multiplex(msg->command)) { + return connection_edge_process_ordered_relay_cell(msg, circ, conn, + layer_hint); + } else { + // If conflux says this cell is in-order, then begin processing + // cells from queue until there are none. Otherwise, we do nothing + // until further cells arrive. + if (conflux_process_relay_msg(circ->conflux, circ, layer_hint, + (relay_msg_t *) msg)) { + conflux_msg_t *c_msg = NULL; + + /* First, process this cell */ + int ret = connection_edge_process_ordered_relay_cell( + msg, circ, conn, layer_hint); + if (ret < 0) { + return ret; + } + + /* Now, check queue for more */ + while ((c_msg = conflux_dequeue_relay_msg(circ))) { + conn = relay_lookup_conn(circ, c_msg->msg, CELL_DIRECTION_OUT, + layer_hint); + ret = connection_edge_process_ordered_relay_cell(c_msg->msg, circ, + conn, + layer_hint); + if (ret < 0) { + /* Negative return value is a fatal error. Return early and tear down + * circuit */ + conflux_relay_msg_free(c_msg); + return ret; + } + conflux_relay_msg_free(c_msg); + } + } + } + + return 0; +} + +/** + * Helper function to process a relay cell that is in the proper order + * for processing right now. */ +static int +connection_edge_process_ordered_relay_cell(const relay_msg_t *msg, + circuit_t *circ, + edge_connection_t *conn, + crypt_path_t *layer_hint) +{ + int optimistic_data = 0; /* Set to 1 if we receive data on a stream + * that's in the EXIT_CONN_STATE_RESOLVING + * or EXIT_CONN_STATE_CONNECTING states. */ + /* Tell circpad that we've received a recognized cell */ - circpad_deliver_recognized_relay_cell_events(circ, rh.command, layer_hint); + circpad_deliver_recognized_relay_cell_events(circ, msg->command, layer_hint); /* either conn is NULL, in which case we've got a control cell, or else * conn points to the recognized stream. */ @@ -2095,22 +2156,21 @@ if (conn->base_.type == CONN_TYPE_EXIT && (conn->base_.state == EXIT_CONN_STATE_CONNECTING || conn->base_.state == EXIT_CONN_STATE_RESOLVING) && - rh.command == RELAY_COMMAND_DATA) { + msg->command == RELAY_COMMAND_DATA) { /* Allow DATA cells to be delivered to an exit node in state * EXIT_CONN_STATE_CONNECTING or EXIT_CONN_STATE_RESOLVING. * This speeds up HTTP, for example. */ optimistic_data = 1; - } else if (rh.stream_id == 0 && rh.command == RELAY_COMMAND_DATA) { + } else if (msg->stream_id == 0 && msg->command == RELAY_COMMAND_DATA) { log_warn(LD_BUG, "Somehow I had a connection that matched a " "data cell with stream ID 0."); } else { return connection_edge_process_relay_cell_not_open( - &rh, cell, circ, conn, layer_hint); + msg, circ, conn, layer_hint); } } - return handle_relay_cell_command(cell, circ, conn, layer_hint, - &rh, optimistic_data); + return handle_relay_msg(msg, circ, conn, layer_hint, optimistic_data); } /** How many relay_data cells have we built, ever? */ @@ -2141,20 +2201,14 @@ } /** - * 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) + circuit_t *on_circuit, + crypt_path_t *cpath) { if (!n_available) return 0; @@ -2164,12 +2218,18 @@ (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; + relay_cell_fmt_t cell_format = circuit_get_relay_format(on_circuit, cpath); + size_t target_length = + relay_cell_max_payload_size(cell_format, RELAY_COMMAND_DATA); + +#define RELAY_CELL_PADDING_GAP 4 + + /* Any relay data payload containing fewer than this many real bytes is + * considered to have enough randomness to. */ + size_t target_length_with_random = target_length - + RELAY_CELL_PADDING_GAP - 16; if (force_random_bytes) { - target_length = RELAY_PAYLOAD_LENGTH_FOR_RANDOM_SENDMES; - } else { - target_length = RELAY_PAYLOAD_SIZE; + target_length = target_length_with_random; } /* Decide how many bytes we will actually put into this cell. */ @@ -2186,7 +2246,7 @@ /* 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) { + if (package_length <= target_length_with_random) { /* This cell will have enough randomness in the padding to make a future * sendme cell unpredictable. */ on_circuit->have_sent_sufficiently_random_cell = 1; @@ -2234,7 +2294,7 @@ tor_assert(conn); - if (conn->base_.marked_for_close) { + if (BUG(conn->base_.marked_for_close)) { log_warn(LD_BUG, "called on conn that's already marked for close at %s:%d.", conn->base_.marked_for_close_file, conn->base_.marked_for_close); @@ -2278,7 +2338,8 @@ } length = connection_edge_get_inbuf_bytes_to_package(bytes_to_process, - package_partial, circ); + package_partial, circ, + cpath_layer); if (!length) return 0; @@ -2313,21 +2374,13 @@ buf_add(entry_conn->pending_optimistic_data, payload, length); } + /* Send a data cell. This handles the circuit package window. */ if (connection_edge_send_command(conn, RELAY_COMMAND_DATA, payload, length) < 0 ) { /* circuit got marked for close, don't continue, don't need to mark conn */ return 0; } - /* 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; - } - /* Handle the stream-level SENDME package window. */ if (sendme_note_stream_data_packaged(conn, length) < 0) { connection_stop_reading(TO_CONN(conn)); @@ -2359,6 +2412,15 @@ log_debug(layer_hint?LD_APP:LD_EXIT,"Too big queue, no resuming"); return; } + + /* If we have a conflux negotiated, and it still can't send on + * any circuit, then do not resume sending. */ + if (circ->conflux && !conflux_can_send(circ->conflux)) { + log_debug(layer_hint?LD_APP:LD_EXIT, + "Conflux can't send, not resuming edges"); + return; + } + log_debug(layer_hint?LD_APP:LD_EXIT,"resuming"); if (CIRCUIT_IS_ORIGIN(circ)) @@ -2392,20 +2454,6 @@ return 0; } - /* How many cells do we have space for? It will be the minimum of - * the number needed to exhaust the package window, and the minimum - * needed to fill the cell queue. */ - - max_to_package = congestion_control_get_package_window(circ, layer_hint); - if (CIRCUIT_IS_ORIGIN(circ)) { - cells_on_queue = circ->n_chan_cells.n; - } else { - or_circuit_t *or_circ = TO_OR_CIRCUIT(circ); - cells_on_queue = or_circ->p_chan_cells.n; - } - if (cell_queue_highwatermark() - cells_on_queue < max_to_package) - max_to_package = cell_queue_highwatermark() - cells_on_queue; - /* Once we used to start listening on the streams in the order they * appeared in the linked list. That leads to starvation on the * streams that appeared later on the list, since the first streams @@ -2444,11 +2492,13 @@ /* Activate reading starting from the chosen stream */ for (conn=chosen_stream; conn; conn = conn->next_stream) { /* Start reading for the streams starting from here */ - if (conn->base_.marked_for_close || conn->package_window <= 0 || - conn->xoff_received) + if (conn->base_.marked_for_close || conn->package_window <= 0) continue; - if (!layer_hint || conn->cpath_layer == layer_hint) { - connection_start_reading(TO_CONN(conn)); + + if (edge_uses_cpath(conn, layer_hint)) { + if (!conn->xoff_received) { + connection_start_reading(TO_CONN(conn)); + } if (connection_get_inbuf_len(TO_CONN(conn)) > 0) ++n_packaging_streams; @@ -2456,11 +2506,13 @@ } /* Go back and do the ones we skipped, circular-style */ for (conn = first_conn; conn != chosen_stream; conn = conn->next_stream) { - if (conn->base_.marked_for_close || conn->package_window <= 0 || - conn->xoff_received) + if (conn->base_.marked_for_close || conn->package_window <= 0) continue; - if (!layer_hint || conn->cpath_layer == layer_hint) { - connection_start_reading(TO_CONN(conn)); + + if (edge_uses_cpath(conn, layer_hint)) { + if (!conn->xoff_received) { + connection_start_reading(TO_CONN(conn)); + } if (connection_get_inbuf_len(TO_CONN(conn)) > 0) ++n_packaging_streams; @@ -2472,6 +2524,32 @@ again: + /* If we're using conflux, the circuit we decide to send on may change + * after we're sending. Get it again, and re-check package windows + * for it */ + if (circ->conflux) { + if (circuit_consider_stop_edge_reading(circ, layer_hint)) + return -1; + + circ = conflux_decide_next_circ(circ->conflux); + + /* Get the destination layer hint for this circuit */ + layer_hint = conflux_get_destination_hop(circ); + } + + /* How many cells do we have space for? It will be the minimum of + * the number needed to exhaust the package window, and the minimum + * needed to fill the cell queue. */ + max_to_package = congestion_control_get_package_window(circ, layer_hint); + if (CIRCUIT_IS_ORIGIN(circ)) { + cells_on_queue = circ->n_chan_cells.n; + } else { + or_circuit_t *or_circ = TO_OR_CIRCUIT(circ); + cells_on_queue = or_circ->p_chan_cells.n; + } + if (cell_queue_highwatermark() - cells_on_queue < max_to_package) + max_to_package = cell_queue_highwatermark() - cells_on_queue; + cells_per_conn = CEIL_DIV(max_to_package, n_packaging_streams); packaged_this_round = 0; @@ -2485,7 +2563,7 @@ for (conn=first_conn; conn; conn=conn->next_stream) { if (conn->base_.marked_for_close || conn->package_window <= 0) continue; - if (!layer_hint || conn->cpath_layer == layer_hint) { + if (edge_uses_cpath(conn, layer_hint)) { int n = cells_per_conn, r; /* handle whatever might still be on the inbuf */ r = connection_edge_package_raw_inbuf(conn, 1, &n); @@ -2519,7 +2597,6 @@ */ if (packaged_this_round && packaged_this_round < max_to_package && n_streams_left) { - max_to_package -= packaged_this_round; n_packaging_streams = n_streams_left; goto again; } @@ -2543,7 +2620,7 @@ or_circuit_t *or_circ = TO_OR_CIRCUIT(circ); log_debug(domain,"considering circ->package_window %d", circ->package_window); - if (congestion_control_get_package_window(circ, layer_hint) <= 0) { + if (circuit_get_package_window(circ, layer_hint) <= 0) { log_debug(domain,"yes, not-at-origin. stopped."); for (conn = or_circ->n_streams; conn; conn=conn->next_stream) connection_stop_reading(TO_CONN(conn)); @@ -2554,11 +2631,11 @@ /* else, layer hint is defined, use it */ log_debug(domain,"considering layer_hint->package_window %d", layer_hint->package_window); - if (congestion_control_get_package_window(circ, layer_hint) <= 0) { + if (circuit_get_package_window(circ, layer_hint) <= 0) { log_debug(domain,"yes, at-origin. stopped."); for (conn = TO_ORIGIN_CIRCUIT(circ)->p_streams; conn; conn=conn->next_stream) { - if (conn->cpath_layer == layer_hint) + if (edge_uses_cpath(conn, layer_hint)) connection_stop_reading(TO_CONN(conn)); } return 1; @@ -2794,21 +2871,28 @@ alloc += geoip_client_cache_total; const size_t dns_cache_total = dns_cache_total_allocation(); alloc += dns_cache_total; + const size_t conflux_total = conflux_get_total_bytes_allocation(); + alloc += conflux_total; if (alloc >= get_options()->MaxMemInQueues_low_threshold) { last_time_under_memory_pressure = approx_time(); if (alloc >= get_options()->MaxMemInQueues) { /* Note this overload down */ rep_hist_note_overload(OVERLOAD_GENERAL); - /* If we're spending over 20% of the memory limit on hidden service - * descriptors, free them until we're down to 10%. Do the same for geoip - * client cache. */ - if (hs_cache_total > get_options()->MaxMemInQueues / 5) { + /* If we're spending over the configured limit on hidden service + * descriptors, free them until we're down to 50% of the limit. */ + if (hs_cache_total > hs_cache_get_max_bytes()) { const size_t bytes_to_remove = - hs_cache_total - (size_t)(get_options()->MaxMemInQueues / 10); - removed = hs_cache_handle_oom(now, bytes_to_remove); + hs_cache_total - (size_t)(hs_cache_get_max_bytes() / 2); + removed = hs_cache_handle_oom(bytes_to_remove); oom_stats_n_bytes_removed_hsdir += removed; alloc -= removed; + static ratelim_t hs_cache_oom_ratelim = RATELIM_INIT(600); + log_fn_ratelim(&hs_cache_oom_ratelim, LOG_NOTICE, LD_REND, + "HSDir cache exceeded limit " + "(%"TOR_PRIuSZ " > %"PRIu64 " bytes). " + "Pruned %"TOR_PRIuSZ " bytes during cell_queues_check_size.", + hs_cache_total, hs_cache_get_max_bytes(), removed); } if (geoip_client_cache_total > get_options()->MaxMemInQueues / 5) { const size_t bytes_to_remove = @@ -2825,6 +2909,14 @@ oom_stats_n_bytes_removed_dns += removed; alloc -= removed; } + /* Like onion service above, try to go down to 10% if we are above 20% */ + if (conflux_total > get_options()->MaxMemInQueues / 5) { + const size_t bytes_to_remove = + conflux_total - (size_t)(get_options()->MaxMemInQueues / 10); + removed = conflux_handle_oom(bytes_to_remove); + oom_stats_n_bytes_removed_cell += removed; + alloc -= removed; + } removed = circuits_handle_oom(alloc); oom_stats_n_bytes_removed_cell += removed; return 1; @@ -2835,11 +2927,11 @@ /** Return true if we've been under memory pressure in the last * MEMORY_PRESSURE_INTERVAL seconds. */ -int +bool have_been_under_memory_pressure(void) { - return last_time_under_memory_pressure + MEMORY_PRESSURE_INTERVAL - < approx_time(); + return approx_time() < + last_time_under_memory_pressure + MEMORY_PRESSURE_INTERVAL; } /** @@ -2902,44 +2994,63 @@ chan->num_p_circuits = 0; } -/** Block (if block is true) or unblock (if block is false) +/** + * Called when a circuit becomes blocked or unblocked due to the channel + * cell queue. + * + * Block (if block is true) or unblock (if block is false) * every edge connection that is using circ to write to chan, * and start or stop reading as appropriate. - * - * If stream_id is nonzero, block only the edge connection whose - * stream_id matches it. - * - * Returns the number of streams whose status we changed. */ -static int -set_streams_blocked_on_circ(circuit_t *circ, channel_t *chan, - int block, streamid_t stream_id) +static void +set_circuit_blocked_on_chan(circuit_t *circ, channel_t *chan, int block) { edge_connection_t *edge = NULL; - int n = 0; if (circ->n_chan == chan) { - circ->streams_blocked_on_n_chan = block; + circ->circuit_blocked_on_n_chan = block; if (CIRCUIT_IS_ORIGIN(circ)) edge = TO_ORIGIN_CIRCUIT(circ)->p_streams; } else { - circ->streams_blocked_on_p_chan = block; + circ->circuit_blocked_on_p_chan = block; tor_assert(!CIRCUIT_IS_ORIGIN(circ)); edge = TO_OR_CIRCUIT(circ)->n_streams; } - for (; edge; edge = edge->next_stream) { + set_block_state_for_streams(circ, edge, block, 0); +} + +/** + * Helper function to block or unblock streams in a stream list. + * + * If stream_id is 0, apply the block state to all streams + * in the stream list. If it is non-zero, only apply to that specific stream. + */ +static void +set_block_state_for_streams(circuit_t *circ, edge_connection_t *stream_list, + int block, streamid_t stream_id) +{ + /* If we have a conflux object, we need to examine its status before + * blocking and unblocking streams. */ + if (circ->conflux) { + bool can_send = conflux_can_send(circ->conflux); + + if (block && can_send) { + /* Don't actually block streams, since conflux can send*/ + return; + } else if (!block && !can_send) { + /* Don't actually unblock streams, since conflux still can't send */ + return; + } + } + + for (edge_connection_t *edge = stream_list; edge; edge = edge->next_stream) { connection_t *conn = TO_CONN(edge); if (stream_id && edge->stream_id != stream_id) continue; - if (edge->edge_blocked_on_circ != block) { - ++n; - edge->edge_blocked_on_circ = block; - } - - if (!conn->read_event) { - /* This connection is a placeholder for something; probably a DNS - * request. It can't actually stop or start reading.*/ + if (!conn->read_event || edge->xoff_received || + conn->marked_for_close) { + /* This connection should not start or stop reading. */ continue; } @@ -2952,8 +3063,6 @@ connection_start_reading(conn); } } - - return n; } /** Extract the command from a packed cell. */ @@ -2991,7 +3100,7 @@ destroy_cell_queue_t *destroy_queue=NULL; circuit_t *circ; or_circuit_t *or_circ; - int streams_blocked; + int circ_blocked; packed_cell_t *cell; /* Get the cmux */ @@ -3031,18 +3140,31 @@ if (circ->n_chan == chan) { queue = &circ->n_chan_cells; - streams_blocked = circ->streams_blocked_on_n_chan; + circ_blocked = circ->circuit_blocked_on_n_chan; } else { or_circ = TO_OR_CIRCUIT(circ); tor_assert(or_circ->p_chan == chan); queue = &TO_OR_CIRCUIT(circ)->p_chan_cells; - streams_blocked = circ->streams_blocked_on_p_chan; + circ_blocked = circ->circuit_blocked_on_p_chan; } - /* Circuitmux told us this was active, so it should have cells */ - if (/*BUG(*/ queue->n == 0 /*)*/) { - log_warn(LD_BUG, "Found a supposedly active circuit with no cells " - "to send. Trying to recover."); + /* Circuitmux told us this was active, so it should have cells. + * + * Note: In terms of logic and coherence, this should never happen but the + * cmux dragon is powerful. Reason is that when the OOM is triggered, when + * cleaning up circuits, we mark them for close and then clear their cell + * queues. And so, we can have a circuit considered active by the cmux + * dragon but without cells. The cmux subsystem is only notified of this + * when the circuit is freed which leaves a tiny window between close and + * free to end up here. + * + * We are accepting this as an "ok" race else the changes are likely non + * trivial to make the mark for close to set the num cells to 0 and change + * the free functions to detach the circuit conditionally without creating + * a chain effect of madness. + * + * The lesson here is arti will prevail and leave the cmux dragon alone. */ + if (queue->n == 0) { circuitmux_set_num_cells(cmux, circ, 0); if (! circ->marked_for_close) circuit_mark_for_close(circ, END_CIRC_REASON_INTERNAL); @@ -3124,8 +3246,8 @@ /* Is the cell queue low enough to unblock all the streams that are waiting * to write to this circuit? */ - if (streams_blocked && queue->n <= cell_queue_lowwatermark()) - set_streams_blocked_on_circ(circ, chan, 0, 0); /* unblock streams */ + if (circ_blocked && queue->n <= cell_queue_lowwatermark()) + set_circuit_blocked_on_chan(circ, chan, 0); /* unblock streams */ /* If n_flushed < max still, loop around and pick another circuit */ } @@ -3137,7 +3259,7 @@ /* Minimum value is the maximum circuit window size. * * This value is set to a lower bound we believe is reasonable with congestion - * control and basic network tunning parameters. + * control and basic network running parameters. * * SENDME cells makes it that we can control how many cells can be inflight on * a circuit from end to end. This logic makes it that on any circuit cell @@ -3170,7 +3292,7 @@ #define RELAY_CIRC_CELL_QUEUE_SIZE_DEFAULT \ (50 * RELAY_CIRC_CELL_QUEUE_SIZE_MIN) -/* The maximum number of cell a circuit queue can contain. This is updated at +/* The maximum number of cells a circuit queue can contain. This is updated at * every new consensus and controlled by a parameter. */ static int32_t max_circuit_cell_queue_size = RELAY_CIRC_CELL_QUEUE_SIZE_DEFAULT; @@ -3223,30 +3345,40 @@ * The given cell is copied onto the circuit queue so the caller must * cleanup the memory. * - * This function is part of the fast path. */ -void + * This function is part of the fast path. + * + * Return 1 if the cell was successfully sent. + * Return 0 if the cell can not be sent. The caller MUST NOT close the circuit. + * Return -1 indicating an error and that the caller should mark the circuit + * for close. */ +int append_cell_to_circuit_queue(circuit_t *circ, channel_t *chan, cell_t *cell, cell_direction_t direction, streamid_t fromstream) { or_circuit_t *orcirc = NULL; + edge_connection_t *stream_list = NULL; cell_queue_t *queue; int32_t max_queue_size; - int streams_blocked; + int circ_blocked; int exitward; - if (circ->marked_for_close) - return; + if (circ->marked_for_close) { + return 0; + } exitward = (direction == CELL_DIRECTION_OUT); if (exitward) { queue = &circ->n_chan_cells; - streams_blocked = circ->streams_blocked_on_n_chan; + circ_blocked = circ->circuit_blocked_on_n_chan; max_queue_size = max_circuit_cell_queue_size_out; + if (CIRCUIT_IS_ORIGIN(circ)) + stream_list = TO_ORIGIN_CIRCUIT(circ)->p_streams; } else { orcirc = TO_OR_CIRCUIT(circ); queue = &orcirc->p_chan_cells; - streams_blocked = circ->streams_blocked_on_p_chan; + circ_blocked = circ->circuit_blocked_on_p_chan; max_queue_size = max_circuit_cell_queue_size; + stream_list = TO_OR_CIRCUIT(circ)->n_streams; } if (PREDICT_UNLIKELY(queue->n >= max_queue_size)) { @@ -3262,9 +3394,8 @@ "Closing circuit for safety reasons.", (exitward) ? "Outbound" : "Inbound", queue->n, max_queue_size); - circuit_mark_for_close(circ, END_CIRC_REASON_RESOURCELIMIT); stats_n_circ_max_cell_reached++; - return; + return -1; } /* Very important that we copy to the circuit queue because all calls to @@ -3275,18 +3406,21 @@ /* Check and run the OOM if needed. */ if (PREDICT_UNLIKELY(cell_queues_check_size())) { /* We ran the OOM handler which might have closed this circuit. */ - if (circ->marked_for_close) - return; + if (circ->marked_for_close) { + return 0; + } } - /* If we have too many cells on the circuit, we should stop reading from - * the edge streams for a while. */ - if (!streams_blocked && queue->n >= cell_queue_highwatermark()) - set_streams_blocked_on_circ(circ, chan, 1, 0); /* block streams */ - - if (streams_blocked && fromstream) { - /* This edge connection is apparently not blocked; block it. */ - set_streams_blocked_on_circ(circ, chan, 1, fromstream); + /* If we have too many cells on the circuit, note that it should + * be blocked from new cells. */ + if (!circ_blocked && queue->n >= cell_queue_highwatermark()) + set_circuit_blocked_on_chan(circ, chan, 1); + + if (circ_blocked && fromstream) { + /* This edge connection is apparently not blocked; this can happen for + * new streams on a blocked circuit, for their CONNECTED response. + * block it now, unless we have conflux. */ + set_block_state_for_streams(circ, stream_list, 1, fromstream); } update_circuit_on_cmux(circ, direction); @@ -3298,6 +3432,7 @@ /* New way: mark this as having waiting cells for the scheduler */ scheduler_channel_has_waiting_cells(chan); + return 1; } /** Append an encoded value of addr to payload_out, which must @@ -3392,8 +3527,37 @@ circuit_queue_streams_are_blocked(circuit_t *circ) { if (CIRCUIT_IS_ORIGIN(circ)) { - return circ->streams_blocked_on_n_chan; + return circ->circuit_blocked_on_n_chan; + } else { + return circ->circuit_blocked_on_p_chan; + } +} + +/** Return the format to use. + * + * NULL can be passed but not for both. */ +relay_cell_fmt_t +circuit_get_relay_format(const circuit_t *circ, const crypt_path_t *cpath) +{ + if (circ && CIRCUIT_IS_ORCIRC(circ)) { + return CONST_TO_OR_CIRCUIT(circ)->relay_cell_format; + } else if (cpath) { + return cpath->relay_cell_format; } else { - return circ->streams_blocked_on_p_chan; + /* We end up here when both params are NULL, which is not allowed, or when + * only an origin circuit is given (which again is not allowed). */ + tor_assert_unreached(); } } + +/** + * Return the maximum relay payload that can be sent to the chosen + * point, with the specified command. + */ +size_t +circuit_max_relay_payload(const circuit_t *circ, const crypt_path_t *cpath, + uint8_t relay_command) +{ + relay_cell_fmt_t fmt = circuit_get_relay_format(circ, cpath); + return relay_cell_max_payload_size(fmt, relay_command); +} diff -Nru tor-0.4.7.16/src/core/or/relay.h tor-0.4.9.6/src/core/or/relay.h --- tor-0.4.7.16/src/core/or/relay.h 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/core/or/relay.h 2026-03-25 14:30:34.000000000 +0000 @@ -12,6 +12,8 @@ #ifndef TOR_RELAY_H #define TOR_RELAY_H +#include "core/or/relay_msg_st.h" + extern uint64_t stats_n_relay_cells_relayed; extern uint64_t stats_n_relay_cells_delivered; extern uint64_t stats_n_circ_max_cell_reached; @@ -26,8 +28,11 @@ cell_direction_t cell_direction); size_t cell_queues_get_total_allocation(void); +#ifdef TOR_UNIT_TESTS void relay_header_pack(uint8_t *dest, const relay_header_t *src); void relay_header_unpack(relay_header_t *dest, const uint8_t *src); +#endif + MOCK_DECL(int, relay_send_command_from_edge_,(streamid_t stream_id, circuit_t *circ, uint8_t relay_command, const char *payload, @@ -62,7 +67,7 @@ void dump_cell_pool_usage(int severity); size_t packed_cell_mem_cost(void); -int have_been_under_memory_pressure(void); +bool have_been_under_memory_pressure(void); /* For channeltls.c */ void packed_cell_free_(packed_cell_t *cell); @@ -76,9 +81,9 @@ int exitward, const cell_t *cell, int wide_circ_ids, int use_stats); -void append_cell_to_circuit_queue(circuit_t *circ, channel_t *chan, - cell_t *cell, cell_direction_t direction, - streamid_t fromstream); +int append_cell_to_circuit_queue(circuit_t *circ, channel_t *chan, + cell_t *cell, cell_direction_t direction, + streamid_t fromstream); void destroy_cell_queue_init(destroy_cell_queue_t *queue); void destroy_cell_queue_clear(destroy_cell_queue_t *queue); @@ -108,14 +113,20 @@ 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); +relay_cell_fmt_t circuit_get_relay_format(const circuit_t *circ, + const crypt_path_t *cpath); +size_t circuit_max_relay_payload(const circuit_t *circ, + const crypt_path_t *cpath, + uint8_t relay_command); + #ifdef RELAY_PRIVATE STATIC int -handle_relay_cell_command(cell_t *cell, circuit_t *circ, - edge_connection_t *conn, crypt_path_t *layer_hint, - relay_header_t *rh, int optimistic_data); +handle_relay_msg(const relay_msg_t *msg, circuit_t *circ, + edge_connection_t *conn, crypt_path_t *layer_hint, + int optimistic_data); -STATIC int connected_cell_parse(const relay_header_t *rh, const cell_t *cell, - tor_addr_t *addr_out, int *ttl_out); +STATIC int connected_cell_parse(const relay_msg_t *msg, tor_addr_t *addr_out, + int *ttl_out); /** An address-and-ttl tuple as yielded by resolved_cell_parse */ typedef struct address_ttl_t { tor_addr_t addr; @@ -125,22 +136,22 @@ STATIC void address_ttl_free_(address_ttl_t *addr); #define address_ttl_free(addr) \ FREE_AND_NULL(address_ttl_t, address_ttl_free_, (addr)) -STATIC int resolved_cell_parse(const cell_t *cell, const relay_header_t *rh, +STATIC int resolved_cell_parse(const relay_msg_t *msg, smartlist_t *addresses_out, int *errcode_out); STATIC int connection_edge_process_resolved_cell(edge_connection_t *conn, - const cell_t *cell, - const relay_header_t *rh); + const relay_msg_t *msg); STATIC packed_cell_t *packed_cell_new(void); STATIC packed_cell_t *cell_queue_pop(cell_queue_t *queue); STATIC destroy_cell_t *destroy_cell_queue_pop(destroy_cell_queue_t *queue); 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 int connection_edge_process_relay_cell(const relay_msg_t *msg, + circuit_t *circ, + edge_connection_t *conn, + crypt_path_t *layer_hint); STATIC size_t connection_edge_get_inbuf_bytes_to_package(size_t n_available, int package_partial, - circuit_t *on_circuit); + circuit_t *on_circuit, + crypt_path_t *cpath); #endif /* defined(RELAY_PRIVATE) */ diff -Nru tor-0.4.7.16/src/core/or/relay_crypto_st.h tor-0.4.9.6/src/core/or/relay_crypto_st.h --- tor-0.4.7.16/src/core/or/relay_crypto_st.h 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/core/or/relay_crypto_st.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,38 +0,0 @@ -/* Copyright (c) 2001 Matej Pfajfar. - * Copyright (c) 2001-2004, Roger Dingledine. - * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2021, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -/** - * @file relay_crypto_st.h - * @brief Relay-cell encryption state structure. - **/ - -#ifndef RELAY_CRYPTO_ST_H -#define RELAY_CRYPTO_ST_H - -#define crypto_cipher_t aes_cnt_cipher_t -struct crypto_cipher_t; -struct crypto_digest_t; - -struct relay_crypto_t { - /* crypto environments */ - /** Encryption key and counter for cells heading towards the OR at this - * step. */ - struct crypto_cipher_t *f_crypto; - /** Encryption key and counter for cells heading back from the OR at this - * step. */ - struct crypto_cipher_t *b_crypto; - - /** Digest state for cells heading towards the OR at this step. */ - struct crypto_digest_t *f_digest; /* for integrity checking */ - /** 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 /* !defined(RELAY_CRYPTO_ST_H) */ diff -Nru tor-0.4.7.16/src/core/or/relay_msg.c tor-0.4.9.6/src/core/or/relay_msg.c --- tor-0.4.7.16/src/core/or/relay_msg.c 1970-01-01 00:00:00.000000000 +0000 +++ tor-0.4.9.6/src/core/or/relay_msg.c 2026-03-25 14:30:34.000000000 +0000 @@ -0,0 +1,286 @@ +/* Copyright (c) 2023, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file relay_msg.c + * \brief Encoding relay messages into cells. + **/ + +#define RELAY_MSG_PRIVATE + +#include "app/config/config.h" + +#include "core/or/cell_st.h" +#include "core/or/circuitlist.h" +#include "core/or/relay.h" +#include "core/or/relay_msg.h" +#include "lib/crypt_ops/crypto_rand.h" + +#include "core/or/cell_st.h" +#include "core/or/relay_msg_st.h" +#include "core/or/crypt_path_st.h" +#include "core/or/or_circuit_st.h" + +/* + * Public API + */ + +/** Free the given relay message. */ +void +relay_msg_free_(relay_msg_t *msg) +{ + if (!msg) { + return; + } + tor_free(msg); +} + +/** Clear a relay message as in free its content and reset all fields to 0. + * This is useful for stack allocated memory. */ +void +relay_msg_clear(relay_msg_t *msg) +{ + tor_assert(msg); + memset(msg, 0, sizeof(*msg)); +} + +/* Positions of fields within a v0 message. */ +#define V0_CMD_OFFSET 0 +#define V0_STREAM_ID_OFFSET 3 +#define V0_LEN_OFFSET 9 +#define V0_PAYLOAD_OFFSET 11 + +/* Positions of fields within a v1 message. */ +#define V1_CMD_OFFSET 16 +#define V1_LEN_OFFSET 17 +#define V1_STREAM_ID_OFFSET 19 +#define V1_PAYLOAD_OFFSET_NO_STREAM_ID 19 +#define V1_PAYLOAD_OFFSET_WITH_STREAM_ID 21 + +/** Allocate a new relay message and copy the content of the given message. + * + * This message allocation _will_ own its body, even if the original did not. + * + * Requires that msg is well-formed, and that its length is within + * allowable bounds. + **/ +relay_msg_t * +relay_msg_copy(const relay_msg_t *msg) +{ + tor_assert(msg->length <= RELAY_PAYLOAD_SIZE_MAX); + void *alloc = tor_malloc_zero(sizeof(relay_msg_t) + msg->length); + relay_msg_t *new_msg = alloc; + uint8_t *body = ((uint8_t*)alloc) + sizeof(relay_msg_t); + + memcpy(new_msg, msg, sizeof(*msg)); + new_msg->body = body; + memcpy(body, msg->body, msg->length); + + return new_msg; +} + +/* 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 +relay_cell_pad(cell_t *cell, size_t end_of_message) +{ + // We add 4 bytes of zero before padding, for forward-compatibility. + const size_t skip = 4; + + if (end_of_message + skip >= CELL_PAYLOAD_SIZE) { + /* nothing to do. */ + return; + } + + crypto_fast_rng_getbytes(get_thread_fast_rng(), + &cell->payload[end_of_message + skip], + CELL_PAYLOAD_SIZE - (end_of_message + skip)); +} + +/** Encode the relay message in 'msg' into cell, according to the + * v0 rules. */ +static int +encode_v0_cell(const relay_msg_t *msg, + cell_t *cell_out) +{ + size_t maxlen = + relay_cell_max_payload_size(RELAY_CELL_FORMAT_V0, msg->command); + IF_BUG_ONCE(msg->length > maxlen) { + return -1; + } + + uint8_t *out = cell_out->payload; + + out[V0_CMD_OFFSET] = (uint8_t) msg->command; + set_uint16(out+V0_STREAM_ID_OFFSET, htons(msg->stream_id)); + set_uint16(out+V0_LEN_OFFSET, htons(msg->length)); + memcpy(out + RELAY_HEADER_SIZE_V0, msg->body, msg->length); + relay_cell_pad(cell_out, RELAY_HEADER_SIZE_V0 + msg->length); + + return 0; +} + +/** Encode the relay message in 'msg' into cell, according to the + * v0 rules. */ +static int +encode_v1_cell(const relay_msg_t *msg, + cell_t *cell_out) +{ + bool expects_streamid = relay_cmd_expects_streamid_in_v1(msg->command); + size_t maxlen = + relay_cell_max_payload_size(RELAY_CELL_FORMAT_V1, msg->command); + IF_BUG_ONCE(msg->length > maxlen) { + return -1; + } + + uint8_t *out = cell_out->payload; + out[V1_CMD_OFFSET] = msg->command; + set_uint16(out+V1_LEN_OFFSET, htons(msg->length)); + size_t payload_offset; + if (expects_streamid) { + IF_BUG_ONCE(msg->stream_id == 0) { + return -1; + } + set_uint16(out+V1_STREAM_ID_OFFSET, htons(msg->stream_id)); + payload_offset = V1_PAYLOAD_OFFSET_WITH_STREAM_ID; + } else { + IF_BUG_ONCE(msg->stream_id != 0) { + return -1; + } + + payload_offset = V1_PAYLOAD_OFFSET_NO_STREAM_ID; + } + + memcpy(out + payload_offset, msg->body, msg->length); + relay_cell_pad(cell_out, payload_offset + msg->length); + return 0; +} + +/** Try to decode 'cell' into a V0 relay message. + * + * Return 0 on success, -1 on error. + */ +static int +decode_v0_cell(const cell_t *cell, relay_msg_t *out) +{ + memset(out, 0, sizeof(relay_msg_t)); + out->is_relay_early = (cell->command == CELL_RELAY_EARLY); + + const uint8_t *body = cell->payload; + out->command = get_uint8(body + V0_CMD_OFFSET); + out->stream_id = ntohs(get_uint16(body + V0_STREAM_ID_OFFSET)); + out->length = ntohs(get_uint16(body + V0_LEN_OFFSET)); + + if (out->length > CELL_PAYLOAD_SIZE - RELAY_HEADER_SIZE_V0) { + return -1; + } + out->body = body + V0_PAYLOAD_OFFSET; + + return 0; +} + +/** Try to decode 'cell' into a V1 relay message. + * + * Return 0 on success, -1 on error.= + */ +static int +decode_v1_cell(const cell_t *cell, relay_msg_t *out) +{ + memset(out, 0, sizeof(relay_msg_t)); + out->is_relay_early = (cell->command == CELL_RELAY_EARLY); + + const uint8_t *body = cell->payload; + out->command = get_uint8(body + V1_CMD_OFFSET); + if (! is_known_relay_command(out->command)) + return -1; + + out->length = ntohs(get_uint16(body + V1_LEN_OFFSET)); + size_t payload_offset; + if (relay_cmd_expects_streamid_in_v1(out->command)) { + out->stream_id = ntohs(get_uint16(body + V1_STREAM_ID_OFFSET)); + payload_offset = V1_PAYLOAD_OFFSET_WITH_STREAM_ID; + } else { + payload_offset = V1_PAYLOAD_OFFSET_NO_STREAM_ID; + } + + if (out->length > CELL_PAYLOAD_SIZE - payload_offset) + return -1; + out->body = body + payload_offset; + + return 0; +} +/** + * Encode 'msg' into 'cell' according to the rules of 'format'. + * + * Does not set any "recognized", "digest" or "tag" fields, + * since those are necessarily part of the crypto logic. + * + * Clears the circuit ID on the cell. + * + * Return 0 on success, and -1 if 'msg' is not well-formed. + */ +int +relay_msg_encode_cell(relay_cell_fmt_t format, + const relay_msg_t *msg, + cell_t *cell_out) +{ + memset(cell_out, 0, sizeof(cell_t)); + cell_out->command = msg->is_relay_early ? + CELL_RELAY_EARLY : CELL_RELAY; + + switch (format) { + case RELAY_CELL_FORMAT_V0: + return encode_v0_cell(msg, cell_out); + case RELAY_CELL_FORMAT_V1: + return encode_v1_cell(msg, cell_out); + default: + tor_fragile_assert(); + return -1; + } +} + +/** + * Decode 'cell' (which must be RELAY or RELAY_EARLY) into a newly allocated + * 'relay_msg_t'. + * + * Note that the resulting relay_msg_t will have a reference to 'cell'. + * Do not change 'cell' while the resulting message is still in use! + * + * Return -1 on error, and 0 on success. + */ +int +relay_msg_decode_cell_in_place(relay_cell_fmt_t format, + const cell_t *cell, + relay_msg_t *msg_out) +{ + switch (format) { + case RELAY_CELL_FORMAT_V0: + return decode_v0_cell(cell, msg_out); + case RELAY_CELL_FORMAT_V1: + return decode_v1_cell(cell, msg_out); + default: + tor_fragile_assert(); + return -1; + } +} + +/** + * As relay_msg_decode_cell_in_place, but allocate a new relay_msg_t + * on success. + * + * Return NULL on error. + */ +relay_msg_t * +relay_msg_decode_cell(relay_cell_fmt_t format, + const cell_t *cell) +{ + relay_msg_t *msg = tor_malloc(sizeof(relay_msg_t)); + if (relay_msg_decode_cell_in_place(format, cell, msg) < 0) { + relay_msg_free(msg); + return NULL; + } else { + return msg; + } +} diff -Nru tor-0.4.7.16/src/core/or/relay_msg.h tor-0.4.9.6/src/core/or/relay_msg.h --- tor-0.4.7.16/src/core/or/relay_msg.h 1970-01-01 00:00:00.000000000 +0000 +++ tor-0.4.9.6/src/core/or/relay_msg.h 2026-03-25 14:30:34.000000000 +0000 @@ -0,0 +1,88 @@ +/* Copyright (c) 2023, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file relay_msg.h + * \brief Header file for relay_msg.c. + **/ + +#ifndef TOR_RELAY_MSG_H +#define TOR_RELAY_MSG_H + +#include "core/or/or.h" + +#include "core/or/relay_msg_st.h" + +/* Relay message */ +void relay_msg_free_(relay_msg_t *msg); +void relay_msg_clear(relay_msg_t *msg); +relay_msg_t *relay_msg_copy(const relay_msg_t *msg); + +int relay_msg_encode_cell(relay_cell_fmt_t format, + const relay_msg_t *msg, + cell_t *cell_out) ATTR_WUR; +int relay_msg_decode_cell_in_place(relay_cell_fmt_t format, + const cell_t *cell, + relay_msg_t *msg_out) ATTR_WUR; +relay_msg_t *relay_msg_decode_cell( + relay_cell_fmt_t format, + const cell_t *cell) ATTR_WUR; + +#define relay_msg_free(msg) \ + FREE_AND_NULL(relay_msg_t, relay_msg_free_, (msg)) + +/* Getters */ + +/* + * NOTE: The following are inlined for performance reasons. These values are + * accessed everywhere and so, even if not expensive, we avoid a function call. + */ + +/** Return true iff 'cmd' uses a stream ID when using + * the v1 relay message format. */ +static bool +relay_cmd_expects_streamid_in_v1(uint8_t relay_command) +{ + switch (relay_command) { + case RELAY_COMMAND_BEGIN: + case RELAY_COMMAND_BEGIN_DIR: + case RELAY_COMMAND_CONNECTED: + case RELAY_COMMAND_DATA: + case RELAY_COMMAND_END: + case RELAY_COMMAND_RESOLVE: + case RELAY_COMMAND_RESOLVED: + case RELAY_COMMAND_XOFF: + case RELAY_COMMAND_XON: + return true; + default: + return false; + } +} + +/** Return the size of the relay cell payload for the given relay + * cell format. */ +static inline size_t +relay_cell_max_payload_size(relay_cell_fmt_t format, + uint8_t relay_command) +{ + switch (format) { + case RELAY_CELL_FORMAT_V0: + return CELL_PAYLOAD_SIZE - RELAY_HEADER_SIZE_V0; + case RELAY_CELL_FORMAT_V1: { + if (relay_cmd_expects_streamid_in_v1(relay_command)) { + return CELL_PAYLOAD_SIZE - RELAY_HEADER_SIZE_V1_WITH_STREAM_ID; + } else { + return CELL_PAYLOAD_SIZE - RELAY_HEADER_SIZE_V1_NO_STREAM_ID; + } + } + default: + tor_fragile_assert(); + return 0; + } +} + +#ifdef RELAY_MSG_PRIVATE + +#endif /* RELAY_MSG_PRIVATE */ + +#endif /* TOR_RELAY_MSG_H */ diff -Nru tor-0.4.7.16/src/core/or/relay_msg_st.h tor-0.4.9.6/src/core/or/relay_msg_st.h --- tor-0.4.7.16/src/core/or/relay_msg_st.h 1970-01-01 00:00:00.000000000 +0000 +++ tor-0.4.9.6/src/core/or/relay_msg_st.h 2026-03-25 14:30:34.000000000 +0000 @@ -0,0 +1,47 @@ +/* Copyright (c) 2023, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * @file relay_msg_st.h + * @brief A relay message which contains a relay command and parameters, + * if any, that is from a relay cell. + **/ + +#ifndef TOR_RELAY_MSG_ST_H +#define TOR_RELAY_MSG_ST_H + +#include "core/or/or.h" + +/** A relay message object which contains pointers to the header and payload. + * + * One acquires a relay message through the use of an iterator. Once you get a + * reference, the getters MUST be used to access data. + * + * This CAN NOT be made opaque so to avoid heap allocation in the fast path. */ +typedef struct relay_msg_t { + /* Relay command of a message. */ + uint8_t command; + /* Length of the message body. + * + * This value MUST always be less than or equal to the lower of: + * - the number of bytes available in `body`. + * - relay_cell_max_format(_, command). + * + * (These bounds on the length field are guaranteed by all message decoding + * functions, and enforced by all message encoding functions.) + */ + uint16_t length; + /* Optional routing header: stream ID of a message or 0. */ + streamid_t stream_id; + /* Indicate if this is a message from a relay early cell. */ + bool is_relay_early; + /* Message body of a relay message. + * + * Code MUST NOT access any part of `body` beyond the first `length` bytes. + * + * NOTE that this struct does not own the body; instead, this is a pointer + * into a different object. */ + const uint8_t *body; +} relay_msg_t; + +#endif /* !defined(TOR_RELAY_MSG_ST_H) */ diff -Nru tor-0.4.7.16/src/core/or/scheduler.h tor-0.4.9.6/src/core/or/scheduler.h --- tor-0.4.7.16/src/core/or/scheduler.h 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/core/or/scheduler.h 2026-03-25 14:30:34.000000000 +0000 @@ -102,9 +102,9 @@ *****************************************************************************/ /* Default interval that KIST runs (in ms). */ -#define KIST_SCHED_RUN_INTERVAL_DEFAULT 10 -/* Minimum interval that KIST runs. This value disables KIST. */ -#define KIST_SCHED_RUN_INTERVAL_MIN 0 +#define KIST_SCHED_RUN_INTERVAL_DEFAULT 2 +/* Minimum interval that KIST runs. */ +#define KIST_SCHED_RUN_INTERVAL_MIN 2 /* Maximum interval that KIST runs (in ms). */ #define KIST_SCHED_RUN_INTERVAL_MAX 100 diff -Nru tor-0.4.7.16/src/core/or/scheduler_kist.c tor-0.4.9.6/src/core/or/scheduler_kist.c --- tor-0.4.7.16/src/core/or/scheduler_kist.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/core/or/scheduler_kist.c 2026-03-25 14:30:34.000000000 +0000 @@ -13,6 +13,7 @@ #include "app/config/config.h" #include "core/mainloop/connection.h" #include "feature/nodelist/networkstatus.h" +#include "feature/relay/routermode.h" #define CHANNEL_OBJECT_PRIVATE #include "core/or/channel.h" #include "core/or/channeltls.h" @@ -446,10 +447,16 @@ * by only writing a channel's outbuf to the kernel if it has 8 cells or more * in it. * - * Note: The number 8 has been picked for no particular reasons except that it - * is 4096 bytes which is a common number for buffering. A TLS record can hold - * up to 16KiB thus using 8 cells means that a relay will at most send a TLS - * record of 4KiB or 1/4 of the maximum capacity of a TLS record. + * Note: The number 8 was picked so that, when using 512-byte cells, it + * would produce 4096 bytes: a common number for buffering. A TLS + * record can hold up to 16KiB; thus, using 8 512-byte cells means that + * a relay will at most send a TLS record of 4KiB or 1/4 of the maximum + * capacity of a TLS record. + * + * Of course, the above calculation became incorrect when we moved to + * 514-byte cells in order to accommodate a 4-byte circuit ID; we may + * want to consider profiling with '7' to see if it produces better + * results. (TODO) */ MOCK_IMPL(int, channel_should_write_to_kernel, (outbuf_table_t *table, channel_t *chan)) @@ -810,12 +817,19 @@ log_debug(LD_SCHED, "KISTSchedRunInterval=0, turning to the consensus."); - /* Will either be the consensus value or the default. Note that 0 can be - * returned which means the consensus wants us to NOT use KIST. */ - return networkstatus_get_param(NULL, "KISTSchedRunInterval", + /* Clients and relays have a separate consensus parameter. Clients + * need a lower KIST interval, since they have only a couple connections */ + if (server_mode(get_options())) { + return networkstatus_get_param(NULL, "KISTSchedRunInterval", + KIST_SCHED_RUN_INTERVAL_DEFAULT, + KIST_SCHED_RUN_INTERVAL_MIN, + KIST_SCHED_RUN_INTERVAL_MAX); + } else { + return networkstatus_get_param(NULL, "KISTSchedRunIntervalClient", KIST_SCHED_RUN_INTERVAL_DEFAULT, KIST_SCHED_RUN_INTERVAL_MIN, KIST_SCHED_RUN_INTERVAL_MAX); + } } /* Set KISTLite mode that is KIST without kernel support. */ diff -Nru tor-0.4.7.16/src/core/or/sendme.c tor-0.4.9.6/src/core/or/sendme.c --- tor-0.4.7.16/src/core/or/sendme.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/core/or/sendme.c 2026-03-25 14:30:34.000000000 +0000 @@ -7,7 +7,9 @@ * creating/parsing cells and handling the content. */ +// For access to cpath pvt_crypto field. #define SENDME_PRIVATE +#define CRYPT_PATH_PRIVATE #include "core/or/or.h" @@ -27,6 +29,15 @@ #include "lib/ctime/di_ops.h" #include "trunnel/sendme_cell.h" +/** + * Return true iff tag_len is some length we recognize. + */ +static inline bool +tag_len_ok(size_t tag_len) +{ + return tag_len == SENDME_TAG_LEN_CGO || tag_len == SENDME_TAG_LEN_TOR1; +} + /* Return the minimum version given by the consensus (if any) that should be * used when emitting a SENDME cell. */ STATIC int @@ -71,17 +82,18 @@ return circ_digest; } -/* Return true iff the given cell digest matches the first digest in the +/* Return true iff the given cell tag matches the first digest in the * circuit sendme list. */ static bool -v1_digest_matches(const uint8_t *circ_digest, const uint8_t *cell_digest) +v1_tag_matches(const uint8_t *circ_digest, + const uint8_t *cell_tag, size_t tag_len) { tor_assert(circ_digest); - tor_assert(cell_digest); + tor_assert(cell_tag); /* 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)) { + if (tor_memneq(circ_digest, cell_tag, tag_len)) { log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "SENDME v1 cell digest do not match."); return false; @@ -98,13 +110,22 @@ * 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) +cell_v1_is_valid(const sendme_cell_t *cell, const uint8_t *circ_digest, + size_t circ_digest_len) { tor_assert(cell); tor_assert(circ_digest); + size_t tag_len = sendme_cell_get_data_len(cell); + if (! tag_len_ok(tag_len)) + return false; + if (sendme_cell_getlen_data_v1_digest(cell) < tag_len) + return false; + if (tag_len != circ_digest_len) + return false; + const uint8_t *cell_digest = sendme_cell_getconstarray_data_v1_digest(cell); - return v1_digest_matches(circ_digest, cell_digest); + return v1_tag_matches(circ_digest, cell_digest, tag_len); } /* Return true iff the given cell version can be handled or if the minimum @@ -156,8 +177,16 @@ * 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. */ +/* + * NOTE: This function uses `layer_hint` to determine + * what the sendme tag length will be, and nothing else. + * Notably, we _don't_ keep a separate queue + * of expected tags for each layer! + */ STATIC bool -sendme_is_valid(const circuit_t *circ, const uint8_t *cell_payload, +sendme_is_valid(circuit_t *circ, + const crypt_path_t *layer_hint, + const uint8_t *cell_payload, size_t cell_payload_len) { uint8_t cell_version; @@ -182,7 +211,28 @@ } /* Validate that we can handle this cell version. */ - if (!cell_version_can_be_handled(cell_version)) { + if (CIRCUIT_IS_ORCIRC(circ) && + TO_OR_CIRCUIT(circ)->used_legacy_circuit_handshake && + cell_version == 0) { + /* exception, allow v0 sendmes on circuits made with CREATE_FAST */ + log_info(LD_CIRC, "Permitting sendme version 0 on legacy circuit."); + /* Record this choice on the circuit, so we can avoid counting + * directory fetches on this circuit toward our geoip stats. */ + TO_OR_CIRCUIT(circ)->used_obsolete_sendme = 1; + } else if (!cell_version_can_be_handled(cell_version)) { + goto invalid; + } + + /* Determine the expected tag length for this sendme. */ + size_t circ_expects_tag_len; + if (layer_hint) { + circ_expects_tag_len = + relay_crypto_sendme_tag_len(&layer_hint->pvt_crypto); + } else if (CIRCUIT_IS_ORCIRC(circ)) { + const or_circuit_t *or_circ = CONST_TO_OR_CIRCUIT(circ); + circ_expects_tag_len = relay_crypto_sendme_tag_len(&or_circ->crypto); + } else { + tor_assert_nonfatal_unreached(); goto invalid; } @@ -198,12 +248,10 @@ "We received a SENDME but we have no cell digests to match. " "Closing circuit."); goto invalid; - } - - /* Validate depending on the version now. */ + } /* Validate depending on the version now. */ switch (cell_version) { case 0x01: - if (!cell_v1_is_valid(cell, circ_digest)) { + if (!cell_v1_is_valid(cell, circ_digest, circ_expects_tag_len)) { goto invalid; } break; @@ -229,17 +277,19 @@ } /* 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. + * least of RELAY_PAYLOAD_SIZE_MAX 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) +build_cell_payload_v1(const uint8_t *cell_tag, const size_t tag_len, + uint8_t *payload) { ssize_t len = -1; sendme_cell_t *cell = NULL; - tor_assert(cell_digest); + tor_assert(cell_tag); + tor_assert(tag_len_ok(tag_len)); tor_assert(payload); cell = sendme_cell_new(); @@ -247,14 +297,14 @@ /* 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); + sendme_cell_set_data_len(cell, tag_len); + sendme_cell_setlen_data_v1_digest(cell, tag_len); /* Copy the digest into the data payload. */ - memcpy(sendme_cell_getarray_data_v1_digest(cell), cell_digest, - sendme_cell_get_data_len(cell)); + memcpy(sendme_cell_getarray_data_v1_digest(cell), cell_tag, tag_len); /* Finally, encode the cell into the payload. */ - len = sendme_cell_encode(payload, RELAY_PAYLOAD_SIZE, cell); + len = sendme_cell_encode(payload, RELAY_PAYLOAD_SIZE_MAX, cell); sendme_cell_free(cell); return len; @@ -267,19 +317,19 @@ * 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) + const uint8_t *cell_tag, size_t tag_len) { uint8_t emit_version; - uint8_t payload[RELAY_PAYLOAD_SIZE]; + uint8_t payload[RELAY_PAYLOAD_SIZE_MAX]; ssize_t payload_len; tor_assert(circ); - tor_assert(cell_digest); + tor_assert(cell_tag); emit_version = get_emit_min_version(); switch (emit_version) { case 0x01: - payload_len = build_cell_payload_v1(cell_digest, payload); + payload_len = build_cell_payload_v1(cell_tag, tag_len, 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. */ @@ -307,61 +357,39 @@ return 0; } -/* Record the cell digest only if the next cell is expected to be a SENDME. */ +/* Record the sendme tag as expected in a future SENDME, */ static void -record_cell_digest_on_circ(circuit_t *circ, const uint8_t *sendme_digest) +record_cell_digest_on_circ(circuit_t *circ, + const uint8_t *sendme_tag, + size_t tag_len) { tor_assert(circ); - tor_assert(sendme_digest); + tor_assert(sendme_tag); /* 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)); + // We always allocate the largest possible tag here to + // make sure we don't have heap overflow bugs. + uint8_t *tag; + if (tag_len == SENDME_TAG_LEN_CGO) { + tag = tor_malloc_zero(SENDME_TAG_LEN_TOR1); + memcpy(tag, sendme_tag, tag_len); + // (The final bytes were initialized to zero.) + } else if (tag_len == SENDME_TAG_LEN_TOR1) { + tag = tor_memdup(sendme_tag, SENDME_TAG_LEN_TOR1); + } else { + tor_assert_unreached(); + } + + smartlist_add(circ->sendme_last_digests, tag); } /* * 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 inflight window value minus - * one cell (the possible SENDME cell) should be a multiple of the - * cells-per-sendme increment value (set via consensus parameter, negotiated - * for the circuit, and passed in as sendme_inc). - * - * 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. - */ -STATIC bool -circuit_sendme_cell_is_next(int deliver_window, int sendme_inc) -{ - /* 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. - * - * Because deliver_window starts at CIRCWINDOW_START and counts down, - * to get the actual number of received cells for this check, we must - * first convert to receieved cells, or the modulus operator will fail. - */ - tor_assert(deliver_window <= CIRCWINDOW_START); - if (((CIRCWINDOW_START - (deliver_window - 1)) % sendme_inc) != 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. @@ -420,7 +448,8 @@ sendme_circuit_consider_sending(circuit_t *circ, crypt_path_t *layer_hint) { bool sent_one_sendme = false; - const uint8_t *digest; + const uint8_t *tag; + size_t tag_len = 0; int sendme_inc = sendme_get_inc_count(circ, layer_hint); while ((layer_hint ? layer_hint->deliver_window : circ->deliver_window) <= @@ -428,12 +457,13 @@ log_debug(LD_CIRC,"Queuing circuit sendme."); if (layer_hint) { layer_hint->deliver_window += sendme_inc; - digest = cpath_get_sendme_digest(layer_hint); + tag = cpath_get_sendme_tag(layer_hint, &tag_len); } else { circ->deliver_window += sendme_inc; - digest = relay_crypto_get_sendme_digest(&TO_OR_CIRCUIT(circ)->crypto); + tag = relay_crypto_get_sendme_tag(&TO_OR_CIRCUIT(circ)->crypto, + &tag_len); } - if (send_circuit_level_sendme(circ, layer_hint, digest) < 0) { + if (send_circuit_level_sendme(circ, layer_hint, tag, tag_len) < 0) { return; /* The circuit's closed, don't continue */ } /* Current implementation is not suppose to send multiple SENDME at once @@ -470,7 +500,7 @@ /* 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)) { + if (!sendme_is_valid(circ, layer_hint, cell_payload, cell_payload_len)) { return -END_CIRC_REASON_TORPROTOCOL; } @@ -491,7 +521,7 @@ return sendme_process_circuit_level_impl(layer_hint, circ); } - return congestion_control_dispatch_cc_alg(cc, circ, layer_hint); + return congestion_control_dispatch_cc_alg(cc, circ); } /** @@ -697,7 +727,8 @@ void sendme_record_cell_digest_on_circ(circuit_t *circ, crypt_path_t *cpath) { - uint8_t *sendme_digest; + const uint8_t *sendme_tag; + size_t tag_len = 0; tor_assert(circ); @@ -711,60 +742,11 @@ /* 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, - sendme_get_inc_count(circ, cpath))) { - return; - } - - if (cpath) { - /* Record incoming digest. */ - cpath_sendme_record_cell_digest(cpath, false); + sendme_tag = cpath_get_sendme_tag(cpath, &tag_len); } else { - /* Record forward digest. */ - relay_crypto_record_sendme_digest(&TO_OR_CIRCUIT(circ)->crypto, true); + sendme_tag = + relay_crypto_get_sendme_tag(&TO_OR_CIRCUIT(circ)->crypto, &tag_len); } -} - -/* 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_sent_cell_for_sendme(circ, cpath)) { - 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; + record_cell_digest_on_circ(circ, sendme_tag, tag_len); } diff -Nru tor-0.4.7.16/src/core/or/sendme.h tor-0.4.9.6/src/core/or/sendme.h --- tor-0.4.7.16/src/core/or/sendme.h 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/core/or/sendme.h 2026-03-25 14:30:34.000000000 +0000 @@ -37,9 +37,6 @@ /* 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 @@ -68,13 +65,13 @@ STATIC bool cell_version_can_be_handled(uint8_t cell_version); -STATIC ssize_t build_cell_payload_v1(const uint8_t *cell_digest, +STATIC ssize_t build_cell_payload_v1(const uint8_t *cell_tag, + size_t tag_len, uint8_t *payload); -STATIC bool sendme_is_valid(const circuit_t *circ, +STATIC bool sendme_is_valid(circuit_t *circ, + const crypt_path_t *layer_hint, const uint8_t *cell_payload, size_t cell_payload_len); -STATIC bool circuit_sendme_cell_is_next(int deliver_window, - int sendme_inc); #endif /* defined(TOR_UNIT_TESTS) */ diff -Nru tor-0.4.7.16/src/core/or/status.c tor-0.4.9.6/src/core/or/status.c --- tor-0.4.7.16/src/core/or/status.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/core/or/status.c 2026-03-25 14:30:34.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (c) 2010-2021, The Tor Project, Inc. */ +/* Copyright (c) 2010-2025, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -24,6 +24,7 @@ #include "feature/relay/router.h" #include "feature/relay/routermode.h" #include "core/or/circuitlist.h" +#include "core/or/channelpadding.h" #include "core/mainloop/mainloop.h" #include "feature/stats/rephist.h" #include "feature/hibernate/hibernate.h" @@ -221,10 +222,11 @@ } double fullness_pct = 100; + // TODO CGO: This is slightly wrong? if (stats_n_data_cells_packaged && !hibernating) { fullness_pct = 100*(((double)stats_n_data_bytes_packaged) / - ((double)stats_n_data_cells_packaged*RELAY_PAYLOAD_SIZE)); + ((double)stats_n_data_cells_packaged*RELAY_PAYLOAD_SIZE_MAX)); } const double overhead_pct = ( r - 1.0 ) * 100.0; @@ -243,6 +245,7 @@ rep_hist_log_circuit_handshake_stats(now); rep_hist_log_link_protocol_counts(); dos_log_heartbeat(); + channelpadding_log_heartbeat(); } circuit_log_ancient_one_hop_circuits(1800); diff -Nru tor-0.4.7.16/src/core/or/versions.c tor-0.4.9.6/src/core/or/versions.c --- tor-0.4.7.16/src/core/or/versions.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/core/or/versions.c 2026-03-25 14:30:34.000000000 +0000 @@ -286,7 +286,7 @@ cp += 2; out->svn_revision = (int) strtol(cp,&eos,10); } else if (!strcmpstart(cp, "(git-")) { - char *close_paren = strchr(cp, ')'); + const char *close_paren = strchr(cp, ')'); int hexlen; char digest[DIGEST_LEN]; if (! close_paren) @@ -488,6 +488,26 @@ protocol_list_supports_protocol(protocols, PRT_RELAY, PROTOVER_RELAY_NTOR_V3); + /* Conflux requires congestion control. */ + out->supports_conflux = + protocol_list_supports_protocol(protocols, PRT_FLOWCTRL, + PROTOVER_FLOWCTRL_CC) && + protocol_list_supports_protocol(protocols, PRT_CONFLUX, + PROTOVER_CONFLUX_V1); + + out->supports_ntor_v3 = + protocol_list_supports_protocol(protocols, PRT_RELAY, + PROTOVER_RELAY_NTOR_V3); + + /* CGO requires congestion control and subproto negotiation. */ + out->supports_cgo = + protocol_list_supports_protocol(protocols, PRT_FLOWCTRL, + PROTOVER_FLOWCTRL_CC) && + protocol_list_supports_protocol(protocols, PRT_RELAY, + PROTOVER_RELAY_NEGOTIATE_SUBPROTO) && + protocol_list_supports_protocol(protocols, PRT_RELAY, + PROTOVER_RELAY_CRYPT_CGO); + protover_summary_flags_t *new_cached = tor_memdup(out, sizeof(*out)); cached = strmap_set(protover_summary_map, protocols, new_cached); tor_assert(!cached); diff -Nru tor-0.4.7.16/src/core/proto/include.am tor-0.4.9.6/src/core/proto/include.am --- tor-0.4.7.16/src/core/proto/include.am 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/core/proto/include.am 2026-03-25 14:30:34.000000000 +0000 @@ -1,6 +1,6 @@ # ADD_C_FILE: INSERT SOURCES HERE. -LIBTOR_APP_A_SOURCES += \ +LIBTOR_APP_A_SOURCES += \ src/core/proto/proto_cell.c \ src/core/proto/proto_control0.c \ src/core/proto/proto_ext_or.c \ diff -Nru tor-0.4.7.16/src/core/proto/proto_socks.c tor-0.4.9.6/src/core/proto/proto_socks.c --- tor-0.4.7.16/src/core/proto/proto_socks.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/core/proto/proto_socks.c 2026-03-25 14:30:34.000000000 +0000 @@ -186,18 +186,15 @@ } if (*is_socks4a) { - // We cannot rely on trunnel here, as we want to detect if - // we have abnormally long hostname field. - const char *hostname = (char *)raw_data + SOCKS4_NETWORK_LEN + - usernamelen + 1; - size_t hostname_len = (char *)raw_data + datalen - hostname; - - if (hostname_len <= sizeof(req->address)) { - const char *trunnel_hostname = + const char *trunnel_hostname = socks4_client_request_get_socks4a_addr_hostname(trunnel_req); - - if (trunnel_hostname) - strlcpy(req->address, trunnel_hostname, sizeof(req->address)); + if (BUG(!trunnel_hostname)) { + res = SOCKS_RESULT_INVALID; + goto end; + } + size_t hostname_len = strlen(trunnel_hostname); + if (hostname_len < sizeof(req->address)) { + strlcpy(req->address, trunnel_hostname, sizeof(req->address)); } else { log_warn(LD_APP, "socks4: Destaddr too long. Rejecting."); res = SOCKS_RESULT_INVALID; @@ -451,6 +448,19 @@ const char *password = socks5_client_userpass_auth_getconstarray_passwd(trunnel_req); + /* Detect invalid SOCKS5 extended-parameter requests. */ + if (usernamelen >= 8 && + tor_memeq(username, "", 8)) { + /* This is indeed an extended-parameter request. */ + if (usernamelen != 9 || + tor_memneq(username, "0", 9)) { + /* This request is an unrecognized version, or it includes an Arti RPC + * object ID (which we do not recognize). */ + res = SOCKS_RESULT_INVALID; + goto end; + } + } + if (usernamelen && username) { tor_free(req->username); req->username = tor_memdup_nulterm(username, usernamelen); @@ -919,11 +929,12 @@ "This is a SOCKS Proxy, Not An HTTP Proxy\n" "\n" "\n" - "

    This is a SOCKs proxy, not an HTTP proxy.

    \n" + "

    This is a SOCKS proxy, 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" + "

    \n" + "

    \n" "This is not correct: This port is configured as a SOCKS proxy, not\n" "an HTTP proxy. If you need an HTTP proxy tunnel, use the HTTPTunnelPort\n" "configuration option in place of, or in addition to, SOCKSPort.\n" diff -Nru tor-0.4.7.16/src/ext/compat_blake2.h tor-0.4.9.6/src/ext/compat_blake2.h --- tor-0.4.7.16/src/ext/compat_blake2.h 1970-01-01 00:00:00.000000000 +0000 +++ tor-0.4.9.6/src/ext/compat_blake2.h 2026-03-25 14:30:34.000000000 +0000 @@ -0,0 +1,47 @@ +/* Copyright (c) 2023, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file compat_blake2.h + * + * \brief Compatibility adapter providing blake2b using ext/equix/hashx + **/ + +#ifndef TOR_COMPAT_BLAKE2_H +#define TOR_COMPAT_BLAKE2_H + +#include +#include +#include "lib/cc/compat_compiler.h" +#include "ext/equix/hashx/src/blake2.h" + +static inline int +blake2b_init_param(blake2b_state *S, const blake2b_param *P) +{ + return hashx_blake2b_init_param(S, P); +} + +static inline int +blake2b_init(blake2b_state *S, const uint8_t digest_length) +{ + blake2b_param P; + memset(&P, 0, sizeof P); + P.digest_length = digest_length; + P.fanout = 1; + P.depth = 1; + return blake2b_init_param(S, &P); +} + +static inline int +blake2b_update(blake2b_state *S, const uint8_t *in, uint64_t inlen) +{ + return hashx_blake2b_update(S, in, inlen); +} + +static inline int +blake2b_final(blake2b_state *S, uint8_t *out, uint8_t outlen) +{ + return hashx_blake2b_final(S, out, outlen); +} + +#endif /* !defined(TOR_COMPAT_BLAKE2_H) */ diff -Nru tor-0.4.7.16/src/ext/equix/hashx/include/hashx.h tor-0.4.9.6/src/ext/equix/hashx/include/hashx.h --- tor-0.4.7.16/src/ext/equix/hashx/include/hashx.h 1970-01-01 00:00:00.000000000 +0000 +++ tor-0.4.9.6/src/ext/equix/hashx/include/hashx.h 2026-03-25 14:30:34.000000000 +0000 @@ -0,0 +1,195 @@ +/* Copyright (c) 2020 tevador */ +/* See LICENSE for licensing information */ + +/* + * HashX is an algorithm designed for client puzzles and proof-of-work schemes. + * While traditional cryptographic hash functions use a fixed one-way + * compression function, each HashX instance represents a unique pseudorandomly + * generated one-way function. + * + * Example of usage: + * + #include + #include + + int main() { + char seed[] = "this is a seed that will generate a hash function"; + char hash[HASHX_SIZE]; + hashx_ctx* ctx = hashx_alloc(HASHX_TRY_COMPILE); + if (ctx == NULL) + return 1; + if (hashx_make(ctx, seed, sizeof(seed)) != EQUIX_OK) + return 1; + if (hashx_exec(ctx, 123456789, hash) != EQUIX_OK) + return 1; + hashx_free(ctx); + for (unsigned i = 0; i < HASHX_SIZE; ++i) + printf("%02x", hash[i] & 0xff); + printf("\n"); + return 0; + } + * + */ + +#ifndef HASHX_H +#define HASHX_H + +#include +#include + +/* + * Input of the hash function. + * + * Counter mode (default): a 64-bit unsigned integer + * Block mode: pointer to a buffer and the number of bytes to be hashed +*/ +#ifndef HASHX_BLOCK_MODE +#define HASHX_INPUT uint64_t input +#else +#define HASHX_INPUT const void* input, size_t size +#endif + +/* The default (and maximum) hash size is 32 bytes */ +#ifndef HASHX_SIZE +#define HASHX_SIZE 32 +#endif + +/* Opaque struct representing a HashX instance */ +typedef struct hashx_ctx hashx_ctx; + +/* Type of hash context / type of compiled function */ +typedef enum hashx_type { + HASHX_TYPE_INTERPRETED = 1, /* Only the interpreted implementation */ + HASHX_TYPE_COMPILED, /* Require the compiler, fail if unavailable */ + HASHX_TRY_COMPILE, /* (hashx_alloc) Try compiler, don't require */ +} hashx_type; + +/* Result code for hashx_make and hashx_exec */ +typedef enum hashx_result { + HASHX_OK = 0, + HASHX_FAIL_UNPREPARED, /* Trying to run an unmade hash funciton */ + HASHX_FAIL_UNDEFINED, /* Unrecognized hashx_type enum value */ + HASHX_FAIL_SEED, /* Can't construct a hash function from this seed */ + HASHX_FAIL_COMPILE, /* Can't compile, and no fallback is enabled. */ +} hashx_result; + +#if defined(_WIN32) || defined(__CYGWIN__) +#define HASHX_WIN +#endif + +/* Shared/static library definitions */ +#ifdef HASHX_WIN + #ifdef HASHX_SHARED + #define HASHX_API __declspec(dllexport) + #elif !defined(HASHX_STATIC) + #define HASHX_API __declspec(dllimport) + #else + #define HASHX_API + #endif + #define HASHX_PRIVATE +#else + #ifdef HASHX_SHARED + #define HASHX_API __attribute__ ((visibility ("default"))) + #else + #define HASHX_API __attribute__ ((visibility ("hidden"))) + #endif + #define HASHX_PRIVATE __attribute__ ((visibility ("hidden"))) +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Allocate a HashX instance. + * + * @param type is the type of instance to be created. + * + * @return pointer to a new HashX instance. Returns NULL on memory allocation + * failures only. Other failures are reported in hashx_make. + */ +HASHX_API hashx_ctx* hashx_alloc(hashx_type type); + +/* + * Create a new HashX function from a variable-length seed value. + * + * The seed value will be hashed internally in order to initialize the state + * of the HashX program generator and create a new unique hash function. + * + * @param ctx is pointer to a HashX instance. + * @param seed is a pointer to the seed value. + * @param size is the size of the seed. + * + * @return HASHX_OK on success, HASHX_FAIL_SEED if the specific seed is + * not associated with a valid hash program, and HASHX_FAIL_COMPILE + * if the compiler failed for OS-specific reasons and the interpreter + * fallback was disabled by allocating the context with + * HASHX_TYPE_COMPILED rather than HASHX_TRY_COMPILE. + */ +HASHX_API hashx_result hashx_make(hashx_ctx* ctx, + const void* seed, size_t size); + +/* + * Asks the specific implementation of a function created with hashx_make. + * + * This will equal the parameter to hashx_alloc() if a specific type was + * chosen there, but a context allocated with HASHX_TRY_COMPILE will allow + * the implementation to vary dynamically during hashx_make. + * + * @param ctx is pointer to a HashX instance. + * @param type_out is a pointer to which, on success, we write + * a HASHX_TYPE_* value. + * + * @return HASHX_OK on success, or HASHX_FAIL_UNPREPARED if hashx_make has not + * been invoked successfully on this context. +*/ +HASHX_API hashx_result hashx_query_type(hashx_ctx* ctx, hashx_type *type_out); + +/* + * Execute the HashX function. + * + * @param ctx is pointer to a HashX instance. A HashX function must have + * been previously created by invoking hashx_make successfully. + * @param HASHX_INPUT is the input to be hashed (see definition above). + * @param output is a pointer to the result buffer. HASHX_SIZE bytes will be + * written. + * + * @return HASHX_OK on success, or HASHX_FAIL_UNPREPARED if hashx_make has not + * been invoked successfully on this context. + */ +HASHX_API hashx_result hashx_exec(const hashx_ctx* ctx, + HASHX_INPUT, void* output); + +/* + * Free a HashX instance. + * + * Has no effect if ctx is NULL. + * + * @param ctx is pointer to a HashX instance. +*/ +HASHX_API void hashx_free(hashx_ctx* ctx); + +#ifdef HASHX_RNG_CALLBACK +/* + * Set a callback for inspecting or modifying the HashX random number stream. + * + * The callback and its user pointer are associated with the provided context + * even if it's re-used for another hash program. A callback value of NULL + * disables the callback. + * + * @param ctx is pointer to a HashX instance. + * @param callback is invoked after each new 64-bit pseudorandom value + * is generated in a buffer. The callback may record it and/or replace + * it. A NULL pointer here disables the callback. + * @param user_data is an opaque parameter given to the callback + */ +HASHX_API void hashx_rng_callback(hashx_ctx* ctx, + void (*callback)(uint64_t*, void*), + void* user_data); +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff -Nru tor-0.4.7.16/src/ext/equix/hashx/src/blake2.c tor-0.4.9.6/src/ext/equix/hashx/src/blake2.c --- tor-0.4.7.16/src/ext/equix/hashx/src/blake2.c 1970-01-01 00:00:00.000000000 +0000 +++ tor-0.4.9.6/src/ext/equix/hashx/src/blake2.c 2026-03-25 14:30:34.000000000 +0000 @@ -0,0 +1,462 @@ +/* Copyright (c) 2020 tevador */ +/* See LICENSE for licensing information */ + +/* Original code from Argon2 reference source code package used under CC0 + * https://github.com/P-H-C/phc-winner-argon2 + * Copyright 2015 + * Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves +*/ + +#include +#include +#include +#include + +#include "blake2.h" +#include "hashx_endian.h" + +static const uint64_t blake2b_IV[8] = { + UINT64_C(0x6a09e667f3bcc908), UINT64_C(0xbb67ae8584caa73b), + UINT64_C(0x3c6ef372fe94f82b), UINT64_C(0xa54ff53a5f1d36f1), + UINT64_C(0x510e527fade682d1), UINT64_C(0x9b05688c2b3e6c1f), + UINT64_C(0x1f83d9abfb41bd6b), UINT64_C(0x5be0cd19137e2179) }; + +#define BLAKE2_SIGMA_0_0 0 +#define BLAKE2_SIGMA_0_1 1 +#define BLAKE2_SIGMA_0_2 2 +#define BLAKE2_SIGMA_0_3 3 +#define BLAKE2_SIGMA_0_4 4 +#define BLAKE2_SIGMA_0_5 5 +#define BLAKE2_SIGMA_0_6 6 +#define BLAKE2_SIGMA_0_7 7 +#define BLAKE2_SIGMA_0_8 8 +#define BLAKE2_SIGMA_0_9 9 +#define BLAKE2_SIGMA_0_10 10 +#define BLAKE2_SIGMA_0_11 11 +#define BLAKE2_SIGMA_0_12 12 +#define BLAKE2_SIGMA_0_13 13 +#define BLAKE2_SIGMA_0_14 14 +#define BLAKE2_SIGMA_0_15 15 + +#define BLAKE2_SIGMA_1_0 14 +#define BLAKE2_SIGMA_1_1 10 +#define BLAKE2_SIGMA_1_2 4 +#define BLAKE2_SIGMA_1_3 8 +#define BLAKE2_SIGMA_1_4 9 +#define BLAKE2_SIGMA_1_5 15 +#define BLAKE2_SIGMA_1_6 13 +#define BLAKE2_SIGMA_1_7 6 +#define BLAKE2_SIGMA_1_8 1 +#define BLAKE2_SIGMA_1_9 12 +#define BLAKE2_SIGMA_1_10 0 +#define BLAKE2_SIGMA_1_11 2 +#define BLAKE2_SIGMA_1_12 11 +#define BLAKE2_SIGMA_1_13 7 +#define BLAKE2_SIGMA_1_14 5 +#define BLAKE2_SIGMA_1_15 3 + +#define BLAKE2_SIGMA_2_0 11 +#define BLAKE2_SIGMA_2_1 8 +#define BLAKE2_SIGMA_2_2 12 +#define BLAKE2_SIGMA_2_3 0 +#define BLAKE2_SIGMA_2_4 5 +#define BLAKE2_SIGMA_2_5 2 +#define BLAKE2_SIGMA_2_6 15 +#define BLAKE2_SIGMA_2_7 13 +#define BLAKE2_SIGMA_2_8 10 +#define BLAKE2_SIGMA_2_9 14 +#define BLAKE2_SIGMA_2_10 3 +#define BLAKE2_SIGMA_2_11 6 +#define BLAKE2_SIGMA_2_12 7 +#define BLAKE2_SIGMA_2_13 1 +#define BLAKE2_SIGMA_2_14 9 +#define BLAKE2_SIGMA_2_15 4 + +#define BLAKE2_SIGMA_3_0 7 +#define BLAKE2_SIGMA_3_1 9 +#define BLAKE2_SIGMA_3_2 3 +#define BLAKE2_SIGMA_3_3 1 +#define BLAKE2_SIGMA_3_4 13 +#define BLAKE2_SIGMA_3_5 12 +#define BLAKE2_SIGMA_3_6 11 +#define BLAKE2_SIGMA_3_7 14 +#define BLAKE2_SIGMA_3_8 2 +#define BLAKE2_SIGMA_3_9 6 +#define BLAKE2_SIGMA_3_10 5 +#define BLAKE2_SIGMA_3_11 10 +#define BLAKE2_SIGMA_3_12 4 +#define BLAKE2_SIGMA_3_13 0 +#define BLAKE2_SIGMA_3_14 15 +#define BLAKE2_SIGMA_3_15 8 + +#define BLAKE2_SIGMA_4_0 9 +#define BLAKE2_SIGMA_4_1 0 +#define BLAKE2_SIGMA_4_2 5 +#define BLAKE2_SIGMA_4_3 7 +#define BLAKE2_SIGMA_4_4 2 +#define BLAKE2_SIGMA_4_5 4 +#define BLAKE2_SIGMA_4_6 10 +#define BLAKE2_SIGMA_4_7 15 +#define BLAKE2_SIGMA_4_8 14 +#define BLAKE2_SIGMA_4_9 1 +#define BLAKE2_SIGMA_4_10 11 +#define BLAKE2_SIGMA_4_11 12 +#define BLAKE2_SIGMA_4_12 6 +#define BLAKE2_SIGMA_4_13 8 +#define BLAKE2_SIGMA_4_14 3 +#define BLAKE2_SIGMA_4_15 13 + +#define BLAKE2_SIGMA_5_0 2 +#define BLAKE2_SIGMA_5_1 12 +#define BLAKE2_SIGMA_5_2 6 +#define BLAKE2_SIGMA_5_3 10 +#define BLAKE2_SIGMA_5_4 0 +#define BLAKE2_SIGMA_5_5 11 +#define BLAKE2_SIGMA_5_6 8 +#define BLAKE2_SIGMA_5_7 3 +#define BLAKE2_SIGMA_5_8 4 +#define BLAKE2_SIGMA_5_9 13 +#define BLAKE2_SIGMA_5_10 7 +#define BLAKE2_SIGMA_5_11 5 +#define BLAKE2_SIGMA_5_12 15 +#define BLAKE2_SIGMA_5_13 14 +#define BLAKE2_SIGMA_5_14 1 +#define BLAKE2_SIGMA_5_15 9 + +#define BLAKE2_SIGMA_6_0 12 +#define BLAKE2_SIGMA_6_1 5 +#define BLAKE2_SIGMA_6_2 1 +#define BLAKE2_SIGMA_6_3 15 +#define BLAKE2_SIGMA_6_4 14 +#define BLAKE2_SIGMA_6_5 13 +#define BLAKE2_SIGMA_6_6 4 +#define BLAKE2_SIGMA_6_7 10 +#define BLAKE2_SIGMA_6_8 0 +#define BLAKE2_SIGMA_6_9 7 +#define BLAKE2_SIGMA_6_10 6 +#define BLAKE2_SIGMA_6_11 3 +#define BLAKE2_SIGMA_6_12 9 +#define BLAKE2_SIGMA_6_13 2 +#define BLAKE2_SIGMA_6_14 8 +#define BLAKE2_SIGMA_6_15 11 + +#define BLAKE2_SIGMA_7_0 13 +#define BLAKE2_SIGMA_7_1 11 +#define BLAKE2_SIGMA_7_2 7 +#define BLAKE2_SIGMA_7_3 14 +#define BLAKE2_SIGMA_7_4 12 +#define BLAKE2_SIGMA_7_5 1 +#define BLAKE2_SIGMA_7_6 3 +#define BLAKE2_SIGMA_7_7 9 +#define BLAKE2_SIGMA_7_8 5 +#define BLAKE2_SIGMA_7_9 0 +#define BLAKE2_SIGMA_7_10 15 +#define BLAKE2_SIGMA_7_11 4 +#define BLAKE2_SIGMA_7_12 8 +#define BLAKE2_SIGMA_7_13 6 +#define BLAKE2_SIGMA_7_14 2 +#define BLAKE2_SIGMA_7_15 10 + +#define BLAKE2_SIGMA_8_0 6 +#define BLAKE2_SIGMA_8_1 15 +#define BLAKE2_SIGMA_8_2 14 +#define BLAKE2_SIGMA_8_3 9 +#define BLAKE2_SIGMA_8_4 11 +#define BLAKE2_SIGMA_8_5 3 +#define BLAKE2_SIGMA_8_6 0 +#define BLAKE2_SIGMA_8_7 8 +#define BLAKE2_SIGMA_8_8 12 +#define BLAKE2_SIGMA_8_9 2 +#define BLAKE2_SIGMA_8_10 13 +#define BLAKE2_SIGMA_8_11 7 +#define BLAKE2_SIGMA_8_12 1 +#define BLAKE2_SIGMA_8_13 4 +#define BLAKE2_SIGMA_8_14 10 +#define BLAKE2_SIGMA_8_15 5 + +#define BLAKE2_SIGMA_9_0 10 +#define BLAKE2_SIGMA_9_1 2 +#define BLAKE2_SIGMA_9_2 8 +#define BLAKE2_SIGMA_9_3 4 +#define BLAKE2_SIGMA_9_4 7 +#define BLAKE2_SIGMA_9_5 6 +#define BLAKE2_SIGMA_9_6 1 +#define BLAKE2_SIGMA_9_7 5 +#define BLAKE2_SIGMA_9_8 15 +#define BLAKE2_SIGMA_9_9 11 +#define BLAKE2_SIGMA_9_10 9 +#define BLAKE2_SIGMA_9_11 14 +#define BLAKE2_SIGMA_9_12 3 +#define BLAKE2_SIGMA_9_13 12 +#define BLAKE2_SIGMA_9_14 13 +#define BLAKE2_SIGMA_9_15 0 + +#define BLAKE2_SIGMA_10_0 0 +#define BLAKE2_SIGMA_10_1 1 +#define BLAKE2_SIGMA_10_2 2 +#define BLAKE2_SIGMA_10_3 3 +#define BLAKE2_SIGMA_10_4 4 +#define BLAKE2_SIGMA_10_5 5 +#define BLAKE2_SIGMA_10_6 6 +#define BLAKE2_SIGMA_10_7 7 +#define BLAKE2_SIGMA_10_8 8 +#define BLAKE2_SIGMA_10_9 9 +#define BLAKE2_SIGMA_10_10 10 +#define BLAKE2_SIGMA_10_11 11 +#define BLAKE2_SIGMA_10_12 12 +#define BLAKE2_SIGMA_10_13 13 +#define BLAKE2_SIGMA_10_14 14 +#define BLAKE2_SIGMA_10_15 15 + +#define BLAKE2_SIGMA_11_0 14 +#define BLAKE2_SIGMA_11_1 10 +#define BLAKE2_SIGMA_11_2 4 +#define BLAKE2_SIGMA_11_3 8 +#define BLAKE2_SIGMA_11_4 9 +#define BLAKE2_SIGMA_11_5 15 +#define BLAKE2_SIGMA_11_6 13 +#define BLAKE2_SIGMA_11_7 6 +#define BLAKE2_SIGMA_11_8 1 +#define BLAKE2_SIGMA_11_9 12 +#define BLAKE2_SIGMA_11_10 0 +#define BLAKE2_SIGMA_11_11 2 +#define BLAKE2_SIGMA_11_12 11 +#define BLAKE2_SIGMA_11_13 7 +#define BLAKE2_SIGMA_11_14 5 +#define BLAKE2_SIGMA_11_15 3 + +static FORCE_INLINE uint64_t rotr64(const uint64_t w, const unsigned c) { + return (w >> c) | (w << (64 - c)); +} + +static FORCE_INLINE void blake2b_set_lastblock(blake2b_state* S) { + S->f[0] = (uint64_t)-1; +} + +static FORCE_INLINE void blake2b_increment_counter(blake2b_state* S, + uint64_t inc) { + S->t[0] += inc; + S->t[1] += (S->t[0] < inc); +} + +static FORCE_INLINE void blake2b_init0(blake2b_state* S) { + memset(S, 0, sizeof(*S)); + memcpy(S->h, blake2b_IV, sizeof(S->h)); +} + +int hashx_blake2b_init_param(blake2b_state* S, const blake2b_param* P) { + const unsigned char* p = (const unsigned char*)P; + unsigned int i; + + if (NULL == P || NULL == S) { + return -1; + } + + blake2b_init0(S); + /* IV XOR Parameter Block */ + for (i = 0; i < 8; ++i) { + S->h[i] ^= load64(&p[i * sizeof(S->h[i])]); + } + S->outlen = P->digest_length; + return 0; +} + +#define SIGMA(r, k) BLAKE2_SIGMA_ ## r ## _ ## k + +#define G(r, i, j, a, b, c, d) \ + do { \ + a = a + b + m[SIGMA(r, i)]; \ + d = rotr64(d ^ a, 32); \ + c = c + d; \ + b = rotr64(b ^ c, 24); \ + a = a + b + m[SIGMA(r, j)]; \ + d = rotr64(d ^ a, 16); \ + c = c + d; \ + b = rotr64(b ^ c, 63); \ + } while ((void)0, 0) + +#define ROUND_INNER(r) \ + do { \ + G(r, 0, 1, v[0], v[4], v[8], v[12]); \ + G(r, 2, 3, v[1], v[5], v[9], v[13]); \ + G(r, 4, 5, v[2], v[6], v[10], v[14]); \ + G(r, 6, 7, v[3], v[7], v[11], v[15]); \ + G(r, 8, 9, v[0], v[5], v[10], v[15]); \ + G(r, 10, 11, v[1], v[6], v[11], v[12]); \ + G(r, 12, 13, v[2], v[7], v[8], v[13]); \ + G(r, 14, 15, v[3], v[4], v[9], v[14]); \ + } while ((void)0, 0) + +#define ROUND(r) ROUND_INNER(r) + +static void blake2b_compress(blake2b_state* S, const uint8_t* block) { + uint64_t m[16]; + uint64_t v[16]; + unsigned int i; + + for (i = 0; i < 16; ++i) { + m[i] = load64(block + i * sizeof(m[i])); + } + + for (i = 0; i < 8; ++i) { + v[i] = S->h[i]; + } + + v[8] = blake2b_IV[0]; + v[9] = blake2b_IV[1]; + v[10] = blake2b_IV[2]; + v[11] = blake2b_IV[3]; + v[12] = blake2b_IV[4] ^ S->t[0]; + v[13] = blake2b_IV[5] ^ S->t[1]; + v[14] = blake2b_IV[6] ^ S->f[0]; + v[15] = blake2b_IV[7] ^ S->f[1]; + + ROUND(0); + ROUND(1); + ROUND(2); + ROUND(3); + ROUND(4); + ROUND(5); + ROUND(6); + ROUND(7); + ROUND(8); + ROUND(9); + ROUND(10); + ROUND(11); + + for (i = 0; i < 8; ++i) { + S->h[i] = S->h[i] ^ v[i] ^ v[i + 8]; + } +} + +static void blake2b_compress_4r(blake2b_state* S, const uint8_t* block) { + uint64_t m[16]; + uint64_t v[16]; + unsigned int i; + + for (i = 0; i < 16; ++i) { + m[i] = load64(block + i * sizeof(m[i])); + } + + for (i = 0; i < 8; ++i) { + v[i] = S->h[i]; + } + + v[8] = blake2b_IV[0]; + v[9] = blake2b_IV[1]; + v[10] = blake2b_IV[2]; + v[11] = blake2b_IV[3]; + v[12] = blake2b_IV[4] ^ S->t[0]; + v[13] = blake2b_IV[5] ^ S->t[1]; + v[14] = blake2b_IV[6] ^ S->f[0]; + v[15] = blake2b_IV[7] ^ S->f[1]; + + ROUND(0); + ROUND(1); + ROUND(2); + ROUND(3); + + for (i = 0; i < 8; ++i) { + S->h[i] = S->h[i] ^ v[i] ^ v[i + 8]; + } +} + +int hashx_blake2b_update(blake2b_state* S, const void* in, size_t inlen) { + const uint8_t* pin = (const uint8_t*)in; + + if (inlen == 0) { + return 0; + } + + /* Sanity check */ + if (S == NULL || in == NULL) { + return -1; + } + + /* Is this a reused state? */ + if (S->f[0] != 0) { + return -1; + } + + if (S->buflen + inlen > BLAKE2B_BLOCKBYTES) { + /* Complete current block */ + size_t left = S->buflen; + size_t fill = BLAKE2B_BLOCKBYTES - left; + memcpy(&S->buf[left], pin, fill); + blake2b_increment_counter(S, BLAKE2B_BLOCKBYTES); + blake2b_compress(S, S->buf); + S->buflen = 0; + inlen -= fill; + pin += fill; + /* Avoid buffer copies when possible */ + while (inlen > BLAKE2B_BLOCKBYTES) { + blake2b_increment_counter(S, BLAKE2B_BLOCKBYTES); + blake2b_compress(S, pin); + inlen -= BLAKE2B_BLOCKBYTES; + pin += BLAKE2B_BLOCKBYTES; + } + } + memcpy(&S->buf[S->buflen], pin, inlen); + S->buflen += (unsigned int)inlen; + return 0; +} + +int hashx_blake2b_final(blake2b_state* S, void* out, size_t outlen) { + uint8_t buffer[BLAKE2B_OUTBYTES] = { 0 }; + unsigned int i; + + /* Sanity checks */ + if (S == NULL || out == NULL || outlen < S->outlen) { + return -1; + } + + /* Is this a reused state? */ + if (S->f[0] != 0) { + return -1; + } + + blake2b_increment_counter(S, S->buflen); + blake2b_set_lastblock(S); + memset(&S->buf[S->buflen], 0, BLAKE2B_BLOCKBYTES - S->buflen); /* Padding */ + blake2b_compress(S, S->buf); + + for (i = 0; i < 8; ++i) { /* Output full hash to temp buffer */ + store64(buffer + sizeof(S->h[i]) * i, S->h[i]); + } + + memcpy(out, buffer, S->outlen); + + return 0; +} + +/* 4-round version of Blake2b */ +void hashx_blake2b_4r(const blake2b_param* params, const void* in, + size_t inlen, void* out) { + + blake2b_state state; + const uint8_t* p = (const uint8_t*)params; + + blake2b_init0(&state); + /* IV XOR Parameter Block */ + for (unsigned i = 0; i < 8; ++i) { + state.h[i] ^= load64(&p[i * sizeof(state.h[i])]); + } + //state.outlen = blake_params.digest_length; + + const uint8_t* pin = (const uint8_t*)in; + + while (inlen > BLAKE2B_BLOCKBYTES) { + blake2b_increment_counter(&state, BLAKE2B_BLOCKBYTES); + blake2b_compress_4r(&state, pin); + inlen -= BLAKE2B_BLOCKBYTES; + pin += BLAKE2B_BLOCKBYTES; + } + + memcpy(state.buf, pin, inlen); + blake2b_increment_counter(&state, inlen); + blake2b_set_lastblock(&state); + blake2b_compress_4r(&state, state.buf); + + /* Output hash */ + memcpy(out, state.h, sizeof(state.h)); +} diff -Nru tor-0.4.7.16/src/ext/equix/hashx/src/blake2.h tor-0.4.9.6/src/ext/equix/hashx/src/blake2.h --- tor-0.4.7.16/src/ext/equix/hashx/src/blake2.h 1970-01-01 00:00:00.000000000 +0000 +++ tor-0.4.9.6/src/ext/equix/hashx/src/blake2.h 2026-03-25 14:30:34.000000000 +0000 @@ -0,0 +1,73 @@ +/* Copyright (c) 2020 tevador */ +/* See LICENSE for licensing information */ + +/* Original code from Argon2 reference source code package used under CC0 Licence + * https://github.com/P-H-C/phc-winner-argon2 + * Copyright 2015 + * Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves +*/ + +#ifndef PORTABLE_BLAKE2_H +#define PORTABLE_BLAKE2_H + +#include +#include +#include +#include + +#if defined(__cplusplus) +extern "C" { +#endif + +enum blake2b_constant { + BLAKE2B_BLOCKBYTES = 128, + BLAKE2B_OUTBYTES = 64, + BLAKE2B_KEYBYTES = 64, + BLAKE2B_SALTBYTES = 16, + BLAKE2B_PERSONALBYTES = 16 +}; + +#pragma pack(push, 1) +typedef struct blake2b_param { + uint8_t digest_length; /* 1 */ + uint8_t key_length; /* 2 */ + uint8_t fanout; /* 3 */ + uint8_t depth; /* 4 */ + uint32_t leaf_length; /* 8 */ + uint64_t node_offset; /* 16 */ + uint8_t node_depth; /* 17 */ + uint8_t inner_length; /* 18 */ + uint8_t reserved[14]; /* 32 */ + uint8_t salt[BLAKE2B_SALTBYTES]; /* 48 */ + uint8_t personal[BLAKE2B_PERSONALBYTES]; /* 64 */ +} blake2b_param; +#pragma pack(pop) + +typedef struct blake2b_state { + uint64_t h[8]; + uint64_t t[2]; + uint64_t f[2]; + uint8_t buf[BLAKE2B_BLOCKBYTES]; + unsigned buflen; + unsigned outlen; + uint8_t last_node; +} blake2b_state; + +/* Ensure param structs have not been wrongly padded */ +/* Poor man's static_assert */ +enum { + blake2_size_check_0 = 1 / !!(CHAR_BIT == 8), + blake2_size_check_2 = + 1 / !!(sizeof(blake2b_param) == sizeof(uint64_t) * CHAR_BIT) +}; + +HASHX_PRIVATE int hashx_blake2b_init_param(blake2b_state* S, const blake2b_param* P); +HASHX_PRIVATE int hashx_blake2b_update(blake2b_state* S, const void* in, size_t inlen); +HASHX_PRIVATE int hashx_blake2b_final(blake2b_state* S, void* out, size_t outlen); +HASHX_PRIVATE void hashx_blake2b_4r(const blake2b_param* P, const void* in, size_t inlen, void* out); + +#if defined(__cplusplus) +} +#endif + +#endif diff -Nru tor-0.4.7.16/src/ext/equix/hashx/src/compiler.c tor-0.4.9.6/src/ext/equix/hashx/src/compiler.c --- tor-0.4.7.16/src/ext/equix/hashx/src/compiler.c 1970-01-01 00:00:00.000000000 +0000 +++ tor-0.4.9.6/src/ext/equix/hashx/src/compiler.c 2026-03-25 14:30:34.000000000 +0000 @@ -0,0 +1,19 @@ +/* Copyright (c) 2020 tevador */ +/* See LICENSE for licensing information */ + +#include + +#include "compiler.h" +#include "virtual_memory.h" +#include "program.h" +#include "context.h" + +void hashx_compiler_init(hashx_ctx* ctx) { + /* This can fail, but it's uncommon. We report this up the call chain + * later, at the same time as an mprotect or similar failure. */ + ctx->compiler_mem = hashx_vm_alloc(COMP_CODE_SIZE); +} + +void hashx_compiler_destroy(hashx_ctx* ctx) { + hashx_vm_free(ctx->compiler_mem, COMP_CODE_SIZE); +} diff -Nru tor-0.4.7.16/src/ext/equix/hashx/src/compiler.h tor-0.4.9.6/src/ext/equix/hashx/src/compiler.h --- tor-0.4.7.16/src/ext/equix/hashx/src/compiler.h 1970-01-01 00:00:00.000000000 +0000 +++ tor-0.4.9.6/src/ext/equix/hashx/src/compiler.h 2026-03-25 14:30:34.000000000 +0000 @@ -0,0 +1,77 @@ +/* Copyright (c) 2020 tevador */ +/* See LICENSE for licensing information */ + +#ifndef COMPILER_H +#define COMPILER_H + +#include +#include +#include +#include "virtual_memory.h" +#include "program.h" + +HASHX_PRIVATE bool hashx_compile_x86(const hashx_program* program, uint8_t* code); + +HASHX_PRIVATE bool hashx_compile_a64(const hashx_program* program, uint8_t* code); + +#if defined(_M_X64) || defined(__x86_64__) +#define HASHX_COMPILER_X86 +#define hashx_compile(p,c) hashx_compile_x86(p,c) +#elif defined(__aarch64__) +#define HASHX_COMPILER_A64 +#define hashx_compile(p,c) hashx_compile_a64(p,c) +#else +#define hashx_compile(p,c) (false) +#endif + +HASHX_PRIVATE void hashx_compiler_init(hashx_ctx* compiler); +HASHX_PRIVATE void hashx_compiler_destroy(hashx_ctx* compiler); + +/* Compiled code sizes in bytes: + * + * Prologue Epilogue MulH Reg-Reg Reg-Imm32 Branch+Tgt MaxInst + * X86 69 64 9 3..4 7 15 10 (br) + * A64 40 36 4 4 12 24 24 (br) + * + * Maximum code sizes, assuming an arbitrary instruction mix including unlimited + * branch instructions. (Branch size * 512 + prologue + epilogue) + * + * Max possible code size (any instructions) + * X86 5253 + * A64 12364 + * + * Actual code sizes tend to be much smaller due to the instruction mix chosen + * by the program generator. To get a quick overview of the statistics, we + * measure the sample mean and sample standard deviation for 1 million random + * hash programs: + * + * Mean Std Deviation 4096 bytes at + * X86 2786.4 26.259 49.9 standard deviations + * A64 3507.7 58.526 10.1 standard deviations + * + * If we search for PRNG sequences that maximize generated code size, it's easy + * to find aarch64 code that needs in the range of 4100-4300 bytes. On x86, this + * search still doesn't turn up programs anywhere close to a full page. + * + * Anyway, this is all to say that a one-page buffer is fine except for in + * extremely rare cases on aarch64, and a two-page buffer is enough for any + * behavior we can expect from the program generator under arbitrary input, + * but only a 4-page buffer is enough for fully arbitrary instruction streams + * on any architecture. + * + * Let's use a 2-page buffer on aarch64, or 1-page elsewhere. + * + * Note that the buffer allocation is done by platform-independent code, + * so COMP_CODE_SIZE must always have a valid size even on platforms where + * it is not actually supported or used. + * + * If this buffer fills up, compilation will fail with a runtime error. + */ + +#ifdef HASHX_COMPILER_A64 +#define COMP_CODE_SIZE (4096 * 2) +#else +#define COMP_CODE_SIZE (4096 * 1) +#endif + +#endif diff -Nru tor-0.4.7.16/src/ext/equix/hashx/src/compiler_a64.c tor-0.4.9.6/src/ext/equix/hashx/src/compiler_a64.c --- tor-0.4.7.16/src/ext/equix/hashx/src/compiler_a64.c 1970-01-01 00:00:00.000000000 +0000 +++ tor-0.4.9.6/src/ext/equix/hashx/src/compiler_a64.c 2026-03-25 14:30:34.000000000 +0000 @@ -0,0 +1,164 @@ +/* Copyright (c) 2020 tevador */ +/* See LICENSE for licensing information */ + +#include +#include + +#include "compiler.h" +#include "program.h" +#include "virtual_memory.h" +#include "unreachable.h" + +#define EMIT(p,x) do { \ + memcpy(p, x, sizeof(x)); \ + p += sizeof(x); \ + } while (0) +#define EMIT_U32(p,x) *((uint32_t*)(p)) = x; p += sizeof(uint32_t) +#define EMIT_IMM32(p,x) \ + EMIT_U32(p, 0x9280000c | \ + ((x <= INT32_MAX) << 30) | \ + (((x <= INT32_MAX) ? (x & 0xFFFF) : (~x & 0xFFFF)) << 5)); \ + EMIT_U32(p, 0xf2a0000c | \ + (((x >> 16) & 0xFFFF) << 5)); + +#ifdef HASHX_COMPILER_A64 + +/* Largest compiled instruction (BRANCH) */ +#define COMP_MAX_INSTR_SIZE 24 + +static const uint8_t a64_prologue[] = { + 0x07, 0x1c, 0x40, 0xf9, /* ldr x7, [x0, #56] */ + 0x06, 0x18, 0x40, 0xf9, /* ldr x6, [x0, #48] */ + 0x05, 0x14, 0x40, 0xf9, /* ldr x5, [x0, #40] */ + 0x04, 0x10, 0x40, 0xf9, /* ldr x4, [x0, #32] */ + 0x03, 0x0c, 0x40, 0xf9, /* ldr x3, [x0, #24] */ + 0x02, 0x08, 0x40, 0xf9, /* ldr x2, [x0, #16] */ + 0x01, 0x04, 0x40, 0xf9, /* ldr x1, [x0, #8] */ + 0xe8, 0x03, 0x00, 0xaa, /* mov x8, x0 */ + 0x00, 0x00, 0x40, 0xf9, /* ldr x0, [x0] */ + 0xe9, 0x03, 0x1f, 0x2a, /* mov w9, wzr */ +}; + +static const uint8_t a64_epilogue[] = { + 0x00, 0x01, 0x00, 0xf9, /* str x0, [x8] */ + 0x01, 0x05, 0x00, 0xf9, /* str x1, [x8, #8] */ + 0x02, 0x09, 0x00, 0xf9, /* str x2, [x8, #16] */ + 0x03, 0x0d, 0x00, 0xf9, /* str x3, [x8, #24] */ + 0x04, 0x11, 0x00, 0xf9, /* str x4, [x8, #32] */ + 0x05, 0x15, 0x00, 0xf9, /* str x5, [x8, #40] */ + 0x06, 0x19, 0x00, 0xf9, /* str x6, [x8, #48] */ + 0x07, 0x1d, 0x00, 0xf9, /* str x7, [x8, #56] */ + 0xc0, 0x03, 0x5f, 0xd6, /* ret */ +}; + +bool hashx_compile_a64(const hashx_program* program, uint8_t* code) { + if (!hashx_vm_rw(code, COMP_CODE_SIZE)) + return false; + uint8_t* pos = code; + uint8_t* target = NULL; + int creg = -1; + EMIT(pos, a64_prologue); + for (size_t i = 0; i < program->code_size; ++i) { + if (pos + COMP_MAX_INSTR_SIZE > code + COMP_CODE_SIZE) + return false; + const instruction* instr = &program->code[i]; + switch (instr->opcode) + { + case INSTR_UMULH_R: + EMIT_U32(pos, 0x9bc07c00 | + (instr->src << 16) | + (instr->dst << 5) | + (instr->dst)); + if (target != NULL) { + creg = instr->dst; + } + break; + case INSTR_SMULH_R: + EMIT_U32(pos, 0x9b407c00 | + (instr->src << 16) | + (instr->dst << 5) | + (instr->dst)); + if (target != NULL) { + creg = instr->dst; + } + break; + case INSTR_MUL_R: + assert(creg != instr->dst); + EMIT_U32(pos, 0x9b007c00 | + (instr->src << 16) | + (instr->dst << 5) | + (instr->dst)); + break; + case INSTR_SUB_R: + assert(creg != instr->dst); + EMIT_U32(pos, 0xcb000000 | + (instr->src << 16) | + (instr->dst << 5) | + (instr->dst)); + break; + case INSTR_XOR_R: + assert(creg != instr->dst); + EMIT_U32(pos, 0xca000000 | + (instr->src << 16) | + (instr->dst << 5) | + (instr->dst)); + break; + case INSTR_ADD_RS: + assert(creg != instr->dst); + EMIT_U32(pos, 0x8b000000 | + (instr->src << 16) | + (instr->imm32 << 10) | + (instr->dst << 5) | + (instr->dst)); + break; + case INSTR_ROR_C: + assert(creg != instr->dst); + EMIT_U32(pos, 0x93c00000 | + (instr->dst << 16) | + (instr->imm32 << 10) | + (instr->dst << 5) | + (instr->dst)); + break; + case INSTR_ADD_C: + assert(creg != instr->dst); + EMIT_IMM32(pos, instr->imm32); + EMIT_U32(pos, 0x8b0c0000 | + (instr->dst << 5) | + (instr->dst)); + break; + case INSTR_XOR_C: + assert(creg != instr->dst); + EMIT_IMM32(pos, instr->imm32); + EMIT_U32(pos, 0xca0c0000 | + (instr->dst << 5) | + (instr->dst)); + break; + case INSTR_TARGET: + target = pos; + break; + case INSTR_BRANCH: + EMIT_IMM32(pos, instr->imm32); + EMIT_U32(pos, 0x2a00012b | (creg << 16)); + EMIT_U32(pos, 0x6a0c017f); + EMIT_U32(pos, 0x5a891129); + EMIT_U32(pos, 0x54000000 | + ((((uint32_t)(target - pos)) >> 2) & 0x7FFFF) << 5); + target = NULL; + creg = -1; + break; + default: + UNREACHABLE; + } + } + if (pos + sizeof a64_epilogue > code + COMP_CODE_SIZE) + return false; + EMIT(pos, a64_epilogue); + if (!hashx_vm_rx(code, COMP_CODE_SIZE)) + return false; +#ifdef __GNUC__ + __builtin___clear_cache((void*)code, (void*)pos); +#endif + return true; +} + +#endif diff -Nru tor-0.4.7.16/src/ext/equix/hashx/src/compiler_x86.c tor-0.4.9.6/src/ext/equix/hashx/src/compiler_x86.c --- tor-0.4.7.16/src/ext/equix/hashx/src/compiler_x86.c 1970-01-01 00:00:00.000000000 +0000 +++ tor-0.4.9.6/src/ext/equix/hashx/src/compiler_x86.c 2026-03-25 14:30:34.000000000 +0000 @@ -0,0 +1,159 @@ +/* Copyright (c) 2020 tevador */ +/* See LICENSE for licensing information */ + +#include + +#include "compiler.h" +#include "program.h" +#include "virtual_memory.h" +#include "unreachable.h" + +#if defined(_WIN32) || defined(__CYGWIN__) +#define WINABI +#endif + +#define EMIT(p,x) do { \ + memcpy(p, x, sizeof(x)); \ + p += sizeof(x); \ + } while (0) +#define EMIT_BYTE(p,x) *((p)++) = x +#define EMIT_U16(p,x) *((uint16_t*)(p)) = x; p += sizeof(uint16_t) +#define EMIT_U32(p,x) *((uint32_t*)(p)) = x; p += sizeof(uint32_t) +#define EMIT_U64(p,x) *((uint64_t*)(p)) = x; p += sizeof(uint64_t) + +#define GEN_SIB(scale, index, base) ((scale << 6) | (index << 3) | base) + +#ifdef HASHX_COMPILER_X86 + +/* Largest compiled instruction (BRANCH) */ +#define COMP_MAX_INSTR_SIZE 10 + +static const uint8_t x86_prologue[] = { +#ifndef WINABI + 0x48, 0x89, 0xF9, /* mov rcx, rdi */ + 0x48, 0x83, 0xEC, 0x20, /* sub rsp, 32 */ + 0x4C, 0x89, 0x24, 0x24, /* mov qword ptr [rsp+0], r12 */ + 0x4C, 0x89, 0x6C, 0x24, 0x08, /* mov qword ptr [rsp+8], r13 */ + 0x4C, 0x89, 0x74, 0x24, 0x10, /* mov qword ptr [rsp+16], r14 */ + 0x4C, 0x89, 0x7C, 0x24, 0x18, /* mov qword ptr [rsp+24], r15 */ +#else + 0x4C, 0x89, 0x64, 0x24, 0x08, /* mov qword ptr [rsp+8], r12 */ + 0x4C, 0x89, 0x6C, 0x24, 0x10, /* mov qword ptr [rsp+16], r13 */ + 0x4C, 0x89, 0x74, 0x24, 0x18, /* mov qword ptr [rsp+24], r14 */ + 0x4C, 0x89, 0x7C, 0x24, 0x20, /* mov qword ptr [rsp+32], r15 */ + 0x48, 0x83, 0xEC, 0x10, /* sub rsp, 16 */ + 0x48, 0x89, 0x34, 0x24, /* mov qword ptr [rsp+0], rsi */ + 0x48, 0x89, 0x7C, 0x24, 0x08, /* mov qword ptr [rsp+8], rdi */ +#endif + 0x31, 0xF6, /* xor esi, esi */ + 0x8D, 0x7E, 0xFF, /* lea edi, [rsi-1] */ + 0x4C, 0x8B, 0x01, /* mov r8, qword ptr [rcx+0] */ + 0x4C, 0x8B, 0x49, 0x08, /* mov r9, qword ptr [rcx+8] */ + 0x4C, 0x8B, 0x51, 0x10, /* mov r10, qword ptr [rcx+16] */ + 0x4C, 0x8B, 0x59, 0x18, /* mov r11, qword ptr [rcx+24] */ + 0x4C, 0x8B, 0x61, 0x20, /* mov r12, qword ptr [rcx+32] */ + 0x4C, 0x8B, 0x69, 0x28, /* mov r13, qword ptr [rcx+40] */ + 0x4C, 0x8B, 0x71, 0x30, /* mov r14, qword ptr [rcx+48] */ + 0x4C, 0x8B, 0x79, 0x38 /* mov r15, qword ptr [rcx+56] */ +}; + +static const uint8_t x86_epilogue[] = { + 0x4C, 0x89, 0x01, /* mov qword ptr [rcx+0], r8 */ + 0x4C, 0x89, 0x49, 0x08, /* mov qword ptr [rcx+8], r9 */ + 0x4C, 0x89, 0x51, 0x10, /* mov qword ptr [rcx+16], r10 */ + 0x4C, 0x89, 0x59, 0x18, /* mov qword ptr [rcx+24], r11 */ + 0x4C, 0x89, 0x61, 0x20, /* mov qword ptr [rcx+32], r12 */ + 0x4C, 0x89, 0x69, 0x28, /* mov qword ptr [rcx+40], r13 */ + 0x4C, 0x89, 0x71, 0x30, /* mov qword ptr [rcx+48], r14 */ + 0x4C, 0x89, 0x79, 0x38, /* mov qword ptr [rcx+56], r15 */ +#ifndef WINABI + 0x4C, 0x8B, 0x24, 0x24, /* mov r12, qword ptr [rsp+0] */ + 0x4C, 0x8B, 0x6C, 0x24, 0x08, /* mov r13, qword ptr [rsp+8] */ + 0x4C, 0x8B, 0x74, 0x24, 0x10, /* mov r14, qword ptr [rsp+16] */ + 0x4C, 0x8B, 0x7C, 0x24, 0x18, /* mov r15, qword ptr [rsp+24] */ + 0x48, 0x83, 0xC4, 0x20, /* add rsp, 32 */ +#else + 0x48, 0x8B, 0x34, 0x24, /* mov rsi, qword ptr [rsp+0] */ + 0x48, 0x8B, 0x7C, 0x24, 0x08, /* mov rdi, qword ptr [rsp+8] */ + 0x48, 0x83, 0xC4, 0x10, /* add rsp, 16 */ + 0x4C, 0x8B, 0x64, 0x24, 0x08, /* mov r12, qword ptr [rsp+8] */ + 0x4C, 0x8B, 0x6C, 0x24, 0x10, /* mov r13, qword ptr [rsp+16] */ + 0x4C, 0x8B, 0x74, 0x24, 0x18, /* mov r14, qword ptr [rsp+24] */ + 0x4C, 0x8B, 0x7C, 0x24, 0x20, /* mov r15, qword ptr [rsp+32] */ +#endif + 0xC3 /* ret */ +}; + +bool hashx_compile_x86(const hashx_program* program, uint8_t* code) { + if (!hashx_vm_rw(code, COMP_CODE_SIZE)) + return false; + uint8_t* pos = code; + uint8_t* target = NULL; + EMIT(pos, x86_prologue); + for (size_t i = 0; i < program->code_size; ++i) { + if (pos + COMP_MAX_INSTR_SIZE > code + COMP_CODE_SIZE) + return false; + const instruction* instr = &program->code[i]; + switch (instr->opcode) + { + case INSTR_UMULH_R: + EMIT_U64(pos, 0x8b4ce0f749c08b49 | + (((uint64_t)instr->src) << 40) | + (((uint64_t)instr->dst) << 16)); + EMIT_BYTE(pos, 0xc2 + 8 * instr->dst); + break; + case INSTR_SMULH_R: + EMIT_U64(pos, 0x8b4ce8f749c08b49 | + (((uint64_t)instr->src) << 40) | + (((uint64_t)instr->dst) << 16)); + EMIT_BYTE(pos, 0xc2 + 8 * instr->dst); + break; + case INSTR_MUL_R: + EMIT_U32(pos, 0xc0af0f4d | (instr->dst << 27) | (instr->src << 24)); + break; + case INSTR_SUB_R: + EMIT_U16(pos, 0x2b4d); + EMIT_BYTE(pos, 0xc0 | (instr->dst << 3) | instr->src); + break; + case INSTR_XOR_R: + EMIT_U16(pos, 0x334d); + EMIT_BYTE(pos, 0xc0 | (instr->dst << 3) | instr->src); + break; + case INSTR_ADD_RS: + EMIT_U32(pos, 0x00048d4f | + (instr->dst << 19) | + GEN_SIB(instr->imm32, instr->src, instr->dst) << 24); + break; + case INSTR_ROR_C: + EMIT_U32(pos, 0x00c8c149 | (instr->dst << 16) | (instr->imm32 << 24)); + break; + case INSTR_ADD_C: + EMIT_U16(pos, 0x8149); + EMIT_BYTE(pos, 0xc0 | instr->dst); + EMIT_U32(pos, instr->imm32); + break; + case INSTR_XOR_C: + EMIT_U16(pos, 0x8149); + EMIT_BYTE(pos, 0xf0 | instr->dst); + EMIT_U32(pos, instr->imm32); + break; + case INSTR_TARGET: + target = pos; /* +2 */ + EMIT_U32(pos, 0x440fff85); + EMIT_BYTE(pos, 0xf7); + break; + case INSTR_BRANCH: + EMIT_U64(pos, ((uint64_t)instr->imm32) << 32 | 0xc2f7f209); + EMIT_U16(pos, ((target - pos) << 8) | 0x74); + break; + default: + UNREACHABLE; + } + } + if (pos + sizeof x86_epilogue > code + COMP_CODE_SIZE) + return false; + EMIT(pos, x86_epilogue); + return hashx_vm_rx(code, COMP_CODE_SIZE); +} + +#endif diff -Nru tor-0.4.7.16/src/ext/equix/hashx/src/context.c tor-0.4.9.6/src/ext/equix/hashx/src/context.c --- tor-0.4.7.16/src/ext/equix/hashx/src/context.c 1970-01-01 00:00:00.000000000 +0000 +++ tor-0.4.9.6/src/ext/equix/hashx/src/context.c 2026-03-25 14:30:34.000000000 +0000 @@ -0,0 +1,67 @@ +/* Copyright (c) 2020 tevador */ +/* See LICENSE for licensing information */ + +#include +#include + +#include +#include "context.h" +#include "compiler.h" +#include "program.h" + +#define STRINGIZE_INNER(x) #x +#define STRINGIZE(x) STRINGIZE_INNER(x) + +/* Salt used when generating hash functions. Useful for domain separation. */ +#ifndef HASHX_SALT +#define HASHX_SALT HashX v1 +#endif + +/* Blake2b params used to generate program keys */ +const blake2b_param hashx_blake2_params = { + .digest_length = 64, + .key_length = 0, + .fanout = 1, + .depth = 1, + .leaf_length = 0, + .node_offset = 0, + .node_depth = 0, + .inner_length = 0, + .reserved = { 0 }, + .salt = STRINGIZE(HASHX_SALT), + .personal = { 0 } +}; + +hashx_ctx* hashx_alloc(hashx_type type) { + hashx_ctx* ctx = malloc(sizeof(hashx_ctx)); + if (ctx == NULL) + return NULL; + + memset(ctx, 0, sizeof *ctx); + ctx->ctx_type = type; + if (type == HASHX_TYPE_COMPILED || type == HASHX_TRY_COMPILE) { + hashx_compiler_init(ctx); + } + +#ifdef HASHX_BLOCK_MODE + memcpy(&ctx->params, &hashx_blake2_params, 32); +#endif + return ctx; +} + +void hashx_free(hashx_ctx* ctx) { + if (ctx != NULL) { + hashx_compiler_destroy(ctx); + free(ctx); + } +} + +#ifdef HASHX_RNG_CALLBACK +void hashx_rng_callback(hashx_ctx* ctx, + void (*callback)(uint64_t*, void*), + void* callback_user_data) +{ + ctx->program.rng_callback = callback; + ctx->program.rng_callback_user_data = callback_user_data; +} +#endif diff -Nru tor-0.4.7.16/src/ext/equix/hashx/src/context.h tor-0.4.9.6/src/ext/equix/hashx/src/context.h --- tor-0.4.7.16/src/ext/equix/hashx/src/context.h 1970-01-01 00:00:00.000000000 +0000 +++ tor-0.4.9.6/src/ext/equix/hashx/src/context.h 2026-03-25 14:30:34.000000000 +0000 @@ -0,0 +1,39 @@ +/* Copyright (c) 2020 tevador */ +/* See LICENSE for licensing information */ + +#ifndef CONTEXT_H +#define CONTEXT_H + +#include + +#include "hashx.h" +#include "blake2.h" +#include "siphash.h" +#include "program.h" + +#ifdef __cplusplus +extern "C" { +#endif + +HASHX_PRIVATE extern const blake2b_param hashx_blake2_params; + +#ifdef __cplusplus +} +#endif + +typedef struct hashx_program hashx_program; + +/* HashX context. */ +typedef struct hashx_ctx { + uint8_t* compiler_mem; + hashx_type ctx_type; + hashx_type func_type; + hashx_program program; +#ifndef HASHX_BLOCK_MODE + siphash_state keys; +#else + blake2b_param params; +#endif +} hashx_ctx; + +#endif diff -Nru tor-0.4.7.16/src/ext/equix/hashx/src/force_inline.h tor-0.4.9.6/src/ext/equix/hashx/src/force_inline.h --- tor-0.4.7.16/src/ext/equix/hashx/src/force_inline.h 1970-01-01 00:00:00.000000000 +0000 +++ tor-0.4.9.6/src/ext/equix/hashx/src/force_inline.h 2026-03-25 14:30:34.000000000 +0000 @@ -0,0 +1,9 @@ +#ifndef FORCE_INLINE +#if defined(_MSC_VER) +#define FORCE_INLINE __inline +#elif defined(__GNUC__) || defined(__clang__) +#define FORCE_INLINE __inline__ +#else +#define FORCE_INLINE +#endif +#endif diff -Nru tor-0.4.7.16/src/ext/equix/hashx/src/hashx.c tor-0.4.9.6/src/ext/equix/hashx/src/hashx.c --- tor-0.4.7.16/src/ext/equix/hashx/src/hashx.c 1970-01-01 00:00:00.000000000 +0000 +++ tor-0.4.9.6/src/ext/equix/hashx/src/hashx.c 2026-03-25 14:30:34.000000000 +0000 @@ -0,0 +1,172 @@ +/* Copyright (c) 2020 tevador */ +/* See LICENSE for licensing information */ + +#include +#include +#include + +#include +#include "blake2.h" +#include "hashx_endian.h" +#include "program.h" +#include "context.h" +#include "compiler.h" + +#if HASHX_SIZE > 32 +#error HASHX_SIZE cannot be more than 32 +#endif + +#ifndef HASHX_BLOCK_MODE +#define HASHX_INPUT_ARGS input +#else +#define HASHX_INPUT_ARGS input, size +#endif + +static bool initialize_program(hashx_ctx* ctx, siphash_state keys[2]) { + if (!hashx_program_generate(&keys[0], &ctx->program)) { + return false; + } +#ifndef HASHX_BLOCK_MODE + memcpy(&ctx->keys, &keys[1], 32); +#else + memcpy(&ctx->params.salt, &keys[1], 32); +#endif + return true; +} + +hashx_result hashx_make(hashx_ctx* ctx, const void* seed, size_t size) { + assert(ctx != NULL); + assert(seed != NULL || size == 0); + + uint8_t keys_bytes[2 * sizeof(siphash_state)]; + blake2b_state hash_state; + hashx_blake2b_init_param(&hash_state, &hashx_blake2_params); + hashx_blake2b_update(&hash_state, seed, size); + hashx_blake2b_final(&hash_state, keys_bytes, sizeof(keys_bytes)); + + siphash_state keys[2]; + keys[0].v0 = load64(keys_bytes + 0 * sizeof(uint64_t)); + keys[0].v1 = load64(keys_bytes + 1 * sizeof(uint64_t)); + keys[0].v2 = load64(keys_bytes + 2 * sizeof(uint64_t)); + keys[0].v3 = load64(keys_bytes + 3 * sizeof(uint64_t)); + keys[1].v0 = load64(keys_bytes + 4 * sizeof(uint64_t)); + keys[1].v1 = load64(keys_bytes + 5 * sizeof(uint64_t)); + keys[1].v2 = load64(keys_bytes + 6 * sizeof(uint64_t)); + keys[1].v3 = load64(keys_bytes + 7 * sizeof(uint64_t)); + + ctx->func_type = (hashx_type)0; + if (!initialize_program(ctx, keys)) { + return HASHX_FAIL_SEED; + } + + switch (ctx->ctx_type) { + case HASHX_TYPE_INTERPRETED: + ctx->func_type = HASHX_TYPE_INTERPRETED; + return HASHX_OK; + case HASHX_TYPE_COMPILED: + case HASHX_TRY_COMPILE: + if (ctx->compiler_mem != NULL && + hashx_compile(&ctx->program, ctx->compiler_mem)) { + ctx->func_type = HASHX_TYPE_COMPILED; + return HASHX_OK; + } + if (ctx->ctx_type == HASHX_TRY_COMPILE) { + ctx->func_type = HASHX_TYPE_INTERPRETED; + return HASHX_OK; + } else { + return HASHX_FAIL_COMPILE; + } + default: + return HASHX_FAIL_UNDEFINED; + } +} + +hashx_result hashx_query_type(hashx_ctx* ctx, hashx_type *type_out) { + assert(ctx != NULL); + assert(type_out != NULL); + + if (ctx->func_type == (hashx_type)0) { + return HASHX_FAIL_UNPREPARED; + } + *type_out = ctx->func_type; + return HASHX_OK; +} + +hashx_result hashx_exec(const hashx_ctx* ctx, HASHX_INPUT, void* output) { + assert(ctx != NULL); + assert(output != NULL); + + uint64_t r[8]; +#ifndef HASHX_BLOCK_MODE + hashx_siphash24_ctr_state512(&ctx->keys, input, r); +#else + hashx_blake2b_4r(&ctx->params, input, size, r); +#endif + + if (ctx->func_type == HASHX_TYPE_COMPILED) { + typedef void program_func(uint64_t r[8]); + assert(ctx->compiler_mem != NULL); + ((program_func*)ctx->compiler_mem)(r); + } else if (ctx->func_type == HASHX_TYPE_INTERPRETED) { + hashx_program_execute(&ctx->program, r); + } else { + return HASHX_FAIL_UNPREPARED; + } + + /* Hash finalization to remove bias toward 0 caused by multiplications */ +#ifndef HASHX_BLOCK_MODE + r[0] += ctx->keys.v0; + r[1] += ctx->keys.v1; + r[6] += ctx->keys.v2; + r[7] += ctx->keys.v3; +#else + const uint8_t* p = (const uint8_t*)&ctx->params; + r[0] ^= load64(&p[8 * 0]); + r[1] ^= load64(&p[8 * 1]); + r[2] ^= load64(&p[8 * 2]); + r[3] ^= load64(&p[8 * 3]); + r[4] ^= load64(&p[8 * 4]); + r[5] ^= load64(&p[8 * 5]); + r[6] ^= load64(&p[8 * 6]); + r[7] ^= load64(&p[8 * 7]); +#endif + /* 1 SipRound per 4 registers is enough to pass SMHasher. */ + SIPROUND(r[0], r[1], r[2], r[3]); + SIPROUND(r[4], r[5], r[6], r[7]); + + /* output */ +#if HASHX_SIZE > 0 + /* optimized output for hash sizes that are multiples of 8 */ +#if HASHX_SIZE % 8 == 0 + uint8_t* temp_out = (uint8_t*)output; +#if HASHX_SIZE >= 8 + store64(temp_out + 0, r[0] ^ r[4]); +#endif +#if HASHX_SIZE >= 16 + store64(temp_out + 8, r[1] ^ r[5]); +#endif +#if HASHX_SIZE >= 24 + store64(temp_out + 16, r[2] ^ r[6]); +#endif +#if HASHX_SIZE >= 32 + store64(temp_out + 24, r[3] ^ r[7]); +#endif +#else /* any output size */ + uint8_t temp_out[32]; +#if HASHX_SIZE > 0 + store64(temp_out + 0, r[0] ^ r[4]); +#endif +#if HASHX_SIZE > 8 + store64(temp_out + 8, r[1] ^ r[5]); +#endif +#if HASHX_SIZE > 16 + store64(temp_out + 16, r[2] ^ r[6]); +#endif +#if HASHX_SIZE > 24 + store64(temp_out + 24, r[3] ^ r[7]); +#endif + memcpy(output, temp_out, HASHX_SIZE); +#endif +#endif + return HASHX_OK; +} diff -Nru tor-0.4.7.16/src/ext/equix/hashx/src/hashx_endian.h tor-0.4.9.6/src/ext/equix/hashx/src/hashx_endian.h --- tor-0.4.7.16/src/ext/equix/hashx/src/hashx_endian.h 1970-01-01 00:00:00.000000000 +0000 +++ tor-0.4.9.6/src/ext/equix/hashx/src/hashx_endian.h 2026-03-25 14:30:34.000000000 +0000 @@ -0,0 +1,103 @@ +#ifndef ENDIAN_H +#define ENDIAN_H + +#include +#include +#include "force_inline.h" + +/* Argon2 Team - Begin Code */ +/* + Not an exhaustive list, but should cover the majority of modern platforms + Additionally, the code will always be correct---this is only a performance + tweak. +*/ +#if (defined(__BYTE_ORDER__) && \ + (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)) || \ + defined(__LITTLE_ENDIAN__) || defined(__ARMEL__) || defined(__MIPSEL__) || \ + defined(__AARCH64EL__) || defined(__amd64__) || defined(__i386__) || \ + defined(_M_IX86) || defined(_M_X64) || defined(_M_AMD64) || \ + defined(_M_ARM) +#define NATIVE_LITTLE_ENDIAN +#endif +/* Argon2 Team - End Code */ + +static FORCE_INLINE uint32_t load32(const void* src) { +#if defined(NATIVE_LITTLE_ENDIAN) + uint32_t w; + memcpy(&w, src, sizeof w); + return w; +#else + const uint8_t* p = (const uint8_t*)src; + uint32_t w = *p++; + w |= (uint32_t)(*p++) << 8; + w |= (uint32_t)(*p++) << 16; + w |= (uint32_t)(*p++) << 24; + return w; +#endif +} + +static FORCE_INLINE uint64_t load64_native(const void* src) { + uint64_t w; + memcpy(&w, src, sizeof w); + return w; +} + +static FORCE_INLINE uint64_t load64(const void* src) { +#if defined(NATIVE_LITTLE_ENDIAN) + return load64_native(src); +#else + const uint8_t* p = (const uint8_t*)src; + uint64_t w = *p++; + w |= (uint64_t)(*p++) << 8; + w |= (uint64_t)(*p++) << 16; + w |= (uint64_t)(*p++) << 24; + w |= (uint64_t)(*p++) << 32; + w |= (uint64_t)(*p++) << 40; + w |= (uint64_t)(*p++) << 48; + w |= (uint64_t)(*p++) << 56; + return w; +#endif +} + +static FORCE_INLINE void store32(void* dst, uint32_t w) { +#if defined(NATIVE_LITTLE_ENDIAN) + memcpy(dst, &w, sizeof w); +#else + uint8_t* p = (uint8_t*)dst; + *p++ = (uint8_t)w; + w >>= 8; + *p++ = (uint8_t)w; + w >>= 8; + *p++ = (uint8_t)w; + w >>= 8; + *p++ = (uint8_t)w; +#endif +} + +static FORCE_INLINE void store64_native(void* dst, uint64_t w) { + memcpy(dst, &w, sizeof w); +} + +static FORCE_INLINE void store64(void* dst, uint64_t w) { +#if defined(NATIVE_LITTLE_ENDIAN) + store64_native(dst, w); +#else + uint8_t* p = (uint8_t*)dst; + *p++ = (uint8_t)w; + w >>= 8; + *p++ = (uint8_t)w; + w >>= 8; + *p++ = (uint8_t)w; + w >>= 8; + *p++ = (uint8_t)w; + w >>= 8; + *p++ = (uint8_t)w; + w >>= 8; + *p++ = (uint8_t)w; + w >>= 8; + *p++ = (uint8_t)w; + w >>= 8; + *p++ = (uint8_t)w; +#endif +} +#endif diff -Nru tor-0.4.7.16/src/ext/equix/hashx/src/instruction.h tor-0.4.9.6/src/ext/equix/hashx/src/instruction.h --- tor-0.4.7.16/src/ext/equix/hashx/src/instruction.h 1970-01-01 00:00:00.000000000 +0000 +++ tor-0.4.9.6/src/ext/equix/hashx/src/instruction.h 2026-03-25 14:30:34.000000000 +0000 @@ -0,0 +1,31 @@ +/* Copyright (c) 2020 tevador */ +/* See LICENSE for licensing information */ + +#ifndef INSTRUCTION_H +#define INSTRUCTION_H + +#include + +typedef enum instr_type { + INSTR_UMULH_R, /* unsigned high multiplication by a register */ + INSTR_SMULH_R, /* signed high multiplication by a register */ + INSTR_MUL_R, /* multiplication by a register */ + INSTR_SUB_R, /* subtraction of a register */ + INSTR_XOR_R, /* xor with a register */ + INSTR_ADD_RS, /* addition of a shifted register */ + INSTR_ROR_C, /* rotation by a constant */ + INSTR_ADD_C, /* addition of a constant */ + INSTR_XOR_C, /* xor with a constant */ + INSTR_TARGET, /* branch instruction target */ + INSTR_BRANCH, /* conditional branch */ +} instr_type; + +typedef struct instruction { + instr_type opcode; + int src; + int dst; + uint32_t imm32; + uint32_t op_par; +} instruction; + +#endif diff -Nru tor-0.4.7.16/src/ext/equix/hashx/src/program.c tor-0.4.9.6/src/ext/equix/hashx/src/program.c --- tor-0.4.7.16/src/ext/equix/hashx/src/program.c 1970-01-01 00:00:00.000000000 +0000 +++ tor-0.4.9.6/src/ext/equix/hashx/src/program.c 2026-03-25 14:30:34.000000000 +0000 @@ -0,0 +1,777 @@ +/* Copyright (c) 2020 tevador */ +/* See LICENSE for licensing information */ + +#include +#include +#include +#include + +#include "program.h" +#include "unreachable.h" +#include "siphash_rng.h" + +/* instructions are generated until this CPU cycle */ +#define TARGET_CYCLE 192 + +/* requirements for the program to be acceptable */ +#define REQUIREMENT_SIZE 512 +#define REQUIREMENT_MUL_COUNT 192 +#define REQUIREMENT_LATENCY 195 + +/* R5 (x86 = r13) register cannot be used as the destination of INSTR_ADD_RS */ +#define REGISTER_NEEDS_DISPLACEMENT 5 + +#define PORT_MAP_SIZE (TARGET_CYCLE + 4) +#define NUM_PORTS 3 +#define MAX_RETRIES 1 +#define LOG2_BRANCH_PROB 4 +#define BRANCH_MASK 0x80000000 + +#define TRACE false +#define TRACE_PRINT(...) do { if (TRACE) printf(__VA_ARGS__); } while (false) + +#define MAX(a,b) ((a) > (b) ? (a) : (b)) + +/* If the instruction is a multiplication. */ +static inline bool is_mul(instr_type type) { + return type <= INSTR_MUL_R; +} + +#ifdef HASHX_PROGRAM_STATS +/* If the instruction is a 64x64->128 bit multiplication. */ +static inline bool is_wide_mul(instr_type type) { + return type < INSTR_MUL_R; +} +#endif + +/* Ivy Bridge integer execution ports: P0, P1, P5 */ +typedef enum execution_port { + PORT_NONE = 0, + PORT_P0 = 1, + PORT_P1 = 2, + PORT_P5 = 4, + PORT_P01 = PORT_P0 | PORT_P1, + PORT_P05 = PORT_P0 | PORT_P5, + PORT_P015 = PORT_P0 | PORT_P1 | PORT_P5 +} execution_port; + +static const char* execution_port_names[] = { + "PORT_NONE", "PORT_P0", "PORT_P1", "PORT_P01", "PORT_P5", "PORT_P05", "PORT_P15", "PORT_P015" +}; + +typedef struct instr_template { + instr_type type; /* instruction type */ + const char* x86_asm; /* x86 assembly */ + int x86_size; /* x86 code size */ + int latency; /* latency in cycles */ + execution_port uop1; /* ex. ports for the 1st uop */ + execution_port uop2; /* ex. ports for the 2nd uop */ + uint32_t immediate_mask; /* mask for imm32 */ + instr_type group; /* instruction group */ + bool imm_can_be_0; /* if imm32 can be zero */ + bool distinct_dst; /* if dst and src must be distinct */ + bool op_par_src; /* operation parameter is equal to src */ + bool has_src; /* if the instruction has a source operand */ + bool has_dst; /* if the instr. has a destination operand */ +} instr_template; + +typedef struct register_info { + int latency; /* cycle when the register value will be ready */ + instr_type last_op; /* last op applied to the register */ + uint32_t last_op_par; /* parameter of the last op (~0 = constant) */ +} register_info; + +typedef struct program_item { + const instr_template** templates; + uint32_t mask0; + uint32_t mask1; + bool duplicates; +} program_item; + +typedef struct generator_ctx { + int cycle; + int sub_cycle; + int mul_count; + bool chain_mul; + int latency; + siphash_rng gen; + register_info registers[8]; + execution_port ports[PORT_MAP_SIZE][NUM_PORTS]; +} generator_ctx; + +static const instr_template tpl_umulh_r = { + .type = INSTR_UMULH_R, + .x86_asm = "mul r", + .x86_size = 9, /* mov, mul, mov */ + .latency = 4, + .uop1 = PORT_P1, + .uop2 = PORT_P5, + .immediate_mask = 0, + .group = INSTR_UMULH_R, + .imm_can_be_0 = false, + .distinct_dst = false, + .op_par_src = false, + .has_src = true, + .has_dst = true, +}; + +static const instr_template tpl_smulh_r = { + .type = INSTR_SMULH_R, + .x86_asm = "imul r", + .x86_size = 9, /* mov, mul, mov */ + .latency = 4, + .uop1 = PORT_P1, + .uop2 = PORT_P5, + .immediate_mask = 0, + .group = INSTR_SMULH_R, + .imm_can_be_0 = false, + .distinct_dst = false, + .op_par_src = false, + .has_src = true, + .has_dst = true, +}; + +static const instr_template tpl_mul_r = { + .type = INSTR_MUL_R, + .x86_asm = "imul r,r", + .x86_size = 4, + .latency = 3, + .uop1 = PORT_P1, + .uop2 = PORT_NONE, + .immediate_mask = 0, + .group = INSTR_MUL_R, + .imm_can_be_0 = false, + .distinct_dst = true, + .op_par_src = true, + .has_src = true, + .has_dst = true, +}; + +static const instr_template tpl_sub_r = { + .type = INSTR_SUB_R, + .x86_asm = "sub r,r", + .x86_size = 3, + .latency = 1, + .uop1 = PORT_P015, + .uop2 = PORT_NONE, + .immediate_mask = 0, + .group = INSTR_ADD_RS, + .imm_can_be_0 = false, + .distinct_dst = true, + .op_par_src = true, + .has_src = true, + .has_dst = true, +}; + +static const instr_template tpl_xor_r = { + .type = INSTR_XOR_R, + .x86_asm = "xor r,r", + .x86_size = 3, + .latency = 1, + .uop1 = PORT_P015, + .uop2 = PORT_NONE, + .immediate_mask = 0, + .group = INSTR_XOR_R, + .imm_can_be_0 = false, + .distinct_dst = true, + .op_par_src = true, + .has_src = true, + .has_dst = true, +}; + +static const instr_template tpl_add_rs = { + .type = INSTR_ADD_RS, + .x86_asm = "lea r,r+r*s", + .x86_size = 4, + .latency = 1, + .uop1 = PORT_P01, + .uop2 = PORT_NONE, + .immediate_mask = 3, + .group = INSTR_ADD_RS, + .imm_can_be_0 = true, + .distinct_dst = true, + .op_par_src = true, + .has_src = true, + .has_dst = true, +}; + +static const instr_template tpl_ror_c = { + .type = INSTR_ROR_C, + .x86_asm = "ror r,i", + .x86_size = 4, + .latency = 1, + .uop1 = PORT_P05, + .uop2 = PORT_NONE, + .immediate_mask = 63, + .group = INSTR_ROR_C, + .imm_can_be_0 = false, + .distinct_dst = true, + .op_par_src = false, + .has_src = false, + .has_dst = true, +}; + +static const instr_template tpl_add_c = { + .type = INSTR_ADD_C, + .x86_asm = "add r,i", + .x86_size = 7, + .latency = 1, + .uop1 = PORT_P015, + .uop2 = PORT_NONE, + .immediate_mask = UINT32_MAX, + .group = INSTR_ADD_C, + .imm_can_be_0 = false, + .distinct_dst = true, + .op_par_src = false, + .has_src = false, + .has_dst = true, +}; + +static const instr_template tpl_xor_c = { + .type = INSTR_XOR_C, + .x86_asm = "xor r,i", + .x86_size = 7, + .latency = 1, + .uop1 = PORT_P015, + .uop2 = PORT_NONE, + .immediate_mask = UINT32_MAX, + .group = INSTR_XOR_C, + .imm_can_be_0 = false, + .distinct_dst = true, + .op_par_src = false, + .has_src = false, + .has_dst = true, +}; + + +static const instr_template tpl_target = { + .type = INSTR_TARGET, + .x86_asm = "cmovz esi, edi", + .x86_size = 5, /* test, cmovz */ + .latency = 1, + .uop1 = PORT_P015, + .uop2 = PORT_P015, + .immediate_mask = 0, + .group = INSTR_TARGET, + .imm_can_be_0 = false, + .distinct_dst = true, + .op_par_src = false, + .has_src = false, + .has_dst = false, +}; + +static const instr_template tpl_branch = { + .type = INSTR_BRANCH, + .x86_asm = "jz target", + .x86_size = 10, /* or, test, jz */ + .latency = 1, + .uop1 = PORT_P015, + .uop2 = PORT_P015, + .immediate_mask = BRANCH_MASK, + .group = INSTR_BRANCH, + .imm_can_be_0 = false, + .distinct_dst = true, + .op_par_src = false, + .has_src = false, + .has_dst = false, +}; + +static const instr_template* instr_lookup[] = { + &tpl_ror_c, + &tpl_xor_c, + &tpl_add_c, + &tpl_add_c, + &tpl_sub_r, + &tpl_xor_r, + &tpl_xor_c, + &tpl_add_rs, +}; + +static const instr_template* wide_mul_lookup[] = { + &tpl_smulh_r, + &tpl_umulh_r +}; + +static const instr_template* mul_lookup = &tpl_mul_r; +static const instr_template* target_lookup = &tpl_target; +static const instr_template* branch_lookup = &tpl_branch; + +static const program_item item_mul = { + .templates = &mul_lookup, + .mask0 = 0, + .mask1 = 0, + .duplicates = true +}; + +static const program_item item_target = { + .templates = &target_lookup, + .mask0 = 0, + .mask1 = 0, + .duplicates = true +}; + +static const program_item item_branch = { + .templates = &branch_lookup, + .mask0 = 0, + .mask1 = 0, + .duplicates = true +}; + +static const program_item item_wide_mul = { + .templates = wide_mul_lookup, + .mask0 = 1, + .mask1 = 1, + .duplicates = true +}; + +static const program_item item_any = { + .templates = instr_lookup, + .mask0 = 7, + .mask1 = 3, /* instructions that don't need a src register */ + .duplicates = false +}; + +static const program_item* program_layout[] = { + &item_mul, + &item_target, + &item_any, + &item_mul, + &item_any, + &item_any, + &item_mul, + &item_any, + &item_any, + &item_mul, + &item_any, + &item_any, + &item_wide_mul, + &item_any, + &item_any, + &item_mul, + &item_any, + &item_any, + &item_mul, + &item_branch, + &item_any, + &item_mul, + &item_any, + &item_any, + &item_wide_mul, + &item_any, + &item_any, + &item_mul, + &item_any, + &item_any, + &item_mul, + &item_any, + &item_any, + &item_mul, + &item_any, + &item_any, +}; + +static const instr_template* select_template(generator_ctx* ctx, instr_type last_instr, int attempt) { + const program_item* item = program_layout[ctx->sub_cycle % 36]; + const instr_template* tpl; + do { + int index = item->mask0 ? hashx_siphash_rng_u8(&ctx->gen) & (attempt > 0 ? item->mask1 : item->mask0) : 0; + tpl = item->templates[index]; + } while (!item->duplicates && tpl->group == last_instr); + return tpl; +} + +static uint32_t branch_mask(siphash_rng* gen) { + uint32_t mask = 0; + int popcnt = 0; + while (popcnt < LOG2_BRANCH_PROB) { + int bit = hashx_siphash_rng_u8(gen) % 32; + uint32_t bitmask = 1U << bit; + if (!(mask & bitmask)) { + mask |= bitmask; + popcnt++; + } + } + return mask; +} + +static void instr_from_template(const instr_template* tpl, siphash_rng* gen, instruction* instr) { + instr->opcode = tpl->type; + if (tpl->immediate_mask) { + if (tpl->immediate_mask == BRANCH_MASK) { + instr->imm32 = branch_mask(gen); + } + else do { + instr->imm32 = hashx_siphash_rng_u32(gen) & tpl->immediate_mask; + } while (instr->imm32 == 0 && !tpl->imm_can_be_0); + } + if (!tpl->op_par_src) { + if (tpl->distinct_dst) { + instr->op_par = UINT32_MAX; + } + else { + instr->op_par = hashx_siphash_rng_u32(gen); + } + } + if (!tpl->has_src) { + instr->src = -1; + } + if (!tpl->has_dst) { + instr->dst = -1; + } +} + +static bool select_register(int available_regs[8], int regs_count, siphash_rng* gen, int* reg_out) { + if (regs_count == 0) + return false; + + int index; + + if (regs_count > 1) { + index = hashx_siphash_rng_u32(gen) % regs_count; + } + else { + index = 0; + } + *reg_out = available_regs[index]; + return true; +} + +static bool select_destination(const instr_template* tpl, instruction* instr, generator_ctx* ctx, int cycle) { + int available_regs[8]; + int regs_count = 0; + /* Conditions for the destination register: + // * value must be ready at the required cycle + // * cannot be the same as the source register unless the instruction allows it + // - this avoids optimizable instructions such as "xor r, r" or "sub r, r" + // * register cannot be multiplied twice in a row unless chain_mul is true + // - this avoids accumulation of trailing zeroes in registers due to excessive multiplication + // - allowChainedMul is set to true if an attempt to find source/destination registers failed (this is quite rare, but prevents a catastrophic failure of the generator) + // * either the last instruction applied to the register or its source must be different than this instruction + // - this avoids optimizable instruction sequences such as "xor r1, r2; xor r1, r2" or "ror r, C1; ror r, C2" or "add r, C1; add r, C2" + // * register r5 cannot be the destination of the IADD_RS instruction (limitation of the x86 lea instruction) */ + for (int i = 0; i < 8; ++i) { + bool available = ctx->registers[i].latency <= cycle; + available &= ((!tpl->distinct_dst) | (i != instr->src)); + available &= (ctx->chain_mul | (tpl->group != INSTR_MUL_R) | (ctx->registers[i].last_op != INSTR_MUL_R)); + available &= ((ctx->registers[i].last_op != tpl->group) | (ctx->registers[i].last_op_par != instr->op_par)); + available &= ((instr->opcode != INSTR_ADD_RS) | (i != REGISTER_NEEDS_DISPLACEMENT)); + available_regs[regs_count] = available ? i : 0; + regs_count += available; + } + return select_register(available_regs, regs_count, &ctx->gen, &instr->dst); +} + +static bool select_source(const instr_template* tpl, instruction* instr, generator_ctx* ctx, int cycle) { + int available_regs[8]; + int regs_count = 0; + /* all registers that are ready at the cycle */ + for (int i = 0; i < 8; ++i) { + if (ctx->registers[i].latency <= cycle) + available_regs[regs_count++] = i; + } + /* if there are only 2 available registers for ADD_RS and one of them is r5, select it as the source because it cannot be the destination */ + if (regs_count == 2 && instr->opcode == INSTR_ADD_RS) { + if (available_regs[0] == REGISTER_NEEDS_DISPLACEMENT || available_regs[1] == REGISTER_NEEDS_DISPLACEMENT) { + instr->op_par = instr->src = REGISTER_NEEDS_DISPLACEMENT; + return true; + } + } + if (select_register(available_regs, regs_count, &ctx->gen, &instr->src)) { + if (tpl->op_par_src) + instr->op_par = instr->src; + return true; + } + return false; +} + +static int schedule_uop(execution_port uop, generator_ctx* ctx, int cycle, bool commit) { + /* The scheduling here is done optimistically by checking port availability in order P5 -> P0 -> P1 to not overload + port P1 (multiplication) by instructions that can go to any port. */ + for (; cycle < PORT_MAP_SIZE; ++cycle) { + if ((uop & PORT_P5) && !ctx->ports[cycle][2]) { + if (commit) { + ctx->ports[cycle][2] = uop; + } + TRACE_PRINT("%s scheduled to port P5 at cycle %i (commit = %i)\n", execution_port_names[uop], cycle, commit); + return cycle; + } + if ((uop & PORT_P0) && !ctx->ports[cycle][0]) { + if (commit) { + ctx->ports[cycle][0] = uop; + } + TRACE_PRINT("%s scheduled to port P0 at cycle %i (commit = %i)\n", execution_port_names[uop], cycle, commit); + return cycle; + } + if ((uop & PORT_P1) != 0 && !ctx->ports[cycle][1]) { + if (commit) { + ctx->ports[cycle][1] = uop; + } + TRACE_PRINT("%s scheduled to port P1 at cycle %i (commit = %i)\n", execution_port_names[uop], cycle, commit); + return cycle; + } + } + return -1; +} + +static int schedule_instr(const instr_template* tpl, generator_ctx* ctx, bool commit) { + if (tpl->uop2 == PORT_NONE) { + /* this instruction has only one uOP */ + return schedule_uop(tpl->uop1, ctx, ctx->cycle, commit); + } + else { + /* instructions with 2 uOPs are scheduled conservatively by requiring both uOPs to execute in the same cycle */ + for (int cycle = ctx->cycle; cycle < PORT_MAP_SIZE; ++cycle) { + + int cycle1 = schedule_uop(tpl->uop1, ctx, cycle, false); + int cycle2 = schedule_uop(tpl->uop2, ctx, cycle, false); + + if (cycle1 >= 0 && cycle1 == cycle2) { + if (commit) { + schedule_uop(tpl->uop1, ctx, cycle, true); + schedule_uop(tpl->uop2, ctx, cycle, true); + } + return cycle1; + } + } + } + + return -1; +} + +static void print_registers(const generator_ctx* ctx) { + for (int i = 0; i < 8; ++i) { + printf(" R%i = %i\n", i, ctx->registers[i].latency); + } +} + +bool hashx_program_generate(const siphash_state* key, hashx_program* program) { + generator_ctx ctx = { + .cycle = 0, + .sub_cycle = 0, /* 3 sub-cycles = 1 cycle */ + .mul_count = 0, + .chain_mul = false, + .latency = 0, + .ports = {{ 0 }} + }; + hashx_siphash_rng_init(&ctx.gen, key); +#ifdef HASHX_RNG_CALLBACK + ctx.gen.callback = program->rng_callback; + ctx.gen.callback_user_data = program->rng_callback_user_data; +#endif + for (int i = 0; i < 8; ++i) { + ctx.registers[i].last_op = -1; + ctx.registers[i].latency = 0; + ctx.registers[i].last_op_par = (uint32_t)-1; + } + program->code_size = 0; + + int attempt = 0; + instr_type last_instr = -1; +#ifdef HASHX_PROGRAM_STATS + program->x86_size = 0; +#endif + + while (program->code_size < HASHX_PROGRAM_MAX_SIZE) { + instruction* instr = &program->code[program->code_size]; + TRACE_PRINT("CYCLE: %i/%i\n", ctx.sub_cycle, ctx.cycle); + + /* select an instruction template */ + const instr_template* tpl = select_template(&ctx, last_instr, attempt); + last_instr = tpl->group; + + TRACE_PRINT("Template: %s\n", tpl->x86_asm); + + instr_from_template(tpl, &ctx.gen, instr); + + /* calculate the earliest cycle when this instruction (all of its uOPs) can be scheduled for execution */ + int scheduleCycle = schedule_instr(tpl, &ctx, false); + if (scheduleCycle < 0) { + TRACE_PRINT("Unable to map operation '%s' to execution port (cycle %i)\n", tpl->x86_asm, ctx.cycle); + /* __debugbreak(); */ + break; + } + + ctx.chain_mul = attempt > 0; + + /* find a source register (if applicable) that will be ready when this instruction executes */ + if (tpl->has_src) { + if (!select_source(tpl, instr, &ctx, scheduleCycle)) { + TRACE_PRINT("; src STALL (attempt %i)\n", attempt); + if (attempt++ < MAX_RETRIES) { + continue; + } + if (TRACE) { + printf("; select_source FAILED at cycle %i\n", ctx.cycle); + print_registers(&ctx); + /* __debugbreak(); */ + } + ctx.sub_cycle += 3; + ctx.cycle = ctx.sub_cycle / 3; + attempt = 0; + continue; + } + TRACE_PRINT("; src = r%i\n", instr->src); + } + + /* find a destination register that will be ready when this instruction executes */ + if (tpl->has_dst) { + if (!select_destination(tpl, instr, &ctx, scheduleCycle)) { + TRACE_PRINT("; dst STALL (attempt %i)\n", attempt); + if (attempt++ < MAX_RETRIES) { + continue; + } + if (TRACE) { + printf("; select_destination FAILED at cycle %i\n", ctx.cycle); + print_registers(&ctx); + /* __debugbreak(); */ + } + ctx.sub_cycle += 3; + ctx.cycle = ctx.sub_cycle / 3; + attempt = 0; + continue; + } + TRACE_PRINT("; dst = r%i\n", instr->dst); + } + attempt = 0; + + /* recalculate when the instruction can be scheduled for execution based on operand availability */ + scheduleCycle = schedule_instr(tpl, &ctx, true); + + if (scheduleCycle < 0) { + TRACE_PRINT("Unable to map operation '%s' to execution port (cycle %i)\n", tpl->x86_asm, ctx.cycle); + break; + } + + /* terminating condition */ + if (scheduleCycle >= TARGET_CYCLE) { + break; + } + + if (tpl->has_dst) { + register_info* ri = &ctx.registers[instr->dst]; + int retireCycle = scheduleCycle + tpl->latency; + ri->latency = retireCycle; + ri->last_op = tpl->group; + ri->last_op_par = instr->op_par; + ctx.latency = MAX(retireCycle, ctx.latency); + TRACE_PRINT("; RETIRED at cycle %i\n", retireCycle); + } + + program->code_size++; +#ifdef HASHX_PROGRAM_STATS + program->x86_size += tpl->x86_size; +#endif + + ctx.mul_count += is_mul(instr->opcode); + + ++ctx.sub_cycle; + ctx.sub_cycle += (tpl->uop2 != PORT_NONE); + ctx.cycle = ctx.sub_cycle / 3; + } + +#ifdef HASHX_PROGRAM_STATS + memset(program->asic_latencies, 0, sizeof(program->asic_latencies)); + + program->counter = ctx.gen.counter; + program->wide_mul_count = 0; + program->mul_count = ctx.mul_count; + + /* Calculate ASIC latency: + Assumes 1 cycle latency for all operations and unlimited parallelization. */ + for (size_t i = 0; i < program->code_size; ++i) { + instruction* instr = &program->code[i]; + if (instr->dst < 0) + continue; + int last_dst = program->asic_latencies[instr->dst] + 1; + int lat_src = instr->dst != instr->src ? program->asic_latencies[instr->src] + 1 : 0; + program->asic_latencies[instr->dst] = MAX(last_dst, lat_src); + program->wide_mul_count += is_wide_mul(instr->opcode); + } + + program->asic_latency = 0; + program->cpu_latency = 0; + for (int i = 0; i < 8; ++i) { + program->asic_latency = MAX(program->asic_latency, program->asic_latencies[i]); + program->cpu_latencies[i] = ctx.registers[i].latency; + program->cpu_latency = MAX(program->cpu_latency, program->cpu_latencies[i]); + } + + program->ipc = program->code_size / (double)program->cpu_latency; + program->branch_count = 0; + memset(program->branches, 0, sizeof(program->branches)); + + if (TRACE) { + printf("; ALU port utilization:\n"); + printf("; (* = in use, _ = idle)\n"); + for (int i = 0; i < PORT_MAP_SIZE; ++i) { + printf("; %3i ", i); + for (int j = 0; j < NUM_PORTS; ++j) { + printf("%c", (ctx.ports[i][j] ? '*' : '_')); + } + printf("\n"); + } + } +#endif + + /* reject programs that don't meet the uniform complexity requirements */ + /* this happens in less than 1 seed out of 10000 */ + return + (program->code_size == REQUIREMENT_SIZE) && + (ctx.mul_count == REQUIREMENT_MUL_COUNT) && + (ctx.latency == REQUIREMENT_LATENCY - 1); /* cycles are numbered from 0 */ +} + +static const char* x86_reg_map[] = { "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15" }; + +void hashx_program_asm_x86(const hashx_program* program) { + size_t target = 0; + for (size_t i = 0; i < program->code_size; ++i) { + const instruction* instr = &program->code[i]; + switch (instr->opcode) + { + case INSTR_SUB_R: + printf("sub %s, %s\n", x86_reg_map[instr->dst], x86_reg_map[instr->src]); + break; + case INSTR_XOR_R: + printf("xor %s, %s\n", x86_reg_map[instr->dst], x86_reg_map[instr->src]); + break; + case INSTR_ADD_RS: + printf("lea %s, [%s+%s*%u]\n", x86_reg_map[instr->dst], x86_reg_map[instr->dst], x86_reg_map[instr->src], 1 << instr->imm32); + break; + case INSTR_MUL_R: + printf("imul %s, %s\n", x86_reg_map[instr->dst], x86_reg_map[instr->src]); + break; + case INSTR_ROR_C: + printf("ror %s, %u\n", x86_reg_map[instr->dst], instr->imm32); + break; + case INSTR_ADD_C: + printf("add %s, %i\n", x86_reg_map[instr->dst], instr->imm32); + break; + case INSTR_XOR_C: + printf("xor %s, %i\n", x86_reg_map[instr->dst], instr->imm32); + break; + case INSTR_UMULH_R: + printf("mov rax, %s\n", x86_reg_map[instr->dst]); + printf("mul %s\n", x86_reg_map[instr->src]); + printf("mov %s, rdx\n", x86_reg_map[instr->dst]); + break; + case INSTR_SMULH_R: + printf("mov rax, %s\n", x86_reg_map[instr->dst]); + printf("imul %s\n", x86_reg_map[instr->src]); + printf("mov %s, rdx\n", x86_reg_map[instr->dst]); + break; + case INSTR_TARGET: + printf("test edi, edi\n"); + printf("target_%i: cmovz esi, edi\n", (int)i); + target = i; + break; + case INSTR_BRANCH: + printf("or edx, esi\n"); + printf("test edx, %i\n", instr->imm32); + printf("jz target_%i\n", (int)target); + break; + default: + UNREACHABLE; + } + } +} diff -Nru tor-0.4.7.16/src/ext/equix/hashx/src/program.h tor-0.4.9.6/src/ext/equix/hashx/src/program.h --- tor-0.4.7.16/src/ext/equix/hashx/src/program.h 1970-01-01 00:00:00.000000000 +0000 +++ tor-0.4.9.6/src/ext/equix/hashx/src/program.h 2026-03-25 14:30:34.000000000 +0000 @@ -0,0 +1,52 @@ +/* Copyright (c) 2020 tevador */ +/* See LICENSE for licensing information */ + +#ifndef PROGRAM_H +#define PROGRAM_H + +#include +#include +#include +#include "instruction.h" +#include "siphash.h" +#include "blake2.h" + +#define HASHX_PROGRAM_MAX_SIZE 512 + +typedef struct hashx_program { + instruction code[HASHX_PROGRAM_MAX_SIZE]; + size_t code_size; +#ifdef HASHX_PROGRAM_STATS + unsigned counter; + double ipc; + int x86_size; + int cpu_latency; + int asic_latency; + int mul_count; + int wide_mul_count; + int cpu_latencies[8]; + int asic_latencies[8]; + int branch_count; + int branches[16]; +#endif +#ifdef HASHX_RNG_CALLBACK + void (*rng_callback)(uint64_t *buffer, void *user_data); + void *rng_callback_user_data; +#endif +} hashx_program; + +#ifdef __cplusplus +extern "C" { +#endif + +HASHX_PRIVATE bool hashx_program_generate(const siphash_state* key, hashx_program* program); + +HASHX_PRIVATE void hashx_program_execute(const hashx_program* program, uint64_t r[8]); + +HASHX_PRIVATE void hashx_program_asm_x86(const hashx_program* program); + +#ifdef __cplusplus +} +#endif + +#endif diff -Nru tor-0.4.7.16/src/ext/equix/hashx/src/program_exec.c tor-0.4.9.6/src/ext/equix/hashx/src/program_exec.c --- tor-0.4.7.16/src/ext/equix/hashx/src/program_exec.c 1970-01-01 00:00:00.000000000 +0000 +++ tor-0.4.9.6/src/ext/equix/hashx/src/program_exec.c 2026-03-25 14:30:34.000000000 +0000 @@ -0,0 +1,158 @@ +/* Copyright (c) 2020 tevador */ +/* See LICENSE for licensing information */ + +#include "program.h" +#include "force_inline.h" +#include "unreachable.h" +#include "siphash.h" +#include "hashx_endian.h" + +#if defined(__SIZEOF_INT128__) +typedef unsigned __int128 uint128_t; +typedef __int128 int128_t; +static FORCE_INLINE uint64_t umulh(uint64_t a, uint64_t b) { + return ((uint128_t)a * b) >> 64; + } +static FORCE_INLINE int64_t smulh(int64_t a, int64_t b) { + return ((int128_t)a * b) >> 64; +} +#define HAVE_UMULH +#define HAVE_SMULH +#endif + +#if defined(_MSC_VER) +#pragma warning (disable : 4146) /* unary minus applied to unsigned type */ +#define HAS_VALUE(X) X ## 0 +#define EVAL_DEFINE(X) HAS_VALUE(X) +#include +#include + +static FORCE_INLINE uint64_t rotr64(uint64_t x, unsigned int c) { + return _rotr64(x, c); +} + +#define HAVE_ROTR + +#if EVAL_DEFINE(__MACHINEARM64_X64(1)) +static FORCE_INLINE uint64_t umulh(uint64_t a, uint64_t b) { + return __umulh(a, b); +} +#define HAVE_UMULH +#endif + +#if EVAL_DEFINE(__MACHINEX64(1)) +static FORCE_INLINE int64_t smulh(int64_t a, int64_t b) { + int64_t hi; + _mul128(a, b, &hi); + return hi; +} +#define HAVE_SMULH +#endif + +#endif + +#ifndef HAVE_ROTR +static FORCE_INLINE uint64_t rotr64(uint64_t a, unsigned int b) { + return (a >> b) | (a << (64 - b)); +} +#define HAVE_ROTR +#endif + +#ifndef HAVE_UMULH +#define LO(x) ((x)&0xffffffff) +#define HI(x) ((x)>>32) +static uint64_t umulh(uint64_t a, uint64_t b) { + uint64_t ah = HI(a), al = LO(a); + uint64_t bh = HI(b), bl = LO(b); + uint64_t x00 = al * bl; + uint64_t x01 = al * bh; + uint64_t x10 = ah * bl; + uint64_t x11 = ah * bh; + uint64_t m1 = LO(x10) + LO(x01) + HI(x00); + uint64_t m2 = HI(x10) + HI(x01) + LO(x11) + HI(m1); + uint64_t m3 = HI(x11) + HI(m2); + + return (m3 << 32) + LO(m2); +} +#undef LO +#undef HI +#define HAVE_UMULH +#endif + +#ifndef HAVE_SMULH +static int64_t smulh(int64_t a, int64_t b) { + int64_t hi = umulh(a, b); + if (a < 0LL) hi -= b; + if (b < 0LL) hi -= a; + return hi; +} +#define HAVE_SMULH +#endif + +static FORCE_INLINE uint64_t sign_extend_2s_compl(uint32_t x) { + return (-1 == ~0) ? + (uint64_t)(int64_t)(int32_t)(x) : + (x > INT32_MAX ? (x | 0xffffffff00000000ULL) : (uint64_t)x); +} + +void hashx_program_execute(const hashx_program* program, uint64_t r[8]) { + size_t target = 0; + bool branch_enable = true; + uint32_t result = 0; +#ifdef HASHX_PROGRAM_STATS + int branch_idx = 0; +#endif + for (size_t i = 0; i < program->code_size; ++i) { + const instruction* instr = &program->code[i]; + switch (instr->opcode) + { + case INSTR_UMULH_R: + result = (uint32_t) (r[instr->dst] = umulh(r[instr->dst], + r[instr->src])); + break; + case INSTR_SMULH_R: + result = (uint32_t) (r[instr->dst] = smulh(r[instr->dst], + r[instr->src])); + break; + case INSTR_MUL_R: + r[instr->dst] *= r[instr->src]; + break; + case INSTR_SUB_R: + r[instr->dst] -= r[instr->src]; + break; + case INSTR_XOR_R: + r[instr->dst] ^= r[instr->src]; + break; + case INSTR_ADD_RS: + r[instr->dst] += r[instr->src] << instr->imm32; + break; + case INSTR_ROR_C: + r[instr->dst] = rotr64(r[instr->dst], instr->imm32); + break; + case INSTR_ADD_C: + r[instr->dst] += sign_extend_2s_compl(instr->imm32); + break; + case INSTR_XOR_C: + r[instr->dst] ^= sign_extend_2s_compl(instr->imm32); + break; + case INSTR_TARGET: + target = i; + break; + case INSTR_BRANCH: + if (branch_enable && (result & instr->imm32) == 0) { + i = target; + branch_enable = false; +#ifdef HASHX_PROGRAM_STATS + ((hashx_program*)program)->branch_count++; + ((hashx_program*)program)->branches[branch_idx]++; +#endif + } +#ifdef HASHX_PROGRAM_STATS + branch_idx++; +#endif + break; + default: + UNREACHABLE; + } + } +} diff -Nru tor-0.4.7.16/src/ext/equix/hashx/src/siphash.c tor-0.4.9.6/src/ext/equix/hashx/src/siphash.c --- tor-0.4.7.16/src/ext/equix/hashx/src/siphash.c 1970-01-01 00:00:00.000000000 +0000 +++ tor-0.4.9.6/src/ext/equix/hashx/src/siphash.c 2026-03-25 14:30:34.000000000 +0000 @@ -0,0 +1,66 @@ +/* Copyright (c) 2020 tevador */ +/* See LICENSE for licensing information */ + +#include "siphash.h" +#include "hashx_endian.h" +#include "unreachable.h" + +uint64_t hashx_siphash13_ctr(uint64_t input, const siphash_state* keys) { + uint64_t v0 = keys->v0; + uint64_t v1 = keys->v1; + uint64_t v2 = keys->v2; + uint64_t v3 = keys->v3; + + v3 ^= input; + + SIPROUND(v0, v1, v2, v3); + + v0 ^= input; + v2 ^= 0xff; + + SIPROUND(v0, v1, v2, v3); + SIPROUND(v0, v1, v2, v3); + SIPROUND(v0, v1, v2, v3); + + return (v0 ^ v1) ^ (v2 ^ v3); +} + +void hashx_siphash24_ctr_state512(const siphash_state* keys, uint64_t input, + uint64_t state_out[8]) { + + uint64_t v0 = keys->v0; + uint64_t v1 = keys->v1; + uint64_t v2 = keys->v2; + uint64_t v3 = keys->v3; + + v1 ^= 0xee; + v3 ^= input; + + SIPROUND(v0, v1, v2, v3); + SIPROUND(v0, v1, v2, v3); + + v0 ^= input; + v2 ^= 0xee; + + SIPROUND(v0, v1, v2, v3); + SIPROUND(v0, v1, v2, v3); + SIPROUND(v0, v1, v2, v3); + SIPROUND(v0, v1, v2, v3); + + state_out[0] = v0; + state_out[1] = v1; + state_out[2] = v2; + state_out[3] = v3; + + v1 ^= 0xdd; + + SIPROUND(v0, v1, v2, v3); + SIPROUND(v0, v1, v2, v3); + SIPROUND(v0, v1, v2, v3); + SIPROUND(v0, v1, v2, v3); + + state_out[4] = v0; + state_out[5] = v1; + state_out[6] = v2; + state_out[7] = v3; +} diff -Nru tor-0.4.7.16/src/ext/equix/hashx/src/siphash.h tor-0.4.9.6/src/ext/equix/hashx/src/siphash.h --- tor-0.4.7.16/src/ext/equix/hashx/src/siphash.h 1970-01-01 00:00:00.000000000 +0000 +++ tor-0.4.9.6/src/ext/equix/hashx/src/siphash.h 2026-03-25 14:30:34.000000000 +0000 @@ -0,0 +1,35 @@ +/* Copyright (c) 2020 tevador */ +/* See LICENSE for licensing information */ + +#ifndef SIPHASH_H +#define SIPHASH_H + +#include +#include + +#define ROTL(x, b) (((x) << (b)) | ((x) >> (64 - (b)))) +#define SIPROUND(v0, v1, v2, v3) \ + do { \ + v0 += v1; v2 += v3; v1 = ROTL(v1, 13); \ + v3 = ROTL(v3, 16); v1 ^= v0; v3 ^= v2; \ + v0 = ROTL(v0, 32); v2 += v1; v0 += v3; \ + v1 = ROTL(v1, 17); v3 = ROTL(v3, 21); \ + v1 ^= v2; v3 ^= v0; v2 = ROTL(v2, 32); \ + } while (0) + +typedef struct siphash_state { + uint64_t v0, v1, v2, v3; +} siphash_state; + +#ifdef __cplusplus +extern "C" { +#endif + +HASHX_PRIVATE uint64_t hashx_siphash13_ctr(uint64_t input, const siphash_state* keys); +HASHX_PRIVATE void hashx_siphash24_ctr_state512(const siphash_state* keys, uint64_t input, uint64_t state_out[8]); + +#ifdef __cplusplus +} +#endif + +#endif diff -Nru tor-0.4.7.16/src/ext/equix/hashx/src/siphash_rng.c tor-0.4.9.6/src/ext/equix/hashx/src/siphash_rng.c --- tor-0.4.7.16/src/ext/equix/hashx/src/siphash_rng.c 1970-01-01 00:00:00.000000000 +0000 +++ tor-0.4.9.6/src/ext/equix/hashx/src/siphash_rng.c 2026-03-25 14:30:34.000000000 +0000 @@ -0,0 +1,41 @@ +/* Copyright (c) 2020 tevador */ +/* See LICENSE for licensing information */ + +#include "siphash_rng.h" + +void hashx_siphash_rng_init(siphash_rng* gen, const siphash_state* state) { + gen->keys = *state; + gen->counter = 0; + gen->count8 = 0; + gen->count32 = 0; +} + +uint8_t hashx_siphash_rng_u8(siphash_rng* gen) { + if (gen->count8 == 0) { + gen->buffer8 = hashx_siphash13_ctr(gen->counter, &gen->keys); + gen->counter++; + gen->count8 = sizeof(gen->buffer8); +#ifdef HASHX_RNG_CALLBACK + if (gen->callback) { + gen->callback(&gen->buffer8, gen->callback_user_data); + } +#endif + } + gen->count8--; + return gen->buffer8 >> (gen->count8 * 8); +} + +uint32_t hashx_siphash_rng_u32(siphash_rng* gen) { + if (gen->count32 == 0) { + gen->buffer32 = hashx_siphash13_ctr(gen->counter, &gen->keys); + gen->counter++; + gen->count32 = sizeof(gen->buffer32) / sizeof(uint32_t); +#ifdef HASHX_RNG_CALLBACK + if (gen->callback) { + gen->callback(&gen->buffer32, gen->callback_user_data); + } +#endif + } + gen->count32--; + return (uint32_t)(gen->buffer32 >> (gen->count32 * 32)); +} diff -Nru tor-0.4.7.16/src/ext/equix/hashx/src/siphash_rng.h tor-0.4.9.6/src/ext/equix/hashx/src/siphash_rng.h --- tor-0.4.7.16/src/ext/equix/hashx/src/siphash_rng.h 1970-01-01 00:00:00.000000000 +0000 +++ tor-0.4.9.6/src/ext/equix/hashx/src/siphash_rng.h 2026-03-25 14:30:34.000000000 +0000 @@ -0,0 +1,34 @@ +/* Copyright (c) 2020 tevador */ +/* See LICENSE for licensing information */ + +#ifndef SIPHASH_GENERATOR_H +#define SIPHASH_GENERATOR_H + +#include +#include +#include "siphash.h" + +typedef struct siphash_rng { + siphash_state keys; + uint64_t counter; + uint64_t buffer8, buffer32; + unsigned count8, count32; +#ifdef HASHX_RNG_CALLBACK + void (*callback)(uint64_t *buffer, void *user_data); + void *callback_user_data; +#endif +} siphash_rng; + +#ifdef __cplusplus +extern "C" { +#endif + +HASHX_PRIVATE void hashx_siphash_rng_init(siphash_rng* gen, const siphash_state* state); +HASHX_PRIVATE uint32_t hashx_siphash_rng_u32(siphash_rng* gen); +HASHX_PRIVATE uint8_t hashx_siphash_rng_u8(siphash_rng* gen); + +#ifdef __cplusplus +} +#endif + +#endif diff -Nru tor-0.4.7.16/src/ext/equix/hashx/src/unreachable.h tor-0.4.9.6/src/ext/equix/hashx/src/unreachable.h --- tor-0.4.7.16/src/ext/equix/hashx/src/unreachable.h 1970-01-01 00:00:00.000000000 +0000 +++ tor-0.4.9.6/src/ext/equix/hashx/src/unreachable.h 2026-03-25 14:30:34.000000000 +0000 @@ -0,0 +1,9 @@ +#ifndef UNREACHABLE +#ifdef __GNUC__ +#define UNREACHABLE __builtin_unreachable() +#elif _MSC_VER +#define UNREACHABLE __assume(0) +#else +#define UNREACHABLE +#endif +#endif diff -Nru tor-0.4.7.16/src/ext/equix/hashx/src/virtual_memory.c tor-0.4.9.6/src/ext/equix/hashx/src/virtual_memory.c --- tor-0.4.7.16/src/ext/equix/hashx/src/virtual_memory.c 1970-01-01 00:00:00.000000000 +0000 +++ tor-0.4.9.6/src/ext/equix/hashx/src/virtual_memory.c 2026-03-25 14:30:34.000000000 +0000 @@ -0,0 +1,141 @@ +/* Copyright (c) 2020 tevador */ +/* See LICENSE for licensing information */ + +#include "virtual_memory.h" + +#ifdef HASHX_WIN +#include +#else +#ifdef __APPLE__ +#include +#endif +#include +#include +#ifndef MAP_ANONYMOUS +#define MAP_ANONYMOUS MAP_ANON +#endif +#define PAGE_READONLY PROT_READ +#define PAGE_READWRITE (PROT_READ | PROT_WRITE) +#define PAGE_EXECUTE_READ (PROT_READ | PROT_EXEC) +#define PAGE_EXECUTE_READWRITE (PROT_READ | PROT_WRITE | PROT_EXEC) +#if defined(__NetBSD__) && defined(PROT_MPROTECT) +#define PAGE_MMAP_PROT (PAGE_READWRITE | PROT_MPROTECT(PROT_EXEC)) +#else +#define PAGE_MMAP_PROT PAGE_READWRITE +#endif +#endif + +void* hashx_vm_alloc(size_t bytes) { + void* mem; +#ifdef HASHX_WIN + mem = VirtualAlloc(NULL, bytes, MEM_COMMIT, PAGE_READWRITE); +#else + mem = mmap(NULL, bytes, PAGE_MMAP_PROT, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); + if (mem == MAP_FAILED) + return NULL; +#endif + return mem; +} + +static inline bool page_protect(void* ptr, size_t bytes, int rules) { +#ifdef HASHX_WIN + DWORD oldp; + if (!VirtualProtect(ptr, bytes, (DWORD)rules, &oldp)) { + return false; + } +#else + if (mprotect(ptr, bytes, rules) != 0) + return false; +#endif + return true; +} + +bool hashx_vm_rw(void* ptr, size_t bytes) { + return page_protect(ptr, bytes, PAGE_READWRITE); +} + +bool hashx_vm_rx(void* ptr, size_t bytes) { + return page_protect(ptr, bytes, PAGE_EXECUTE_READ); +} + +#ifdef EQUIX_SUPPORT_HUGEPAGES + +#ifdef HASHX_WIN + +static bool set_privilege(const char* pszPrivilege, BOOL bEnable) { + HANDLE hToken; + TOKEN_PRIVILEGES tp; + BOOL status; + DWORD error; + + if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES + | TOKEN_QUERY, &hToken)) + return false; + + if (!LookupPrivilegeValue(NULL, pszPrivilege, &tp.Privileges[0].Luid)) + return false; + + tp.PrivilegeCount = 1; + + if (bEnable) + tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; + else + tp.Privileges[0].Attributes = 0; + + status = AdjustTokenPrivileges(hToken, FALSE, &tp, 0, + (PTOKEN_PRIVILEGES)NULL, 0); + error = GetLastError(); + + CloseHandle(hToken); + + return status && (error == ERROR_SUCCESS); +} +#endif /* HASHX_WIN */ + +void* hashx_vm_alloc_huge(size_t bytes) { + void* mem; +#ifdef HASHX_WIN + if (!set_privilege("SeLockMemoryPrivilege", 1)) { + /* Failed, but try the VirtualAlloc anyway */ + } + SIZE_T page_min = GetLargePageMinimum(); + if (page_min > 0) { + mem = VirtualAlloc(NULL, ALIGN_SIZE(bytes, page_min), MEM_COMMIT + | MEM_RESERVE | MEM_LARGE_PAGES, PAGE_READWRITE); + } + else { + mem = NULL; + } +#else +#ifdef __APPLE__ + mem = mmap(NULL, bytes, PAGE_READWRITE, MAP_PRIVATE | MAP_ANONYMOUS, + VM_FLAGS_SUPERPAGE_SIZE_2MB, 0); +#elif defined(__FreeBSD__) + mem = mmap(NULL, bytes, PAGE_READWRITE, MAP_PRIVATE | MAP_ANONYMOUS + | MAP_ALIGNED_SUPER, -1, 0); +#elif defined(__OpenBSD__) || defined(__NetBSD__) + (void)bytes; + mem = MAP_FAILED; // OpenBSD and NetBSD do not support huge pages +#else + mem = mmap(NULL, bytes, PAGE_READWRITE, MAP_PRIVATE | MAP_ANONYMOUS + | MAP_HUGETLB | MAP_POPULATE, -1, 0); +#endif + if (mem == MAP_FAILED) { + mem = NULL; + } +#endif + return mem; +} +#endif /* EQUIX_SUPPORT_HUGEPAGES */ + +void hashx_vm_free(void* ptr, size_t bytes) { + if (!ptr) { + return; + } +#ifdef HASHX_WIN + (void)bytes; + VirtualFree(ptr, 0, MEM_RELEASE); +#else + munmap(ptr, bytes); +#endif +} diff -Nru tor-0.4.7.16/src/ext/equix/hashx/src/virtual_memory.h tor-0.4.9.6/src/ext/equix/hashx/src/virtual_memory.h --- tor-0.4.7.16/src/ext/equix/hashx/src/virtual_memory.h 1970-01-01 00:00:00.000000000 +0000 +++ tor-0.4.9.6/src/ext/equix/hashx/src/virtual_memory.h 2026-03-25 14:30:34.000000000 +0000 @@ -0,0 +1,23 @@ +/* Copyright (c) 2020 tevador */ +/* See LICENSE for licensing information */ + +#ifndef VIRTUAL_MEMORY_H +#define VIRTUAL_MEMORY_H + +#include +#include +#include +#include + +#define ALIGN_SIZE(pos, align) ((((pos) - 1) / (align) + 1) * (align)) + +HASHX_PRIVATE void* hashx_vm_alloc(size_t size); +HASHX_PRIVATE bool hashx_vm_rw(void* ptr, size_t size); +HASHX_PRIVATE bool hashx_vm_rx(void* ptr, size_t size); +HASHX_PRIVATE void hashx_vm_free(void* ptr, size_t size); + +#ifdef EQUIX_SUPPORT_HUGEPAGES +HASHX_PRIVATE void* hashx_vm_alloc_huge(size_t size); +#endif + +#endif diff -Nru tor-0.4.7.16/src/ext/equix/include/equix.h tor-0.4.9.6/src/ext/equix/include/equix.h --- tor-0.4.7.16/src/ext/equix/include/equix.h 1970-01-01 00:00:00.000000000 +0000 +++ tor-0.4.9.6/src/ext/equix/include/equix.h 2026-03-25 14:30:34.000000000 +0000 @@ -0,0 +1,166 @@ +/* Copyright (c) 2020 tevador */ +/* See LICENSE for licensing information */ + +#ifndef EQUIX_H +#define EQUIX_H + +#include +#include + +/* + * The solver will return at most this many solutions. + */ +#define EQUIX_MAX_SOLS 8 + +/* + * The number of indices. + */ +#define EQUIX_NUM_IDX 8 + +/* + * 16-bit index. + */ +typedef uint16_t equix_idx; + +/* + * The solution. + */ +typedef struct equix_solution { + equix_idx idx[EQUIX_NUM_IDX]; +} equix_solution; + +/* + * Extra informational flags returned by the solver + */ +typedef enum equix_solution_flags { + EQUIX_SOLVER_DID_USE_COMPILER = (1 << 0), +} equix_solution_flags; + +/* + * Fixed size buffer containing up to EQUIX_MAX_SOLS solutions. + */ +typedef struct equix_solutions_buffer { + unsigned count; + equix_solution_flags flags; + equix_solution sols[EQUIX_MAX_SOLS]; +} equix_solutions_buffer; + +/* + * Result type for solve and verify operations + */ +typedef enum equix_result { + EQUIX_OK, /* Solution is valid */ + EQUIX_FAIL_CHALLENGE, /* The challenge is invalid (the internal hash + function doesn't pass validation). */ + EQUIX_FAIL_ORDER, /* Indices are not in the correct order. */ + EQUIX_FAIL_PARTIAL_SUM, /* The partial sums of the hash values don't + have the required number of trailing zeroes. */ + EQUIX_FAIL_FINAL_SUM, /* The hash values don't sum to zero. */ + EQUIX_FAIL_COMPILE, /* Can't compile, and no fallback is enabled */ + EQUIX_FAIL_NO_SOLVER, /* Solve requested on a context with no solver */ + EQUIX_FAIL_INTERNAL, /* Internal error (bug) */ +} equix_result; + +/* + * Opaque struct that holds the Equi-X context + */ +typedef struct equix_ctx equix_ctx; + +/* + * Flags for context creation + */ +typedef enum equix_ctx_flags { + EQUIX_CTX_VERIFY = 0, /* Context for verification */ + EQUIX_CTX_SOLVE = 1, /* Context for solving */ + EQUIX_CTX_MUST_COMPILE = 2, /* Must compile internal hash function */ + EQUIX_CTX_TRY_COMPILE = 4, /* Compile if possible */ + EQUIX_CTX_HUGEPAGES = 8, /* Allocate solver memory using HugePages */ +} equix_ctx_flags; + +#if defined(_WIN32) || defined(__CYGWIN__) +#define EQUIX_WIN +#endif + +/* Shared/static library definitions */ +#ifdef EQUIX_WIN + #ifdef EQUIX_SHARED + #define EQUIX_API __declspec(dllexport) + #elif !defined(EQUIX_STATIC) + #define EQUIX_API __declspec(dllimport) + #else + #define EQUIX_API + #endif + #define EQUIX_PRIVATE +#else + #ifdef EQUIX_SHARED + #define EQUIX_API __attribute__ ((visibility ("default"))) + #else + #define EQUIX_API __attribute__ ((visibility ("hidden"))) + #endif + #define EQUIX_PRIVATE __attribute__ ((visibility ("hidden"))) +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Allocate an Equi-X context. + * + * @param flags is the type of context to be created + * + * @return pointer to a newly created context. Returns NULL on memory + * allocation failure. + */ +EQUIX_API equix_ctx* equix_alloc(equix_ctx_flags flags); + +/* +* Free an Equi-X a context. +* +* @param ctx is a pointer to the context +*/ +EQUIX_API void equix_free(equix_ctx* ctx); + +/* + * Find Equi-X solutions for the given challenge. + * + * @param ctx pointer to an Equi-X context + * @param challenge pointer to the challenge data + * @param challenge_size size of the challenge + * @param output pointer to the output array where solutions will be + * stored + * + * @return On success, returns EQUIX_OK and sets output->count to the number + * of solutions found, with the solutions themselves written to the + * output buffer. If the challenge is unusable, returns + * EQUIX_FAIL_CHALLENGE. If the EQUIX_CTX_MUST_COMPILE flag is in use + * and the compiler fails, this can return EQUIX_FAIL_COMPILE. + */ +EQUIX_API equix_result equix_solve( + equix_ctx* ctx, + const void* challenge, + size_t challenge_size, + equix_solutions_buffer *output); + +/* + * Verify an Equi-X solution. + * + * @param ctx pointer to an Equi-X context + * @param challenge pointer to the challenge data + * @param challenge_size size of the challenge + * @param solution pointer to the solution to be verified + * + * @return Verification result. This can return EQUIX_OK or any of the + * EQUIX_FAIL_* error codes. + */ +EQUIX_API equix_result equix_verify( + equix_ctx* ctx, + const void* challenge, + size_t challenge_size, + const equix_solution* solution); + +#ifdef __cplusplus +} +#endif + +#endif diff -Nru tor-0.4.7.16/src/ext/equix/src/context.c tor-0.4.9.6/src/ext/equix/src/context.c --- tor-0.4.7.16/src/ext/equix/src/context.c 1970-01-01 00:00:00.000000000 +0000 +++ tor-0.4.9.6/src/ext/equix/src/context.c 2026-03-25 14:30:34.000000000 +0000 @@ -0,0 +1,66 @@ +/* Copyright (c) 2020 tevador */ +/* See LICENSE for licensing information */ + +#include +#include +#include +#include "context.h" +#include "solver_heap.h" + +equix_ctx* equix_alloc(equix_ctx_flags flags) { + equix_ctx* ctx = malloc(sizeof(equix_ctx)); + if (ctx == NULL) { + goto failure; + } + ctx->flags = (equix_ctx_flags)0; + + if (flags & EQUIX_CTX_MUST_COMPILE) { + ctx->hash_func = hashx_alloc(HASHX_TYPE_COMPILED); + } else if (flags & EQUIX_CTX_TRY_COMPILE) { + ctx->hash_func = hashx_alloc(HASHX_TRY_COMPILE); + } else { + ctx->hash_func = hashx_alloc(HASHX_TYPE_INTERPRETED); + } + if (ctx->hash_func == NULL) { + goto failure; + } + + if (flags & EQUIX_CTX_SOLVE) { + if (flags & EQUIX_CTX_HUGEPAGES) { +#ifdef EQUIX_SUPPORT_HUGEPAGES + ctx->heap = hashx_vm_alloc_huge(sizeof(solver_heap)); +#else + ctx->heap = NULL; +#endif + } + else { + ctx->heap = malloc(sizeof(solver_heap)); + } + if (ctx->heap == NULL) { + goto failure; + } + } else { + ctx->heap = NULL; + } + + ctx->flags = flags; + return ctx; +failure: + equix_free(ctx); + return NULL; +} + +void equix_free(equix_ctx* ctx) { + if (ctx != NULL) { + if (ctx->flags & EQUIX_CTX_SOLVE) { + if (ctx->flags & EQUIX_CTX_HUGEPAGES) { + hashx_vm_free(ctx->heap, sizeof(solver_heap)); + } + else { + free(ctx->heap); + } + } + hashx_free(ctx->hash_func); + free(ctx); + } +} diff -Nru tor-0.4.7.16/src/ext/equix/src/context.h tor-0.4.9.6/src/ext/equix/src/context.h --- tor-0.4.7.16/src/ext/equix/src/context.h 1970-01-01 00:00:00.000000000 +0000 +++ tor-0.4.9.6/src/ext/equix/src/context.h 2026-03-25 14:30:34.000000000 +0000 @@ -0,0 +1,18 @@ +/* Copyright (c) 2020 tevador */ +/* See LICENSE for licensing information */ + +#ifndef CONTEXT_H +#define CONTEXT_H + +#include +#include + +typedef struct solver_heap solver_heap; + +typedef struct equix_ctx { + hashx_ctx* hash_func; + solver_heap* heap; + equix_ctx_flags flags; +} equix_ctx; + +#endif diff -Nru tor-0.4.7.16/src/ext/equix/src/equix.c tor-0.4.9.6/src/ext/equix/src/equix.c --- tor-0.4.7.16/src/ext/equix/src/equix.c 1970-01-01 00:00:00.000000000 +0000 +++ tor-0.4.9.6/src/ext/equix/src/equix.c 2026-03-25 14:30:34.000000000 +0000 @@ -0,0 +1,131 @@ +/* Copyright (c) 2020 tevador */ +/* See LICENSE for licensing information */ + +#include +#include +#include +#include + +#include +#include +#include "context.h" +#include "solver.h" +#include + +static bool verify_order(const equix_solution* solution) { + return + tree_cmp4(&solution->idx[0], &solution->idx[4]) && + tree_cmp2(&solution->idx[0], &solution->idx[2]) && + tree_cmp2(&solution->idx[4], &solution->idx[6]) && + tree_cmp1(&solution->idx[0], &solution->idx[1]) && + tree_cmp1(&solution->idx[2], &solution->idx[3]) && + tree_cmp1(&solution->idx[4], &solution->idx[5]) && + tree_cmp1(&solution->idx[6], &solution->idx[7]); +} + +static uint64_t sum_pair(hashx_ctx* hash_func, equix_idx left, equix_idx right) { + uint8_t hash_left[HASHX_SIZE]; + uint8_t hash_right[HASHX_SIZE]; + hashx_result r_left = hashx_exec(hash_func, left, hash_left); + hashx_result r_right = hashx_exec(hash_func, right, hash_right); + if (r_left == HASHX_OK && r_right == HASHX_OK) { + return load64(hash_left) + load64(hash_right); + } + assert(false); + return ~(uint64_t)0; +} + +static equix_result verify_internal(hashx_ctx* hash_func, const equix_solution* solution) { + uint64_t pair0 = sum_pair(hash_func, solution->idx[0], solution->idx[1]); + if (pair0 & EQUIX_STAGE1_MASK) { + return EQUIX_FAIL_PARTIAL_SUM; + } + uint64_t pair1 = sum_pair(hash_func, solution->idx[2], solution->idx[3]); + if (pair1 & EQUIX_STAGE1_MASK) { + return EQUIX_FAIL_PARTIAL_SUM; + } + uint64_t pair4 = pair0 + pair1; + if (pair4 & EQUIX_STAGE2_MASK) { + return EQUIX_FAIL_PARTIAL_SUM; + } + uint64_t pair2 = sum_pair(hash_func, solution->idx[4], solution->idx[5]); + if (pair2 & EQUIX_STAGE1_MASK) { + return EQUIX_FAIL_PARTIAL_SUM; + } + uint64_t pair3 = sum_pair(hash_func, solution->idx[6], solution->idx[7]); + if (pair3 & EQUIX_STAGE1_MASK) { + return EQUIX_FAIL_PARTIAL_SUM; + } + uint64_t pair5 = pair2 + pair3; + if (pair5 & EQUIX_STAGE2_MASK) { + return EQUIX_FAIL_PARTIAL_SUM; + } + uint64_t pair6 = pair4 + pair5; + if (pair6 & EQUIX_FULL_MASK) { + return EQUIX_FAIL_FINAL_SUM; + } + return EQUIX_OK; +} + +static equix_result equix_hashx_make( + equix_ctx* ctx, + const void* challenge, + size_t challenge_size) +{ + switch (hashx_make(ctx->hash_func, challenge, challenge_size)) { + case HASHX_OK: + return EQUIX_OK; + case HASHX_FAIL_SEED: + return EQUIX_FAIL_CHALLENGE; + case HASHX_FAIL_COMPILE: + return EQUIX_FAIL_COMPILE; + case HASHX_FAIL_UNDEFINED: + case HASHX_FAIL_UNPREPARED: + default: + return EQUIX_FAIL_INTERNAL; + } +} + +equix_result equix_solve( + equix_ctx* ctx, + const void* challenge, + size_t challenge_size, + equix_solutions_buffer *output) +{ + if ((ctx->flags & EQUIX_CTX_SOLVE) == 0) { + return EQUIX_FAIL_NO_SOLVER; + } + + equix_result result = equix_hashx_make(ctx, challenge, challenge_size); + if (result != EQUIX_OK) { + return result; + } + + output->flags = 0; + hashx_type func_type; + if (hashx_query_type(ctx->hash_func, &func_type) == HASHX_OK && + func_type == HASHX_TYPE_COMPILED) { + output->flags |= EQUIX_SOLVER_DID_USE_COMPILER; + } + + output->count = equix_solver_solve(ctx->hash_func, ctx->heap, output->sols); + return EQUIX_OK; +} + +equix_result equix_verify( + equix_ctx* ctx, + const void* challenge, + size_t challenge_size, + const equix_solution* solution) +{ + if (!verify_order(solution)) { + return EQUIX_FAIL_ORDER; + } + + equix_result result = equix_hashx_make(ctx, challenge, challenge_size); + if (result != EQUIX_OK) { + return result; + } + + return verify_internal(ctx->hash_func, solution); +} diff -Nru tor-0.4.7.16/src/ext/equix/src/solver.c tor-0.4.9.6/src/ext/equix/src/solver.c --- tor-0.4.7.16/src/ext/equix/src/solver.c 1970-01-01 00:00:00.000000000 +0000 +++ tor-0.4.9.6/src/ext/equix/src/solver.c 2026-03-25 14:30:34.000000000 +0000 @@ -0,0 +1,283 @@ +/* Copyright (c) 2020 tevador */ +/* See LICENSE for licensing information */ + +#include "solver.h" +#include "context.h" +#include "solver_heap.h" +#include +#include +#include +#include +#include + +#ifdef _MSC_VER +#pragma warning (disable : 4146) /* unary minus applied to unsigned type */ +#endif + +#define CLEAR(x) memset(&x, 0, sizeof(x)) +#define MAKE_ITEM(bucket, left, right) ((left) << 17 | (right) << 8 | (bucket)) +#define ITEM_BUCKET(item) (item) % NUM_COARSE_BUCKETS +#define ITEM_LEFT_IDX(item) (item) >> 17 +#define ITEM_RIGHT_IDX(item) ((item) >> 8) & 511 +#define INVERT_BUCKET(idx) -(idx) % NUM_COARSE_BUCKETS +#define INVERT_SCRATCH(idx) -(idx) % NUM_FINE_BUCKETS +#define STAGE1_IDX(buck, pos) heap->stage1_indices.buckets[buck].items[pos] +#define STAGE2_IDX(buck, pos) heap->stage2_indices.buckets[buck].items[pos] +#define STAGE3_IDX(buck, pos) heap->stage3_indices.buckets[buck].items[pos] +#define STAGE1_DATA(buck, pos) heap->stage1_data.buckets[buck].items[pos] +#define STAGE2_DATA(buck, pos) heap->stage2_data.buckets[buck].items[pos] +#define STAGE3_DATA(buck, pos) heap->stage3_data.buckets[buck].items[pos] +#define STAGE1_SIZE(buck) heap->stage1_indices.counts[buck] +#define STAGE2_SIZE(buck) heap->stage2_indices.counts[buck] +#define STAGE3_SIZE(buck) heap->stage3_indices.counts[buck] +#define SCRATCH(buck, pos) heap->scratch_ht.buckets[buck].items[pos] +#define SCRATCH_SIZE(buck) heap->scratch_ht.counts[buck] +#define SWAP_IDX(a, b) \ + do { \ + equix_idx temp = a; \ + a = b; \ + b = temp; \ + } while(0) +#define CARRY (bucket_idx != 0) +#define BUCK_START 0 +#define BUCK_END (NUM_COARSE_BUCKETS / 2 + 1) + +typedef uint32_t u32; +typedef stage1_idx_item s1_idx; +typedef stage2_idx_item s2_idx; +typedef stage3_idx_item s3_idx; + +static FORCE_INLINE bool hash_value(hashx_ctx* hash_func, equix_idx index, uint64_t *value_out) { + char hash[HASHX_SIZE]; + hashx_result result = hashx_exec(hash_func, index, hash); + if (result == HASHX_OK) { + *value_out = load64(hash); + return true; + } else { + assert(false); + return false; + } +} + +static void build_solution_stage1(equix_idx* output, solver_heap* heap, s2_idx root) { + u32 bucket = ITEM_BUCKET(root); + u32 bucket_inv = INVERT_BUCKET(bucket); + u32 left_parent_idx = ITEM_LEFT_IDX(root); + u32 right_parent_idx = ITEM_RIGHT_IDX(root); + s1_idx left_parent = STAGE1_IDX(bucket, left_parent_idx); + s1_idx right_parent = STAGE1_IDX(bucket_inv, right_parent_idx); + output[0] = left_parent; + output[1] = right_parent; + if (!tree_cmp1(&output[0], &output[1])) { + SWAP_IDX(output[0], output[1]); + } +} + +static void build_solution_stage2(equix_idx* output, solver_heap* heap, s3_idx root) { + u32 bucket = ITEM_BUCKET(root); + u32 bucket_inv = INVERT_BUCKET(bucket); + u32 left_parent_idx = ITEM_LEFT_IDX(root); + u32 right_parent_idx = ITEM_RIGHT_IDX(root); + s2_idx left_parent = STAGE2_IDX(bucket, left_parent_idx); + s2_idx right_parent = STAGE2_IDX(bucket_inv, right_parent_idx); + build_solution_stage1(&output[0], heap, left_parent); + build_solution_stage1(&output[2], heap, right_parent); + if (!tree_cmp2(&output[0], &output[2])) { + SWAP_IDX(output[0], output[2]); + SWAP_IDX(output[1], output[3]); + } +} + +static void build_solution(equix_solution* solution, solver_heap* heap, s3_idx left, s3_idx right) { + build_solution_stage2(&solution->idx[0], heap, left); + build_solution_stage2(&solution->idx[4], heap, right); + if (!tree_cmp4(&solution->idx[0], &solution->idx[4])) { + SWAP_IDX(solution->idx[0], solution->idx[4]); + SWAP_IDX(solution->idx[1], solution->idx[5]); + SWAP_IDX(solution->idx[2], solution->idx[6]); + SWAP_IDX(solution->idx[3], solution->idx[7]); + } +} + +static void solve_stage0(hashx_ctx* hash_func, solver_heap* heap) { + CLEAR(heap->stage1_indices.counts); + for (u32 i = 0; i < INDEX_SPACE; ++i) { + uint64_t value; + if (!hash_value(hash_func, i, &value)) + break; + u32 bucket_idx = value % NUM_COARSE_BUCKETS; + u32 item_idx = STAGE1_SIZE(bucket_idx); + if (item_idx >= COARSE_BUCKET_ITEMS) + continue; + STAGE1_SIZE(bucket_idx) = item_idx + 1; + STAGE1_IDX(bucket_idx, item_idx) = i; + STAGE1_DATA(bucket_idx, item_idx) = value / NUM_COARSE_BUCKETS; /* 52 bits */ + } +} + +#define MAKE_PAIRS1 \ + stage1_data_item value = STAGE1_DATA(bucket_idx, item_idx) + CARRY; \ + u32 fine_buck_idx = value % NUM_FINE_BUCKETS; \ + u32 fine_cpl_bucket = INVERT_SCRATCH(fine_buck_idx); \ + u32 fine_cpl_size = SCRATCH_SIZE(fine_cpl_bucket); \ + for (u32 fine_idx = 0; fine_idx < fine_cpl_size; ++fine_idx) { \ + u32 cpl_index = SCRATCH(fine_cpl_bucket, fine_idx); \ + stage1_data_item cpl_value = STAGE1_DATA(cpl_bucket, cpl_index); \ + stage1_data_item sum = value + cpl_value; \ + assert((sum % NUM_FINE_BUCKETS) == 0); \ + sum /= NUM_FINE_BUCKETS; /* 45 bits */ \ + u32 s2_buck_id = sum % NUM_COARSE_BUCKETS; \ + u32 s2_item_id = STAGE2_SIZE(s2_buck_id); \ + if (s2_item_id >= COARSE_BUCKET_ITEMS) \ + continue; \ + STAGE2_SIZE(s2_buck_id) = s2_item_id + 1; \ + STAGE2_IDX(s2_buck_id, s2_item_id) = \ + MAKE_ITEM(bucket_idx, item_idx, cpl_index); \ + STAGE2_DATA(s2_buck_id, s2_item_id) = \ + sum / NUM_COARSE_BUCKETS; /* 37 bits */ \ + } \ + +static void solve_stage1(solver_heap* heap) { + CLEAR(heap->stage2_indices.counts); + for (u32 bucket_idx = BUCK_START; bucket_idx < BUCK_END; ++bucket_idx) { + u32 cpl_bucket = INVERT_BUCKET(bucket_idx); + CLEAR(heap->scratch_ht.counts); + u32 cpl_buck_size = STAGE1_SIZE(cpl_bucket); + for (u32 item_idx = 0; item_idx < cpl_buck_size; ++item_idx) { + { + stage1_data_item value = STAGE1_DATA(cpl_bucket, item_idx); + u32 fine_buck_idx = value % NUM_FINE_BUCKETS; + u32 fine_item_idx = SCRATCH_SIZE(fine_buck_idx); + if (fine_item_idx >= FINE_BUCKET_ITEMS) + continue; + SCRATCH_SIZE(fine_buck_idx) = fine_item_idx + 1; + SCRATCH(fine_buck_idx, fine_item_idx) = item_idx; + } + if (cpl_bucket == bucket_idx) { + MAKE_PAIRS1 + } + } + if (cpl_bucket != bucket_idx) { + u32 buck_size = STAGE1_SIZE(bucket_idx); + for (u32 item_idx = 0; item_idx < buck_size; ++item_idx) { + MAKE_PAIRS1 + } + } + } +} + +#define MAKE_PAIRS2 \ + stage2_data_item value = STAGE2_DATA(bucket_idx, item_idx) + CARRY; \ + u32 fine_buck_idx = value % NUM_FINE_BUCKETS; \ + u32 fine_cpl_bucket = INVERT_SCRATCH(fine_buck_idx); \ + u32 fine_cpl_size = SCRATCH_SIZE(fine_cpl_bucket); \ + for (u32 fine_idx = 0; fine_idx < fine_cpl_size; ++fine_idx) { \ + u32 cpl_index = SCRATCH(fine_cpl_bucket, fine_idx); \ + stage2_data_item cpl_value = STAGE2_DATA(cpl_bucket, cpl_index); \ + stage2_data_item sum = value + cpl_value; \ + assert((sum % NUM_FINE_BUCKETS) == 0); \ + sum /= NUM_FINE_BUCKETS; /* 30 bits */ \ + u32 s3_buck_id = sum % NUM_COARSE_BUCKETS; \ + u32 s3_item_id = STAGE3_SIZE(s3_buck_id); \ + if (s3_item_id >= COARSE_BUCKET_ITEMS) \ + continue; \ + STAGE3_SIZE(s3_buck_id) = s3_item_id + 1; \ + STAGE3_IDX(s3_buck_id, s3_item_id) = \ + MAKE_ITEM(bucket_idx, item_idx, cpl_index); \ + STAGE3_DATA(s3_buck_id, s3_item_id) = \ + (stage3_data_item)(sum / NUM_COARSE_BUCKETS); /* 22 bits */ \ + } \ + +static void solve_stage2(solver_heap* heap) { + CLEAR(heap->stage3_indices.counts); + for (u32 bucket_idx = BUCK_START; bucket_idx < BUCK_END; ++bucket_idx) { + u32 cpl_bucket = INVERT_BUCKET(bucket_idx); + CLEAR(heap->scratch_ht.counts); + u32 cpl_buck_size = STAGE2_SIZE(cpl_bucket); + for (u32 item_idx = 0; item_idx < cpl_buck_size; ++item_idx) { + { + stage2_data_item value = STAGE2_DATA(cpl_bucket, item_idx); + u32 fine_buck_idx = value % NUM_FINE_BUCKETS; + u32 fine_item_idx = SCRATCH_SIZE(fine_buck_idx); + if (fine_item_idx >= FINE_BUCKET_ITEMS) + continue; + SCRATCH_SIZE(fine_buck_idx) = fine_item_idx + 1; + SCRATCH(fine_buck_idx, fine_item_idx) = item_idx; + } + if (cpl_bucket == bucket_idx) { + MAKE_PAIRS2 + } + } + if (cpl_bucket != bucket_idx) { + u32 buck_size = STAGE2_SIZE(bucket_idx); + for (u32 item_idx = 0; item_idx < buck_size; ++item_idx) { + MAKE_PAIRS2 + } + } + } +} + +#define MAKE_PAIRS3 \ + stage3_data_item value = STAGE3_DATA(bucket_idx, item_idx) + CARRY; \ + u32 fine_buck_idx = value % NUM_FINE_BUCKETS; \ + u32 fine_cpl_bucket = INVERT_SCRATCH(fine_buck_idx); \ + u32 fine_cpl_size = SCRATCH_SIZE(fine_cpl_bucket); \ + for (u32 fine_idx = 0; fine_idx < fine_cpl_size; ++fine_idx) { \ + u32 cpl_index = SCRATCH(fine_cpl_bucket, fine_idx); \ + stage3_data_item cpl_value = STAGE3_DATA(cpl_bucket, cpl_index); \ + stage3_data_item sum = value + cpl_value; \ + assert((sum % NUM_FINE_BUCKETS) == 0); \ + sum /= NUM_FINE_BUCKETS; /* 15 bits */ \ + if ((sum & EQUIX_STAGE1_MASK) == 0) { \ + /* we have a solution */ \ + s3_idx item_left = STAGE3_IDX(bucket_idx, item_idx); \ + s3_idx item_right = STAGE3_IDX(cpl_bucket, cpl_index); \ + build_solution(&output[sols_found], heap, item_left, item_right); \ + if (++(sols_found) >= EQUIX_MAX_SOLS) { \ + return sols_found; \ + } \ + } \ + } \ + +static int solve_stage3(solver_heap* heap, equix_solution output[EQUIX_MAX_SOLS]) { + int sols_found = 0; + + for (u32 bucket_idx = BUCK_START; bucket_idx < BUCK_END; ++bucket_idx) { + u32 cpl_bucket = -bucket_idx & (NUM_COARSE_BUCKETS - 1); + CLEAR(heap->scratch_ht.counts); + u32 cpl_buck_size = STAGE3_SIZE(cpl_bucket); + for (u32 item_idx = 0; item_idx < cpl_buck_size; ++item_idx) { + { + stage3_data_item value = STAGE3_DATA(cpl_bucket, item_idx); + u32 fine_buck_idx = value % NUM_FINE_BUCKETS; + u32 fine_item_idx = SCRATCH_SIZE(fine_buck_idx); + if (fine_item_idx >= FINE_BUCKET_ITEMS) + continue; + SCRATCH_SIZE(fine_buck_idx) = fine_item_idx + 1; + SCRATCH(fine_buck_idx, fine_item_idx) = item_idx; + } + if (cpl_bucket == bucket_idx) { + MAKE_PAIRS3 + } + } + if (cpl_bucket != bucket_idx) { + u32 buck_size = STAGE3_SIZE(bucket_idx); + for (u32 item_idx = 0; item_idx < buck_size; ++item_idx) { + MAKE_PAIRS3 + } + } + } + + return sols_found; +} + +int equix_solver_solve( + hashx_ctx* hash_func, + solver_heap* heap, + equix_solution output[EQUIX_MAX_SOLS]) +{ + solve_stage0(hash_func, heap); + solve_stage1(heap); + solve_stage2(heap); + return solve_stage3(heap, output); +} diff -Nru tor-0.4.7.16/src/ext/equix/src/solver.h tor-0.4.9.6/src/ext/equix/src/solver.h --- tor-0.4.7.16/src/ext/equix/src/solver.h 1970-01-01 00:00:00.000000000 +0000 +++ tor-0.4.9.6/src/ext/equix/src/solver.h 2026-03-25 14:30:34.000000000 +0000 @@ -0,0 +1,44 @@ +/* Copyright (c) 2020 tevador */ +/* See LICENSE for licensing information */ + +#ifndef SOLVER_H +#define SOLVER_H + +#include +#include +#include +#include "context.h" + +#define EQUIX_STAGE1_MASK ((1ull << 15) - 1) +#define EQUIX_STAGE2_MASK ((1ull << 30) - 1) +#define EQUIX_FULL_MASK ((1ull << 60) - 1) + +static inline bool tree_cmp1(const equix_idx* left, const equix_idx* right) { + return *left <= *right; +} + +static inline uint32_t tree_idx2(const equix_idx* idx) { + return + (uint32_t)idx[1] << 1*16 | + (uint32_t)idx[0] << 0*16; +} + +static inline bool tree_cmp2(const equix_idx* left, const equix_idx* right) { + return tree_idx2(left) <= tree_idx2(right); +} + +static inline uint64_t tree_idx4(const equix_idx* idx) { + return + (uint64_t)idx[3] << 3*16 | + (uint64_t)idx[2] << 2*16 | + (uint64_t)idx[1] << 1*16 | + (uint64_t)idx[0] << 0*16; +} + +static inline bool tree_cmp4(const equix_idx* left, const equix_idx* right) { + return tree_idx4(left) <= tree_idx4(right); +} + +EQUIX_PRIVATE int equix_solver_solve(hashx_ctx* hash_func, solver_heap* heap, equix_solution output[EQUIX_MAX_SOLS]); + +#endif diff -Nru tor-0.4.7.16/src/ext/equix/src/solver_heap.h tor-0.4.9.6/src/ext/equix/src/solver_heap.h --- tor-0.4.7.16/src/ext/equix/src/solver_heap.h 1970-01-01 00:00:00.000000000 +0000 +++ tor-0.4.9.6/src/ext/equix/src/solver_heap.h 2026-03-25 14:30:34.000000000 +0000 @@ -0,0 +1,108 @@ +/* Copyright (c) 2020 tevador */ +/* See LICENSE for licensing information */ + +#ifndef SOLVER_HEAP_H +#define SOLVER_HEAP_H + +#include +#include + +#define INDEX_SPACE (UINT32_C(1) << 16) +#define NUM_COARSE_BUCKETS 256 +#define NUM_FINE_BUCKETS 128 +#define COARSE_BUCKET_ITEMS 336 +#define FINE_BUCKET_ITEMS 12 + +typedef uint16_t fine_item; + +typedef struct fine_bucket { + fine_item items[FINE_BUCKET_ITEMS]; +} fine_bucket; + +typedef struct fine_hashtab { + uint8_t counts[NUM_FINE_BUCKETS]; + fine_bucket buckets[NUM_FINE_BUCKETS]; +} fine_hashtab; + +typedef equix_idx stage1_idx_item; /* 16 bits */ + +typedef uint64_t stage1_data_item; /* 52 bits */ + +typedef struct stage1_idx_bucket { + stage1_idx_item items[COARSE_BUCKET_ITEMS]; +} stage1_idx_bucket; + +typedef struct stage1_data_bucket { + stage1_data_item items[COARSE_BUCKET_ITEMS]; +} stage1_data_bucket; + +typedef struct stage1_idx_hashtab { + uint16_t counts[NUM_COARSE_BUCKETS]; + stage1_idx_bucket buckets[NUM_COARSE_BUCKETS]; +} stage1_idx_hashtab; + +typedef struct stage1_data_hashtab { + stage1_data_bucket buckets[NUM_COARSE_BUCKETS]; +} stage1_data_hashtab; + +typedef uint32_t stage2_idx_item; /* 26 bits: 8 bits = left bucket index + 9 bits = left item index + 9 bits = right item index */ + +typedef struct stage2_idx_bucket { + stage2_idx_item items[COARSE_BUCKET_ITEMS]; +} stage2_idx_bucket; + +typedef struct stage2_idx_hashtab { + uint16_t counts[NUM_COARSE_BUCKETS]; + stage2_idx_bucket buckets[NUM_COARSE_BUCKETS]; +} stage2_idx_hashtab; + +#ifdef SOLVER_PACKED_STAGE2 +#pragma pack(push, 1) +typedef struct stage2_data_item { + uint32_t upper; /* 22 bits */ + uint8_t middle; /* 8 bits */ + uint8_t lower; /* 7 bits */ +} stage2_data_item; +#pragma pack(pop) +#else +typedef uint64_t stage2_data_item; /* 37 bits */ +#endif + +typedef struct stage2_data_bucket { + stage2_data_item items[COARSE_BUCKET_ITEMS]; +} stage2_data_bucket; + +typedef struct stage2_data_hashtab { + stage2_data_bucket buckets[NUM_COARSE_BUCKETS]; +} stage2_data_hashtab; + +typedef uint32_t stage3_data_item; /* 22 bits */ + +typedef struct stage3_data_bucket { + stage3_data_item items[COARSE_BUCKET_ITEMS]; +} stage3_data_bucket; + +typedef struct stage3_data_hashtab { + stage3_data_bucket buckets[NUM_COARSE_BUCKETS]; +} stage3_data_hashtab; + +typedef stage2_idx_hashtab stage3_idx_hashtab; +typedef stage2_idx_item stage3_idx_item; + +typedef struct solver_heap { + stage1_idx_hashtab stage1_indices; /* 172 544 bytes */ + stage2_idx_hashtab stage2_indices; /* 344 576 bytes */ + stage2_data_hashtab stage2_data; /* 688 128 bytes */ + union { + stage1_data_hashtab stage1_data; /* 688 128 bytes */ + struct { + stage3_idx_hashtab stage3_indices; /* 344 576 bytes */ + stage3_data_hashtab stage3_data; /* 344 064 bytes */ + }; + }; + fine_hashtab scratch_ht; /* 3 200 bytes */ +} solver_heap; /* TOTAL: 1 897 088 bytes */ + +#endif diff -Nru tor-0.4.7.16/src/ext/include.am tor-0.4.9.6/src/ext/include.am --- tor-0.4.7.16/src/ext/include.am 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/ext/include.am 2026-03-25 14:30:34.000000000 +0000 @@ -1,19 +1,22 @@ -AM_CPPFLAGS += -I$(srcdir)/src/ext -Isrc/ext +AM_CPPFLAGS += \ + -I$(srcdir)/src/ext/ \ + -I$(srcdir)/src/ext/equix/hashx/include/ EXTRA_DIST += src/ext/ext.md EXTHEADERS = \ - src/ext/ht.h \ - src/ext/byteorder.h \ - src/ext/tinytest.h \ + src/ext/ht.h \ + src/ext/byteorder.h \ + src/ext/tinytest.h \ src/ext/tor_readpassphrase.h \ - src/ext/strlcat.c \ - src/ext/strlcpy.c \ - src/ext/getdelim.c \ + src/ext/strlcat.c \ + src/ext/strlcpy.c \ + src/ext/getdelim.c \ src/ext/tinytest_macros.h \ - src/ext/tor_queue.h \ + src/ext/tor_queue.h \ src/ext/siphash.h \ + src/ext/compat_blake2.h \ src/ext/timeouts/timeout.h \ src/ext/timeouts/timeout-debug.h \ src/ext/timeouts/timeout-bitops.c \ @@ -143,6 +146,60 @@ LIBED25519_DONNA=src/ext/ed25519/donna/libed25519_donna.a noinst_LIBRARIES += $(LIBED25519_DONNA) +src_ext_equix_libhashx_a_CPPFLAGS = \ + -I$(srcdir)/src/ext/equix/hashx/include/ \ + -I$(srcdir)/src/ext/equix/hashx/src/ \ + -DHASHX_SIZE=@HASHX_SIZE@ \ + -DEQUIX_STATIC=1 -DHASHX_STATIC=1 + +src_ext_equix_libhashx_a_SOURCES = \ + src/ext/equix/hashx/src/blake2.c \ + src/ext/equix/hashx/src/compiler.c \ + src/ext/equix/hashx/src/compiler_a64.c \ + src/ext/equix/hashx/src/compiler_x86.c \ + src/ext/equix/hashx/src/context.c \ + src/ext/equix/hashx/src/hashx.c \ + src/ext/equix/hashx/src/program.c \ + src/ext/equix/hashx/src/program_exec.c \ + src/ext/equix/hashx/src/siphash.c \ + src/ext/equix/hashx/src/siphash_rng.c \ + src/ext/equix/hashx/src/virtual_memory.c + +src_ext_equix_libequix_a_CPPFLAGS = \ + -I$(srcdir)/src/ext/equix/include/ \ + -I$(srcdir)/src/ext/equix/src/ \ + $(src_ext_equix_libhashx_a_CPPFLAGS) + +src_ext_equix_libequix_a_SOURCES = \ + src/ext/equix/src/context.c \ + src/ext/equix/src/equix.c \ + src/ext/equix/src/solver.c + +EQUIX_HDRS = \ + src/ext/equix/hashx/include/hashx.h \ + src/ext/equix/hashx/src/blake2.h \ + src/ext/equix/hashx/src/compiler.h \ + src/ext/equix/hashx/src/context.h \ + src/ext/equix/hashx/src/force_inline.h \ + src/ext/equix/hashx/src/hashx_endian.h \ + src/ext/equix/hashx/src/instruction.h \ + src/ext/equix/hashx/src/program.h \ + src/ext/equix/hashx/src/siphash_rng.h \ + src/ext/equix/hashx/src/siphash.h \ + src/ext/equix/hashx/src/unreachable.h \ + src/ext/equix/hashx/src/virtual_memory.h \ + src/ext/equix/include/equix.h \ + src/ext/equix/src/context.h \ + src/ext/equix/src/solver_heap.h \ + src/ext/equix/src/solver.h + +EQUIX_LIBS = \ + src/ext/equix/libhashx.a \ + src/ext/equix/libequix.a + +noinst_HEADERS += $(EQUIX_HDRS) +noinst_LIBRARIES += $(EQUIX_LIBS) + if BUILD_KECCAK_TINY src_ext_keccak_tiny_libkeccak_tiny_a_CFLAGS=\ @CFLAGS_CONSTTIME@ @@ -159,6 +216,21 @@ noinst_LIBRARIES += $(LIBKECCAK_TINY) endif +src_ext_polyval_libpolyval_a_CFLAGS=\ + @CFLAGS_CONSTTIME@ +src_ext_polyval_libpolyval_a_SOURCES= \ + src/ext/polyval/polyval.c + +POLYVAL_HDRS = \ + src/ext/polyval/polyval.h \ + src/ext/polyval/pclmul.c \ + src/ext/polyval/ctmul64.c \ + src/ext/polyval/ctmul.c + +noinst_HEADERS += $(POLYVAL_HDRS) +LIBPOLYVAL=src/ext/polyval/libpolyval.a +noinst_LIBRARIES += $(LIBPOLYVAL) + EXTRA_DIST += \ src/ext/timeouts/bench/bench-add.lua \ src/ext/timeouts/bench/bench-aux.lua \ diff -Nru tor-0.4.7.16/src/ext/polyval/ctmul.c tor-0.4.9.6/src/ext/polyval/ctmul.c --- tor-0.4.7.16/src/ext/polyval/ctmul.c 1970-01-01 00:00:00.000000000 +0000 +++ tor-0.4.9.6/src/ext/polyval/ctmul.c 2026-03-25 14:30:34.000000000 +0000 @@ -0,0 +1,311 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* + * We compute "carryless multiplications" through normal integer + * multiplications, masking out enough bits to create "holes" in which + * carries may expand without altering our bits; we really use 8 data + * bits per 32-bit word, spaced every fourth bit. Accumulated carries + * may not exceed 8 in total, which fits in 4 bits. + * + * It would be possible to use a 3-bit spacing, allowing two operands, + * one with 7 non-zero data bits, the other one with 10 or 11 non-zero + * data bits; this asymmetric splitting makes the overall code more + * complex with thresholds and exceptions, and does not appear to be + * worth the effort. + */ + +/* + * We cannot really autodetect whether multiplications are "slow" or + * not. A typical example is the ARM Cortex M0+, which exists in two + * versions: one with a 1-cycle multiplication opcode, the other with + * a 32-cycle multiplication opcode. They both use exactly the same + * architecture and ABI, and cannot be distinguished from each other + * at compile-time. + * + * Since most modern CPU (even embedded CPU) still have fast + * multiplications, we use the "fast mul" code by default. + */ + +// A 32x32 -> 64 multiply. +#define MUL(x, y) (((uint64_t)(x)) * ((uint64_t)(y))) + +#ifdef BR_SLOW_MUL + +/* + * This implementation uses Karatsuba-like reduction to make fewer + * integer multiplications (9 instead of 16), at the expense of extra + * logical operations (XOR, shifts...). On modern x86 CPU that offer + * fast, pipelined multiplications, this code is about twice slower than + * the simpler code with 16 multiplications. This tendency may be + * reversed on low-end platforms with expensive multiplications. + */ + +#define MUL32(h, l, x, y) do { \ + uint64_t mul32tmp = MUL(x, y); \ + (h) = (uint32_t)(mul32tmp >> 32); \ + (l) = (uint32_t)mul32tmp; \ + } while (0) + +static inline void +bmul(uint32_t *hi, uint32_t *lo, uint32_t x, uint32_t y) +{ + uint32_t x0, x1, x2, x3; + uint32_t y0, y1, y2, y3; + uint32_t a0, a1, a2, a3, a4, a5, a6, a7, a8; + uint32_t b0, b1, b2, b3, b4, b5, b6, b7, b8; + + x0 = x & (uint32_t)0x11111111; + x1 = x & (uint32_t)0x22222222; + x2 = x & (uint32_t)0x44444444; + x3 = x & (uint32_t)0x88888888; + y0 = y & (uint32_t)0x11111111; + y1 = y & (uint32_t)0x22222222; + y2 = y & (uint32_t)0x44444444; + y3 = y & (uint32_t)0x88888888; + + /* + * (x0+W*x1)*(y0+W*y1) -> a0:b0 + * (x2+W*x3)*(y2+W*y3) -> a3:b3 + * ((x0+x2)+W*(x1+x3))*((y0+y2)+W*(y1+y3)) -> a6:b6 + */ + a0 = x0; + b0 = y0; + a1 = x1 >> 1; + b1 = y1 >> 1; + a2 = a0 ^ a1; + b2 = b0 ^ b1; + a3 = x2 >> 2; + b3 = y2 >> 2; + a4 = x3 >> 3; + b4 = y3 >> 3; + a5 = a3 ^ a4; + b5 = b3 ^ b4; + a6 = a0 ^ a3; + b6 = b0 ^ b3; + a7 = a1 ^ a4; + b7 = b1 ^ b4; + a8 = a6 ^ a7; + b8 = b6 ^ b7; + + MUL32(b0, a0, b0, a0); + MUL32(b1, a1, b1, a1); + MUL32(b2, a2, b2, a2); + MUL32(b3, a3, b3, a3); + MUL32(b4, a4, b4, a4); + MUL32(b5, a5, b5, a5); + MUL32(b6, a6, b6, a6); + MUL32(b7, a7, b7, a7); + MUL32(b8, a8, b8, a8); + + a0 &= (uint32_t)0x11111111; + a1 &= (uint32_t)0x11111111; + a2 &= (uint32_t)0x11111111; + a3 &= (uint32_t)0x11111111; + a4 &= (uint32_t)0x11111111; + a5 &= (uint32_t)0x11111111; + a6 &= (uint32_t)0x11111111; + a7 &= (uint32_t)0x11111111; + a8 &= (uint32_t)0x11111111; + b0 &= (uint32_t)0x11111111; + b1 &= (uint32_t)0x11111111; + b2 &= (uint32_t)0x11111111; + b3 &= (uint32_t)0x11111111; + b4 &= (uint32_t)0x11111111; + b5 &= (uint32_t)0x11111111; + b6 &= (uint32_t)0x11111111; + b7 &= (uint32_t)0x11111111; + b8 &= (uint32_t)0x11111111; + + a2 ^= a0 ^ a1; + b2 ^= b0 ^ b1; + a0 ^= (a2 << 1) ^ (a1 << 2); + b0 ^= (b2 << 1) ^ (b1 << 2); + a5 ^= a3 ^ a4; + b5 ^= b3 ^ b4; + a3 ^= (a5 << 1) ^ (a4 << 2); + b3 ^= (b5 << 1) ^ (b4 << 2); + a8 ^= a6 ^ a7; + b8 ^= b6 ^ b7; + a6 ^= (a8 << 1) ^ (a7 << 2); + b6 ^= (b8 << 1) ^ (b7 << 2); + a6 ^= a0 ^ a3; + b6 ^= b0 ^ b3; + *lo = a0 ^ (a6 << 2) ^ (a3 << 4); + *hi = b0 ^ (b6 << 2) ^ (b3 << 4) ^ (a6 >> 30) ^ (a3 >> 28); +} + +#else + +/* + * Simple multiplication in GF(2)[X], using 16 integer multiplications. + */ + +static inline void +bmul(uint32_t *hi, uint32_t *lo, uint32_t x, uint32_t y) +{ + uint32_t x0, x1, x2, x3; + uint32_t y0, y1, y2, y3; + uint64_t z0, z1, z2, z3; + uint64_t z; + + x0 = x & (uint32_t)0x11111111; + x1 = x & (uint32_t)0x22222222; + x2 = x & (uint32_t)0x44444444; + x3 = x & (uint32_t)0x88888888; + y0 = y & (uint32_t)0x11111111; + y1 = y & (uint32_t)0x22222222; + y2 = y & (uint32_t)0x44444444; + y3 = y & (uint32_t)0x88888888; + z0 = MUL(x0, y0) ^ MUL(x1, y3) ^ MUL(x2, y2) ^ MUL(x3, y1); + z1 = MUL(x0, y1) ^ MUL(x1, y0) ^ MUL(x2, y3) ^ MUL(x3, y2); + z2 = MUL(x0, y2) ^ MUL(x1, y1) ^ MUL(x2, y0) ^ MUL(x3, y3); + z3 = MUL(x0, y3) ^ MUL(x1, y2) ^ MUL(x2, y1) ^ MUL(x3, y0); + z0 &= (uint64_t)0x1111111111111111; + z1 &= (uint64_t)0x2222222222222222; + z2 &= (uint64_t)0x4444444444444444; + z3 &= (uint64_t)0x8888888888888888; + z = z0 | z1 | z2 | z3; + *lo = (uint32_t)z; + *hi = (uint32_t)(z >> 32); +} + +#endif + +static void +pv_mul_y_h_ctmul(polyval_t *pv) +{ + uint32_t *yw = pv->y.v; + const uint32_t *hw = pv->key.h.v; + + /* + * Throughout the loop we handle the y and h values as arrays + * of 32-bit words. + */ + { + int i; + uint32_t a[9], b[9], zw[8]; + uint32_t c0, c1, c2, c3, d0, d1, d2, d3, e0, e1, e2, e3; + + /* + * We multiply two 128-bit field elements. We use + * Karatsuba to turn that into three 64-bit + * multiplications, which are themselves done with a + * total of nine 32-bit multiplications. + */ + + /* + * y[0,1]*h[0,1] -> 0..2 + * y[2,3]*h[2,3] -> 3..5 + * (y[0,1]+y[2,3])*(h[0,1]+h[2,3]) -> 6..8 + */ + a[0] = yw[0]; + b[0] = hw[0]; + a[1] = yw[1]; + b[1] = hw[1]; + a[2] = a[0] ^ a[1]; + b[2] = b[0] ^ b[1]; + + a[3] = yw[2]; + b[3] = hw[2]; + a[4] = yw[3]; + b[4] = hw[3]; + a[5] = a[3] ^ a[4]; + b[5] = b[3] ^ b[4]; + + a[6] = a[0] ^ a[3]; + b[6] = b[0] ^ b[3]; + a[7] = a[1] ^ a[4]; + b[7] = b[1] ^ b[4]; + a[8] = a[6] ^ a[7]; + b[8] = b[6] ^ b[7]; + + for (i = 0; i < 9; i ++) { + bmul(&b[i], &a[i], b[i], a[i]); + } + + c0 = a[0]; + c1 = b[0] ^ a[2] ^ a[0] ^ a[1]; + c2 = a[1] ^ b[2] ^ b[0] ^ b[1]; + c3 = b[1]; + d0 = a[3]; + d1 = b[3] ^ a[5] ^ a[3] ^ a[4]; + d2 = a[4] ^ b[5] ^ b[3] ^ b[4]; + d3 = b[4]; + e0 = a[6]; + e1 = b[6] ^ a[8] ^ a[6] ^ a[7]; + e2 = a[7] ^ b[8] ^ b[6] ^ b[7]; + e3 = b[7]; + + e0 ^= c0 ^ d0; + e1 ^= c1 ^ d1; + e2 ^= c2 ^ d2; + e3 ^= c3 ^ d3; + c2 ^= e0; + c3 ^= e1; + d0 ^= e2; + d1 ^= e3; + +#if 0 + // This rotation is GHASH-only. + /* + * GHASH specification has the bits "reversed" (most + * significant is in fact least significant), which does + * not matter for a carryless multiplication, except that + * the 255-bit result must be shifted by 1 bit. + */ + zw[0] = c0 << 1; + zw[1] = (c1 << 1) | (c0 >> 31); + zw[2] = (c2 << 1) | (c1 >> 31); + zw[3] = (c3 << 1) | (c2 >> 31); + zw[4] = (d0 << 1) | (c3 >> 31); + zw[5] = (d1 << 1) | (d0 >> 31); + zw[6] = (d2 << 1) | (d1 >> 31); + zw[7] = (d3 << 1) | (d2 >> 31); +#else + zw[0] = c0; + zw[1] = c1; + zw[2] = c2; + zw[3] = c3; + zw[4] = d0; + zw[5] = d1; + zw[6] = d2; + zw[7] = d3; +#endif + + /* + * We now do the reduction modulo the field polynomial + * to get back to 128 bits. + */ + for (i = 0; i < 4; i ++) { + uint32_t lw; + + lw = zw[i]; + zw[i + 4] ^= lw ^ (lw >> 1) ^ (lw >> 2) ^ (lw >> 7); + zw[i + 3] ^= (lw << 31) ^ (lw << 30) ^ (lw << 25); + } + memcpy(yw, zw + 4, 16); + } +} +#undef MUL diff -Nru tor-0.4.7.16/src/ext/polyval/ctmul64.c tor-0.4.9.6/src/ext/polyval/ctmul64.c --- tor-0.4.7.16/src/ext/polyval/ctmul64.c 1970-01-01 00:00:00.000000000 +0000 +++ tor-0.4.9.6/src/ext/polyval/ctmul64.c 2026-03-25 14:30:34.000000000 +0000 @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* + * This is the 64-bit variant of br_ghash_ctmul32(), with 64-bit operands + * and bit reversal of 64-bit words. + */ + +static inline uint64_t +bmul64(uint64_t x, uint64_t y) +{ + uint64_t x0, x1, x2, x3; + uint64_t y0, y1, y2, y3; + uint64_t z0, z1, z2, z3; + + x0 = x & (uint64_t)0x1111111111111111; + x1 = x & (uint64_t)0x2222222222222222; + x2 = x & (uint64_t)0x4444444444444444; + x3 = x & (uint64_t)0x8888888888888888; + y0 = y & (uint64_t)0x1111111111111111; + y1 = y & (uint64_t)0x2222222222222222; + y2 = y & (uint64_t)0x4444444444444444; + y3 = y & (uint64_t)0x8888888888888888; + z0 = (x0 * y0) ^ (x1 * y3) ^ (x2 * y2) ^ (x3 * y1); + z1 = (x0 * y1) ^ (x1 * y0) ^ (x2 * y3) ^ (x3 * y2); + z2 = (x0 * y2) ^ (x1 * y1) ^ (x2 * y0) ^ (x3 * y3); + z3 = (x0 * y3) ^ (x1 * y2) ^ (x2 * y1) ^ (x3 * y0); + z0 &= (uint64_t)0x1111111111111111; + z1 &= (uint64_t)0x2222222222222222; + z2 &= (uint64_t)0x4444444444444444; + z3 &= (uint64_t)0x8888888888888888; + return z0 | z1 | z2 | z3; +} + +static uint64_t +rev64(uint64_t x) +{ +#define RMS(m, s) do { \ + x = ((x & (uint64_t)(m)) << (s)) \ + | ((x >> (s)) & (uint64_t)(m)); \ + } while (0) + + RMS(0x5555555555555555, 1); + RMS(0x3333333333333333, 2); + RMS(0x0F0F0F0F0F0F0F0F, 4); + RMS(0x00FF00FF00FF00FF, 8); + RMS(0x0000FFFF0000FFFF, 16); + return (x << 32) | (x >> 32); + +#undef RMS +} + + +static void +pv_mul_y_h_ctmul64(polyval_t *pv) +{ + uint64_t y0, y1; + uint64_t h0, h1, h2, h0r, h1r, h2r; + + y0 = CTMUL64_MEMBER(pv->y).lo; + y1 = CTMUL64_MEMBER(pv->y).hi; + h0 = CTMUL64_MEMBER(pv->key.h).lo; + h1 = CTMUL64_MEMBER(pv->key.h).hi; + h0r = rev64(h0); + h1r = rev64(h1); + + h2 = h0 ^ h1; + h2r = h0r ^ h1r; + { + uint64_t y0r, y1r, y2, y2r; + uint64_t z0, z1, z2, z0h, z1h, z2h; + uint64_t v0, v1, v2, v3; + + y0r = rev64(y0); + y1r = rev64(y1); + y2 = y0 ^ y1; + y2r = y0r ^ y1r; + + z0 = bmul64(y0, h0); + z1 = bmul64(y1, h1); + z2 = bmul64(y2, h2); + z0h = bmul64(y0r, h0r); + z1h = bmul64(y1r, h1r); + z2h = bmul64(y2r, h2r); + z2 ^= z0 ^ z1; + z2h ^= z0h ^ z1h; + z0h = rev64(z0h) >> 1; + z1h = rev64(z1h) >> 1; + z2h = rev64(z2h) >> 1; + + v0 = z0; + v1 = z0h ^ z2; + v2 = z1 ^ z2h; + v3 = z1h; + +#if 0 + // This step is GHASH only. + v3 = (v3 << 1) | (v2 >> 63); + v2 = (v2 << 1) | (v1 >> 63); + v1 = (v1 << 1) | (v0 >> 63); + v0 = (v0 << 1); +#endif + + v2 ^= v0 ^ (v0 >> 1) ^ (v0 >> 2) ^ (v0 >> 7); + v1 ^= (v0 << 63) ^ (v0 << 62) ^ (v0 << 57); + v3 ^= v1 ^ (v1 >> 1) ^ (v1 >> 2) ^ (v1 >> 7); + v2 ^= (v1 << 63) ^ (v1 << 62) ^ (v1 << 57); + + CTMUL64_MEMBER(pv->y).lo = v2; + CTMUL64_MEMBER(pv->y).hi = v3; + } +} diff -Nru tor-0.4.7.16/src/ext/polyval/pclmul.c tor-0.4.9.6/src/ext/polyval/pclmul.c --- tor-0.4.7.16/src/ext/polyval/pclmul.c 1970-01-01 00:00:00.000000000 +0000 +++ tor-0.4.9.6/src/ext/polyval/pclmul.c 2026-03-25 14:30:34.000000000 +0000 @@ -0,0 +1,253 @@ +/* + * Copyright (c) 2017 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* + * This is the GHASH implementation that leverages the pclmulqdq opcode + * (from the AES-NI instructions). + */ + +#include + +#ifndef __GNUC__ +#define __attribute__(x) +#endif + +#define BR_TARGET(x) __attribute__((target(x))) + +#if defined(__GNUC__) && !defined(__clang__) + _Pragma("GCC target(\"sse2,ssse3,sse4.1,aes,pclmul\")") +#endif + +#if 0 +/* + * Test CPU support for PCLMULQDQ. + */ +static inline int +pclmul_supported(void) +{ + /* + * Bit mask for features in ECX: + * 1 PCLMULQDQ support + */ + return br_cpuid(0, 0, 0x00000002, 0); +} + +/* see bearssl_hash.h */ +br_ghash +br_ghash_pclmul_get(void) +{ + return pclmul_supported() ? &br_ghash_pclmul : 0; +} + +BR_TARGETS_X86_UP +#endif +/* + * Call pclmulqdq. Clang appears to have trouble with the intrinsic, so, + * for that compiler, we use inline assembly. Inline assembly is + * potentially a bit slower because the compiler does not understand + * what the opcode does, and thus cannot optimize instruction + * scheduling. + * + * We use a target of "sse2" only, so that Clang may still handle the + * '__m128i' type and allocate SSE2 registers. + */ +#ifdef __clang__AND_NOT_WORKING + BR_TARGET("sse2") +static inline __m128i +pclmulqdq00(__m128i x, __m128i y) +{ + __asm__ ("pclmulqdq $0x00, %1, %0" : "+x" (x) : "x" (y)); + return x; +} +BR_TARGET("sse2") +static inline __m128i +pclmulqdq11(__m128i x, __m128i y) +{ + __asm__ ("pclmulqdq $0x11, %1, %0" : "+x" (x) : "x" (y)); + return x; +} +#else +#define pclmulqdq00(x, y) _mm_clmulepi64_si128(x, y, 0x00) +#define pclmulqdq11(x, y) _mm_clmulepi64_si128(x, y, 0x11) +#endif + +/* + * From a 128-bit value kw, compute kx as the XOR of the two 64-bit + * halves of kw (into the right half of kx; left half is unspecified). + */ +#define BK(kw, kx) do { \ + kx = _mm_xor_si128(kw, _mm_shuffle_epi32(kw, 0x0E)); \ + } while (0) + +/* + * Combine two 64-bit values (k0:k1) into a 128-bit (kw) value and + * the XOR of the two values (kx). + */ +#define PBK(k0, k1, kw, kx) do { \ + kw = _mm_unpacklo_epi64(k1, k0); \ + kx = _mm_xor_si128(k0, k1); \ + } while (0) + +/* + * Perform reduction in GF(2^128). The 256-bit value is in x0..x3; + * result is written in x0..x1. + */ +#define REDUCE_F128(x0, x1, x2, x3) do { \ + x1 = _mm_xor_si128( \ + x1, \ + _mm_xor_si128( \ + _mm_xor_si128( \ + x3, \ + _mm_srli_epi64(x3, 1)), \ + _mm_xor_si128( \ + _mm_srli_epi64(x3, 2), \ + _mm_srli_epi64(x3, 7)))); \ + x2 = _mm_xor_si128( \ + _mm_xor_si128( \ + x2, \ + _mm_slli_epi64(x3, 63)), \ + _mm_xor_si128( \ + _mm_slli_epi64(x3, 62), \ + _mm_slli_epi64(x3, 57))); \ + x0 = _mm_xor_si128( \ + x0, \ + _mm_xor_si128( \ + _mm_xor_si128( \ + x2, \ + _mm_srli_epi64(x2, 1)), \ + _mm_xor_si128( \ + _mm_srli_epi64(x2, 2), \ + _mm_srli_epi64(x2, 7)))); \ + x1 = _mm_xor_si128( \ + _mm_xor_si128( \ + x1, \ + _mm_slli_epi64(x2, 63)), \ + _mm_xor_si128( \ + _mm_slli_epi64(x2, 62), \ + _mm_slli_epi64(x2, 57))); \ + } while (0) + + +BR_TARGET("ssse3,pclmul") +static inline void +expand_key_pclmul(const polyval_t *pv, pv_expanded_key_t *out) +{ + __m128i h1w, h1x; + __m128i lastw, lastx; + __m128i t0, t1, t2, t3; + + h1w = PCLMUL_MEMBER(pv->key.h); + BK(h1w, h1x); + lastw = h1w; + + for (int i = PV_BLOCK_STRIDE - 2; i >= 0; --i) { + BK(lastw, lastx); + + t1 = pclmulqdq11(lastw, h1w); + t3 = pclmulqdq00(lastw, h1w); + t2 = pclmulqdq00(lastx, h1x); + t2 = _mm_xor_si128(t2, _mm_xor_si128(t1, t3)); + t0 = _mm_shuffle_epi32(t1, 0x0E); + t1 = _mm_xor_si128(t1, _mm_shuffle_epi32(t2, 0x0E)); + t2 = _mm_xor_si128(t2, _mm_shuffle_epi32(t3, 0x0E)); + REDUCE_F128(t0, t1, t2, t3); + out->k[i] = lastw = _mm_unpacklo_epi64(t1, t0); + } +} + +// Add PCLMUL_BLOCK_STRIDE * 16 bytes from input. +BR_TARGET("ssse3,pclmul") +static inline void +pv_add_multiple_pclmul(polyval_t *pv, + const uint8_t *input, + const pv_expanded_key_t *expanded) +{ + __m128i t0, t1, t2, t3; + + t1 = _mm_setzero_si128(); + t2 = _mm_setzero_si128(); + t3 = _mm_setzero_si128(); + + for (int i = 0; i < PV_BLOCK_STRIDE; ++i, input += 16) { + __m128i aw = _mm_loadu_si128((void *)(input)); + __m128i ax; + __m128i hx, hw; + if (i == 0) { + aw = _mm_xor_si128(aw, PCLMUL_MEMBER(pv->y)); + } + if (i == PV_BLOCK_STRIDE - 1) { + hw = PCLMUL_MEMBER(pv->key.h); + } else { + hw = expanded->k[i]; + } + BK(aw, ax); + BK(hw, hx); + t1 = _mm_xor_si128(t1, pclmulqdq11(aw, hw)); + t3 = _mm_xor_si128(t3, pclmulqdq00(aw, hw)); + t2 = _mm_xor_si128(t2, pclmulqdq00(ax, hx)); + } + + t2 = _mm_xor_si128(t2, _mm_xor_si128(t1, t3)); + t0 = _mm_shuffle_epi32(t1, 0x0E); + t1 = _mm_xor_si128(t1, _mm_shuffle_epi32(t2, 0x0E)); + t2 = _mm_xor_si128(t2, _mm_shuffle_epi32(t3, 0x0E)); + + REDUCE_F128(t0, t1, t2, t3); + PCLMUL_MEMBER(pv->y) = _mm_unpacklo_epi64(t1, t0); +} + + +/* see bearssl_hash.h */ +BR_TARGET("ssse3,pclmul") +static inline void +pv_mul_y_h_pclmul(polyval_t *pv) +{ + __m128i yw, h1w, h1x; + + h1w = PCLMUL_MEMBER(pv->key.h); + BK(h1w, h1x); + + { + __m128i aw, ax; + __m128i t0, t1, t2, t3; + + aw = PCLMUL_MEMBER(pv->y); + BK(aw, ax); + + t1 = pclmulqdq11(aw, h1w); + t3 = pclmulqdq00(aw, h1w); + t2 = pclmulqdq00(ax, h1x); + t2 = _mm_xor_si128(t2, _mm_xor_si128(t1, t3)); + t0 = _mm_shuffle_epi32(t1, 0x0E); + t1 = _mm_xor_si128(t1, _mm_shuffle_epi32(t2, 0x0E)); + t2 = _mm_xor_si128(t2, _mm_shuffle_epi32(t3, 0x0E)); +#if 0 // This step is GHASH-only. + SL_256(t0, t1, t2, t3); +#endif + REDUCE_F128(t0, t1, t2, t3); + yw = _mm_unpacklo_epi64(t1, t0); + } + + PCLMUL_MEMBER(pv->y) = yw; +} diff -Nru tor-0.4.7.16/src/ext/polyval/polyval.c tor-0.4.9.6/src/ext/polyval/polyval.c --- tor-0.4.7.16/src/ext/polyval/polyval.c 1970-01-01 00:00:00.000000000 +0000 +++ tor-0.4.9.6/src/ext/polyval/polyval.c 2026-03-25 14:30:34.000000000 +0000 @@ -0,0 +1,561 @@ +/* Copyright (c) 2025, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file polyval.h + * \brief Implementation for polyval universal hash function. + * + * Polyval, which was first defined for AES-GCM-SIV, is a + * universal hash based on multiplication in GF(2^128). + * Unlike the more familiar GHASH, it is defined to work on + * little-endian inputs, and so is more straightforward and efficient + * on little-endian architectures. + * + * In Tor we use it as part of the Counter Galois Onion relay + * encryption format. + **/ + +/* Implementation notes: + * + * Our implementation is based on the GHASH code from BearSSL + * by Thomas Pornin. There are three implementations: + * + * pclmul.c -- An x86-only version, based on the CLMUL instructions + * introduced for westlake processors in 2010. + * + * ctmul64.c -- A portable contant-time implementation for 64-bit + * processors. + * + * ctmul.c -- A portable constant-time implementation for 32-bit + * processors with an efficient 32x32->64 multiply instruction. + * + * Note that the "ctmul" implementations are only constant-time + * if the corresponding CPU multiply and rotate instructions are + * also constant-time. But that's an architectural assumption we + * make in Tor. + */ + +#include "ext/polyval/polyval.h" +#include "lib/cc/compat_compiler.h" + +#include + +#ifdef PV_USE_PCLMUL_DETECT +#include +#endif + +typedef pv_u128_ u128; + +/* ======== + * We declare these functions, to help implement polyval. + * + * They have different definitions depending on our representation + * of 128-bit integers. + */ +#if 0 +/** + * Read a u128-bit little-endian integer from 'bytes', + * which may not be aligned. + */ +static inline u128 u128_from_bytes(const uint8_t *bytes); +/** + * Store a u128-bit little-endian integer to 'bytes_out', + * which may not be aligned. + */ +static inline void u128_to_bytes(u128, uint8_t *bytes_out); +/** + * XOR a u128 into the y field of a polyval_t struct. + * + * (Within the polyval struct, perform "y ^= v"). + */ +static inline void pv_xor_y(polyval_t *, u128 v); + +/* ======== + * The function which we expect our backend to implement. + */ +/** + * Within the polyval struct, perform "y *= h". + * + * (This is a carryless multiply in the Polyval galois field) + */ +static void pv_mul_y_h(polyval_t *);h +#endif + +/* ===== + * Endianness conversion for big-endian platforms + */ +#ifdef WORDS_BIGENDIAN +#ifdef __GNUC__ +#define bswap64(x) __builtin_bswap64(x) +#define bswap32(x) __builtin_bswap32(x) +#else +/* The (compiler should optimize these into a decent bswap instruction) */ +static inline uint64_t +bswap64(uint64_t value) +{ + return + ((value & 0xFF00000000000000) >> 56) | + ((value & 0x00FF000000000000) >> 40) | + ((value & 0x0000FF0000000000) >> 24) | + ((value & 0x000000FF00000000) >> 8) | + ((value & 0x00000000FF000000) << 8) | + ((value & 0x0000000000FF0000) << 24) | + ((value & 0x000000000000FF00) << 40) | + ((value & 0x00000000000000FF) << 56); +} + +static inline uint32_t +bswap32(uint32_t value) +{ + return + ((value & 0xFF000000) >> 24) | + ((value & 0x00FF0000) >> 8) | + ((value & 0x0000FF00) << 8) | + ((value & 0x000000FF) << 24); +} +#endif +#endif + +#ifdef WORDS_BIGENDIAN +#define convert_byte_order64(x) bswap64(x) +#define convert_byte_order32(x) bswap32(x) +#else +#define convert_byte_order64(x) (x) +#define convert_byte_order32(x) (x) +#endif + +#if defined PV_USE_PCLMUL_UNCONDITIONAL +#define PCLMUL_MEMBER(v) (v) +#define PV_USE_PCLMUL + +#elif defined PV_USE_PCLMUL_DETECT +#define PCLMUL_MEMBER(v) (v).u128x1 +#define CTMUL64_MEMBER(v) (v).u64x2 +#define PV_USE_PCLMUL +#define PV_USE_CTMUL64 + +#elif defined PV_USE_CTMUL64 +#define CTMUL64_MEMBER(v) (v) +#endif + +#ifdef PV_USE_PCLMUL +#include "ext/polyval/pclmul.c" + +DISABLE_GCC_WARNING("-Waggregate-return") +static inline u128 +u128_from_bytes_pclmul(const uint8_t *bytes) +{ + u128 r; + PCLMUL_MEMBER(r) = _mm_loadu_si128((const __m128i*)bytes); + return r; +} +ENABLE_GCC_WARNING("-Waggregate-return") + +static inline void +u128_to_bytes_pclmul(u128 val, uint8_t *bytes_out) +{ + _mm_storeu_si128((__m128i*)bytes_out, PCLMUL_MEMBER(val)); +} +static inline void +pv_xor_y_pclmul(polyval_t *pv, u128 v) +{ + PCLMUL_MEMBER(pv->y) = _mm_xor_si128(PCLMUL_MEMBER(pv->y), + PCLMUL_MEMBER(v)); +} +#endif + +#if defined(PV_USE_CTMUL64) +#include "ext/polyval/ctmul64.c" + +DISABLE_GCC_WARNING("-Waggregate-return") +static inline u128 +u128_from_bytes_ctmul64(const uint8_t *bytes) +{ + u128 r; + memcpy(&CTMUL64_MEMBER(r).lo, bytes, 8); + memcpy(&CTMUL64_MEMBER(r).hi, bytes + 8, 8); + CTMUL64_MEMBER(r).lo = convert_byte_order64(CTMUL64_MEMBER(r).lo); + CTMUL64_MEMBER(r).hi = convert_byte_order64(CTMUL64_MEMBER(r).hi); + return r; +} +ENABLE_GCC_WARNING("-Waggregate-return") + +static inline void +u128_to_bytes_ctmul64(u128 val, uint8_t *bytes_out) +{ + uint64_t lo = convert_byte_order64(CTMUL64_MEMBER(val).lo); + uint64_t hi = convert_byte_order64(CTMUL64_MEMBER(val).hi); + memcpy(bytes_out, &lo, 8); + memcpy(bytes_out + 8, &hi, 8); +} +static inline void +pv_xor_y_ctmul64(polyval_t *pv, u128 val) +{ + CTMUL64_MEMBER(pv->y).lo ^= CTMUL64_MEMBER(val).lo; + CTMUL64_MEMBER(pv->y).hi ^= CTMUL64_MEMBER(val).hi; +} +#endif + +#if defined(PV_USE_CTMUL) +#include "ext/polyval/ctmul.c" + +DISABLE_GCC_WARNING("-Waggregate-return") +static inline u128 +u128_from_bytes_ctmul(const uint8_t *bytes) +{ + u128 r; + memcpy(&r.v, bytes, 16); + for (int i = 0; i < 4; ++i) { + r.v[i] = convert_byte_order32(r.v[i]); + } + return r; +} +ENABLE_GCC_WARNING("-Waggregate-return") + +static inline void +u128_to_bytes_ctmul(u128 val, uint8_t *bytes_out) +{ + uint32_t v[4]; + for (int i = 0; i < 4; ++i) { + v[i] = convert_byte_order32(val.v[i]); + } + memcpy(bytes_out, v, 16); +} +static inline void +pv_xor_y_ctmul(polyval_t *pv, u128 val) +{ + for (int i = 0; i < 4; ++i) { + pv->y.v[i] ^= val.v[i]; + } +} +#endif + +struct expanded_key_none {}; +static inline void add_multiple_none(polyval_t *pv, + const uint8_t *input, + const struct expanded_key_none *expanded) +{ + (void) pv; + (void) input; + (void) expanded; +} +static inline void expand_key_none(const polyval_t *inp, + struct expanded_key_none *out) +{ + (void) inp; + (void) out; +} + +/* Kludge: a special value to use for block_stride when we don't support + * processing multiple blocks at once. Previously we used 0, but that + * caused warnings with some comparisons. */ +#define BLOCK_STRIDE_NONE 0xffff + +DISABLE_GCC_WARNING("-Waggregate-return") +#define PV_DECLARE(prefix, \ + st, \ + u128_from_bytes, \ + u128_to_bytes, \ + pv_xor_y, \ + pv_mul_y_h, \ + block_stride, \ + expanded_key_tp, expand_fn, add_multiple_fn) \ + st void \ + prefix ## polyval_key_init(polyval_key_t *pvk, const uint8_t *key) \ + { \ + pvk->h = u128_from_bytes(key); \ + } \ + st void \ + prefix ## polyval_init(polyval_t *pv, const uint8_t *key) \ + { \ + polyval_key_init(&pv->key, key); \ + memset(&pv->y, 0, sizeof(u128)); \ + } \ + st void \ + prefix ## polyval_init_from_key(polyval_t *pv, const polyval_key_t *key) \ + { \ + memcpy(&pv->key, key, sizeof(polyval_key_t)); \ + memset(&pv->y, 0, sizeof(u128)); \ + } \ + st void \ + prefix ## polyval_add_block(polyval_t *pv, const uint8_t *block) \ + { \ + u128 b = u128_from_bytes(block); \ + pv_xor_y(pv, b); \ + pv_mul_y_h(pv); \ + } \ + st void \ + prefix ## polyval_add_zpad(polyval_t *pv, const uint8_t *data, size_t n) \ + { \ + /* since block_stride is a constant, this should get optimized */ \ + if ((block_stride != BLOCK_STRIDE_NONE) \ + && n >= (block_stride) * 16) { \ + expanded_key_tp expanded_key; \ + expand_fn(pv, &expanded_key); \ + while (n >= (block_stride) * 16) { \ + add_multiple_fn(pv, data, &expanded_key); \ + n -= block_stride*16; \ + data += block_stride * 16; \ + } \ + } \ + while (n > 16) { \ + polyval_add_block(pv, data); \ + data += 16; \ + n -= 16; \ + } \ + if (n) { \ + uint8_t block[16]; \ + memset(&block, 0, sizeof(block)); \ + memcpy(block, data, n); \ + polyval_add_block(pv, block); \ + } \ + } \ + st void \ + prefix ## polyval_get_tag(const polyval_t *pv, uint8_t *tag_out) \ + { \ + u128_to_bytes(pv->y, tag_out); \ + } \ + st void \ + prefix ## polyval_reset(polyval_t *pv) \ + { \ + memset(&pv->y, 0, sizeof(u128)); \ + } +ENABLE_GCC_WARNING("-Waggregate-return") + +#ifdef PV_USE_PCLMUL_DETECT +/* We use a boolean to distinguish whether to use the PCLMUL instructions, + * but instead we could use function pointers. It's probably worth + * benchmarking, though it's unlikely to make a measurable difference. + */ +static bool use_pclmul = false; + +/* Declare _both_ variations of our code, statically, + * with different prefixes. */ +DISABLE_GCC_WARNING("-Waggregate-return") +PV_DECLARE(pclmul_, static, + u128_from_bytes_pclmul, + u128_to_bytes_pclmul, + pv_xor_y_pclmul, + pv_mul_y_h_pclmul, + PV_BLOCK_STRIDE, + pv_expanded_key_t, + expand_key_pclmul, + pv_add_multiple_pclmul) + +PV_DECLARE(ctmul64_, static, + u128_from_bytes_ctmul64, + u128_to_bytes_ctmul64, + pv_xor_y_ctmul64, + pv_mul_y_h_ctmul64, + BLOCK_STRIDE_NONE, + struct expanded_key_none, + expand_key_none, + add_multiple_none) +ENABLE_GCC_WARNING("-Waggregate-return") + +void +polyval_key_init(polyval_key_t *pv, const uint8_t *key) +{ + if (use_pclmul) + pclmul_polyval_key_init(pv, key); + else + ctmul64_polyval_key_init(pv, key); +} +void +polyval_init(polyval_t *pv, const uint8_t *key) +{ + if (use_pclmul) + pclmul_polyval_init(pv, key); + else + ctmul64_polyval_init(pv, key); +} +void +polyval_init_from_key(polyval_t *pv, const polyval_key_t *key) +{ + if (use_pclmul) + pclmul_polyval_init_from_key(pv, key); + else + ctmul64_polyval_init_from_key(pv, key); +} +void +polyval_add_block(polyval_t *pv, const uint8_t *block) +{ + if (use_pclmul) + pclmul_polyval_add_block(pv, block); + else + ctmul64_polyval_add_block(pv, block); +} +void +polyval_add_zpad(polyval_t *pv, const uint8_t *data, size_t n) +{ + if (use_pclmul) + pclmul_polyval_add_zpad(pv, data, n); + else + ctmul64_polyval_add_zpad(pv, data, n); +} +void +polyval_get_tag(const polyval_t *pv, uint8_t *tag_out) +{ + if (use_pclmul) + pclmul_polyval_get_tag(pv, tag_out); + else + ctmul64_polyval_get_tag(pv, tag_out); +} +void +polyval_reset(polyval_t *pv) +{ + if (use_pclmul) + pclmul_polyval_reset(pv); + else + ctmul64_polyval_reset(pv); +} + +#elif defined(PV_USE_PCLMUL) +PV_DECLARE(, , + u128_from_bytes_pclmul, + u128_to_bytes_pclmul, + pv_xor_y_pclmul, + pv_mul_y_h_pclmul, + PV_BLOCK_STRIDE, + pv_expanded_key_t, + expand_key_pclmul, + pv_add_multiple_pclmul) +#elif defined(PV_USE_CTMUL64) +PV_DECLARE(, , + u128_from_bytes_ctmul64, + u128_to_bytes_ctmul64, + pv_xor_y_ctmul64, + pv_mul_y_h_ctmul64, + BLOCK_STRIDE_NONE, + struct expanded_key_none, + expand_key_none, + add_multiple_none) + +#elif defined(PV_USE_CTMUL) +DISABLE_GCC_WARNING("-Waggregate-return") +PV_DECLARE(, , u128_from_bytes_ctmul, + u128_to_bytes_ctmul, + pv_xor_y_ctmul, + pv_mul_y_h_ctmul, + BLOCK_STRIDE_NONE, + struct expanded_key_none, + expand_key_none, + add_multiple_none) +ENABLE_GCC_WARNING("-Waggregate-return") +#endif + +#ifdef PV_USE_PCLMUL_DETECT +void +polyval_detect_implementation(void) +{ + unsigned int eax, ebx, ecx, edx; + use_pclmul = false; + if (__get_cpuid(1, &eax, &ebx, &ecx, &edx)) { + if (0 != (ecx & bit_PCLMUL)) { + use_pclmul = true; + } + } +} +#else +void +polyval_detect_implementation(void) +{ +} +#endif + +#ifdef POLYVAL_USE_EXPANDED_KEYS + +#ifdef PV_USE_PCLMUL_DETECT +#define SHOULD_EXPAND() (use_pclmul) +#else +#define SHOULD_EXPAND() (1) +#endif + +void +polyvalx_init(polyvalx_t *pvx, const uint8_t *key) +{ + polyval_init(&pvx->pv, key); + if (SHOULD_EXPAND()) { + expand_key_pclmul(&pvx->pv, &pvx->expanded); + } +} +void +polyvalx_init_from_key(polyvalx_t *pvx, const polyval_key_t *key) +{ + polyval_init_from_key(&pvx->pv, key); + if (SHOULD_EXPAND()) { + expand_key_pclmul(&pvx->pv, &pvx->expanded); + } +} +void +polyvalx_add_block(polyvalx_t *pvx, const uint8_t *block) +{ + polyval_add_block(&pvx->pv, block); +} +void +polyvalx_add_zpad(polyvalx_t *pvx, const uint8_t *data, size_t n) +{ + if (SHOULD_EXPAND() && n >= PV_BLOCK_STRIDE * 16) { + while (n > PV_BLOCK_STRIDE * 16) { + pv_add_multiple_pclmul(&pvx->pv, data, &pvx->expanded); + data += PV_BLOCK_STRIDE * 16; + n -= PV_BLOCK_STRIDE * 16; + } + } + while (n > 16) { + polyval_add_block(&pvx->pv, data); + data += 16; + n -= 16; + } + if (n) { + uint8_t block[16]; + memset(&block, 0, sizeof(block)); + memcpy(block, data, n); + polyval_add_block(&pvx->pv, block); + } +} +void +polyvalx_get_tag(const polyvalx_t *pvx, uint8_t *tag_out) +{ + polyval_get_tag(&pvx->pv, tag_out); +} +void polyvalx_reset(polyvalx_t *pvx) +{ + polyval_reset(&pvx->pv); +} +#endif + +#if 0 +#include +int +main(int c, char **v) +{ + // From RFC 8452 appendix A + uint8_t key[16] = + { 0x25, 0x62, 0x93, 0x47, 0x58, 0x92, 0x42, 0x76, + 0x1d, 0x31, 0xf8, 0x26, 0xba, 0x4b, 0x75, 0x7b }; + uint8_t block1[16] = + { 0x4f, 0x4f, 0x95, 0x66, 0x8c, 0x83, 0xdf, 0xb6, + 0x40, 0x17, 0x62, 0xbb, 0x2d, 0x01, 0xa2, 0x62 }; + uint8_t block2[16] = { + 0xd1, 0xa2, 0x4d, 0xdd, 0x27, 0x21, 0xd0, 0x06, + 0xbb, 0xe4, 0x5f, 0x20, 0xd3, 0xc9, 0xf3, 0x62 }; + uint8_t expect_result[16] = { + 0xf7, 0xa3, 0xb4, 0x7b, 0x84, 0x61, 0x19, 0xfa, + 0xe5, 0xb7, 0x86, 0x6c, 0xf5, 0xe5, 0xb7, 0x7e }; + + polyval_t pv; + uint8_t tag[16]; + polyval_init(&pv, key); + polyval_add_block(&pv, block1); + polyval_add_block(&pv, block2); + polyval_get_tag(&pv, tag); + if (!memcmp(expect_result, tag, 16)) { + puts("OK"); + return 0; + } else { + puts("NOPE"); + return 1; + } +} +#endif diff -Nru tor-0.4.7.16/src/ext/polyval/polyval.h tor-0.4.9.6/src/ext/polyval/polyval.h --- tor-0.4.7.16/src/ext/polyval/polyval.h 1970-01-01 00:00:00.000000000 +0000 +++ tor-0.4.9.6/src/ext/polyval/polyval.h 2026-03-25 14:30:34.000000000 +0000 @@ -0,0 +1,185 @@ +/* Copyright (c) 2025, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file polyval.h + * \brief APIs for polyval universal hash function. + **/ + +#ifndef TOR_POLYVAL_H +#define TOR_POLYVAL_H + +#include "orconfig.h" +#include "lib/cc/torint.h" + +/* Decide which implementation to use. */ +#if defined(__amd64__) || defined(__amd64) || defined(__x86_64__) \ + || defined(_M_X64) || defined(_M_IX86) || defined(__i486) \ + || defined(__i386__) +#define PV_INTEL_ARCH +#endif + +#if defined(PV_INTEL_ARCH) && defined(__PCLMUL__) +/* We're building for an architecture that always has the intel + * intrinsics for carryless multiply. + * No need for runtime detection. + */ +#define PV_USE_PCLMUL_UNCONDITIONAL +#define PCLMUL_ANY + +#elif defined(PV_INTEL_ARCH) && SIZEOF_VOID_P >= 8 +/* We _might_ have PCLMUL, or we might not. + * We need to detect it at runtime. + */ +#define PV_USE_PCLMUL_DETECT +#define PCLMUL_ANY + +#elif SIZEOF_VOID_P >= 8 +/* It's a 64-bit architecture; use the generic 64-bit constant-time + * implementation. + */ +#define PV_USE_CTMUL64 +#elif SIZEOF_VOID_P == 4 +/* It's a 64-bit architecture; use the generic 32-bit constant-time + * implementation. + */ +#define PV_USE_CTMUL +#else +#error "sizeof(void*) is implausibly weird." +#endif + +#ifdef PCLMUL_ANY +#include + +#define POLYVAL_USE_EXPANDED_KEYS +#endif + +/** + * Declare a 128 bit integer type. + # The exact representation will depend on which implementation we've chosen. + */ +#if defined(PV_USE_PCLMUL_UNCONDITIONAL) +typedef __m128i pv_u128_; +#elif defined(PV_USE_PCLMUL_DETECT) +typedef union pv_u128_ { + __m128i u128x1; + struct { + uint64_t lo; + uint64_t hi; + } u64x2; +} pv_u128_; +#elif defined(PV_USE_CTMUL64) +typedef struct pv_u128_ { + uint64_t lo; + uint64_t hi; +} pv_u128_; +#elif defined(PV_USE_CTMUL) +typedef struct pv_u128_ { + uint32_t v[4]; +} pv_u128_; +#endif + +/** A key for a polyval hash, plus any precomputed key material. */ +typedef struct polyval_key_t { + pv_u128_ h; +} polyval_key_t; + +/** + * State for an instance of the polyval hash. + **/ +typedef struct polyval_t { + /** The key used for this instance of polyval. */ + polyval_key_t key; + /** The accumulator */ + pv_u128_ y; +} polyval_t; + +/** + * Length of a polyval key, in bytes. + */ +#define POLYVAL_KEY_LEN 16 +/** + * Length of a polyval block, in bytes. + */ +#define POLYVAL_BLOCK_LEN 16 +/** + * Length of a polyval tag (output), in bytes. + */ +#define POLYVAL_TAG_LEN 16 + +/** Do any necessary precomputation from a polyval key, + * and store it. + */ +void polyval_key_init(polyval_key_t *, const uint8_t *key); +/** + * Initialize a polyval instance with a given key. + */ +void polyval_init(polyval_t *, const uint8_t *key); +/** + * Initialize a polyval instance with a preconstructed key. + */ +void polyval_init_from_key(polyval_t *, const polyval_key_t *key); +/** + * Update a polyval instance with a new 16-byte block. + */ +void polyval_add_block(polyval_t *, const uint8_t *block); +/** + * Update a polyval instance with 'n' bytes from 'data'. + * If 'n' is not evenly divisible by 16, pad it at the end with zeros. + * + * NOTE: This is not a general-purpose padding construction; + * it can be insecure if your are using it in context where the input length + * is variable. + */ +void polyval_add_zpad(polyval_t *, const uint8_t *data, size_t n); +/** + * Copy the 16-byte tag from a polyval instance into 'tag_out' + */ +void polyval_get_tag(const polyval_t *, uint8_t *tag_out); +/** + * Reset a polyval instance to its original state, + * retaining its key. + */ +void polyval_reset(polyval_t *); + +/** If a faster-than-default polyval implementation is available, use it. */ +void polyval_detect_implementation(void); + +#ifdef POLYVAL_USE_EXPANDED_KEYS +/* These variations are as for polyval_\*, but they use pre-expanded keys. + * They're appropriate when you know a key is likely to get used more than once + * on a large input. + */ + +/** How many blocks to handle at once with an expanded key */ +#define PV_BLOCK_STRIDE 8 +typedef struct pv_expanded_key_t { + // powers of h in reverse order, down to 2. + // (in other words, contains + // h^PCLMUL_BLOCK_STRIDE .. H^2) + __m128i k[PV_BLOCK_STRIDE-1]; +} pv_expanded_key_t; +typedef struct polyvalx_t { + polyval_t pv; + pv_expanded_key_t expanded; +} polyvalx_t; + +void polyvalx_init(polyvalx_t *, const uint8_t *key); +void polyvalx_init_from_key(polyvalx_t *, const polyval_key_t *key); +void polyvalx_add_block(polyvalx_t *, const uint8_t *block); +void polyvalx_add_zpad(polyvalx_t *, const uint8_t *data, size_t n); +void polyvalx_get_tag(const polyvalx_t *, uint8_t *tag_out); +void polyvalx_reset(polyvalx_t *); + +#else +#define polyvalx_t polyval_t +#define polyvalx_key_init polyval_key_init +#define polyvalx_init polyval_init +#define polyvalx_init_from_key polyval_init_from_key +#define polyvalx_add_block polyval_add_block +#define polyvalx_add_zpad polyval_add_zpad +#define polyvalx_get_tag polyval_get_tag +#define polyvalx_reset polyval_reset +#endif + +#endif diff -Nru tor-0.4.7.16/src/feature/client/bridges.c tor-0.4.9.6/src/feature/client/bridges.c --- tor-0.4.7.16/src/feature/client/bridges.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/feature/client/bridges.c 2026-03-25 14:30:34.000000000 +0000 @@ -140,6 +140,41 @@ } /** + * Returns true if there are enough bridges to make a conflux set + * without re-using the same bridge. + */ +bool +conflux_can_exclude_used_bridges(void) +{ + if (smartlist_len(bridge_list_get()) == 1) { + static bool warned_once = false; + bridge_info_t *bridge = smartlist_get(bridge_list_get(), 0); + tor_assert(bridge); + + /* Snowflake is a special case. With one snowflake bridge, + * you are load balanced among many back-end bridges. + * So we do not need to warn the user for it. */ + if (bridge->transport_name && + strcasecmp(bridge->transport_name, "snowflake") == 0) { + return false; + } + + if (!warned_once) { + log_warn(LD_CIRC, "Only one bridge (transport: '%s') is configured. " + "You should have at least two for conflux, " + "for any transport that is not 'snowflake'.", + bridge->transport_name ? + bridge->transport_name : "vanilla"); + warned_once = true; + } + + return false; + } + + return true; +} + +/** * Given a bridge, return a pointer to its RSA identity digest, or * NULL if we don't know one for it. */ @@ -281,7 +316,8 @@ /** If we have a bridge configured whose digest matches * ei->identity_digest, or a bridge with no known digest whose address * matches ei->addr:ei->port, return 1. Else return 0. - * If ei->onion_key is NULL, check for address/port matches only. + * If ei has no onion key configured, check for address/port matches + * only. * * Note that if the extend_info_t contains multiple addresses, we return true * only if _every_ address is a bridge. @@ -289,7 +325,8 @@ int extend_info_is_a_configured_bridge(const extend_info_t *ei) { - const char *digest = ei->onion_key ? ei->identity_digest : NULL; + const char *digest = curve25519_public_key_is_ok(&ei->curve25519_onion_key) + ? ei->identity_digest : NULL; const tor_addr_port_t *ap1 = NULL, *ap2 = NULL; if (! tor_addr_is_null(&ei->orports[0].addr)) ap1 = &ei->orports[0]; diff -Nru tor-0.4.7.16/src/feature/client/bridges.h tor-0.4.9.6/src/feature/client/bridges.h --- tor-0.4.7.16/src/feature/client/bridges.h 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/feature/client/bridges.h 2026-03-25 14:30:34.000000000 +0000 @@ -67,6 +67,7 @@ (const char *digest)); void bridges_free_all(void); +bool conflux_can_exclude_used_bridges(void); #ifdef TOR_BRIDGES_PRIVATE STATIC void clear_bridge_list(void); diff -Nru tor-0.4.7.16/src/feature/client/circpathbias.c tor-0.4.9.6/src/feature/client/circpathbias.c --- tor-0.4.7.16/src/feature/client/circpathbias.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/feature/client/circpathbias.c 2026-03-25 14:30:34.000000000 +0000 @@ -34,10 +34,10 @@ #include "feature/client/entrynodes.h" #include "feature/nodelist/networkstatus.h" #include "core/or/relay.h" +#include "core/or/relay_msg.h" #include "lib/math/fp.h" #include "lib/math/laplace.h" -#include "core/or/cell_st.h" #include "core/or/cpath_build_state_st.h" #include "core/or/crypt_path_st.h" #include "core/or/extend_info_st.h" @@ -334,12 +334,23 @@ * endpoint could be chosen maliciously. * Similarly, we can't count client-side intro attempts, * because clients can be manipulated into connecting to - * malicious intro points. */ + * malicious intro points. + * + * Finally, avoid counting conflux circuits for now, because + * a malicious exit could cause us to reconnect and blame + * our guard... + * + * TODO-329-PURPOSE: This is not quite right, we could + * instead avoid sending usable probes on conflux circs, + * and count only linked circs as failures, but it is + * not 100% clear that would result in accurate counts. */ if (get_options()->UseEntryGuards == 0 || circ->base_.purpose == CIRCUIT_PURPOSE_TESTING || circ->base_.purpose == CIRCUIT_PURPOSE_CONTROLLER || circ->base_.purpose == CIRCUIT_PURPOSE_S_CONNECT_REND || circ->base_.purpose == CIRCUIT_PURPOSE_S_REND_JOINED || + circ->base_.purpose == CIRCUIT_PURPOSE_CONFLUX_UNLINKED || + circ->base_.purpose == CIRCUIT_PURPOSE_CONFLUX_LINKED || (circ->base_.purpose >= CIRCUIT_PURPOSE_C_INTRODUCING && circ->base_.purpose <= CIRCUIT_PURPOSE_C_INTRODUCE_ACKED)) { @@ -787,7 +798,7 @@ pathbias_send_usable_probe(circuit_t *circ) { /* Based on connection_ap_handshake_send_begin() */ - char payload[CELL_PAYLOAD_SIZE]; + char payload[RELAY_PAYLOAD_SIZE_MAX]; int payload_len; origin_circuit_t *ocirc = TO_ORIGIN_CIRCUIT(circ); crypt_path_t *cpath_layer = NULL; @@ -842,7 +853,7 @@ return -1; } - tor_snprintf(payload,RELAY_PAYLOAD_SIZE, "%s:25", probe_nonce); + tor_snprintf(payload,RELAY_PAYLOAD_SIZE_MAX, "%s:25", probe_nonce); payload_len = (int)strlen(payload)+1; // XXX: need this? Can we assume ipv4 will always be supported? @@ -892,41 +903,37 @@ * If the response is valid, return 0. Otherwise return < 0. */ int -pathbias_check_probe_response(circuit_t *circ, const cell_t *cell) +pathbias_check_probe_response(circuit_t *circ, const relay_msg_t *msg) { /* Based on connection_edge_process_relay_cell() */ - relay_header_t rh; int reason; uint32_t ipv4_host; origin_circuit_t *ocirc = TO_ORIGIN_CIRCUIT(circ); - tor_assert(cell); + tor_assert(msg); tor_assert(ocirc); tor_assert(circ->purpose == CIRCUIT_PURPOSE_PATH_BIAS_TESTING); - relay_header_unpack(&rh, cell->payload); + reason = msg->length > 0 ? get_uint8(msg->body) : END_STREAM_REASON_MISC; - reason = rh.length > 0 ? - get_uint8(cell->payload+RELAY_HEADER_SIZE) : END_STREAM_REASON_MISC; - - if (rh.command == RELAY_COMMAND_END && + if (msg->command == RELAY_COMMAND_END && reason == END_STREAM_REASON_EXITPOLICY && - ocirc->pathbias_probe_id == rh.stream_id) { + ocirc->pathbias_probe_id == msg->stream_id) { /* Check length+extract host: It is in network order after the reason code. * See connection_edge_end(). */ - if (rh.length < 9) { /* reason+ipv4+dns_ttl */ + if (msg->length < 9) { /* reason+ipv4+dns_ttl */ log_notice(LD_PROTOCOL, - "Short path bias probe response length field (%d).", rh.length); + "Short path bias probe response length field (%d).", msg->length); return - END_CIRC_REASON_TORPROTOCOL; } - ipv4_host = ntohl(get_uint32(cell->payload+RELAY_HEADER_SIZE+1)); + ipv4_host = ntohl(get_uint32(msg->body + 1)); /* Check nonce */ if (ipv4_host == ocirc->pathbias_probe_nonce) { pathbias_mark_use_success(ocirc); - circuit_read_valid_data(ocirc, rh.length); + circuit_read_valid_data(ocirc, msg->length); circuit_mark_for_close(circ, END_CIRC_REASON_FINISHED); log_info(LD_CIRC, "Got valid path bias probe back for circ %d, stream %d.", @@ -943,7 +950,7 @@ log_info(LD_CIRC, "Got another cell back back on pathbias probe circuit %d: " "Command: %d, Reason: %d, Stream-id: %d", - ocirc->global_identifier, rh.command, reason, rh.stream_id); + ocirc->global_identifier, msg->command, reason, msg->stream_id); return -1; } @@ -952,58 +959,54 @@ * and if so, count it as valid. */ void -pathbias_count_valid_cells(circuit_t *circ, const cell_t *cell) +pathbias_count_valid_cells(circuit_t *circ, const relay_msg_t *msg) { origin_circuit_t *ocirc = TO_ORIGIN_CIRCUIT(circ); - relay_header_t rh; - - relay_header_unpack(&rh, cell->payload); /* Check to see if this is a cell from a previous connection, * or is a request to close the circuit. */ - switch (rh.command) { + switch (msg->command) { case RELAY_COMMAND_TRUNCATED: /* Truncated cells can arrive on path bias circs. When they do, * just process them. This closes the circ, but it was junk anyway. * No reason to wait for the probe. */ - circuit_read_valid_data(ocirc, rh.length); - circuit_truncated(TO_ORIGIN_CIRCUIT(circ), - get_uint8(cell->payload + RELAY_HEADER_SIZE)); + circuit_read_valid_data(ocirc, msg->length); + circuit_truncated(TO_ORIGIN_CIRCUIT(circ), get_uint8(msg->body)); break; case RELAY_COMMAND_END: if (connection_half_edge_is_valid_end(ocirc->half_streams, - rh.stream_id)) { - circuit_read_valid_data(TO_ORIGIN_CIRCUIT(circ), rh.length); + msg->stream_id)) { + circuit_read_valid_data(TO_ORIGIN_CIRCUIT(circ), msg->length); } break; case RELAY_COMMAND_DATA: if (connection_half_edge_is_valid_data(ocirc->half_streams, - rh.stream_id)) { - circuit_read_valid_data(TO_ORIGIN_CIRCUIT(circ), rh.length); + msg->stream_id)) { + circuit_read_valid_data(TO_ORIGIN_CIRCUIT(circ), msg->length); } break; case RELAY_COMMAND_SENDME: if (connection_half_edge_is_valid_sendme(ocirc->half_streams, - rh.stream_id)) { - circuit_read_valid_data(TO_ORIGIN_CIRCUIT(circ), rh.length); + msg->stream_id)) { + circuit_read_valid_data(TO_ORIGIN_CIRCUIT(circ), msg->length); } break; case RELAY_COMMAND_CONNECTED: if (connection_half_edge_is_valid_connected(ocirc->half_streams, - rh.stream_id)) { - circuit_read_valid_data(TO_ORIGIN_CIRCUIT(circ), rh.length); + msg->stream_id)) { + circuit_read_valid_data(TO_ORIGIN_CIRCUIT(circ), msg->length); } break; case RELAY_COMMAND_RESOLVED: if (connection_half_edge_is_valid_resolved(ocirc->half_streams, - rh.stream_id)) { - circuit_read_valid_data(TO_ORIGIN_CIRCUIT(circ), rh.length); + msg->stream_id)) { + circuit_read_valid_data(TO_ORIGIN_CIRCUIT(circ), msg->length); } break; } diff -Nru tor-0.4.7.16/src/feature/client/circpathbias.h tor-0.4.9.6/src/feature/client/circpathbias.h --- tor-0.4.7.16/src/feature/client/circpathbias.h 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/feature/client/circpathbias.h 2026-03-25 14:30:34.000000000 +0000 @@ -12,6 +12,8 @@ #ifndef TOR_CIRCPATHBIAS_H #define TOR_CIRCPATHBIAS_H +#include "core/or/relay_msg_st.h" + double pathbias_get_extreme_rate(const or_options_t *options); double pathbias_get_extreme_use_rate(const or_options_t *options); int pathbias_get_dropguards(const or_options_t *options); @@ -19,8 +21,8 @@ void pathbias_count_build_success(origin_circuit_t *circ); int pathbias_count_build_attempt(origin_circuit_t *circ); int pathbias_check_close(origin_circuit_t *circ, int reason); -int pathbias_check_probe_response(circuit_t *circ, const cell_t *cell); -void pathbias_count_valid_cells(circuit_t *circ, const cell_t *cell); +int pathbias_check_probe_response(circuit_t *circ, const relay_msg_t *msg); +void pathbias_count_valid_cells(circuit_t *circ, const relay_msg_t *msg); void pathbias_count_use_attempt(origin_circuit_t *circ); void pathbias_mark_use_success(origin_circuit_t *circ); void pathbias_mark_use_rollback(origin_circuit_t *circ); diff -Nru tor-0.4.7.16/src/feature/client/dnsserv.c tor-0.4.9.6/src/feature/client/dnsserv.c --- tor-0.4.7.16/src/feature/client/dnsserv.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/feature/client/dnsserv.c 2026-03-25 14:30:34.000000000 +0000 @@ -319,6 +319,7 @@ break; case RESOLVED_TYPE_ERROR: case RESOLVED_TYPE_ERROR_TRANSIENT: + case RESOLVED_TYPE_NOERROR: /* Addr doesn't matter, since we're not sending it back in the reply.*/ return addr; default: @@ -379,6 +380,8 @@ tor_free(ans); } else if (answer_type == RESOLVED_TYPE_ERROR) { err = DNS_ERR_NOTEXIST; + } else if (answer_type == RESOLVED_TYPE_NOERROR) { + err = DNS_ERR_NONE; } else { /* answer_type == RESOLVED_TYPE_ERROR_TRANSIENT */ err = DNS_ERR_SERVERFAILED; } diff -Nru tor-0.4.7.16/src/feature/client/entrynodes.c tor-0.4.9.6/src/feature/client/entrynodes.c --- tor-0.4.7.16/src/feature/client/entrynodes.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/feature/client/entrynodes.c 2026-03-25 14:30:34.000000000 +0000 @@ -126,6 +126,7 @@ #include "core/or/circuitlist.h" #include "core/or/circuitstats.h" #include "core/or/circuituse.h" +#include "core/or/conflux_pool.h" #include "core/or/policies.h" #include "feature/client/bridges.h" #include "feature/client/circpathbias.h" @@ -152,6 +153,8 @@ #include "app/config/or_state_st.h" #include "src/feature/nodelist/routerstatus_st.h" +#include "core/or/conflux_util.h" + /** A list of existing guard selection contexts. */ static smartlist_t *guard_contexts = NULL; /** The currently enabled guard selection context. */ @@ -611,7 +614,7 @@ } /* Called when we exhaust all guards in our sampled set: Marks all guards as - maybe-reachable so that we 'll try them again. */ + maybe-reachable so that we'll try them again. */ static void mark_all_guards_maybe_reachable(guard_selection_t *gs) { @@ -1059,7 +1062,7 @@ } /** - * Return a smartlist of the all the guards that are not currently + * Return a smartlist of all the guards that are not currently * members of the sample (GUARDS - SAMPLED_GUARDS). The elements of * this list are node_t pointers in the non-bridge case, and * bridge_info_t pointers in the bridge case. Set *n_guards_out @@ -1589,6 +1592,21 @@ return rst; } +/* Allocate and return a new exit guard restriction that excludes all current + * and pending conflux guards */ +STATIC entry_guard_restriction_t * +guard_create_conflux_restriction(const origin_circuit_t *circ, + const uint8_t *exit_id) +{ + entry_guard_restriction_t *rst = NULL; + rst = tor_malloc_zero(sizeof(entry_guard_restriction_t)); + rst->type = RST_EXCL_LIST; + rst->excluded = smartlist_new(); + conflux_add_guards_to_exclude_list(circ, rst->excluded); + memcpy(rst->exclude_id, exit_id, DIGEST_LEN); + return rst; +} + /** If we have fewer than this many possible usable guards, don't set * MD-availability-based restrictions: we might denylist all of them. */ #define MIN_GUARDS_FOR_MD_RESTRICTION 10 @@ -1637,7 +1655,8 @@ guard_obeys_exit_restriction(const entry_guard_t *guard, const entry_guard_restriction_t *rst) { - tor_assert(rst->type == RST_EXIT_NODE); + tor_assert(rst->type == RST_EXIT_NODE || + rst->type == RST_EXCL_LIST); // Exclude the exit ID and all of its family. const node_t *node = node_get_by_id((const char*)rst->exclude_id); @@ -1666,6 +1685,17 @@ } /** + * Return true if a restriction is reachability related, such that it should + * cause us to consider additional primary guards when selecting one. + */ +static bool +entry_guard_restriction_is_reachability(const entry_guard_restriction_t *rst) +{ + tor_assert(rst); + return (rst->type == RST_OUTDATED_MD_DIRSERVER); +} + +/** * Return true iff guard obeys the restrictions defined in rst. * (If rst is NULL, there are no restrictions.) */ @@ -1681,6 +1711,9 @@ return guard_obeys_exit_restriction(guard, rst); } else if (rst->type == RST_OUTDATED_MD_DIRSERVER) { return guard_obeys_md_dirserver_restriction(guard); + } else if (rst->type == RST_EXCL_LIST) { + return guard_obeys_exit_restriction(guard, rst) && + !smartlist_contains_digest(rst->excluded, guard->identity); } tor_assert_nonfatal_unreached(); @@ -1896,7 +1929,7 @@ guard->confirmed_idx = gs->next_confirmed_idx++; smartlist_add(gs->confirmed_entry_guards, guard); - /** The confirmation ordering might not be the sample ording. We need to + /** The confirmation ordering might not be the sample ordering. We need to * reorder */ smartlist_sort(gs->confirmed_entry_guards, compare_guards_by_sampled_idx); @@ -2109,14 +2142,44 @@ const int need_descriptor = (usage == GUARD_USAGE_TRAFFIC); entry_guard_t *chosen_guard = NULL; - int num_entry_guards = get_n_primary_guards_to_use(usage); + int num_entry_guards_to_consider = get_n_primary_guards_to_use(usage); smartlist_t *usable_primary_guards = smartlist_new(); + int num_entry_guards_considered = 0; SMARTLIST_FOREACH_BEGIN(gs->primary_entry_guards, entry_guard_t *, guard) { entry_guard_consider_retry(guard); if (!entry_guard_obeys_restriction(guard, rst)) { log_info(LD_GUARD, "Entry guard %s doesn't obey restriction, we test the" " next one", entry_guard_describe(guard)); + if (!entry_guard_restriction_is_reachability(rst)) { + log_info(LD_GUARD, + "Skipping guard %s due to circuit path restriction. " + "Have %d, considered: %d, to consider: %d", + entry_guard_describe(guard), + smartlist_len(usable_primary_guards), + num_entry_guards_considered, + num_entry_guards_to_consider); + /* If the restriction is a circuit path restriction (as opposed to a + * reachability restriction), count this as considered. */ + num_entry_guards_considered++; + + /* If we have considered enough guards, *and* we actually have a guard, + * then proceed to select one from the list. */ + if (num_entry_guards_considered >= num_entry_guards_to_consider) { + /* This should not happen with 2-leg conflux unless there is a + * race between removing a failed leg and a retry, but check + * anyway and log. */ + if (smartlist_len(usable_primary_guards) == 0) { + static ratelim_t guardlog = RATELIM_INIT(60); + log_fn_ratelim(&guardlog, LOG_NOTICE, LD_GUARD, + "All current guards excluded by path restriction " + "type %d; using an additional guard.", + rst->type); + } else { + break; + } + } + } continue; } if (guard->is_reachable != GUARD_REACHABLE_NO) { @@ -2128,8 +2191,16 @@ *state_out = GUARD_CIRC_STATE_USABLE_ON_COMPLETION; guard->last_tried_to_connect = approx_time(); smartlist_add(usable_primary_guards, guard); - if (smartlist_len(usable_primary_guards) >= num_entry_guards) + num_entry_guards_considered++; + + /* If we have considered enough guards, then proceed to select + * one from the list. */ + if (num_entry_guards_considered >= num_entry_guards_to_consider) { break; + } + } else { + log_info(LD_GUARD, "Guard %s is not reachable", + entry_guard_describe(guard)); } } SMARTLIST_FOREACH_END(guard); @@ -2139,6 +2210,10 @@ "Selected primary guard %s for circuit from a list size of %d.", entry_guard_describe(chosen_guard), smartlist_len(usable_primary_guards)); + /* Describe each guard in the list: */ + SMARTLIST_FOREACH_BEGIN(usable_primary_guards, entry_guard_t *, guard) { + log_info(LD_GUARD, " %s", entry_guard_describe(guard)); + } SMARTLIST_FOREACH_END(guard); smartlist_free(usable_primary_guards); } @@ -2244,16 +2319,22 @@ /* "If any entry in PRIMARY_GUARDS has {is_reachable} status of or , return the first such guard." */ chosen_guard = select_primary_guard_for_circuit(gs, usage, rst, state_out); - if (chosen_guard) + if (chosen_guard) { + log_info(LD_GUARD, "Selected primary guard %s for circuit.", + entry_guard_describe(chosen_guard)); return chosen_guard; + } /* "Otherwise, if the ordered intersection of {CONFIRMED_GUARDS} and {USABLE_FILTERED_GUARDS} is nonempty, return the first entry in that intersection that has {is_pending} set to false." */ chosen_guard = select_confirmed_guard_for_circuit(gs, usage, rst, state_out); - if (chosen_guard) + if (chosen_guard) { + log_info(LD_GUARD, "Selected confirmed guard %s for circuit.", + entry_guard_describe(chosen_guard)); return chosen_guard; + } /* "Otherwise, if there is no such entry, select a member * {USABLE_FILTERED_GUARDS} following the sample ordering" */ @@ -2266,6 +2347,8 @@ return NULL; } + log_info(LD_GUARD, "Selected filtered guard %s for circuit.", + entry_guard_describe(chosen_guard)); return chosen_guard; } @@ -2428,6 +2511,11 @@ STATIC void entry_guard_restriction_free_(entry_guard_restriction_t *rst) { + if (rst && rst->excluded) { + SMARTLIST_FOREACH(rst->excluded, void *, g, + tor_free(g)); + smartlist_free(rst->excluded); + } tor_free(rst); } @@ -3781,7 +3869,8 @@ /** Helper: pick a guard for a circuit, with whatever algorithm is used. */ const node_t * -guards_choose_guard(cpath_build_state_t *state, +guards_choose_guard(const origin_circuit_t *circ, + cpath_build_state_t *state, uint8_t purpose, circuit_guard_state_t **guard_state_out) { @@ -3789,14 +3878,19 @@ const uint8_t *exit_id = NULL; entry_guard_restriction_t *rst = NULL; - /* Only apply restrictions if we have a specific exit node in mind, and only - * if we are not doing vanguard circuits: we don't want to apply guard - * restrictions to vanguard circuits. */ - if (state && !circuit_should_use_vanguards(purpose) && + /* If we this is a conflux circuit, build an exclusion list for it. */ + if (CIRCUIT_IS_CONFLUX(TO_CIRCUIT(circ)) && state + && (exit_id = build_state_get_exit_rsa_id(state))) { + rst = guard_create_conflux_restriction(circ, exit_id); + /* Don't allow connecting back to the exit if there is one */ + if (state && (exit_id = build_state_get_exit_rsa_id(state))) { + /* add the exit_id to the excluded list */ + smartlist_add(rst->excluded, tor_memdup(exit_id, DIGEST_LEN)); + } + } else if (state && !circuit_should_use_vanguards(purpose) && (exit_id = build_state_get_exit_rsa_id(state))) { /* We're building to a targeted exit node, so that node can't be - * chosen as our guard for this circuit. Remember that fact in a - * restriction. */ + * chosen as our guard for this circuit, unless we're vanguards. */ rst = guard_create_exit_restriction(exit_id); tor_assert(rst); } diff -Nru tor-0.4.7.16/src/feature/client/entrynodes.h tor-0.4.9.6/src/feature/client/entrynodes.h --- tor-0.4.7.16/src/feature/client/entrynodes.h 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/feature/client/entrynodes.h 2026-03-25 14:30:34.000000000 +0000 @@ -294,7 +294,9 @@ /* Don't pick the same guard node as our exit node (or its family) */ RST_EXIT_NODE = 0, /* Don't pick dirguards that have previously shown to be outdated */ - RST_OUTDATED_MD_DIRSERVER = 1 + RST_OUTDATED_MD_DIRSERVER = 1, + /* Don't pick guards if they are in the exclusion list */ + RST_EXCL_LIST = 2, } guard_restriction_type_t; /** @@ -312,6 +314,10 @@ * digest must not equal this; and it must not be in the same family as any * node with this digest. */ uint8_t exclude_id[DIGEST_LEN]; + + /* In the case of RST_EXCL_LIST, any identity digests in this list + * must not be used. */ + smartlist_t *excluded; }; /** @@ -337,7 +343,8 @@ /* Common entry points for old and new guard code */ int guards_update_all(void); -const node_t *guards_choose_guard(cpath_build_state_t *state, +const node_t *guards_choose_guard(const origin_circuit_t *circ, + cpath_build_state_t *state, uint8_t purpose, circuit_guard_state_t **guard_state_out); const node_t *guards_choose_dirguard(uint8_t dir_purpose, @@ -597,6 +604,9 @@ STATIC entry_guard_restriction_t *guard_create_dirserver_md_restriction(void); +STATIC entry_guard_restriction_t * guard_create_conflux_restriction( + const origin_circuit_t *circ, const uint8_t *exit_id); + STATIC void entry_guard_restriction_free_(entry_guard_restriction_t *rst); #define entry_guard_restriction_free(rst) \ FREE_AND_NULL(entry_guard_restriction_t, \ diff -Nru tor-0.4.7.16/src/feature/client/include.am tor-0.4.9.6/src/feature/client/include.am --- tor-0.4.7.16/src/feature/client/include.am 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/feature/client/include.am 2026-03-25 14:30:34.000000000 +0000 @@ -1,6 +1,6 @@ # ADD_C_FILE: INSERT SOURCES HERE. -LIBTOR_APP_A_SOURCES += \ +LIBTOR_APP_A_SOURCES += \ src/feature/client/addressmap.c \ src/feature/client/bridges.c \ src/feature/client/circpathbias.c \ diff -Nru tor-0.4.7.16/src/feature/client/transports.c tor-0.4.9.6/src/feature/client/transports.c --- tor-0.4.7.16/src/feature/client/transports.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/feature/client/transports.c 2026-03-25 14:30:34.000000000 +0000 @@ -89,12 +89,15 @@ * old transports from the circuitbuild.c subsystem. **/ +#include "lib/string/printf.h" +#include "lib/evloop/compat_libevent.h" #define PT_PRIVATE #include "core/or/or.h" #include "feature/client/bridges.h" #include "app/config/config.h" #include "core/mainloop/connection.h" #include "core/or/circuitbuild.h" +#include "feature/hibernate/hibernate.h" #include "feature/client/transports.h" #include "feature/relay/router.h" #include "feature/relay/relay_find_addr.h" @@ -491,7 +494,9 @@ launched: */ tor_assert(smartlist_len(mp->transports_to_launch) > 0); - tor_assert(mp->conf_state == PT_PROTO_COMPLETED); + if (BUG(mp->conf_state != PT_PROTO_COMPLETED)) { + goto needs_restart; + } if (smartlist_len(mp->transports_to_launch) != smartlist_len(mp->transports)) goto needs_restart; @@ -516,11 +521,22 @@ { transport_t *t_tmp = NULL; - tor_assert(mp->conf_state == PT_PROTO_COMPLETED); + /* Rate limit this log as a regurlarly dying PT would log this once every + * second (retry time). Every 5 minutes is likely loud enough to notice. */ + static ratelim_t log_died_lim = RATELIM_INIT(300); + log_fn_ratelim(&log_died_lim, LOG_WARN, LD_PT, + "Managed proxy at '%s' died in state %s", mp->argv[0], + managed_proxy_state_to_string(mp->conf_state)); /* destroy the process handle and terminate the process. */ - process_set_data(mp->process, NULL); - process_terminate(mp->process); + if (mp->process) { + process_set_data(mp->process, NULL); + if (we_are_shutting_down()) + log_notice(LD_CONFIG, "Managed proxy \"%s\" having PID %" PRIu64 " " + "is being terminated...", mp->argv[0], + process_get_pid(mp->process)); + process_terminate(mp->process); + } /* destroy all its registered transports, since we will no longer use them. */ @@ -540,9 +556,11 @@ mp->proxy_uri = get_pt_proxy_uri(); mp->proxy_supported = 0; + if (mp->conf_state == PT_PROTO_COMPLETED) + unconfigured_proxies_n++; + /* flag it as an infant proxy so that it gets launched on next tick */ - mp->conf_state = PT_PROTO_INFANT; - unconfigured_proxies_n++; + managed_proxy_set_state(mp, PT_PROTO_INFANT); } /** Launch managed proxy mp. */ @@ -554,6 +572,8 @@ smartlist_t *env = create_managed_proxy_environment(mp); /* Configure our process. */ + tor_assert(mp->process == NULL); + mp->process = process_new(mp->argv[0]); process_set_data(mp->process, mp); process_set_stdout_read_callback(mp->process, managed_proxy_stdout_callback); process_set_stderr_read_callback(mp->process, managed_proxy_stderr_callback); @@ -578,7 +598,7 @@ log_info(LD_CONFIG, "Managed proxy at '%s' has spawned with PID '%" PRIu64 "'.", mp->argv[0], process_get_pid(mp->process)); - mp->conf_state = PT_PROTO_LAUNCHED; + managed_proxy_set_state(mp, PT_PROTO_LAUNCHED); return 0; } @@ -638,6 +658,25 @@ mark_my_descriptor_dirty("configured managed proxies"); } +/** event callback to launch managed proxy after a delay */ +STATIC void +launch_proxy_ev(mainloop_event_t *event, void *v) +{ + managed_proxy_t *mp = v; + + (void) event; + + tor_assert(mp); + if (BUG(mp->conf_state != PT_PROTO_WAITING)) { + return; + } + + if (launch_managed_proxy(mp) < 0) { /* launch fail */ + managed_proxy_set_state(mp, PT_PROTO_FAILED_LAUNCH); + handle_finished_proxy(mp); + } +} + /** Attempt to continue configuring managed proxy mp. * Return 1 if the transport configuration finished, and return 0 * otherwise (if we still have more configuring to do for this @@ -647,10 +686,13 @@ { /* if we haven't launched the proxy yet, do it now */ if (mp->conf_state == PT_PROTO_INFANT) { - if (launch_managed_proxy(mp) < 0) { /* launch fail */ - mp->conf_state = PT_PROTO_FAILED_LAUNCH; - handle_finished_proxy(mp); + const struct timeval delay_tv = { 1, 0 }; + if (!mp->process_launch_ev) { + mp->process_launch_ev = mainloop_event_new(launch_proxy_ev, mp); } + mainloop_event_schedule(mp->process_launch_ev, &delay_tv); + managed_proxy_set_state(mp, PT_PROTO_WAITING); + return 0; } @@ -671,6 +713,7 @@ t->name, fmt_addrport(&t->addr, t->port)); control_event_transport_launched("server", t->name, &t->addr, t->port); } SMARTLIST_FOREACH_END(t); + pt_update_bridge_lines(); } /** Register all the transports supported by client managed proxy @@ -737,6 +780,10 @@ /* free the outgoing proxy URI */ tor_free(mp->proxy_uri); + /* free our version, if any is set. */ + tor_free(mp->version); + tor_free(mp->implementation); + /* do we want to terminate our process if it's still running? */ if (also_terminate_process && mp->process) { /* Note that we do not call process_free(mp->process) here because we let @@ -746,6 +793,9 @@ process_terminate(mp->process); } + if (mp->process_launch_ev) + mainloop_event_free(mp->process_launch_ev); + tor_free(mp); } @@ -810,10 +860,15 @@ managed_proxy_destroy(mp, 1); /* annihilate it. */ break; } - register_proxy(mp); /* register its transports */ - mp->conf_state = PT_PROTO_COMPLETED; /* and mark it as completed. */ + + /* register its transports */ + register_proxy(mp); + + /* and mark it as completed. */ + managed_proxy_set_state(mp, PT_PROTO_COMPLETED); break; case PT_PROTO_INFANT: + case PT_PROTO_WAITING: case PT_PROTO_LAUNCHED: case PT_PROTO_ACCEPTING_METHODS: case PT_PROTO_COMPLETED: @@ -857,7 +912,7 @@ STATIC void handle_proxy_line(const char *line, managed_proxy_t *mp) { - log_info(LD_GENERAL, "Got a line from managed proxy '%s': (%s)", + log_info(LD_PT, "Got a line from managed proxy '%s': (%s)", mp->argv[0], line); if (!strcmpstart(line, PROTO_ENV_ERROR)) { @@ -881,7 +936,7 @@ goto err; tor_assert(mp->conf_protocol != 0); - mp->conf_state = PT_PROTO_ACCEPTING_METHODS; + managed_proxy_set_state(mp, PT_PROTO_ACCEPTING_METHODS); return; } else if (!strcmpstart(line, PROTO_CMETHODS_DONE)) { if (mp->conf_state != PT_PROTO_ACCEPTING_METHODS) @@ -889,7 +944,7 @@ handle_methods_done(mp); - mp->conf_state = PT_PROTO_CONFIGURED; + managed_proxy_set_state(mp, PT_PROTO_CONFIGURED); return; } else if (!strcmpstart(line, PROTO_SMETHODS_DONE)) { if (mp->conf_state != PT_PROTO_ACCEPTING_METHODS) @@ -897,7 +952,7 @@ handle_methods_done(mp); - mp->conf_state = PT_PROTO_CONFIGURED; + managed_proxy_set_state(mp, PT_PROTO_CONFIGURED); return; } else if (!strcmpstart(line, PROTO_CMETHOD_ERROR)) { if (mp->conf_state != PT_PROTO_ACCEPTING_METHODS) @@ -968,7 +1023,7 @@ return; err: - mp->conf_state = PT_PROTO_BROKEN; + managed_proxy_set_state(mp, PT_PROTO_BROKEN); log_warn(LD_CONFIG, "Managed proxy at '%s' failed the configuration protocol" " and will be destroyed.", mp->argv[0]); } @@ -1275,15 +1330,8 @@ goto done; } - /* We check if we received the TRANSPORT parameter, which is the only - * *required* value. */ - const config_line_t *type = config_line_find(values, "TRANSPORT"); - - if (! type) { - log_warn(LD_PT, "Managed proxy \"%s\" wrote a STATUS line without " - "TRANSPORT: %s", mp->argv[0], escaped(data)); - goto done; - } + /* Handle the different messages. */ + handle_status_message(values, mp); /* Prepend the PT name. */ config_line_prepend(&values, "PT", mp->argv[0]); @@ -1298,6 +1346,52 @@ tor_free(status_message); } +STATIC void +handle_status_message(const config_line_t *values, + managed_proxy_t *mp) +{ + if (config_count_key(values, "TYPE") > 1) { + log_warn(LD_PT, "Managed proxy \"%s\" has multiple TYPE key which " + "is not allowed.", mp->argv[0]); + return; + } + const config_line_t *message_type = config_line_find(values, "TYPE"); + + /* Check if we have a TYPE field? */ + if (message_type == NULL) { + log_debug(LD_PT, "Managed proxy \"%s\" wrote a STATUS line without " + "a defined message TYPE", mp->argv[0]); + return; + } + + /* Handle VERSION messages. */ + if (! strcasecmp(message_type->value, "version")) { + const config_line_t *version = config_line_find(values, "VERSION"); + const config_line_t *implementation = config_line_find(values, + "IMPLEMENTATION"); + + if (version == NULL) { + log_warn(LD_PT, "Managed proxy \"%s\" wrote a STATUS TYPE=version line " + "with a missing VERSION field", mp->argv[0]); + return; + } + + if (implementation == NULL) { + log_warn(LD_PT, "Managed proxy \"%s\" wrote a STATUS TYPE=version line " + "with a missing IMPLEMENTATION field", mp->argv[0]); + return; + } + + tor_free(mp->version); + mp->version = tor_strdup(version->value); + + tor_free(mp->implementation); + mp->implementation = tor_strdup(implementation->value); + + return; + } +} + /** Return a newly allocated string that tor should place in * TOR_PT_SERVER_TRANSPORT_OPTIONS while configuring the server * manged proxy in mp. Return NULL if no such options are found. */ @@ -1529,12 +1623,14 @@ char **proxy_argv, int is_server) { managed_proxy_t *mp = tor_malloc_zero(sizeof(managed_proxy_t)); - mp->conf_state = PT_PROTO_INFANT; + managed_proxy_set_state(mp, PT_PROTO_INFANT); mp->is_server = is_server; mp->argv = proxy_argv; mp->transports = smartlist_new(); mp->proxy_uri = get_pt_proxy_uri(); - mp->process = process_new(proxy_argv[0]); + + /* Gets set in launch_managed_proxy(). */ + mp->process = NULL; mp->transports_to_launch = smartlist_new(); SMARTLIST_FOREACH(with_transport_list, const char *, transport, @@ -1738,9 +1834,28 @@ "transport %s %s%s", t->name, addrport, transport_args ? transport_args : ""); + tor_free(transport_args); } SMARTLIST_FOREACH_END(t); + /* Set transport-info line. */ + { + char *version = NULL; + char *impl = NULL; + + if (mp->version) { + tor_asprintf(&version, " version=%s", mp->version); + } + if (mp->implementation) { + tor_asprintf(&impl, " implementation=%s", mp->implementation); + } + /* Always put in the line even if empty. Else, we don't know to which + * transport this applies to. */ + smartlist_add_asprintf(string_chunks, "transport-info%s%s", + version ? version: "", impl ? impl: ""); + tor_free(version); + tor_free(impl); + } } SMARTLIST_FOREACH_END(mp); if (smartlist_len(string_chunks) == 0) { @@ -1757,6 +1872,92 @@ return the_string; } +/** Log the bridge lines that clients can use to connect. */ +void +pt_update_bridge_lines(void) +{ + char fingerprint[FINGERPRINT_LEN+1]; + smartlist_t *string_chunks = NULL; + + if (!server_identity_key_is_set() || !managed_proxy_list) + return; + + if (crypto_pk_get_fingerprint(get_server_identity_key(), fingerprint, 0)<0) { + log_err(LD_BUG, "Error computing fingerprint"); + return; + } + + string_chunks = smartlist_new(); + + SMARTLIST_FOREACH_BEGIN(managed_proxy_list, const managed_proxy_t *, mp) { + if (!mp->is_server) + continue; + + tor_assert(mp->transports); + + SMARTLIST_FOREACH_BEGIN(mp->transports, const transport_t *, t) { + char *transport_args = NULL; + const char *saddr = NULL; + + /* If the transport proxy returned "0.0.0.0" as its address, display + * our external address if we know it, or a placeholder if we don't */ + if (tor_addr_is_null(&t->addr)) { + tor_addr_t addr; + /* Attempt to find the IPv4 and then attempt to find the IPv6 if we + * can't find it. */ + bool found = relay_find_addr_to_publish(get_options(), AF_INET, + RELAY_FIND_ADDR_NO_FLAG, + &addr); + if (!found) { + found = relay_find_addr_to_publish(get_options(), AF_INET6, + RELAY_FIND_ADDR_NO_FLAG, &addr); + } + if (found && !tor_addr_is_null(&addr)) { + saddr = fmt_and_decorate_addr(&addr); + } else { + saddr = ""; + } + } else { + saddr = fmt_and_decorate_addr(&t->addr); + } + + /* If this transport has any arguments with it, prepend a space + * to them so that we can add them to the transport line, and replace + * commas with spaces to make it a valid bridge line. */ + if (t->extra_info_args) { + tor_asprintf(&transport_args, " %s", t->extra_info_args); + for (int i = 0; transport_args[i]; i++) { + if (transport_args[i] == ',') { + transport_args[i] = ' '; + } + } + } + + smartlist_add_asprintf(string_chunks, "Bridge %s %s:%d %s%s", + t->name, saddr, t->port, fingerprint, + transport_args ? transport_args : ""); + tor_free(transport_args); + } SMARTLIST_FOREACH_END(t); + } SMARTLIST_FOREACH_END(mp); + + /* If we have any valid bridgelines, join them into a single string, and + * save them to disk. Don't create an empty file. */ + if (smartlist_len(string_chunks) != 0) { + char *str = smartlist_join_strings(string_chunks, "\n", 1, NULL); + char *fname = get_datadir_fname("bridgelines"); + if (write_str_to_file_if_not_equal(fname, str)) { + log_warn(LD_FS, "Couldn't save bridge lines to disk"); + } else { + log_info(LD_FS, "Saved bridge lines to disk"); + } + tor_free(fname); + tor_free(str); + } + + SMARTLIST_FOREACH(string_chunks, char *, s, tor_free(s)); + smartlist_free(string_chunks); +} + /** Stringify the SOCKS arguments in socks_args according to * 180_pluggable_transport.txt. The string is allocated on the heap * and it's the responsibility of the caller to free it after use. */ @@ -1945,9 +2146,30 @@ { tor_assert(process); - log_warn(LD_PT, - "Pluggable Transport process terminated with status code %" PRIu64, - exit_code); + managed_proxy_t *mp = process_get_data(process); + const char *name = mp ? mp->argv[0] : "N/A"; + + if (!we_are_shutting_down()) + log_warn(LD_PT, "Managed proxy \"%s\" having PID %" PRIu64 " " + "terminated with status code %" PRIu64, + name, process_get_pid(process), exit_code); + else + log_notice(LD_PT, "Managed proxy \"%s\" having PID %" PRIu64 " " + "has exited.", name, process_get_pid(process)); + + if (mp) { + /* We remove this process_t from the mp. */ + tor_assert(mp->process == process); + mp->process = NULL; + + /* Prepare the proxy for restart. */ + proxy_prepare_for_restart(mp); + + if (!we_are_shutting_down()) { + /* We have proxies we want to restart? */ + pt_configure_remaining_proxies(); + } + } /* Returning true here means that the process subsystem will take care of * calling process_free() on our process_t. */ @@ -2023,3 +2245,47 @@ /* The user have not specified a preference for outgoing connections. */ return NULL; } + +STATIC const char * +managed_proxy_state_to_string(enum pt_proto_state state) +{ + switch (state) { + case PT_PROTO_INFANT: + return "Infant"; + case PT_PROTO_WAITING: + return "Waiting"; + case PT_PROTO_LAUNCHED: + return "Launched"; + case PT_PROTO_ACCEPTING_METHODS: + return "Accepting methods"; + case PT_PROTO_CONFIGURED: + return "Configured"; + case PT_PROTO_COMPLETED: + return "Completed"; + case PT_PROTO_BROKEN: + return "Broken"; + case PT_PROTO_FAILED_LAUNCH: + return "Failed to launch"; + } + + /* LCOV_EXCL_START */ + tor_assert_unreached(); + return NULL; + /* LCOV_EXCL_STOP */ +} + +/** Set the internal state of the given mp to the given new_state + * value. */ +STATIC void +managed_proxy_set_state(managed_proxy_t *mp, enum pt_proto_state new_state) +{ + if (mp->conf_state == new_state) + return; + + tor_log(LOG_INFO, LD_PT, "Managed proxy \"%s\" changed state: %s -> %s", + mp->argv[0], + managed_proxy_state_to_string(mp->conf_state), + managed_proxy_state_to_string(new_state)); + + mp->conf_state = new_state; +} diff -Nru tor-0.4.7.16/src/feature/client/transports.h tor-0.4.9.6/src/feature/client/transports.h --- tor-0.4.7.16/src/feature/client/transports.h 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/feature/client/transports.h 2026-03-25 14:30:34.000000000 +0000 @@ -57,6 +57,7 @@ int pt_proxies_configuration_pending(void); char *pt_get_extra_info_descriptor_string(void); +void pt_update_bridge_lines(void); void pt_free_all(void); @@ -76,6 +77,7 @@ /** State of the managed proxy configuration protocol. */ enum pt_proto_state { PT_PROTO_INFANT, /* was just born */ + PT_PROTO_WAITING, /* waiting to be launched */ PT_PROTO_LAUNCHED, /* was just launched */ PT_PROTO_ACCEPTING_METHODS, /* accepting methods */ PT_PROTO_CONFIGURED, /* configured successfully */ @@ -100,6 +102,9 @@ /* A pointer to the process of this managed proxy. */ struct process_t *process; + /* timer event to launch proxy */ + struct mainloop_event_t *process_launch_ev; + /** Boolean: We are re-parsing our config, and we are going to * remove this managed proxy if we don't find it any transport * plugins that use it. */ @@ -114,11 +119,19 @@ /* transports to-be-launched by this proxy */ smartlist_t *transports_to_launch; + /** Version as set by STATUS TYPE=version messages. */ + char *version; + + /** Implementation as set by the STATUS TYPE=version messages. */ + char *implementation; + /* The 'transports' list contains all the transports this proxy has launched. */ smartlist_t *transports; } managed_proxy_t; +struct config_line_t; + STATIC transport_t *transport_new(const tor_addr_t *addr, uint16_t port, const char *name, int socks_ver, const char *extra_info_args); @@ -131,6 +144,8 @@ STATIC void handle_proxy_line(const char *line, managed_proxy_t *mp); STATIC void parse_log_line(const char *line, managed_proxy_t *mp); STATIC void parse_status_line(const char *line, managed_proxy_t *mp); +STATIC void handle_status_message(const struct config_line_t *values, + managed_proxy_t *mp); STATIC char *get_transport_options_for_server_proxy(const managed_proxy_t *mp); STATIC void managed_proxy_destroy(managed_proxy_t *mp, @@ -139,6 +154,7 @@ STATIC managed_proxy_t *managed_proxy_create(const smartlist_t *transport_list, char **proxy_argv, int is_server); +STATIC void launch_proxy_ev(struct mainloop_event_t *event, void *v); STATIC int configure_proxy(managed_proxy_t *mp); STATIC char* get_pt_proxy_uri(void); @@ -153,6 +169,8 @@ STATIC const tor_addr_t *managed_proxy_outbound_address(const or_options_t *, sa_family_t); +STATIC const char *managed_proxy_state_to_string(enum pt_proto_state); +STATIC void managed_proxy_set_state(managed_proxy_t *, enum pt_proto_state); #endif /* defined(PT_PRIVATE) */ #endif /* !defined(TOR_TRANSPORTS_H) */ diff -Nru tor-0.4.7.16/src/feature/control/btrack_orconn_cevent.c tor-0.4.9.6/src/feature/control/btrack_orconn_cevent.c --- tor-0.4.7.16/src/feature/control/btrack_orconn_cevent.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/feature/control/btrack_orconn_cevent.c 2026-03-25 14:30:34.000000000 +0000 @@ -86,8 +86,6 @@ case OR_CONN_STATE_TLS_HANDSHAKING: control_event_bootstrap(BOOTSTRAP_STATUS_CONN_DONE, 0); break; - case OR_CONN_STATE_TLS_CLIENT_RENEGOTIATING: - case OR_CONN_STATE_OR_HANDSHAKING_V2: case OR_CONN_STATE_OR_HANDSHAKING_V3: control_event_bootstrap(BOOTSTRAP_STATUS_HANDSHAKE, 0); break; @@ -140,8 +138,6 @@ case OR_CONN_STATE_TLS_HANDSHAKING: control_event_bootstrap(BOOTSTRAP_STATUS_AP_CONN_DONE, 0); break; - case OR_CONN_STATE_TLS_CLIENT_RENEGOTIATING: - case OR_CONN_STATE_OR_HANDSHAKING_V2: case OR_CONN_STATE_OR_HANDSHAKING_V3: control_event_bootstrap(BOOTSTRAP_STATUS_AP_HANDSHAKE, 0); break; diff -Nru tor-0.4.7.16/src/feature/control/control.c tor-0.4.9.6/src/feature/control/control.c --- tor-0.4.7.16/src/feature/control/control.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/feature/control/control.c 2026-03-25 14:30:34.000000000 +0000 @@ -1,5 +1,5 @@ /* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2021, The Tor Project, Inc. */ + * Copyright (c) 2007-2024, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -252,6 +252,8 @@ if (conn->is_owning_control_connection) { lost_owning_controller("connection", "closed"); } + + control_remove_authenticated_connection(conn); } /** Return true iff cmd is allowable (or at least forgivable) at this diff -Nru tor-0.4.7.16/src/feature/control/control_auth.c tor-0.4.9.6/src/feature/control/control_auth.c --- tor-0.4.7.16/src/feature/control/control_auth.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/feature/control/control_auth.c 2026-03-25 14:30:34.000000000 +0000 @@ -1,5 +1,5 @@ /* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2021, The Tor Project, Inc. */ + * Copyright (c) 2007-2024, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -11,6 +11,7 @@ #include "app/config/config.h" #include "core/mainloop/connection.h" #include "feature/control/control.h" +#include "feature/control/control_events.h" #include "feature/control/control_cmd.h" #include "feature/control/control_auth.h" #include "feature/control/control_cmd_args_st.h" @@ -24,6 +25,36 @@ #include "lib/crypt_ops/crypto_s2k.h" +/* List of authenticated control connections */ +static smartlist_t *control_auth_conns = NULL; + +static void +control_add_authenticated_connection(control_connection_t *conn) +{ + if (!control_auth_conns) + control_auth_conns = smartlist_new(); + + smartlist_add(control_auth_conns, conn); + + if (smartlist_len(control_auth_conns) == 1) + stats_init(); +} + +void +control_remove_authenticated_connection(const control_connection_t *conn) +{ + if (!control_auth_conns) + return; + + smartlist_remove(control_auth_conns, conn); + + if (smartlist_len(control_auth_conns) == 0) { + smartlist_free(control_auth_conns); + control_auth_conns = NULL; + stats_clear(); + } +} + /** If we're using cookie-type authentication, how long should our cookies be? */ #define AUTHENTICATION_COOKIE_LEN 32 @@ -429,6 +460,9 @@ SMARTLIST_FOREACH(sl, char *, str, tor_free(str)); smartlist_free(sl); } + + control_add_authenticated_connection(conn); + return 0; } @@ -438,4 +472,7 @@ if (authentication_cookie) /* Free the auth cookie */ tor_free(authentication_cookie); authentication_cookie_is_set = 0; + + if (control_auth_conns) + smartlist_free(control_auth_conns); } diff -Nru tor-0.4.7.16/src/feature/control/control_auth.h tor-0.4.9.6/src/feature/control/control_auth.h --- tor-0.4.7.16/src/feature/control/control_auth.h 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/feature/control/control_auth.h 2026-03-25 14:30:34.000000000 +0000 @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2021, The Tor Project, Inc. */ + * Copyright (c) 2007-2024, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -12,6 +12,8 @@ #ifndef TOR_CONTROL_AUTH_H #define TOR_CONTROL_AUTH_H +void control_remove_authenticated_connection(const control_connection_t *conn); + struct control_cmd_args_t; struct control_cmd_syntax_t; diff -Nru tor-0.4.7.16/src/feature/control/control_cmd.c tor-0.4.9.6/src/feature/control/control_cmd.c --- tor-0.4.7.16/src/feature/control/control_cmd.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/feature/control/control_cmd.c 2026-03-25 14:30:34.000000000 +0000 @@ -32,6 +32,7 @@ #include "feature/control/control_events.h" #include "feature/control/control_getinfo.h" #include "feature/control/control_proto.h" +#include "feature/hs/hs_config.h" #include "feature/hs/hs_control.h" #include "feature/hs/hs_service.h" #include "feature/nodelist/nodelist.h" @@ -1578,6 +1579,9 @@ add_onion_secret_key_t *pk, smartlist_t *port_cfgs, int max_streams, int max_streams_close_circuit, + int pow_defenses_enabled, + uint32_t pow_queue_rate, + uint32_t pow_queue_burst, smartlist_t *auth_clients_v3, char **address_out) { hs_service_add_ephemeral_status_t ret; @@ -1590,6 +1594,9 @@ case HS_VERSION_THREE: ret = hs_service_add_ephemeral(pk->v3, port_cfgs, max_streams, max_streams_close_circuit, + pow_defenses_enabled, + pow_queue_rate, + pow_queue_burst, auth_clients_v3, address_out); break; default: @@ -1614,7 +1621,15 @@ } static const char *add_onion_keywords[] = { - "Port", "Flags", "MaxStreams", "ClientAuth", "ClientAuthV3", NULL + "Port", + "Flags", + "MaxStreams", + "PoWDefensesEnabled", + "PoWQueueRate", + "PoWQueueBurst", + "ClientAuth", + "ClientAuthV3", + NULL }; static const control_cmd_syntax_t add_onion_syntax = { .min_args = 1, .max_args = 1, @@ -1641,6 +1656,9 @@ int max_streams = 0; int max_streams_close_circuit = 0; int non_anonymous = 0; + int pow_defenses_enabled = HS_CONFIG_V3_POW_DEFENSES_DEFAULT; + uint32_t pow_queue_rate = HS_CONFIG_V3_POW_QUEUE_RATE; + uint32_t pow_queue_burst = HS_CONFIG_V3_POW_QUEUE_BURST; const config_line_t *arg; for (arg = args->kwargs; arg; arg = arg->next) { @@ -1660,6 +1678,30 @@ control_write_endreply(conn, 512, "Invalid MaxStreams"); goto out; } + } else if (!strcasecmp(arg->key, "PoWDefensesEnabled")) { + int ok = 0; + pow_defenses_enabled = (int)tor_parse_long(arg->value, 10, + 0, 1, &ok, NULL); + if (!ok) { + control_write_endreply(conn, 512, "Invalid PoWDefensesEnabled"); + goto out; + } + } else if (!strcasecmp(arg->key, "PoWQueueRate")) { + int ok = 0; + pow_queue_rate = (uint32_t)tor_parse_ulong(arg->value, 10, + 0, UINT32_MAX, &ok, NULL); + if (!ok) { + control_write_endreply(conn, 512, "Invalid PoWQueueRate"); + goto out; + } + } else if (!strcasecmp(arg->key, "PoWQueueBurst")) { + int ok = 0; + pow_queue_burst = (uint32_t)tor_parse_ulong(arg->value, 10, + 0, UINT32_MAX, &ok, NULL); + if (!ok) { + control_write_endreply(conn, 512, "Invalid PoWQueueBurst"); + 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 @@ -1775,6 +1817,9 @@ int ret = add_onion_helper_add_service(hs_version, &pk, port_cfgs, max_streams, max_streams_close_circuit, + pow_defenses_enabled, + pow_queue_rate, + pow_queue_burst, auth_clients_v3, &service_id); port_cfgs = NULL; /* port_cfgs is now owned by the hs_service code. */ auth_clients_v3 = NULL; /* so is auth_clients_v3 */ diff -Nru tor-0.4.7.16/src/feature/control/control_cmd.h tor-0.4.9.6/src/feature/control/control_cmd.h --- tor-0.4.7.16/src/feature/control/control_cmd.h 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/feature/control/control_cmd.h 2026-03-25 14:30:34.000000000 +0000 @@ -98,6 +98,9 @@ add_onion_secret_key_t *pk, smartlist_t *port_cfgs, int max_streams, int max_streams_close_circuit, + int pow_defenses_enabled, + uint32_t pow_queue_rate, + uint32_t pow_queue_burst, smartlist_t *auth_clients_v3, char **address_out); STATIC control_cmd_args_t *control_cmd_parse_args( diff -Nru tor-0.4.7.16/src/feature/control/control_events.c tor-0.4.9.6/src/feature/control/control_events.c --- tor-0.4.7.16/src/feature/control/control_events.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/feature/control/control_events.c 2026-03-25 14:30:34.000000000 +0000 @@ -1,5 +1,5 @@ /* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2021, The Tor Project, Inc. */ + * Copyright (c) 2007-2024, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -1295,6 +1295,21 @@ uint32_t n_written; } cached_bw_events[N_BW_EVENTS_TO_CACHE]; +void +stats_init(void) +{ + stats_prev_n_read = get_bytes_read(); + stats_prev_n_written = get_bytes_written(); +} + +void +stats_clear(void) +{ + memset(cached_bw_events, 0, sizeof cached_bw_events); + stats_prev_n_read = stats_prev_n_written = 0; + n_measurements = next_measurement_idx = 0; +} + /** A second or more has elapsed: tell any interested control * connections how much bandwidth we used. */ int diff -Nru tor-0.4.7.16/src/feature/control/control_events.h tor-0.4.9.6/src/feature/control/control_events.h --- tor-0.4.7.16/src/feature/control/control_events.h 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/feature/control/control_events.h 2026-03-25 14:30:34.000000000 +0000 @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2021, The Tor Project, Inc. */ + * Copyright (c) 2007-2024, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -226,6 +226,9 @@ int control_event_enter_controller_wait(void); +void stats_init(void); +void stats_clear(void); + void control_events_free_all(void); #ifdef CONTROL_MODULE_PRIVATE diff -Nru tor-0.4.7.16/src/feature/control/control_fmt.c tor-0.4.9.6/src/feature/control/control_fmt.c --- tor-0.4.7.16/src/feature/control/control_fmt.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/feature/control/control_fmt.c 2026-03-25 14:30:34.000000000 +0000 @@ -21,6 +21,7 @@ #include "core/or/entry_connection_st.h" #include "core/or/or_connection_st.h" #include "core/or/origin_circuit_st.h" +#include "core/or/conflux_util.h" #include "core/or/socks_request_st.h" #include "feature/control/control_connection_st.h" @@ -153,6 +154,41 @@ tor_free(socks_password_escaped); } + /* Attach the proof-of-work solution effort, if it's nonzero. Clients set + * this to the effort they've chosen, services set this to a value that + * was provided by the client and then verified by the service. */ + if (circ->hs_pow_effort > 0) { + smartlist_add_asprintf(descparts, "HS_POW=v1,%u", circ->hs_pow_effort); + } + + /* Add conflux id and RTT info, for accurate circuit display. The RTT is + * provided to indicate the primary (preferred) circuit of a set + * (which will have the lowest current RTT). + * + * NOTE: Because control port events can happen at arbitrary points, we + * must specifically check exactly what we need from the conflux object. + * We cannot use CIRCUIT_IS_CONFLUX() because this event may have been + * emitted while a set was under partial construction or teardown. */ + if (TO_CIRCUIT(circ)->conflux || TO_CIRCUIT(circ)->conflux_pending_nonce) { + const uint8_t *nonce = conflux_get_nonce(TO_CIRCUIT(circ)); + tor_assert(nonce); + + /* The conflux nonce is an ephemeral cryptographic secret that if known in + * full, enables confirmation or data injection on a set by adding new legs + * at an exit from elsewhere. Only output half of it. */ + smartlist_add_asprintf(descparts, "CONFLUX_ID=%s", + hex_str((const char *)nonce, DIGEST256_LEN/2)); + + /* If we have a conflux object that is fully linked, the circ has an RTT */ + if (TO_CIRCUIT(circ)->conflux && + TO_CIRCUIT(circ)->purpose == CIRCUIT_PURPOSE_CONFLUX_LINKED) { + uint64_t circ_rtt = conflux_get_circ_rtt(TO_CIRCUIT(circ)); + if (circ_rtt) { + smartlist_add_asprintf(descparts, "CONFLUX_RTT=%" PRIu64, circ_rtt); + } + } + } + rv = smartlist_join_strings(descparts, " ", 0, NULL); SMARTLIST_FOREACH(descparts, char *, cp, tor_free(cp)); diff -Nru tor-0.4.7.16/src/feature/control/control_getinfo.c tor-0.4.9.6/src/feature/control/control_getinfo.c --- tor-0.4.7.16/src/feature/control/control_getinfo.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/feature/control/control_getinfo.c 2026-03-25 14:30:34.000000000 +0000 @@ -1257,14 +1257,12 @@ router_all_orports_seem_reachable(options) ? "1" : "0"); } else if (!strcmp(question, "status/reachability-succeeded/dir")) { - *answer = tor_strdup( - router_dirport_seems_reachable(options) ? - "1" : "0"); + *answer = tor_strdup("1"); /* obsolete since tor#2667) */ } else if (!strcmp(question, "status/reachability-succeeded")) { tor_asprintf( answer, "OR=%d DIR=%d", router_all_orports_seem_reachable(options) ? 1 : 0, - router_dirport_seems_reachable(options) ? 1 : 0); + 1); } else if (!strcmp(question, "status/bootstrap-phase")) { *answer = control_event_boot_last_msg(); } else if (!strcmpstart(question, "status/version/")) { diff -Nru tor-0.4.7.16/src/feature/control/getinfo_geoip.c tor-0.4.9.6/src/feature/control/getinfo_geoip.c --- tor-0.4.7.16/src/feature/control/getinfo_geoip.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/feature/control/getinfo_geoip.c 2026-03-25 14:30:34.000000000 +0000 @@ -44,10 +44,7 @@ *errmsg = "GeoIP data not loaded"; return -1; } - if (family == AF_INET) - c = geoip_get_country_by_ipv4(tor_addr_to_ipv4h(&addr)); - else /* AF_INET6 */ - c = geoip_get_country_by_ipv6(tor_addr_to_in6(&addr)); + c = geoip_get_country_by_addr(&addr); *answer = tor_strdup(geoip_get_country_name(c)); } return 0; diff -Nru tor-0.4.7.16/src/feature/control/include.am tor-0.4.9.6/src/feature/control/include.am --- tor-0.4.7.16/src/feature/control/include.am 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/feature/control/include.am 2026-03-25 14:30:34.000000000 +0000 @@ -1,11 +1,11 @@ # ADD_C_FILE: INSERT SOURCES HERE. -LIBTOR_APP_A_SOURCES += \ +LIBTOR_APP_A_SOURCES += \ src/feature/control/btrack.c \ src/feature/control/btrack_circuit.c \ src/feature/control/btrack_orconn.c \ - src/feature/control/btrack_orconn_cevent.c \ - src/feature/control/btrack_orconn_maps.c \ + 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 \ diff -Nru tor-0.4.7.16/src/feature/dirauth/bwauth.c tor-0.4.9.6/src/feature/dirauth/bwauth.c --- tor-0.4.7.16/src/feature/dirauth/bwauth.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/feature/dirauth/bwauth.c 2026-03-25 14:30:34.000000000 +0000 @@ -434,15 +434,19 @@ return -1; } got_bw=1; - } else if (strcmpstart(cp, "node_id=$") == 0) { + // Allow node_id to start with or without the dollar sign. + } else if (strcmpstart(cp, "node_id=") == 0) { if (got_node_id) { log_warn(LD_DIRSERV, "Double node_id= in bandwidth file line: %s", escaped(orig_line)); tor_free(line); return -1; } - cp+=strlen("node_id=$"); - + if (strcmpstart(cp, "node_id=$") == 0) { + cp+=strlen("node_id=$"); + } else if (strcmpstart(cp, "node_id=") == 0) { + cp+=strlen("node_id="); + } if (strlen(cp) != HEX_DIGEST_LEN || base16_decode(out->node_id, DIGEST_LEN, cp, HEX_DIGEST_LEN) != DIGEST_LEN) { diff -Nru tor-0.4.7.16/src/feature/dirauth/dirauth_config.c tor-0.4.9.6/src/feature/dirauth/dirauth_config.c --- tor-0.4.7.16/src/feature/dirauth/dirauth_config.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/feature/dirauth/dirauth_config.c 2026-03-25 14:30:34.000000000 +0000 @@ -16,9 +16,12 @@ #include "lib/encoding/confline.h" #include "lib/confmgt/confmgt.h" #include "lib/conf/confdecl.h" +#include "lib/version/torversion.h" /* Required for dirinfo_type_t in or_options_t */ #include "core/or/or.h" +#include "core/or/tor_version_st.h" +#include "core/or/versions.h" #include "app/config/config.h" #include "app/config/resolve_addr.h" @@ -426,6 +429,7 @@ dirauth_options_validate(const void *arg, char **msg) { const dirauth_options_t *options = arg; + tor_version_t minimal_accepted_server_version, recommended_version; if (options->VersioningAuthoritativeDirectory && (!options->RecommendedClientVersions || @@ -439,12 +443,53 @@ REJECT("Guard bandwdith threshold fraction is invalid."); } - char *t; + if (tor_version_parse(options->MinimalAcceptedServerVersion, + &minimal_accepted_server_version) != 0) { + REJECT("Invalid MinimalAcceptedServerVersion"); + } + + tor_assertf(tor_version_parse(get_short_version(), + &recommended_version) == 0, + "We failed to parse our own version"); + if (tor_version_compare(&recommended_version, + &minimal_accepted_server_version) < 0) { + REJECT("MinimalAcceptedServerVersion wants to reject the version " + "this node is running"); + } + + char *recommended_versions; + int found_recommended_rejected_version = 0; /* Call these functions to produce warnings only. */ - t = format_recommended_version_list(options->RecommendedClientVersions, 1); - tor_free(t); - t = format_recommended_version_list(options->RecommendedServerVersions, 1); - tor_free(t); + recommended_versions = format_recommended_version_list( + options->RecommendedClientVersions, 1); + tor_free(recommended_versions); + + recommended_versions = format_recommended_version_list( + options->RecommendedServerVersions, 1); + + smartlist_t *version_sl = smartlist_new(); + smartlist_split_string(version_sl, recommended_versions, ",", + SPLIT_SKIP_SPACE, 0); + SMARTLIST_FOREACH_BEGIN(version_sl, const char *, version) { + if (version[0] != '\0' && tor_version_parse(version, + &recommended_version) != 0) { + COMPLAIN("Found unparseable version in RecommendedServerVersions"); + continue; + } + + if (tor_version_compare(&recommended_version, + &minimal_accepted_server_version) < 0) { + found_recommended_rejected_version = 1; + break; + } + } SMARTLIST_FOREACH_END(version); + + SMARTLIST_FOREACH(version_sl, char *, version, tor_free(version)); + smartlist_free(version_sl); + tor_free(recommended_versions); + if (found_recommended_rejected_version) + REJECT("MinimalAcceptedServerVersion wants to reject a recommended " + "version"); if (options->TestingAuthDirTimeToLearnReachability > 2*60*60) { COMPLAIN("TestingAuthDirTimeToLearnReachability is insanely high."); diff -Nru tor-0.4.7.16/src/feature/dirauth/dirauth_options.inc tor-0.4.9.6/src/feature/dirauth/dirauth_options.inc --- tor-0.4.7.16/src/feature/dirauth/dirauth_options.inc 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/feature/dirauth/dirauth_options.inc 2026-03-25 14:30:34.000000000 +0000 @@ -76,6 +76,9 @@ /** Which versions of tor should we tell users to run on relays? */ CONF_VAR(RecommendedServerVersions, LINELIST, 0, NULL) +/** Which minimal version of tor do we accept relay descriptors from? */ +CONF_VAR(MinimalAcceptedServerVersion, STRING, 0, "0.4.8.0-alpha-dev") + /** Relays which should be voted Guard regardless of uptime and bandwidth. */ CONF_VAR(AuthDirVoteGuard, ROUTERSET, 0, NULL) @@ -86,11 +89,12 @@ CONF_VAR(AuthDirVoteStableGuaranteeMinUptime, INTERVAL, 0, "30 days") /** If a relay's MTBF is at least this value, then it is always stable. See - * above. */ + * above. (Corresponds to about 7 days for current decay rates.) */ CONF_VAR(AuthDirVoteStableGuaranteeMTBF, INTERVAL, 0, "5 days") /** A relay with at least this much weighted time known can be considered - * familiar enough to be a guard. */ + * familiar enough to be a guard. (Corresponds to about 20 days for current + * decay rates.) */ CONF_VAR(AuthDirVoteGuardGuaranteeTimeKnown, INTERVAL, 0, "8 days") /** A relay with sufficient WFU is around enough to be a guard. */ diff -Nru tor-0.4.7.16/src/feature/dirauth/dirvote.c tor-0.4.9.6/src/feature/dirauth/dirvote.c --- tor-0.4.7.16/src/feature/dirauth/dirvote.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/feature/dirauth/dirvote.c 2026-03-25 14:30:34.000000000 +0000 @@ -115,6 +115,9 @@ char *body; /** The parsed in-progress consensus document. */ networkstatus_t *consensus; + /** Have we reached the critical number of sigs on this consensus, and + * exported it for the consensus transparency module? */ + bool have_exported_for_transparency; } pending_consensus_t; /* DOCDOC dirvote_add_signatures_to_all_pending_consensuses */ @@ -390,7 +393,8 @@ rsf = routerstatus_format_entry(&vrs->status, vrs->version, vrs->protocols, NS_V3_VOTE, - vrs); + vrs, + -1); if (rsf) smartlist_add(chunks, rsf); @@ -618,8 +622,8 @@ * the descriptor digests matched, so somebody is making SHA1 collisions. */ #define CMP_FIELD(utype, itype, field) do { \ - utype aval = (utype) (itype) a->status.field; \ - utype bval = (utype) (itype) b->status.field; \ + utype aval = (utype) (itype) a->field; \ + utype bval = (utype) (itype) b->field; \ utype u = bval - aval; \ itype r2 = (itype) u; \ if (r2 < 0) { \ @@ -638,8 +642,8 @@ CMP_EXACT))) { return r; } - CMP_FIELD(unsigned, int, ipv4_orport); - CMP_FIELD(unsigned, int, ipv4_dirport); + CMP_FIELD(unsigned, int, status.ipv4_orport); + CMP_FIELD(unsigned, int, status.ipv4_dirport); return 0; } @@ -692,10 +696,10 @@ } else { if (cur && (cur_n > most_n || (cur_n == most_n && - cur->status.published_on > most_published))) { + cur->published_on > most_published))) { most = cur; most_n = cur_n; - most_published = cur->status.published_on; + most_published = cur->published_on; } cur_n = 1; cur = rs; @@ -703,7 +707,7 @@ } SMARTLIST_FOREACH_END(rs); if (cur_n > most_n || - (cur && cur_n == most_n && cur->status.published_on > most_published)) { + (cur && cur_n == most_n && cur->published_on > most_published)) { most = cur; // most_n = cur_n; // unused after this point. // most_published = cur->status.published_on; // unused after this point. @@ -1630,7 +1634,11 @@ n_versioning_servers); client_versions = compute_consensus_versions_list(combined_client_versions, n_versioning_clients); - packages = compute_consensus_package_lines(votes); + + if (consensus_method < MIN_METHOD_TO_OMIT_PACKAGE_FINGERPRINTS) + packages = tor_strdup(""); + else + packages = compute_consensus_package_lines(votes); SMARTLIST_FOREACH(combined_server_versions, char *, cp, tor_free(cp)); SMARTLIST_FOREACH(combined_client_versions, char *, cp, tor_free(cp)); @@ -1775,15 +1783,10 @@ } { - if (consensus_method < MIN_METHOD_FOR_CORRECT_BWWEIGHTSCALE) { - max_unmeasured_bw_kb = (int32_t) extract_param_buggy( - params, "maxunmeasuredbw", DEFAULT_MAX_UNMEASURED_BW_KB); - } else { - max_unmeasured_bw_kb = dirvote_get_intermediate_param_value( - param_list, "maxunmeasurdbw", DEFAULT_MAX_UNMEASURED_BW_KB); - if (max_unmeasured_bw_kb < 1) - max_unmeasured_bw_kb = 1; - } + max_unmeasured_bw_kb = dirvote_get_intermediate_param_value( + param_list, "maxunmeasuredbw", DEFAULT_MAX_UNMEASURED_BW_KB); + if (max_unmeasured_bw_kb < 1) + max_unmeasured_bw_kb = 1; } /* Add the actual router entries. */ @@ -2047,7 +2050,6 @@ memcpy(rs_out.descriptor_digest, rs->status.descriptor_digest, DIGEST_LEN); tor_addr_copy(&rs_out.ipv4_addr, &rs->status.ipv4_addr); - rs_out.published_on = rs->status.published_on; rs_out.ipv4_dirport = rs->status.ipv4_dirport; rs_out.ipv4_orport = rs->status.ipv4_orport; tor_addr_copy(&rs_out.ipv6_addr, &alt_orport.addr); @@ -2055,6 +2057,21 @@ rs_out.has_bandwidth = 0; rs_out.has_exitsummary = 0; + time_t published_on = rs->published_on; + + /* Starting with this consensus method, we no longer include a + meaningful published_on time for microdescriptor consensuses. This + makes their diffs smaller and more compressible. + + We need to keep including a meaningful published_on time for NS + consensuses, however, until 035 relays are all obsolete. (They use + it for a purpose similar to the current StaleDesc flag.) + */ + if (consensus_method >= MIN_METHOD_TO_SUPPRESS_MD_PUBLISHED && + flavor == FLAV_MICRODESC) { + published_on = -1; + } + if (chosen_name && !naming_conflict) { strlcpy(rs_out.nickname, chosen_name, sizeof(rs_out.nickname)); } else { @@ -2115,7 +2132,7 @@ /* Starting with consensus method 32, we handle the middle-only * flag specially: when it is present, we clear some flags, and * set others. */ - if (is_middle_only && consensus_method >= MIN_METHOD_FOR_MIDDLEONLY) { + if (is_middle_only) { remove_flag(chosen_flags, "Exit"); remove_flag(chosen_flags, "V2Dir"); remove_flag(chosen_flags, "Guard"); @@ -2276,7 +2293,7 @@ /* Okay!! Now we can write the descriptor... */ /* First line goes into "buf". */ buf = routerstatus_format_entry(&rs_out, NULL, NULL, - rs_format, NULL); + rs_format, NULL, published_on); if (buf) smartlist_add(chunks, buf); } @@ -2352,19 +2369,29 @@ { int64_t weight_scale; - if (consensus_method < MIN_METHOD_FOR_CORRECT_BWWEIGHTSCALE) { - weight_scale = extract_param_buggy(params, "bwweightscale", - BW_WEIGHT_SCALE); - } else { - weight_scale = dirvote_get_intermediate_param_value( - param_list, "bwweightscale", BW_WEIGHT_SCALE); - if (weight_scale < 1) - weight_scale = 1; - } + weight_scale = dirvote_get_intermediate_param_value( + param_list, "bwweightscale", BW_WEIGHT_SCALE); + if (weight_scale < 1) + weight_scale = 1; added_weights = networkstatus_compute_bw_weights_v10(chunks, G, M, E, D, T, weight_scale); } + /* Write the unsigned proposed consensus text to disk, for dir auth + * debugging purposes, and also to put a sig-less consensus file in + * place for (with luck) later export to the consensus transparency + * module. */ + { + char *unsigned_consensus = smartlist_join_strings(chunks, "", 0, NULL); + char *filename = NULL; + tor_asprintf(&filename, "my-consensus-%s", flavor_name); + char *fpath = get_datadir_fname(filename); + write_str_to_file(fpath, unsigned_consensus, 0); + tor_free(filename); + tor_free(fpath); + tor_free(unsigned_consensus); + } + /* Add a signature. */ { char digest[DIGEST256_LEN]; @@ -2462,53 +2489,6 @@ return result; } -/** Extract the value of a parameter from a string encoding a list of - * parameters, badly. - * - * This is a deliberately buggy implementation, for backward compatibility - * with versions of Tor affected by #19011. Once all authorities have - * upgraded to consensus method 31 or later, then we can throw away this - * function. */ -STATIC int64_t -extract_param_buggy(const char *params, - const char *param_name, - int64_t default_value) -{ - int64_t value = default_value; - const char *param_str = NULL; - - if (params) { - char *prefix1 = NULL, *prefix2=NULL; - tor_asprintf(&prefix1, "%s=", param_name); - tor_asprintf(&prefix2, " %s=", param_name); - if (strcmpstart(params, prefix1) == 0) - param_str = params; - else - param_str = strstr(params, prefix2); - tor_free(prefix1); - tor_free(prefix2); - } - - if (param_str) { - int ok=0; - char *eq = strchr(param_str, '='); - if (eq) { - value = tor_parse_long(eq+1, 10, 1, INT32_MAX, &ok, NULL); - if (!ok) { - log_warn(LD_DIR, "Bad element '%s' in %s", - escaped(param_str), param_name); - value = default_value; - } - } else { - log_warn(LD_DIR, "Bad element '%s' in %s", - escaped(param_str), param_name); - value = default_value; - } - } - - return value; -} - /** Given a list of networkstatus_t for each vote, return a newly allocated * string containing the "package" lines for the vote. */ STATIC char * @@ -3524,14 +3504,6 @@ pending[flav].consensus = consensus; n_generated++; - /* Write it out to disk too, for dir auth debugging purposes */ - { - char *filename; - tor_asprintf(&filename, "my-consensus-%s", flavor_name); - write_str_to_file(get_datadir_fname(filename), consensus_body, 0); - tor_free(filename); - } - consensus_body = NULL; consensus = NULL; } @@ -3597,9 +3569,36 @@ return -1; } -/** Helper: we just got the detached_signatures_body sent to us as - * signatures on the currently pending consensus. Add them to pc - * as appropriate. Return the number of signatures added. (?) */ +/** We just got enough sigs on the pending flavor_name-flavor + * consensus that it is time to export it to the consensus transparency + * module. We do this by writing a "consensus-transparency-%s" file which + * the module will detect and act on. + * + * The file needs to be just the bare consensus, with no signatures, so we + * are registering a hash that everybody can agree on. */ +static void +export_consensus_for_transparency(const char *flavor_name) +{ + char *filename = NULL; + tor_asprintf(&filename, "my-consensus-%s", flavor_name); + char *fpath_from = get_datadir_fname(filename); + tor_free(filename); + tor_asprintf(&filename, "consensus-transparency-%s", flavor_name); + char *fpath_to = get_datadir_fname(filename); + tor_free(filename); + + replace_file(fpath_from, fpath_to); + + log_notice(LD_DIR, "Exported consensus transparency file %s.", + fpath_to); + + tor_free(fpath_from); + tor_free(fpath_to); +} + +/** Helper: we just received sigs as + * signatures on the currently pending consensus. Add them to pc + * as appropriate. Return the number of signatures added, or -1 if error. */ static int dirvote_add_signatures_to_pending_consensus( pending_consensus_t *pc, @@ -3663,6 +3662,16 @@ } *msg_out = "Signatures added"; tor_free(new_signatures); + + /* Check if we now have enough sigs that we are confident this + * will be our consensus. */ + if (!pc->have_exported_for_transparency && + networkstatus_check_consensus_signature(pc->consensus, -1) >= 0) { + /* Yes! Send it to the consensus transparency module. */ + export_consensus_for_transparency(flavor_name); + pc->have_exported_for_transparency = 1; + } + } else if (r == 0) { *msg_out = "Signatures ignored"; } else { @@ -3902,13 +3911,18 @@ STATIC microdesc_t * dirvote_create_microdescriptor(const routerinfo_t *ri, int consensus_method) { + (void) consensus_method; // Currently unneeded... microdesc_t *result = NULL; char *key = NULL, *summary = NULL, *family = NULL; size_t keylen; smartlist_t *chunks = smartlist_new(); char *output = NULL; - crypto_pk_t *rsa_pubkey = router_get_rsa_onion_pkey(ri->onion_pkey, - ri->onion_pkey_len); + crypto_pk_t *rsa_pubkey = router_get_rsa_onion_pkey(ri->tap_onion_pkey, + ri->tap_onion_pkey_len); + if (!rsa_pubkey) { + /* We do not yet support creating MDs for relays without TAP onion keys. */ + goto done; + } if (crypto_pk_write_public_key_to_string(rsa_pubkey, &key, &keylen)<0) goto done; @@ -3920,20 +3934,22 @@ if (ri->onion_curve25519_pkey) { char kbuf[CURVE25519_BASE64_PADDED_LEN + 1]; - bool add_padding = (consensus_method < MIN_METHOD_FOR_UNPADDED_NTOR_KEY); - curve25519_public_to_base64(kbuf, ri->onion_curve25519_pkey, add_padding); + curve25519_public_to_base64(kbuf, ri->onion_curve25519_pkey, false); smartlist_add_asprintf(chunks, "ntor-onion-key %s\n", kbuf); } 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); - } + 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 (consensus_method >= MIN_METHOD_FOR_FAMILY_IDS && + ri->family_ids && smartlist_len(ri->family_ids)) { + char *family_ids = smartlist_join_strings(ri->family_ids, " ", 0, NULL); + smartlist_add_asprintf(chunks, "family-ids %s\n", family_ids); + tor_free(family_ids); } if (summary && strcmp(summary, "reject 1-65535")) @@ -4031,10 +4047,8 @@ int high; } microdesc_consensus_methods[] = { {MIN_SUPPORTED_CONSENSUS_METHOD, - MIN_METHOD_FOR_CANONICAL_FAMILIES_IN_MICRODESCS - 1}, - {MIN_METHOD_FOR_CANONICAL_FAMILIES_IN_MICRODESCS, - MIN_METHOD_FOR_UNPADDED_NTOR_KEY - 1}, - {MIN_METHOD_FOR_UNPADDED_NTOR_KEY, + MIN_METHOD_FOR_FAMILY_IDS - 1}, + {MIN_METHOD_FOR_FAMILY_IDS, MAX_SUPPORTED_CONSENSUS_METHOD}, {-1, -1} }; @@ -4744,6 +4758,7 @@ dirauth_set_routerstatus_from_routerinfo(rs, node, ri, now, list_bad_exits, list_middle_only); + vrs->published_on = ri->cache_info.published_on; if (ri->cache_info.signing_key_cert) { memcpy(vrs->ed25519_id, diff -Nru tor-0.4.7.16/src/feature/dirauth/dirvote.h tor-0.4.9.6/src/feature/dirauth/dirvote.h --- tor-0.4.7.16/src/feature/dirauth/dirvote.h 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/feature/dirauth/dirvote.h 2026-03-25 14:30:34.000000000 +0000 @@ -50,29 +50,28 @@ ((MIN_VOTE_SECONDS_TESTING)+(MIN_DIST_SECONDS_TESTING)+1) /** The lowest consensus method that we currently support. */ -#define MIN_SUPPORTED_CONSENSUS_METHOD 28 +#define MIN_SUPPORTED_CONSENSUS_METHOD 32 /** The highest consensus method that we currently support. */ -#define MAX_SUPPORTED_CONSENSUS_METHOD 32 +#define MAX_SUPPORTED_CONSENSUS_METHOD 35 /** - * 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 - -/** Lowest consensus method where an unpadded base64 onion-key-ntor is allowed - * See #7869 */ -#define MIN_METHOD_FOR_UNPADDED_NTOR_KEY 30 - -/** Lowest consensus method for which we use the correct algorithm for - * extracting the bwweightscale= and maxunmeasuredbw= parameters. See #19011. + * Lowest consensus method for which we suppress the published time in + * microdescriptor consensuses. */ -#define MIN_METHOD_FOR_CORRECT_BWWEIGHTSCALE 31 +#define MIN_METHOD_TO_SUPPRESS_MD_PUBLISHED 33 -/** Lowest consensus method for which we handle the MiddleOnly flag specially. +/** + * Lowest (supported) consensus method for which we do not include + * any "package" lines. + **/ +#define MIN_METHOD_TO_OMIT_PACKAGE_FINGERPRINTS 34 + +/** + * Lowest supported consensus method for which we include `family-ids` + * in microdescs. */ -#define MIN_METHOD_FOR_MIDDLEONLY 32 +#define MIN_METHOD_FOR_FAMILY_IDS 35 /** Default bandwidth to clip unmeasured bandwidths to using method >= * MIN_METHOD_TO_CLIP_UNMEASURED_BW. (This is not a consensus method; do not @@ -268,9 +267,6 @@ char *networkstatus_get_detached_signatures(smartlist_t *consensuses); STATIC microdesc_t *dirvote_create_microdescriptor(const routerinfo_t *ri, int consensus_method); -STATIC int64_t extract_param_buggy(const char *params, - const char *param_name, - int64_t default_value); #endif /* defined(DIRVOTE_PRIVATE) */ diff -Nru tor-0.4.7.16/src/feature/dirauth/process_descs.c tor-0.4.9.6/src/feature/dirauth/process_descs.c --- tor-0.4.7.16/src/feature/dirauth/process_descs.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/feature/dirauth/process_descs.c 2026-03-25 14:30:34.000000000 +0000 @@ -110,7 +110,7 @@ tor_strstrip(fingerprint, " "); if (base16_decode(d, DIGEST_LEN, fingerprint, strlen(fingerprint)) != DIGEST_LEN) { - log_warn(LD_DIRSERV, "Couldn't decode fingerprint \"%s\"", + log_warn(LD_DIRSERV, "Couldn't decode fingerprint %s", escaped(fp)); tor_free(fingerprint); return -1; @@ -228,6 +228,12 @@ add_status = RTR_INVALID; } else if (!strcasecmp(nickname, "!middleonly")) { add_status = RTR_MIDDLEONLY; + } else if (!strcasecmp(nickname, "!stripguard")) { + add_status = RTR_STRIPGUARD; + } else if (!strcasecmp(nickname, "!striphsdir")) { + add_status = RTR_STRIPHSDIR; + } else if (!strcasecmp(nickname, "!stripv2dir")) { + add_status = RTR_STRIPV2DIR; } /* Check if fingerprint is RSA or ed25519 by verifying it. */ @@ -404,17 +410,8 @@ static const char please_upgrade_string[] = "Tor version is insecure or unsupported. Please upgrade!"; - /* Anything before 0.4.5.6 is unsupported. Reject them. */ - if (!tor_version_as_new_as(platform,"0.4.5.6")) { - if (msg) { - *msg = please_upgrade_string; - } - return true; - } - - /* Reject 0.4.6.x series. */ - if (tor_version_as_new_as(platform, "0.4.6.0") && - !tor_version_as_new_as(platform, "0.4.7.0-alpha-dev")) { + if (!tor_version_as_new_as(platform, + dirauth_get_options()->MinimalAcceptedServerVersion)) { if (msg) { *msg = please_upgrade_string; } @@ -636,6 +633,9 @@ node->is_valid = (authstatus & RTR_INVALID) ? 0 : 1; node->is_bad_exit = (authstatus & RTR_BADEXIT) ? 1 : 0; node->is_middle_only = (authstatus & RTR_MIDDLEONLY) ? 1 : 0; + node->strip_guard = (authstatus & RTR_STRIPGUARD) ? 1 : 0; + node->strip_hsdir = (authstatus & RTR_STRIPHSDIR) ? 1 : 0; + node->strip_v2dir = (authstatus & RTR_STRIPV2DIR) ? 1 : 0; } /** True iff a is more severe than b. */ @@ -771,6 +771,16 @@ log_info(LD_DIR, "Assessing new descriptor: %s: %s", ri->nickname, ri->platform); + /* For now, TAP keys are still required. */ + if (! ri->tap_onion_pkey) { + log_info(LD_DIRSERV, "Rejecting descriptor from %s (source: %s); " + "it has no TAP key.", + router_describe(ri), source); + *msg = "Missing TAP key in descriptor."; + r = ROUTER_AUTHDIR_REJECTS; + goto fail; + } + /* Check whether this descriptor is semantically identical to the last one * from this server. (We do this here and not in router_add_to_routerlist * because we want to be able to accept the newest router descriptor that @@ -974,6 +984,21 @@ (r & RTR_MIDDLEONLY) ? "" : "not"); node->is_middle_only = (r&RTR_MIDDLEONLY) ? 1: 0; } + if (bool_neq((r & RTR_STRIPGUARD), node->strip_guard)) { + log_info(LD_DIRSERV, "Router '%s' is now %s guard", description, + (r & RTR_STRIPGUARD) ? "stripped of" : "not"); + node->strip_guard = (r&RTR_STRIPGUARD) ? 1: 0; + } + if (bool_neq((r & RTR_STRIPHSDIR), node->strip_hsdir)) { + log_info(LD_DIRSERV, "Router '%s' is now %s hidden service directory", + description, (r & RTR_STRIPHSDIR) ? "stripped of" : "not"); + node->strip_hsdir = (r&RTR_STRIPHSDIR) ? 1: 0; + } + if (bool_neq((r & RTR_STRIPV2DIR), node->strip_v2dir)) { + log_info(LD_DIRSERV, "Router '%s' is now %s v2 directory", + description, (r & RTR_STRIPV2DIR) ? "stripped of" : "not"); + node->strip_v2dir = (r&RTR_STRIPV2DIR) ? 1: 0; + } } SMARTLIST_FOREACH_END(node); routerlist_assert_ok(rl); diff -Nru tor-0.4.7.16/src/feature/dirauth/process_descs.h tor-0.4.9.6/src/feature/dirauth/process_descs.h --- tor-0.4.7.16/src/feature/dirauth/process_descs.h 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/feature/dirauth/process_descs.h 2026-03-25 14:30:34.000000000 +0000 @@ -47,6 +47,9 @@ #define RTR_BADEXIT 16 /**< We'll tell clients not to use this as an exit. */ /** We'll vote to only use this router as a midpoint. */ #define RTR_MIDDLEONLY 32 +#define RTR_STRIPGUARD 64 +#define RTR_STRIPHSDIR 128 +#define RTR_STRIPV2DIR 256 #endif /* defined(PROCESS_DESCS_PRIVATE) || defined(TOR_UNIT_TESTS) */ diff -Nru tor-0.4.7.16/src/feature/dirauth/voteflags.c tor-0.4.9.6/src/feature/dirauth/voteflags.c --- tor-0.4.7.16/src/feature/dirauth/voteflags.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/feature/dirauth/voteflags.c 2026-03-25 14:30:34.000000000 +0000 @@ -112,8 +112,7 @@ } /** Return 1 if ri's descriptor is "active" -- running, valid, - * not hibernating, having observed bw greater 0, and not too old. Else - * return 0. + * not hibernating, and not too old. Else return 0. */ static int router_is_active(const routerinfo_t *ri, const node_t *node, time_t now) @@ -125,20 +124,6 @@ if (!node->is_running || !node->is_valid || ri->is_hibernating) { return 0; } - /* Only require bandwidth capacity in non-test networks, or - * if TestingTorNetwork, and TestingMinExitFlagThreshold is non-zero */ - if (!ri->bandwidthcapacity) { - if (get_options()->TestingTorNetwork) { - if (dirauth_get_options()->TestingMinExitFlagThreshold > 0) { - /* If we're in a TestingTorNetwork, and TestingMinExitFlagThreshold is, - * then require bandwidthcapacity */ - return 0; - } - } else { - /* If we're not in a TestingTorNetwork, then require bandwidthcapacity */ - return 0; - } - } return 1; } @@ -625,6 +610,17 @@ rs->is_exit = rs->is_possible_guard = rs->is_hs_dir = rs->is_v2_dir = 0; } + /* Strip rs flags based on node flags. */ + if (node->strip_guard) { + rs->is_possible_guard = 0; + } + if (node->strip_hsdir) { + rs->is_hs_dir = 0; + } + if (node->strip_v2dir) { + rs->is_v2_dir = 0; + } + /* Set rs->is_staledesc. */ rs->is_staledesc = (ri->cache_info.published_on + DESC_IS_STALE_INTERVAL) < now; diff -Nru tor-0.4.7.16/src/feature/dircache/dircache.c tor-0.4.9.6/src/feature/dircache/dircache.c --- tor-0.4.7.16/src/feature/dircache/dircache.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/feature/dircache/dircache.c 2026-03-25 14:30:34.000000000 +0000 @@ -26,6 +26,7 @@ #include "feature/dircommon/directory.h" #include "feature/dircommon/fp_pair.h" #include "feature/hs/hs_cache.h" +#include "feature/hs/hs_ident.h" #include "feature/nodelist/authcert.h" #include "feature/nodelist/networkstatus.h" #include "feature/nodelist/routerlist.h" @@ -34,6 +35,7 @@ #include "feature/stats/geoip_stats.h" #include "feature/stats/rephist.h" #include "lib/compress/compress.h" +#include "lib/crypt_ops/crypto_format.h" #include "feature/dircache/cached_dir_st.h" #include "feature/dircommon/dir_connection_st.h" @@ -966,12 +968,12 @@ goto done; } + /* Success: we are going to try serving it. */ + geoip_note_ns_response(GEOIP_SERVED); + conn->should_count_geoip_when_finished = 1; + tor_addr_t addr; if (tor_addr_parse(&addr, (TO_CONN(conn))->address) >= 0) { - geoip_note_client_seen(GEOIP_CLIENT_NETWORKSTATUS, - &addr, NULL, - time(NULL)); - geoip_note_ns_response(GEOIP_SUCCESS); /* Note that a request for a network status has started, so that we * can measure the download time later on. */ if (conn->dirreq_id) @@ -1381,6 +1383,17 @@ write_http_response_header(conn, strlen(desc_str), NO_METHOD, 0); connection_buf_add(desc_str, strlen(desc_str), TO_CONN(conn)); + /* We have successfully written the descriptor on the connection outbuf so + * save this query identifier into the dir_connection_t in order + * to associate it to the descriptor when closing. */ + { + /* Decode blinded key. This is certain to work else + * hs_cache_lookup_as_dir() would have failed. */ + ed25519_public_key_t blinded_key; + ed25519_public_from_base64(&blinded_key, pubkey_str); + conn->hs_ident = hs_ident_server_dir_conn_new(&blinded_key); + } + done: return 0; } diff -Nru tor-0.4.7.16/src/feature/dircache/dirserv.c tor-0.4.9.6/src/feature/dircache/dirserv.c --- tor-0.4.7.16/src/feature/dircache/dirserv.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/feature/dircache/dirserv.c 2026-03-25 14:30:34.000000000 +0000 @@ -15,6 +15,7 @@ #include "feature/nodelist/routerlist.h" #include "feature/relay/router.h" #include "feature/relay/routermode.h" +#include "feature/stats/geoip_stats.h" #include "feature/stats/predict_ports.h" #include "feature/dircache/cached_dir_st.h" @@ -778,6 +779,22 @@ tor_compress_free(conn->compress_state); conn->compress_state = NULL; } + + /* only count networkstatus serves as successful when the spool runs dry */ + if (conn->should_count_geoip_when_finished) { + tor_addr_t addr; + /* but as a special case, check if conn is on a circuit that used a + * version-0 sendme (bugs 41191 and 41192), because we don't want to + * count clients that should exit after they receive our consensus. */ + if (!connection_dir_used_obsolete_sendme(conn) && + tor_addr_parse(&addr, (TO_CONN(conn))->address) >= 0) { + geoip_note_client_seen(GEOIP_CLIENT_NETWORKSTATUS, + &addr, NULL, + time(NULL)); + } + geoip_note_ns_response(GEOIP_SUCCESS); + conn->should_count_geoip_when_finished = 0; + } return 0; } diff -Nru tor-0.4.7.16/src/feature/dirclient/dirclient.c tor-0.4.9.6/src/feature/dirclient/dirclient.c --- tor-0.4.7.16/src/feature/dirclient/dirclient.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/feature/dirclient/dirclient.c 2026-03-25 14:30:34.000000000 +0000 @@ -101,7 +101,7 @@ case DIR_PURPOSE_UPLOAD_DIR: return "server descriptor upload"; case DIR_PURPOSE_UPLOAD_VOTE: - return "server vote upload"; + return "consensus vote upload"; case DIR_PURPOSE_UPLOAD_SIGNATURES: return "consensus signature upload"; case DIR_PURPOSE_FETCH_SERVERDESC: @@ -242,14 +242,21 @@ * harmless, and we may as well err on the side of getting things uploaded. */ SMARTLIST_FOREACH_BEGIN(dirservers, dir_server_t *, ds) { - routerstatus_t *rs = &(ds->fake_status); + const routerstatus_t *rs = router_get_consensus_status_by_id(ds->digest); + if (!rs) { + /* prefer to use the address in the consensus, but fall back to + * the hard-coded trusted_dir_server address if we don't have a + * consensus or this digest isn't in our consensus. */ + rs = &ds->fake_status; + } + size_t upload_len = payload_len; if ((type & ds->type) == 0) continue; if (exclude_self && router_digest_is_me(ds->digest)) { - /* we don't upload to ourselves, but at least there's now at least + /* we don't upload to ourselves, but there's now at least * one authority of this type that has what we wanted to upload. */ found = 1; continue; @@ -276,10 +283,8 @@ } if (purpose_needs_anonymity(dir_purpose, router_purpose, NULL)) { indirection = DIRIND_ANONYMOUS; - } else if (!reachable_addr_allows_dir_server(ds, - FIREWALL_DIR_CONNECTION, - 0)) { - if (reachable_addr_allows_dir_server(ds, FIREWALL_OR_CONNECTION, 0)) + } else if (!reachable_addr_allows_rs(rs, FIREWALL_DIR_CONNECTION, 0)) { + if (reachable_addr_allows_rs(rs, FIREWALL_OR_CONNECTION, 0)) indirection = DIRIND_ONEHOP; else indirection = DIRIND_ANONYMOUS; @@ -590,7 +595,13 @@ continue; if (!(ds->type & V3_DIRINFO)) continue; - const routerstatus_t *rs = &ds->fake_status; + const routerstatus_t *rs = router_get_consensus_status_by_id(ds->digest); + if (!rs) { + /* prefer to use the address in the consensus, but fall back to + * the hard-coded trusted_dir_server address if we don't have a + * consensus or this digest isn't in our consensus. */ + rs = &ds->fake_status; + } directory_request_t *req = directory_request_new(dir_purpose); directory_request_set_routerstatus(req, rs); directory_request_set_router_purpose(req, router_purpose); @@ -677,7 +688,6 @@ /* We rejected all addresses in the relay's status. This means we can't * connect to it. */ if (!have_or && !have_dir) { - static int logged_backtrace = 0; char *ipv6_str = tor_addr_to_str_dup(&status->ipv6_addr); log_info(LD_BUG, "Rejected all OR and Dir addresses from %s when " "launching an outgoing directory connection to: IPv4 %s OR %d " @@ -686,10 +696,7 @@ status->ipv4_dirport, ipv6_str, status->ipv6_orport, status->ipv4_dirport); tor_free(ipv6_str); - if (!logged_backtrace) { - log_backtrace(LOG_INFO, LD_BUG, "Addresses came from"); - logged_backtrace = 1; - } + log_backtrace_once(LOG_INFO, LD_BUG, "Addresses came from"); return -1; } @@ -752,6 +759,11 @@ "directory server at %s; will retry", connection_describe_peer(TO_CONN(conn))); connection_dir_download_routerdesc_failed(conn); + } else if (conn->base_.purpose == DIR_PURPOSE_UPLOAD_VOTE || + conn->base_.purpose == DIR_PURPOSE_UPLOAD_SIGNATURES) { + log_warn(LD_DIR, "Failed to post %s to %s.", + dir_conn_purpose_to_string(conn->base_.purpose), + connection_describe_peer(TO_CONN(conn))); } } @@ -1309,15 +1321,11 @@ /* Make sure that the destination addr and port we picked is viable. */ if (!port || tor_addr_is_null(&addr)) { - static int logged_backtrace = 0; log_warn(LD_DIR, "Cannot make an outgoing %sconnection without a remote %sPort.", use_begindir ? "begindir " : "", use_begindir ? "OR" : "Dir"); - if (!logged_backtrace) { - log_backtrace(LOG_INFO, LD_BUG, "Address came from"); - logged_backtrace = 1; - } + log_backtrace_once(LOG_INFO, LD_BUG, "Address came from"); return; } diff -Nru tor-0.4.7.16/src/feature/dircommon/dir_connection_st.h tor-0.4.9.6/src/feature/dircommon/dir_connection_st.h --- tor-0.4.7.16/src/feature/dircommon/dir_connection_st.h 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/feature/dircommon/dir_connection_st.h 2026-03-25 14:30:34.000000000 +0000 @@ -44,7 +44,9 @@ /* Hidden service connection identifier for dir connections: Used by HS client-side code to fetch HS descriptors, and by the service-side code to - upload descriptors. */ + upload descriptors. Also used by the HSDir, setting only the blinded key, + in order to locate back the descriptor in the cache once the dir stream is + closed. */ struct hs_ident_dir_conn_t *hs_ident; /** If this is a one-hop connection, tracks the state of the directory guard @@ -59,6 +61,10 @@ * needs this for the incoming side, so it's moved here. */ uint64_t dirreq_id; + /** 0 normally, 1 if we're serving a consensus and we're delaying counting + * geoip until we've served the final bytes. */ + bool should_count_geoip_when_finished; + #ifdef MEASUREMENTS_21206 /** Number of RELAY_DATA cells received. */ uint32_t data_cells_received; diff -Nru tor-0.4.7.16/src/feature/dircommon/directory.c tor-0.4.9.6/src/feature/dircommon/directory.c --- tor-0.4.7.16/src/feature/dircommon/directory.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/feature/dircommon/directory.c 2026-03-25 14:30:34.000000000 +0000 @@ -16,6 +16,7 @@ #include "feature/dirclient/dirclient.h" #include "feature/dircommon/directory.h" #include "feature/dircommon/fp_pair.h" +#include "feature/hs/hs_cache.h" #include "feature/stats/geoip_stats.h" #include "lib/compress/compress.h" @@ -263,6 +264,38 @@ return !channel_is_client(CONST_TO_OR_CIRCUIT(circ)->p_chan); } +/** Did conn ever send us a version 0 sendme cell and we allowed + * it? Used to decide whether to count consensus fetches from it in our + * geoip stats. + * + * Note that this function might have false negatives in some cases, i.e. + * it could tell us that the conn never sent a v0 sendme when actually it + * did but its linked edge connection or OR connection got broken before + * we called this function. For our geoip stats these false negatives + * would mean overcounting users by including some of the v0-using + * clients. + * + * We think these false positives should be unlikely or maybe even + * impossible when called from connection_dirserv_flushed_some(), but + * be careful calling it from elsewhere. + * */ +bool +connection_dir_used_obsolete_sendme(const dir_connection_t *conn) +{ + const edge_connection_t *edge_conn = NULL; + const circuit_t *circ = NULL; + bool used_obsolete_sendme = 0; + const connection_t *linked_conn = TO_CONN(conn)->linked_conn; + if (linked_conn) + edge_conn = CONST_TO_EDGE_CONN(linked_conn); + if (edge_conn) + circ = edge_conn->on_circuit; + if (circ && CIRCUIT_IS_ORCIRC(circ)) + used_obsolete_sendme = CONST_TO_OR_CIRCUIT(circ)->used_obsolete_sendme; + + return used_obsolete_sendme; +} + /** 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 @@ -327,7 +360,7 @@ const char *cp = headers; while (cp) { if (!strcasecmpstart(cp, which)) { - char *eos; + const char *eos; cp += strlen(which); if ((eos = strchr(cp,'\r'))) return tor_strndup(cp, eos-cp); @@ -492,6 +525,17 @@ connection_dir_client_request_failed(dir_conn); } + /* If we are an HSDir, mark the corresponding descriptor as downloaded. This + * is needed for the OOM cache cleanup. + * + * This is done when the direction connection is closed in order to raise the + * attack cost of filling the cache with bogus descriptors. That attacker + * would need to increase that downloaded counter for the attack to be + * successful which is expensive. */ + if (conn->purpose == DIR_PURPOSE_SERVER && dir_conn->hs_ident) { + hs_cache_mark_dowloaded_as_dir(dir_conn->hs_ident); + } + connection_dir_client_refetch_hsdesc_if_needed(dir_conn); } diff -Nru tor-0.4.7.16/src/feature/dircommon/directory.h tor-0.4.9.6/src/feature/dircommon/directory.h --- tor-0.4.7.16/src/feature/dircommon/directory.h 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/feature/dircommon/directory.h 2026-03-25 14:30:34.000000000 +0000 @@ -95,6 +95,7 @@ int connection_dir_is_encrypted(const dir_connection_t *conn); bool connection_dir_is_anonymous(const dir_connection_t *conn); +bool connection_dir_used_obsolete_sendme(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 -Nru tor-0.4.7.16/src/feature/dircommon/include.am tor-0.4.9.6/src/feature/dircommon/include.am --- tor-0.4.7.16/src/feature/dircommon/include.am 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/feature/dircommon/include.am 2026-03-25 14:30:34.000000000 +0000 @@ -1,6 +1,6 @@ # ADD_C_FILE: INSERT SOURCES HERE. -LIBTOR_APP_A_SOURCES += \ +LIBTOR_APP_A_SOURCES += \ src/feature/dircommon/consdiff.c \ src/feature/dircommon/directory.c \ src/feature/dircommon/fp_pair.c diff -Nru tor-0.4.7.16/src/feature/dirparse/microdesc_parse.c tor-0.4.9.6/src/feature/dirparse/microdesc_parse.c --- tor-0.4.7.16/src/feature/dirparse/microdesc_parse.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/feature/dirparse/microdesc_parse.c 2026-03-25 14:30:34.000000000 +0000 @@ -30,11 +30,12 @@ /** List of tokens recognized in microdescriptors */ // clang-format off static token_rule_t microdesc_token_table[] = { - T1_START("onion-key", K_ONION_KEY, NO_ARGS, NEED_KEY_1024), + T1_START("onion-key", K_ONION_KEY, NO_ARGS, OPT_KEY_1024), T1("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, CONCAT_ARGS, NO_OBJ ), + T01("family-ids", K_FAMILY_IDS, 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 ), @@ -200,14 +201,11 @@ } tok = find_by_keyword(tokens, K_ONION_KEY); - if (!crypto_pk_public_exponent_ok(tok->key)) { + if (tok && tok->key && !crypto_pk_public_exponent_ok(tok->key)) { log_warn(LD_DIR, "Relay's onion key had invalid exponent."); goto err; } - md->onion_pkey = tor_memdup(tok->object_body, tok->object_size); - md->onion_pkey_len = tok->object_size; - crypto_pk_free(tok->key); if ((tok = find_opt_by_keyword(tokens, K_ONION_KEY_NTOR))) { curve25519_public_key_t k; @@ -255,6 +253,16 @@ NULL, NF_WARN_MALFORMED); } + if ((tok = find_opt_by_keyword(tokens, K_FAMILY_IDS))) { + smartlist_t *ids = smartlist_new(); + smartlist_split_string(ids, tok->args[0], " ", + SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0); + if (smartlist_len(ids) > 0) { + md->family_ids = ids; + } else { + smartlist_free(ids); + } + } if ((tok = find_opt_by_keyword(tokens, K_P))) { md->exit_policy = parse_short_policy(tok->args[0]); diff -Nru tor-0.4.7.16/src/feature/dirparse/ns_parse.c tor-0.4.9.6/src/feature/dirparse/ns_parse.c --- tor-0.4.7.16/src/feature/dirparse/ns_parse.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/feature/dirparse/ns_parse.c 2026-03-25 14:30:34.000000000 +0000 @@ -371,14 +371,17 @@ } } + time_t published_on; if (tor_snprintf(timebuf, sizeof(timebuf), "%s %s", tok->args[3+offset], tok->args[4+offset]) < 0 || - parse_iso_time(timebuf, &rs->published_on)<0) { + parse_iso_time(timebuf, &published_on)<0) { log_warn(LD_DIR, "Error parsing time '%s %s' [%d %d]", tok->args[3+offset], tok->args[4+offset], offset, (int)flav); goto err; } + if (vote_rs) + vote_rs->published_on = published_on; if (tor_inet_aton(tok->args[5+offset], &in) == 0) { log_warn(LD_DIR, "Error parsing router address in network-status %s", diff -Nru tor-0.4.7.16/src/feature/dirparse/parsecommon.c tor-0.4.9.6/src/feature/dirparse/parsecommon.c --- tor-0.4.7.16/src/feature/dirparse/parsecommon.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/feature/dirparse/parsecommon.c 2026-03-25 14:30:34.000000000 +0000 @@ -215,6 +215,16 @@ RET_ERR(ebuf); } break; + case OPT_KEY_1024: + /* If there is anything, it must be a 1024-bit RSA key. */ + if (tok->object_body && !tok->key) { + tor_snprintf(ebuf, sizeof(ebuf), "Unexpected object for %s", kwd); + RET_ERR(ebuf); + } + if (!tok->key) { + break; + } + FALLTHROUGH; case NEED_KEY_1024: /* There must be a 1024-bit public key. */ if (tok->key && crypto_pk_num_bits(tok->key) != PK_BYTES*8) { tor_snprintf(ebuf, sizeof(ebuf), "Wrong size on key for %s: %d bits", @@ -395,7 +405,8 @@ } if (!strcmp(tok->object_type, "RSA PUBLIC KEY")) { /* If it's a public key */ - if (o_syn != NEED_KEY && o_syn != NEED_KEY_1024 && o_syn != OBJ_OK) { + if (o_syn != OPT_KEY_1024 && o_syn != NEED_KEY && + o_syn != NEED_KEY_1024 && o_syn != OBJ_OK) { RET_ERR("Unexpected public key."); } tok->key = crypto_pk_asn1_decode(tok->object_body, tok->object_size); diff -Nru tor-0.4.7.16/src/feature/dirparse/parsecommon.h tor-0.4.9.6/src/feature/dirparse/parsecommon.h --- tor-0.4.7.16/src/feature/dirparse/parsecommon.h 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/feature/dirparse/parsecommon.h 2026-03-25 14:30:34.000000000 +0000 @@ -45,6 +45,8 @@ K_UPTIME, K_DIR_SIGNING_KEY, K_FAMILY, + K_FAMILY_CERT, + K_FAMILY_IDS, K_FINGERPRINT, K_HIBERNATING, K_READ_HISTORY, @@ -173,6 +175,7 @@ R3_DESC_AUTH_CLIENT, R3_ENCRYPTED, R3_FLOW_CONTROL, + R3_POW_PARAMS, R_IPO_IDENTIFIER, R_IPO_IP_ADDRESS, @@ -219,6 +222,7 @@ typedef enum { NO_OBJ, /**< No object, ever. */ NEED_OBJ, /**< Object is required. */ + OPT_KEY_1024, /**< If object is present, it must be a 1024 bit public key */ NEED_KEY_1024, /**< Object is required, and must be a 1024 bit public key */ NEED_KEY, /**< Object is required, and must be a public key. */ OBJ_OK, /**< Object is optional. */ diff -Nru tor-0.4.7.16/src/feature/dirparse/routerparse.c tor-0.4.9.6/src/feature/dirparse/routerparse.c --- tor-0.4.7.16/src/feature/dirparse/routerparse.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/feature/dirparse/routerparse.c 2026-03-25 14:30:34.000000000 +0000 @@ -51,6 +51,7 @@ **/ #define ROUTERDESC_TOKEN_TABLE_PRIVATE +#define ROUTERPARSE_PRIVATE #include "core/or/or.h" #include "app/config/config.h" @@ -90,7 +91,7 @@ T1_START( "router", K_ROUTER, GE(5), NO_OBJ ), T01("ipv6-policy", K_IPV6_POLICY, CONCAT_ARGS, NO_OBJ), T1( "signing-key", K_SIGNING_KEY, NO_ARGS, NEED_KEY_1024 ), - T1( "onion-key", K_ONION_KEY, NO_ARGS, NEED_KEY_1024 ), + T01("onion-key", K_ONION_KEY, NO_ARGS, NEED_KEY_1024 ), T1("ntor-onion-key", K_ONION_KEY_NTOR, GE(1), NO_OBJ ), T1_END( "router-signature", K_ROUTER_SIGNATURE, NO_ARGS, NEED_OBJ ), T1( "published", K_PUBLISHED, CONCAT_ARGS, NO_OBJ ), @@ -107,13 +108,14 @@ T1("identity-ed25519", K_IDENTITY_ED25519, NO_ARGS, NEED_OBJ ), T1("master-key-ed25519", K_MASTER_KEY_ED25519, GE(1), NO_OBJ ), T1("router-sig-ed25519", K_ROUTER_SIG_ED25519, GE(1), NO_OBJ ), - T1("onion-key-crosscert", K_ONION_KEY_CROSSCERT, NO_ARGS, NEED_OBJ ), + T01("onion-key-crosscert", K_ONION_KEY_CROSSCERT, NO_ARGS, NEED_OBJ ), T1("ntor-onion-key-crosscert", K_NTOR_ONION_KEY_CROSSCERT, EQ(1), NEED_OBJ ), T01("allow-single-hop-exits",K_ALLOW_SINGLE_HOP_EXITS, NO_ARGS, NO_OBJ ), T01("family", K_FAMILY, ARGS, NO_OBJ ), + T0N("family-cert", K_FAMILY_CERT, ARGS, NEED_OBJ ), T01("caches-extra-info", K_CACHES_EXTRA_INFO, NO_ARGS, NO_OBJ ), T0N("or-address", K_OR_ADDRESS, GE(1), NO_OBJ ), @@ -172,6 +174,10 @@ /* static function prototypes */ static int router_add_exit_policy(routerinfo_t *router,directory_token_t *tok); static smartlist_t *find_all_exitpolicy(smartlist_t *s); +static int check_family_certs(const smartlist_t *family_cert_tokens, + const ed25519_public_key_t *identity_key, + smartlist_t **family_ids_out, + time_t *family_expiration_out); /** Set digest to the SHA-1 digest of the hash of the first router in * s. Return 0 on success, -1 on failure. @@ -595,15 +601,17 @@ if (parse_iso_time(tok->args[0], &router->cache_info.published_on) < 0) goto err; - tok = find_by_keyword(tokens, K_ONION_KEY); - if (!crypto_pk_public_exponent_ok(tok->key)) { - log_warn(LD_DIR, - "Relay's onion key had invalid exponent."); - goto err; + tok = find_opt_by_keyword(tokens, K_ONION_KEY); + if (tok) { + if (!crypto_pk_public_exponent_ok(tok->key)) { + log_warn(LD_DIR, + "Relay's onion key had invalid exponent."); + goto err; + } + router->tap_onion_pkey = tor_memdup(tok->object_body, tok->object_size); + router->tap_onion_pkey_len = tok->object_size; + crypto_pk_free(tok->key); } - router->onion_pkey = tor_memdup(tok->object_body, tok->object_size); - router->onion_pkey_len = tok->object_size; - crypto_pk_free(tok->key); if ((tok = find_opt_by_keyword(tokens, K_ONION_KEY_NTOR))) { curve25519_public_key_t k; @@ -627,26 +635,68 @@ { directory_token_t *ed_sig_tok, *ed_cert_tok, *cc_tap_tok, *cc_ntor_tok, *master_key_tok; - ed_sig_tok = find_opt_by_keyword(tokens, K_ROUTER_SIG_ED25519); - ed_cert_tok = find_opt_by_keyword(tokens, K_IDENTITY_ED25519); - master_key_tok = find_opt_by_keyword(tokens, K_MASTER_KEY_ED25519); + ed_sig_tok = find_by_keyword(tokens, K_ROUTER_SIG_ED25519); + ed_cert_tok = find_by_keyword(tokens, K_IDENTITY_ED25519); + master_key_tok = find_by_keyword(tokens, K_MASTER_KEY_ED25519); + cc_ntor_tok = find_by_keyword(tokens, K_NTOR_ONION_KEY_CROSSCERT); + /* This, and only this, is optional. */ cc_tap_tok = find_opt_by_keyword(tokens, K_ONION_KEY_CROSSCERT); - cc_ntor_tok = find_opt_by_keyword(tokens, K_NTOR_ONION_KEY_CROSSCERT); - int n_ed_toks = !!ed_sig_tok + !!ed_cert_tok + - !!cc_tap_tok + !!cc_ntor_tok; - if ((n_ed_toks != 0 && n_ed_toks != 4) || - (n_ed_toks == 4 && !router->onion_curve25519_pkey)) { - log_warn(LD_DIR, "Router descriptor with only partial ed25519/" - "cross-certification support"); + + if (bool_neq(cc_tap_tok==NULL, router->tap_onion_pkey==NULL)) { + log_warn(LD_DIR, "Router descriptor had only one of (onion-key, " + "onion-key-crosscert)."); goto err; } - if (master_key_tok && !ed_sig_tok) { - log_warn(LD_DIR, "Router descriptor has ed25519 master key but no " - "certificate"); + + IF_BUG_ONCE(! (ed_sig_tok && ed_cert_tok&& cc_ntor_tok &&master_key_tok)) { goto err; } - if (ed_sig_tok) { - tor_assert(ed_cert_tok && cc_tap_tok && cc_ntor_tok); + + tor_cert_t *cert; + { + /* Parse the identity certificate */ + cert = tor_cert_parse( + (const uint8_t*)ed_cert_tok->object_body, + ed_cert_tok->object_size); + if (! cert) { + log_warn(LD_DIR, "Couldn't parse ed25519 cert"); + goto err; + } + /* makes sure it gets freed. */ + router->cache_info.signing_key_cert = cert; + + if (cert->cert_type != CERT_TYPE_ID_SIGNING || + ! cert->signing_key_included) { + log_warn(LD_DIR, "Invalid form for ed25519 cert"); + goto err; + } + } + + if (cc_tap_tok) { + rsa_pubkey = router_get_rsa_onion_pkey(router->tap_onion_pkey, + router->tap_onion_pkey_len); + if (rsa_pubkey == NULL) { + log_warn(LD_DIR, "No pubkey for TAP cross-verification."); + goto err; + } + if (strcmp(cc_tap_tok->object_type, "CROSSCERT")) { + log_warn(LD_DIR, "Wrong object type on onion-key-crosscert " + "in descriptor"); + goto err; + } + if (check_tap_onion_key_crosscert( + (const uint8_t*)cc_tap_tok->object_body, + (int)cc_tap_tok->object_size, + rsa_pubkey, + &cert->signing_key, + (const uint8_t*)router->cache_info.identity_digest)<0) { + log_warn(LD_DIR, "Incorrect TAP cross-verification"); + goto err; + } + } + + { + tor_assert(ed_sig_tok && ed_cert_tok && cc_ntor_tok); const int ed_cert_token_pos = smartlist_pos(tokens, ed_cert_tok); if (ed_cert_token_pos == -1 || router_token_pos == -1 || (ed_cert_token_pos != router_token_pos + 1 && @@ -668,35 +718,14 @@ "in descriptor"); goto err; } - if (strcmp(cc_tap_tok->object_type, "CROSSCERT")) { - log_warn(LD_DIR, "Wrong object type on onion-key-crosscert " - "in descriptor"); - goto err; - } if (strcmp(cc_ntor_tok->args[0], "0") && strcmp(cc_ntor_tok->args[0], "1")) { log_warn(LD_DIR, "Bad sign bit on ntor-onion-key-crosscert"); goto err; } int ntor_cc_sign_bit = !strcmp(cc_ntor_tok->args[0], "1"); - uint8_t d256[DIGEST256_LEN]; const char *signed_start, *signed_end; - tor_cert_t *cert = tor_cert_parse( - (const uint8_t*)ed_cert_tok->object_body, - ed_cert_tok->object_size); - if (! cert) { - log_warn(LD_DIR, "Couldn't parse ed25519 cert"); - goto err; - } - /* makes sure it gets freed. */ - router->cache_info.signing_key_cert = cert; - - if (cert->cert_type != CERT_TYPE_ID_SIGNING || - ! cert->signing_key_included) { - log_warn(LD_DIR, "Invalid form for ed25519 cert"); - goto err; - } if (master_key_tok) { /* This token is optional, but if it's present, it must match @@ -746,6 +775,7 @@ crypto_digest_add_bytes(d, ED_DESC_SIGNATURE_PREFIX, strlen(ED_DESC_SIGNATURE_PREFIX)); crypto_digest_add_bytes(d, signed_start, signed_end-signed_start); + crypto_digest_get_digest(d, (char*)d256, sizeof(d256)); crypto_digest_free(d); @@ -776,18 +806,6 @@ goto err; } - rsa_pubkey = router_get_rsa_onion_pkey(router->onion_pkey, - router->onion_pkey_len); - if (check_tap_onion_key_crosscert( - (const uint8_t*)cc_tap_tok->object_body, - (int)cc_tap_tok->object_size, - rsa_pubkey, - &cert->signing_key, - (const uint8_t*)router->cache_info.identity_digest)<0) { - log_warn(LD_DIR, "Incorrect TAP cross-verification"); - goto err; - } - /* We check this before adding it to the routerlist. */ router->cert_expiration_time = expires; } @@ -882,6 +900,21 @@ } } + { + smartlist_t *family_cert_toks = find_all_by_keyword(tokens, K_FAMILY_CERT); + time_t family_expiration = TIME_MAX; + int r = 0; + if (family_cert_toks) { + r = check_family_certs(family_cert_toks, + &router->cache_info.signing_key_cert->signing_key, + &router->family_ids, + &family_expiration); + smartlist_free(family_cert_toks); + } + if (r<0) + goto err; + } + if (find_opt_by_keyword(tokens, K_CACHES_EXTRA_INFO)) router->caches_extra_info = 1; @@ -1238,6 +1271,115 @@ return out; } +/** + * Parse and validate a single `FAMILY_CERT` token's object. + * + * Arguments are as for `check_family_certs()`. + */ +STATIC int +check_one_family_cert(const uint8_t *cert_body, + size_t cert_body_size, + const ed25519_public_key_t *identity_key, + char **family_id_out, + time_t *family_expiration_out) +{ + tor_cert_t *cert = NULL; + int r = -1; + + cert = tor_cert_parse(cert_body, cert_body_size); + + if (! cert) + goto done; + if (cert->cert_type != CERT_TYPE_FAMILY_V_IDENTITY) { + log_warn(LD_DIR, "Wrong cert type in family certificate."); + goto done; + } + if (! cert->signing_key_included) { + log_warn(LD_DIR, "Missing family key in family certificate."); + goto done; + } + if (! ed25519_pubkey_eq(&cert->signed_key, identity_key)) { + log_warn(LD_DIR, "Key mismatch in family certificate."); + goto done; + } + + time_t valid_until = cert->valid_until; + + /* We're using NULL for the key, since the cert has the signing key included. + * We're using 0 for "now", since we're going to extract the expiration + * separately. + */ + if (tor_cert_checksig(cert, NULL, 0) < 0) { + log_warn(LD_DIR, "Invalid signature in family certificate"); + goto done; + } + + /* At this point we know that the cert is valid. + * We extract the expiration time and the signing key. */ + *family_expiration_out = valid_until; + + char buf[ED25519_BASE64_LEN+1]; + ed25519_public_to_base64(buf, &cert->signing_key); + tor_asprintf(family_id_out, "ed25519:%s", buf); + + r = 0; + done: + tor_cert_free(cert); + return r; +} + +/** + * Given a list of `FAMILY_CERT` tokens, and a relay's ed25519 `identity_key`, + * validate the family certificates in all the tokens, and convert them into + * family IDs in a newly allocated `family_ids_out` list. + * Set `family_expiration_out` to the earliest time at which any certificate + * in the list expires. + * Return 0 on success, and -1 on failure. + */ +static int +check_family_certs(const smartlist_t *family_cert_tokens, + const ed25519_public_key_t *identity_key, + smartlist_t **family_ids_out, + time_t *family_expiration_out) +{ + if (BUG(!identity_key) || + BUG(!family_ids_out) || + BUG(!family_expiration_out)) + return -1; + + *family_expiration_out = TIME_MAX; + + if (family_cert_tokens == NULL || smartlist_len(family_cert_tokens) == 0) { + *family_ids_out = NULL; + return 0; + } + + *family_ids_out = smartlist_new(); + SMARTLIST_FOREACH_BEGIN(family_cert_tokens, directory_token_t *, tok) { + if (BUG(tok->object_body == NULL)) + goto err; + + char *this_id = NULL; + time_t this_expiration = TIME_MAX; + if (check_one_family_cert((const uint8_t*)tok->object_body, + tok->object_size, + identity_key, + &this_id, &this_expiration) < 0) + goto err; + smartlist_add(*family_ids_out, this_id); + *family_expiration_out = MIN(*family_expiration_out, this_expiration); + } SMARTLIST_FOREACH_END(tok); + + smartlist_sort_strings(*family_ids_out); + smartlist_uniq_strings(*family_ids_out); + + return 0; + err: + SMARTLIST_FOREACH(*family_ids_out, char *, cp, tor_free(cp)); + smartlist_free(*family_ids_out); + return -1; +} + /** Called on startup; right now we just handle scanning the unparseable * descriptor dumps, but hang anything else we might need to do in the * future here as well. diff -Nru tor-0.4.7.16/src/feature/dirparse/routerparse.h tor-0.4.9.6/src/feature/dirparse/routerparse.h --- tor-0.4.7.16/src/feature/dirparse/routerparse.h 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/feature/dirparse/routerparse.h 2026-03-25 14:30:34.000000000 +0000 @@ -12,6 +12,8 @@ #ifndef TOR_ROUTERPARSE_H #define TOR_ROUTERPARSE_H +#include "lib/testsupport/testsupport.h" + int router_get_router_hash(const char *s, size_t s_len, char *digest); int router_get_extrainfo_hash(const char *s, size_t s_len, char *digest); @@ -47,4 +49,12 @@ #define ED_DESC_SIGNATURE_PREFIX "Tor router descriptor signature v1" +#ifdef ROUTERPARSE_PRIVATE +STATIC int check_one_family_cert(const uint8_t *cert_body, + size_t cert_body_size, + const struct ed25519_public_key_t *identity_key, + char **family_id_out, + time_t *family_expiration_out); +#endif + #endif /* !defined(TOR_ROUTERPARSE_H) */ diff -Nru tor-0.4.7.16/src/feature/hibernate/hibernate.c tor-0.4.9.6/src/feature/hibernate/hibernate.c --- tor-0.4.7.16/src/feature/hibernate/hibernate.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/feature/hibernate/hibernate.c 2026-03-25 14:30:34.000000000 +0000 @@ -930,6 +930,15 @@ } /** + * Return true iff we are currently shutting down. + */ +MOCK_IMPL(int, +we_are_shutting_down,(void)) +{ + return hibernate_state == HIBERNATE_STATE_EXITING; +} + +/** * Return true iff we are currently hibernating -- that is, if we are in * any non-live state. */ diff -Nru tor-0.4.7.16/src/feature/hibernate/hibernate.h tor-0.4.9.6/src/feature/hibernate/hibernate.h --- tor-0.4.7.16/src/feature/hibernate/hibernate.h 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/feature/hibernate/hibernate.h 2026-03-25 14:30:34.000000000 +0000 @@ -24,6 +24,7 @@ void accounting_add_bytes(size_t n_read, size_t n_written, int seconds); int accounting_record_bandwidth_usage(time_t now, or_state_t *state); void hibernate_begin_shutdown(void); +MOCK_DECL(int, we_are_shutting_down, (void)); MOCK_DECL(int, we_are_hibernating, (void)); MOCK_DECL(int, we_are_fully_hibernating,(void)); void consider_hibernation(time_t now); diff -Nru tor-0.4.7.16/src/feature/hibernate/include.am tor-0.4.9.6/src/feature/hibernate/include.am --- tor-0.4.7.16/src/feature/hibernate/include.am 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/feature/hibernate/include.am 2026-03-25 14:30:34.000000000 +0000 @@ -4,5 +4,5 @@ src/feature/hibernate/hibernate.c # ADD_C_FILE: INSERT HEADERS HERE. -noinst_HEADERS += \ +noinst_HEADERS += \ src/feature/hibernate/hibernate.h diff -Nru tor-0.4.7.16/src/feature/hs/hs_cache.c tor-0.4.9.6/src/feature/hs/hs_cache.c --- tor-0.4.7.16/src/feature/hs/hs_cache.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/feature/hs/hs_cache.c 2026-03-25 14:30:34.000000000 +0000 @@ -13,6 +13,7 @@ #include "app/config/config.h" #include "lib/crypt_ops/crypto_format.h" #include "lib/crypt_ops/crypto_util.h" +#include "lib/cc/torint.h" #include "feature/hs/hs_ident.h" #include "feature/hs/hs_common.h" #include "feature/hs/hs_client.h" @@ -25,6 +26,11 @@ #include "feature/nodelist/networkstatus_st.h" +/** + * Spare room for 1000 descriptors when pruning cache to avoid thrashing + * and memory fragmentation. */ +#define HSCACHE_PRUNE_SPARE_ROOM (1000 * HS_DESC_MAX_LEN) + /* Total counter of the cache size. */ static size_t hs_cache_total_allocation = 0; @@ -68,7 +74,7 @@ } /** Query our cache and return the entry or NULL if not found. */ -static hs_cache_dir_descriptor_t * +STATIC hs_cache_dir_descriptor_t * lookup_v3_desc_as_dir(const uint8_t *key) { tor_assert(key); @@ -147,6 +153,29 @@ tor_assert(desc); + /* Check if we've exceeded the MaxHSDirCacheBytes limit after adding + * this descriptor. If so, prune excess bytes leaving room for more. */ + const size_t max_cache_bytes = hs_cache_get_max_bytes(); + const size_t current_cache_bytes = hs_cache_get_total_allocation(); + if (max_cache_bytes > 0 && current_cache_bytes > max_cache_bytes) { + /* We prune only 1000 descriptors worth of memory here because + * pruning is an expensive O(n^2) option to keep finding lowest + * download count descs. */ + size_t bytes_to_remove = current_cache_bytes/2; + /* Ensure user didn't set a really low max hsdir cache vlue */ + if (HSCACHE_PRUNE_SPARE_ROOM < max_cache_bytes) { + bytes_to_remove = current_cache_bytes - + (max_cache_bytes - HSCACHE_PRUNE_SPARE_ROOM); + } + size_t removed = hs_cache_handle_oom(bytes_to_remove); + static ratelim_t hs_cache_oom_ratelim = RATELIM_INIT(600); + log_fn_ratelim(&hs_cache_oom_ratelim, LOG_NOTICE, LD_REND, + "HSDir cache exceeded limit " + "(%"TOR_PRIuSZ " > %"TOR_PRIuSZ " bytes). " + "Pruned %"TOR_PRIuSZ " bytes during an HS descriptor upload.", + current_cache_bytes, max_cache_bytes, removed); + } + /* Verify if we have an entry in the cache for that key and if yes, check * if we should replace it? */ cache_entry = lookup_v3_desc_as_dir(desc->key); @@ -163,15 +192,21 @@ goto err; } /* We now know that the descriptor we just received is a new one so + * preserve the downloaded counter from the old entry and then * remove the entry we currently have from our cache so we can then * store the new one. */ + desc->n_downloaded = cache_entry->n_downloaded; remove_v3_desc_as_dir(cache_entry); hs_cache_decrement_allocation(cache_get_dir_entry_size(cache_entry)); cache_dir_desc_free(cache_entry); } + /* Store the descriptor we just got. We are sure here that either we * don't have the entry or we have a newer descriptor and the old one - * has been removed from the cache. */ + * has been removed from the cache. We do this *after* pruning + * other descriptors so that this descriptor is not immediately pruned, + * if new. This prevents probing to detect OOM threshholds via its + * absence. */ store_v3_desc_as_dir(desc); /* Update our total cache size with this entry for the OOM. This uses the @@ -224,6 +259,72 @@ return -1; } +/** Clean the v3 cache by removing entries that are below or equal the + * downloaded target. + * + * Stop when the max_remove_bytes is reached. It is possible that more bytes + * are removed if max_remove_bytes is not aligned on cache entry size. + * + * Return the amount of bytes freed. The next_lowest param is set to the + * lowest n_downloaded value in the cache that is above target. + * + * If both next_lowest and returned value are 0, the cache is empty. */ +STATIC size_t +cache_clean_v3_by_downloaded_as_dir(const uint64_t target, + const size_t max_remove_bytes, + uint64_t *next_lowest) +{ + size_t bytes_removed = 0; + uint64_t lowest = 0; + + if (!hs_cache_v3_dir) { /* No cache to clean. Just return. */ + goto end; + } + + log_info(LD_REND, "Cleaning HS cache for downloaded target of %" PRIu64 + ". Maximum bytes to removed: %" TOR_PRIuSZ, + target, max_remove_bytes); + + DIGEST256MAP_FOREACH_MODIFY(hs_cache_v3_dir, key, + hs_cache_dir_descriptor_t *, entry) { + /* Downloaded counter is above target, ignore. Record next lowest. */ + if (entry->n_downloaded > target) { + if (lowest == 0 || lowest > entry->n_downloaded) { + lowest = entry->n_downloaded; + } + continue; + } + /* We have removed enough, avoid cleaning this entry. Reason we continue + * the loop is so we can find the next lowest value. Yes, with many + * entries, this could be expensive but this is only called during OOM + * cleanup which should be fairly rare. */ + if (bytes_removed >= max_remove_bytes) { + continue; + } + size_t entry_size = cache_get_dir_entry_size(entry); + /* Logging. */ + { + char key_b64[BASE64_DIGEST256_LEN + 1]; + digest256_to_base64(key_b64, (const char *) key); + log_info(LD_REND, "Removing v3 descriptor '%s' from HSDir cache. " + "Downloaded %" PRIu64 " times and " + "size of %" TOR_PRIuSZ " bytes", + safe_str_client(key_b64), entry->n_downloaded, entry_size); + } + /* Remove it from our cache. */ + MAP_DEL_CURRENT(key); + bytes_removed += entry_size; + /* Entry is not in the cache anymore, destroy it. */ + cache_dir_desc_free(entry); + /* Update our cache entry allocation size for the OOM. */ + hs_cache_decrement_allocation(entry_size); + } DIGEST256MAP_FOREACH_END; + + end: + *next_lowest = lowest; + return bytes_removed; +} + /** Clean the v3 cache by removing any entry that has expired using the * global_cutoff value. If global_cutoff is 0, the cleaning * process will use the lifetime found in the plaintext data section. Return @@ -334,6 +435,22 @@ return found; } +/** Using the given directory identifier, lookup the descriptor in our cache + * and if present, increment the downloaded counter. This is done when the + * directory connection fetching this descriptor is closed. */ +void +hs_cache_mark_dowloaded_as_dir(const hs_ident_dir_conn_t *ident) +{ + hs_cache_dir_descriptor_t *entry; + + tor_assert(ident); + + entry = lookup_v3_desc_as_dir(ident->blinded_pk.pubkey); + if (entry) { + entry->n_downloaded++; + } +} + /** Clean all directory caches using the current time now. */ void hs_cache_clean_as_dir(time_t now) @@ -581,6 +698,8 @@ tor_assert(service_pk); tor_assert(auth_key); + tor_assert_nonfatal(!ed25519_public_key_is_zero(service_pk)); + tor_assert_nonfatal(!ed25519_public_key_is_zero(auth_key)); /* Lookup the intro state cache for this service key. */ cache = digest256map_get(hs_cache_client_intro_state, service_pk->pubkey); @@ -1069,44 +1188,28 @@ * min_remove_bytes if the caches get emptied out so the caller should be * aware of this. */ size_t -hs_cache_handle_oom(time_t now, size_t min_remove_bytes) +hs_cache_handle_oom(size_t min_remove_bytes) { - time_t k; size_t bytes_removed = 0; + /* The downloaded counter value to remove. Start at 0 and increment to the + * next lowest value in the cache. */ + uint64_t target = 0; /* Our OOM handler called with 0 bytes to remove is a code flow error. */ tor_assert(min_remove_bytes != 0); - /* The algorithm is as follow. K is the oldest expected descriptor age. - * - * 1) Deallocate all entries from v3 cache that are older than K hours - * 2.1) If the amount of remove bytes has been reached, stop. - * 2) Set K = K - RendPostPeriod and repeat process until K is < 0. - * - * This ends up being O(Kn). - */ - - /* Set K to the oldest expected age in seconds which is the maximum - * lifetime of a cache entry. */ - k = hs_cache_max_entry_lifetime(); - + /* Loop until we have an empty cache or we have removed enough bytes. */ do { - time_t cutoff; - - /* If K becomes negative, it means we've empty the caches so stop and - * return what we were able to cleanup. */ - if (k < 0) { + /* This is valid due to the loop condition. At the start, min_remove_bytes + * can't be 0. */ + size_t bytes_to_free = (min_remove_bytes - bytes_removed); + size_t bytes_freed = + cache_clean_v3_by_downloaded_as_dir(target, bytes_to_free, &target); + if (bytes_freed == 0 && target == 0) { + /* Indicate that the cache is empty. */ break; } - /* Compute a cutoff value with K and the current time. */ - cutoff = now - k; - - if (bytes_removed < min_remove_bytes) { - /* We haven't remove enough bytes so clean v3 cache. */ - bytes_removed += cache_clean_v3_as_dir(now, cutoff); - /* Decrement K by a post period to shorten the cutoff. */ - k -= get_options()->RendPostPeriod; - } + bytes_removed += bytes_freed; } while (bytes_removed < min_remove_bytes); return bytes_removed; @@ -1152,6 +1255,14 @@ hs_cache_total_allocation = 0; } +/** Get the configured maximum cache size. */ +uint64_t +hs_cache_get_max_bytes(void) +{ + uint64_t opt = get_options()->MaxHSDirCacheBytes; + return opt != 0 ? opt : get_options()->MaxMemInQueues / 5; +} + /* Return total size of the cache. */ size_t hs_cache_get_total_allocation(void) @@ -1191,3 +1302,17 @@ } } } + +#ifdef TOR_UNIT_TESTS + +/** Test only: Set the downloaded counter value of a HSDir cache entry. */ +void +dir_set_downloaded(const ed25519_public_key_t *pk, uint64_t value) +{ + hs_cache_dir_descriptor_t *entry = lookup_v3_desc_as_dir(pk->pubkey); + if (entry) { + entry->n_downloaded = value; + } +} + +#endif /* TOR_UNIT_TESTS */ diff -Nru tor-0.4.7.16/src/feature/hs/hs_cache.h tor-0.4.9.6/src/feature/hs/hs_cache.h --- tor-0.4.7.16/src/feature/hs/hs_cache.h 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/feature/hs/hs_cache.h 2026-03-25 14:30:34.000000000 +0000 @@ -13,6 +13,7 @@ #include "feature/hs/hs_common.h" #include "feature/hs/hs_descriptor.h" +#include "feature/hs/hs_ident.h" #include "feature/rend/rendcommon.h" #include "feature/nodelist/torcert.h" @@ -68,6 +69,10 @@ /** Encoded descriptor which is basically in text form. It's a NUL terminated * string thus safe to strlen(). */ char *encoded_desc; + /** How many times this descriptor has been downloaded. We use this as an + * heuristic for the OOM cache cleaning. It is very large so we avoid an kind + * of possible wrapping. */ + uint64_t n_downloaded; } hs_cache_dir_descriptor_t; /* Public API */ @@ -82,7 +87,7 @@ void hs_cache_init(void); void hs_cache_free_all(void); void hs_cache_clean_as_dir(time_t now); -size_t hs_cache_handle_oom(time_t now, size_t min_remove_bytes); +size_t hs_cache_handle_oom(size_t min_remove_bytes); unsigned int hs_cache_get_max_descriptor_size(void); @@ -92,6 +97,7 @@ int hs_cache_store_as_dir(const char *desc); int hs_cache_lookup_as_dir(uint32_t version, const char *query, const char **desc_out); +void hs_cache_mark_dowloaded_as_dir(const hs_ident_dir_conn_t *ident); const hs_descriptor_t * hs_cache_lookup_as_client(const struct ed25519_public_key_t *key); @@ -116,6 +122,7 @@ bool hs_cache_client_new_auth_parse(const ed25519_public_key_t *service_pk); +uint64_t hs_cache_get_max_bytes(void); size_t hs_cache_get_total_allocation(void); void hs_cache_decrement_allocation(size_t n); void hs_cache_increment_allocation(size_t n); @@ -144,10 +151,18 @@ } hs_cache_client_descriptor_t; STATIC size_t cache_clean_v3_as_dir(time_t now, time_t global_cutoff); +STATIC size_t cache_clean_v3_by_downloaded_as_dir(const uint64_t target, + const size_t min_remove_bytes, + uint64_t *next_lowest); +STATIC hs_cache_dir_descriptor_t *lookup_v3_desc_as_dir(const uint8_t *key); STATIC hs_cache_client_descriptor_t * lookup_v3_desc_as_client(const uint8_t *key); +#ifdef TOR_UNIT_TESTS +void dir_set_downloaded(const ed25519_public_key_t *pk, uint64_t value); +#endif /* TOR_UNIT_TESTS */ + #endif /* defined(HS_CACHE_PRIVATE) */ #endif /* !defined(TOR_HS_CACHE_H) */ diff -Nru tor-0.4.7.16/src/feature/hs/hs_cell.c tor-0.4.9.6/src/feature/hs/hs_cell.c --- tor-0.4.7.16/src/feature/hs/hs_cell.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/feature/hs/hs_cell.c 2026-03-25 14:30:34.000000000 +0000 @@ -41,7 +41,7 @@ { size_t offset = 0; size_t mac_msg_len; - uint8_t mac_msg[RELAY_PAYLOAD_SIZE] = {0}; + uint8_t mac_msg[RELAY_PAYLOAD_SIZE_MAX] = {0}; tor_assert(encoded_cell); tor_assert(encrypted); @@ -299,8 +299,8 @@ size_t offset = 0; ssize_t encrypted_len; ssize_t encoded_cell_len, encoded_enc_cell_len; - uint8_t encoded_cell[RELAY_PAYLOAD_SIZE] = {0}; - uint8_t encoded_enc_cell[RELAY_PAYLOAD_SIZE] = {0}; + uint8_t encoded_cell[RELAY_PAYLOAD_SIZE_MAX] = {0}; + uint8_t encoded_enc_cell[RELAY_PAYLOAD_SIZE_MAX] = {0}; uint8_t *encrypted = NULL; uint8_t mac[DIGEST256_LEN]; crypto_cipher_t *cipher = NULL; @@ -339,7 +339,7 @@ * ENCRYPTED_DATA and MAC length. */ encrypted_len = sizeof(data->client_kp->pubkey) + encoded_enc_cell_len + sizeof(mac); - tor_assert(encrypted_len < RELAY_PAYLOAD_SIZE); + tor_assert(encrypted_len < RELAY_PAYLOAD_SIZE_MAX); encrypted = tor_malloc_zero(encrypted_len); /* Put the CLIENT_PK first. */ @@ -369,11 +369,85 @@ /* Cleanup. */ memwipe(&keys, 0, sizeof(keys)); memwipe(mac, 0, sizeof(mac)); - memwipe(encrypted, 0, sizeof(encrypted_len)); + memwipe(encrypted, 0, encrypted_len); memwipe(encoded_enc_cell, 0, sizeof(encoded_enc_cell)); tor_free(encrypted); } +/** Build the PoW cell extension and put it in the given extensions object. + * Return 0 on success, -1 on failure. */ +static int +build_introduce_pow_extension(const hs_pow_solution_t *pow_solution, + trn_extension_t *extensions) +{ + ssize_t ret; + size_t pow_ext_encoded_len; + uint8_t *field_array; + trn_extension_field_t *field = NULL; + trn_cell_extension_pow_t *pow_ext = NULL; + + tor_assert(pow_solution); + tor_assert(extensions); + + /* We are creating a cell extension field of type PoW solution. */ + field = trn_extension_field_new(); + trn_extension_field_set_field_type(field, TRUNNEL_EXT_TYPE_POW); + + /* Build PoW extension field. */ + pow_ext = trn_cell_extension_pow_new(); + + /* Copy PoW solution values into PoW extension cell. */ + + /* Equi-X base scheme */ + trn_cell_extension_pow_set_pow_version(pow_ext, TRUNNEL_POW_VERSION_EQUIX); + + memcpy(trn_cell_extension_pow_getarray_pow_nonce(pow_ext), + &pow_solution->nonce, TRUNNEL_POW_NONCE_LEN); + + trn_cell_extension_pow_set_pow_effort(pow_ext, pow_solution->effort); + + memcpy(trn_cell_extension_pow_getarray_pow_seed(pow_ext), + pow_solution->seed_head, TRUNNEL_POW_SEED_HEAD_LEN); + memcpy(trn_cell_extension_pow_getarray_pow_solution(pow_ext), + pow_solution->equix_solution, TRUNNEL_POW_SOLUTION_LEN); + + /* Set the field with the encoded PoW extension. */ + ret = trn_cell_extension_pow_encoded_len(pow_ext); + if (BUG(ret <= 0)) { + goto err; + } + pow_ext_encoded_len = ret; + + /* Set length field and the field array size length. */ + trn_extension_field_set_field_len(field, pow_ext_encoded_len); + trn_extension_field_setlen_field(field, pow_ext_encoded_len); + /* Encode the PoW extension into the cell extension field. */ + field_array = trn_extension_field_getarray_field(field); + ret = trn_cell_extension_pow_encode(field_array, + trn_extension_field_getlen_field(field), pow_ext); + if (BUG(ret <= 0)) { + goto err; + } + tor_assert(ret == (ssize_t)pow_ext_encoded_len); + + /* Finally, encode field into the cell extension. */ + trn_extension_add_fields(extensions, field); + + /* We've just add an extension field to the cell extensions so increment the + * total number. */ + trn_extension_set_num(extensions, trn_extension_get_num(extensions) + 1); + + /* Cleanup. PoW extension has been encoded at this point. */ + trn_cell_extension_pow_free(pow_ext); + + return 0; + +err: + trn_extension_field_free(field); + trn_cell_extension_pow_free(pow_ext); + return -1; +} + /** Build and set the INTRODUCE congestion control extension in the given * extensions. */ static void @@ -384,7 +458,7 @@ /* Build CC request extension. */ field = trn_extension_field_new(); trn_extension_field_set_field_type(field, - TRUNNEL_EXT_TYPE_CC_FIELD_REQUEST); + TRUNNEL_EXT_TYPE_CC_REQUEST); /* No payload indicating a request to use congestion control. */ trn_extension_field_set_field_len(field, 0); @@ -412,10 +486,14 @@ /* Setup extension(s) if any. */ ext = trn_extension_new(); tor_assert(ext); - /* Build congestion control extension is enabled. */ + /* Build congestion control extension if enabled. */ if (data->cc_enabled) { build_introduce_cc_extension(ext); } + /* Build PoW extension if present. */ + if (data->pow_solution) { + build_introduce_pow_extension(data->pow_solution, ext); + } trn_cell_introduce_encrypted_set_extensions(enc_cell, ext); /* Set the rendezvous cookie. */ @@ -631,7 +709,7 @@ ssize_t tmp_cell_mac_offset = sig_len + sizeof(cell->sig_len) + trn_cell_establish_intro_getlen_handshake_mac(cell); - uint8_t tmp_cell_enc[RELAY_PAYLOAD_SIZE] = {0}; + uint8_t tmp_cell_enc[RELAY_PAYLOAD_SIZE_MAX] = {0}; uint8_t mac[TRUNNEL_SHA3_256_LEN], *handshake_ptr; /* We first encode the current fields we have in the cell so we can @@ -660,7 +738,7 @@ { ssize_t tmp_cell_enc_len = 0; ssize_t tmp_cell_sig_offset = (sig_len + sizeof(cell->sig_len)); - uint8_t tmp_cell_enc[RELAY_PAYLOAD_SIZE] = {0}, *sig_ptr; + uint8_t tmp_cell_enc[RELAY_PAYLOAD_SIZE_MAX] = {0}, *sig_ptr; ed25519_signature_t sig; /* We first encode the current fields we have in the cell so we can @@ -686,7 +764,8 @@ } /* Encode the cell. Can't be bigger than a standard cell. */ - cell_len = trn_cell_establish_intro_encode(cell_out, RELAY_PAYLOAD_SIZE, + cell_len = trn_cell_establish_intro_encode(cell_out, + RELAY_PAYLOAD_SIZE_MAX, cell); done: @@ -716,6 +795,70 @@ return ret; } +/** Parse the cell PoW solution extension. Return 0 on success and data + * structure is updated with the PoW effort. Return -1 on any kind of error + * including if PoW couldn't be verified. */ +static int +handle_introduce2_encrypted_cell_pow_extension(const hs_service_t *service, + const hs_service_intro_point_t *ip, + const trn_extension_field_t *field, + hs_cell_introduce2_data_t *data) +{ + int ret = -1; + trn_cell_extension_pow_t *pow = NULL; + hs_pow_solution_t sol; + + tor_assert(field); + tor_assert(ip); + + if (!service->state.pow_state) { + log_info(LD_REND, "Unsolicited PoW solution in INTRODUCE2 request."); + goto end; + } + + if (trn_cell_extension_pow_parse(&pow, + trn_extension_field_getconstarray_field(field), + trn_extension_field_getlen_field(field)) < 0) { + goto end; + } + + /* There is only one version supported at the moment so validate we at least + * have that. */ + if (trn_cell_extension_pow_get_pow_version(pow) != + TRUNNEL_POW_VERSION_EQUIX) { + log_debug(LD_REND, "Unsupported PoW version. Malformed INTRODUCE2"); + goto end; + } + + /* Effort E */ + sol.effort = trn_cell_extension_pow_get_pow_effort(pow); + /* Seed C */ + memcpy(sol.seed_head, trn_cell_extension_pow_getconstarray_pow_seed(pow), + HS_POW_SEED_HEAD_LEN); + /* Nonce N */ + memcpy(sol.nonce, trn_cell_extension_pow_getconstarray_pow_nonce(pow), + HS_POW_NONCE_LEN); + /* Solution S */ + memcpy(sol.equix_solution, + trn_cell_extension_pow_getconstarray_pow_solution(pow), + HS_POW_EQX_SOL_LEN); + + if (hs_pow_verify(&ip->blinded_id, service->state.pow_state, &sol)) { + log_info(LD_REND, "PoW INTRODUCE2 request failed to verify."); + goto end; + } + + log_info(LD_REND, "PoW INTRODUCE2 request successfully verified."); + data->rdv_data.pow_effort = sol.effort; + + /* Successfully parsed and verified the PoW solution */ + ret = 0; + + end: + trn_cell_extension_pow_free(pow); + return ret; +} + /** For the encrypted INTRO2 cell in encrypted_section, use the crypto * material in data to compute the right ntor keys. Also validate the * INTRO2 MAC to ensure that the keys are the right ones. @@ -735,7 +878,7 @@ data->n_subcredentials, data->subcredentials, encrypted_section, - &data->client_pk); + &data->rdv_data.client_pk); if (intro_keys == NULL) { log_info(LD_REND, "Invalid INTRODUCE2 encrypted data. Unable to " "compute key material"); @@ -785,28 +928,42 @@ } /** Parse the given INTRODUCE cell extension. Update the data object - * accordingly depending on the extension. */ -static void -parse_introduce_cell_extension(hs_cell_introduce2_data_t *data, + * accordingly depending on the extension. Return 0 if it validated + * correctly, or return -1 if it is malformed (for example because it + * includes a PoW that doesn't verify). */ +static int +parse_introduce_cell_extension(const hs_service_t *service, + const hs_service_intro_point_t *ip, + hs_cell_introduce2_data_t *data, const trn_extension_field_t *field) { + int ret = 0; trn_extension_field_cc_t *cc_field = NULL; tor_assert(data); tor_assert(field); switch (trn_extension_field_get_field_type(field)) { - case TRUNNEL_EXT_TYPE_CC_FIELD_REQUEST: + case TRUNNEL_EXT_TYPE_CC_REQUEST: /* CC requests, enable it. */ - data->cc_enabled = 1; + data->rdv_data.cc_enabled = 1; data->pv.protocols_known = 1; - data->pv.supports_congestion_control = data->cc_enabled; + data->pv.supports_congestion_control = data->rdv_data.cc_enabled; + break; + case TRUNNEL_EXT_TYPE_POW: + /* PoW request. If successful, the effort is put in the data. */ + if (handle_introduce2_encrypted_cell_pow_extension(service, ip, + field, data) < 0) { + log_fn(LOG_PROTOCOL_WARN, LD_REND, "Invalid PoW cell extension."); + ret = -1; + } break; default: break; } trn_extension_field_cc_free(cc_field); + return ret; } /** Parse the INTRODUCE2 cell using data which contains everything we need to @@ -816,7 +973,8 @@ ssize_t hs_cell_parse_introduce2(hs_cell_introduce2_data_t *data, const origin_circuit_t *circ, - const hs_service_t *service) + const hs_service_t *service, + const hs_service_intro_point_t *ip) { int ret = -1; time_t elapsed; @@ -867,7 +1025,7 @@ * guaranteed to exist because of the length check above). We are gonna use * the client public key to compute the ntor keys and decrypt the payload: */ - memcpy(&data->client_pk.public_key, encrypted_section, + memcpy(&data->rdv_data.client_pk.public_key, encrypted_section, CURVE25519_PUBKEY_LEN); /* Get the right INTRODUCE2 ntor keys and verify the cell MAC */ @@ -883,12 +1041,13 @@ { /* The ENCRYPTED_DATA section starts just after the CLIENT_PK. */ const uint8_t *encrypted_data = - encrypted_section + sizeof(data->client_pk); + encrypted_section + sizeof(data->rdv_data.client_pk); /* It's symmetric encryption so it's correct to use the ENCRYPTED length * for decryption. Computes the length of ENCRYPTED_DATA meaning removing * the CLIENT_PK and MAC length. */ size_t encrypted_data_len = - encrypted_section_len - (sizeof(data->client_pk) + DIGEST256_LEN); + encrypted_section_len - + (sizeof(data->rdv_data.client_pk) + DIGEST256_LEN); /* This decrypts the ENCRYPTED_DATA section of the cell. */ decrypted = decrypt_introduce2(intro_keys->enc_key, @@ -915,12 +1074,12 @@ /* Extract onion key and rendezvous cookie from the cell used for the * rendezvous point circuit e2e encryption. */ - memcpy(data->onion_pk.public_key, + memcpy(data->rdv_data.onion_pk.public_key, trn_cell_introduce_encrypted_getconstarray_onion_key(enc_cell), CURVE25519_PUBKEY_LEN); - memcpy(data->rendezvous_cookie, + memcpy(data->rdv_data.rendezvous_cookie, trn_cell_introduce_encrypted_getconstarray_rend_cookie(enc_cell), - sizeof(data->rendezvous_cookie)); + sizeof(data->rdv_data.rendezvous_cookie)); /* Extract rendezvous link specifiers. */ for (size_t idx = 0; @@ -934,7 +1093,7 @@ if (BUG(!lspec_dup)) { goto done; } - smartlist_add(data->link_specifiers, lspec_dup); + smartlist_add(data->rdv_data.link_specifiers, lspec_dup); } /* Extract any extensions. */ @@ -948,19 +1107,22 @@ /* The number of extensions should match the number of fields. */ break; } - parse_introduce_cell_extension(data, field); + if (parse_introduce_cell_extension(service, ip, data, field) < 0) { + goto done; + } } } /* If the client asked for congestion control, but we don't support it, * that's a failure. It should not have asked, based on our descriptor. */ - if (data->cc_enabled && !congestion_control_enabled()) { + if (data->rdv_data.cc_enabled && !congestion_control_enabled()) { goto done; } /* Success. */ ret = 0; - log_info(LD_REND, "Valid INTRODUCE2 cell. Launching rendezvous circuit."); + log_info(LD_REND, + "Valid INTRODUCE2 cell. Willing to launch rendezvous circuit."); done: if (intro_keys) { @@ -1000,7 +1162,8 @@ memcpy(trn_cell_rendezvous1_getarray_handshake_info(cell), rendezvous_handshake_info, rendezvous_handshake_info_len); /* Encoding. */ - cell_len = trn_cell_rendezvous1_encode(cell_out, RELAY_PAYLOAD_SIZE, cell); + cell_len = trn_cell_rendezvous1_encode(cell_out, + RELAY_PAYLOAD_SIZE_MAX, cell); tor_assert(cell_len > 0); trn_cell_rendezvous1_free(cell); @@ -1039,7 +1202,8 @@ introduce1_set_encrypted(cell, data); /* Final encoding. */ - cell_len = trn_cell_introduce1_encode(cell_out, RELAY_PAYLOAD_SIZE, cell); + cell_len = trn_cell_introduce1_encode(cell_out, + RELAY_PAYLOAD_SIZE_MAX, cell); trn_cell_introduce1_free(cell); return cell_len; diff -Nru tor-0.4.7.16/src/feature/hs/hs_cell.h tor-0.4.9.6/src/feature/hs/hs_cell.h --- tor-0.4.7.16/src/feature/hs/hs_cell.h 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/feature/hs/hs_cell.h 2026-03-25 14:30:34.000000000 +0000 @@ -11,6 +11,7 @@ #include "core/or/or.h" #include "feature/hs/hs_service.h" +#include "feature/hs/hs_pow.h" /** An INTRODUCE1 cell requires at least this amount of bytes (see section * 3.2.2 of the specification). Below this value, the cell must be padded. */ @@ -42,8 +43,27 @@ smartlist_t *link_specifiers; /** Congestion control parameters. */ unsigned int cc_enabled : 1; + /** PoW solution (Can be NULL if disabled). */ + const hs_pow_solution_t *pow_solution; } hs_cell_introduce1_data_t; +/** Introduction data needed to launch a rendezvous circuit. This is set after + * receiving an INTRODUCE2 valid cell. */ +typedef struct hs_cell_intro_rdv_data_t { + /** Onion public key computed using the INTRODUCE2 encrypted section. */ + curve25519_public_key_t onion_pk; + /** Rendezvous cookie taken from the INTRODUCE2 encrypted section. */ + uint8_t rendezvous_cookie[REND_COOKIE_LEN]; + /** Client public key from the INTRODUCE2 encrypted section. */ + curve25519_public_key_t client_pk; + /** Link specifiers of the rendezvous point. Contains link_specifier_t. */ + smartlist_t *link_specifiers; + /** Congestion control parameters. */ + unsigned int cc_enabled : 1; + /** PoW effort. */ + uint32_t pow_effort; +} hs_cell_intro_rdv_data_t; + /** This data structure contains data that we need to parse an INTRODUCE2 cell * which is used by the INTRODUCE2 cell parsing function. On a successful * parsing, the onion_pk and rendezvous_cookie will be populated with the @@ -74,20 +94,12 @@ /*** Mutable Section: Set upon parsing INTRODUCE2 cell. ***/ - /** Onion public key computed using the INTRODUCE2 encrypted section. */ - curve25519_public_key_t onion_pk; - /** Rendezvous cookie taken from the INTRODUCE2 encrypted section. */ - uint8_t rendezvous_cookie[REND_COOKIE_LEN]; - /** Client public key from the INTRODUCE2 encrypted section. */ - curve25519_public_key_t client_pk; - /** Link specifiers of the rendezvous point. Contains link_specifier_t. */ - smartlist_t *link_specifiers; + /** Data needed to launch a rendezvous circuit. */ + hs_cell_intro_rdv_data_t rdv_data; /** Replay cache of the introduction point. */ replaycache_t *replay_cache; /** Flow control negotiation parameters. */ protover_summary_flags_t pv; - /** Congestion control parameters. */ - unsigned int cc_enabled : 1; } hs_cell_introduce2_data_t; /* Build cell API. */ @@ -110,7 +122,8 @@ size_t payload_len); ssize_t hs_cell_parse_introduce2(hs_cell_introduce2_data_t *data, const origin_circuit_t *circ, - const hs_service_t *service); + const hs_service_t *service, + const hs_service_intro_point_t *ip); int hs_cell_parse_introduce_ack(const uint8_t *payload, size_t payload_len); int hs_cell_parse_rendezvous2(const uint8_t *payload, size_t payload_len, uint8_t *handshake_info, diff -Nru tor-0.4.7.16/src/feature/hs/hs_circuit.c tor-0.4.9.6/src/feature/hs/hs_circuit.c --- tor-0.4.7.16/src/feature/hs/hs_circuit.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/feature/hs/hs_circuit.c 2026-03-25 14:30:34.000000000 +0000 @@ -22,6 +22,7 @@ #include "feature/client/circpathbias.h" #include "feature/hs/hs_cell.h" #include "feature/hs/hs_circuit.h" +#include "feature/hs/hs_common.h" #include "feature/hs/hs_ob.h" #include "feature/hs/hs_circuitmap.h" #include "feature/hs/hs_client.h" @@ -34,6 +35,7 @@ #include "lib/crypt_ops/crypto_dh.h" #include "lib/crypt_ops/crypto_rand.h" #include "lib/crypt_ops/crypto_util.h" +#include "lib/time/compat_time.h" /* Trunnel. */ #include "trunnel/ed25519_cert.h" @@ -42,9 +44,22 @@ #include "core/or/congestion_control_st.h" #include "core/or/cpath_build_state_st.h" #include "core/or/crypt_path_st.h" +#include "core/or/extend_info_st.h" #include "feature/nodelist/node_st.h" #include "core/or/origin_circuit_st.h" +/** Helper: Free a pending rend object. */ +static inline void +free_pending_rend(pending_rend_t *req) +{ + if (!req) { + return; + } + link_specifier_smartlist_free(req->rdv_data.link_specifiers); + memwipe(req, 0, sizeof(pending_rend_t)); + tor_free(req); +} + /** A circuit is about to become an e2e rendezvous circuit. Check * circ_purpose and ensure that it's properly set. Return true iff * circuit purpose is properly set, otherwise return false. */ @@ -95,8 +110,12 @@ cpath = tor_malloc_zero(sizeof(crypt_path_t)); cpath->magic = CRYPT_PATH_MAGIC; - if (cpath_init_circuit_crypto(cpath, (char*)keys, sizeof(keys), - is_service_side, 1) < 0) { + // TODO CGO: Pick relay cell format based on capabilities. + cpath->relay_cell_format = RELAY_CELL_FORMAT_V0; + relay_crypto_alg_t alg = is_service_side ? RELAY_CRYPTO_ALG_TOR1_HSS : + RELAY_CRYPTO_ALG_TOR1_HSC; + + if (cpath_init_circuit_crypto(alg, cpath, (char*)keys, sizeof(keys)) < 0) { tor_free(cpath); goto err; } @@ -238,6 +257,7 @@ ident = hs_ident_circuit_new(&service->keys.identity_pk); ed25519_pubkey_copy(&ident->intro_auth_pk, &ip->auth_key_kp.pubkey); + tor_assert_nonfatal(!ed25519_public_key_is_zero(&ident->intro_auth_pk)); return ident; } @@ -252,7 +272,7 @@ hs_service_intro_point_t *ip, origin_circuit_t *circ) { ssize_t cell_len; - uint8_t payload[RELAY_PAYLOAD_SIZE]; + uint8_t payload[RELAY_PAYLOAD_SIZE_MAX]; tor_assert(service); tor_assert(ip); @@ -310,24 +330,26 @@ * MAX_REND_FAILURES then it will give up. */ MOCK_IMPL(STATIC void, launch_rendezvous_point_circuit,(const hs_service_t *service, - const hs_service_intro_point_t *ip, - const hs_cell_introduce2_data_t *data)) + const ed25519_public_key_t *ip_auth_pubkey, + const curve25519_keypair_t *ip_enc_key_kp, + const hs_cell_intro_rdv_data_t *rdv_data, + time_t now)) { int circ_needs_uptime; - time_t now = time(NULL); extend_info_t *info = NULL; origin_circuit_t *circ; tor_assert(service); - tor_assert(ip); - tor_assert(data); + tor_assert(ip_auth_pubkey); + tor_assert(ip_enc_key_kp); + tor_assert(rdv_data); circ_needs_uptime = hs_service_requires_uptime_circ(service->config.ports); /* Get the extend info data structure for the chosen rendezvous point * specified by the given link specifiers. */ - info = hs_get_extend_info_from_lspecs(data->link_specifiers, - &data->onion_pk, + info = hs_get_extend_info_from_lspecs(rdv_data->link_specifiers, + &rdv_data->onion_pk, service->config.is_single_onion); if (info == NULL) { /* We are done here, we can't extend to the rendezvous point. */ @@ -374,7 +396,8 @@ log_info(LD_REND, "Rendezvous circuit launched to %s with cookie %s " "for %s service %s", safe_str_client(extend_info_describe(info)), - safe_str_client(hex_str((const char *) data->rendezvous_cookie, + safe_str_client(hex_str((const char *) + rdv_data->rendezvous_cookie, REND_COOKIE_LEN)), get_service_anonymity_string(service), safe_str_client(service->onion_address)); @@ -391,9 +414,10 @@ * key will be used for the RENDEZVOUS1 cell that will be sent on the * circuit once opened. */ curve25519_keypair_generate(&ephemeral_kp, 0); - if (hs_ntor_service_get_rendezvous1_keys(&ip->auth_key_kp.pubkey, - &ip->enc_key_kp, - &ephemeral_kp, &data->client_pk, + if (hs_ntor_service_get_rendezvous1_keys(ip_auth_pubkey, + ip_enc_key_kp, + &ephemeral_kp, + &rdv_data->client_pk, &keys) < 0) { /* This should not really happened but just in case, don't make tor * freak out, close the circuit and move on. */ @@ -404,15 +428,22 @@ goto end; } circ->hs_ident = create_rp_circuit_identifier(service, - data->rendezvous_cookie, - &ephemeral_kp.pubkey, &keys); + rdv_data->rendezvous_cookie, + &ephemeral_kp.pubkey, &keys); memwipe(&ephemeral_kp, 0, sizeof(ephemeral_kp)); memwipe(&keys, 0, sizeof(keys)); tor_assert(circ->hs_ident); } + /* Remember PoW state if this introduction included a valid proof of work + * client puzzle extension. */ + if (rdv_data->pow_effort > 0) { + circ->hs_pow_effort = rdv_data->pow_effort; + circ->hs_with_pow_circ = 1; + } + /* Setup congestion control if asked by the client from the INTRO cell. */ - if (data->cc_enabled) { + if (rdv_data->cc_enabled) { hs_circ_setup_congestion_control(circ, congestion_control_sendme_inc(), service->config.is_single_onion); } @@ -494,6 +525,10 @@ if (new_circ == NULL) { log_warn(LD_REND, "Failed to launch rendezvous circuit to %s", safe_str_client(extend_info_describe(bstate->chosen_exit))); + + hs_metrics_failed_rdv(&circ->hs_ident->identity_pk, + HS_METRICS_ERR_RDV_RETRY); + goto done; } @@ -594,6 +629,298 @@ * Thus possible that this passes through. */ } +/** Return less than 0 if a precedes b, 0 if a equals b and greater than 0 if + * b precedes a. Note that *higher* effort is *earlier* in the pqueue. */ +static int +compare_rend_request_by_effort_(const void *_a, const void *_b) +{ + const pending_rend_t *a = _a, *b = _b; + if (a->rdv_data.pow_effort > b->rdv_data.pow_effort) { + return -1; + } else if (a->rdv_data.pow_effort == b->rdv_data.pow_effort) { + /* tie-breaker! use the time it was added to the queue. older better. */ + if (a->enqueued_ts < b->enqueued_ts) + return -1; + if (a->enqueued_ts > b->enqueued_ts) + return 1; + return 0; + } else { + return 1; + } +} + +/** Return 1 if a request waiting in our service-side pqueue is old + * enough that we should just discard it rather than trying to respond, + * or 0 if we still like it. As a heuristic, choose half of the total + * permitted time interval (so we don't approve trying to respond to + * requests when we will then give up on them a moment later). + */ +static int +queued_rend_request_is_too_old(pending_rend_t *req, time_t now) +{ + if ((req->enqueued_ts + MAX_REND_TIMEOUT/2) < now) + return 1; + return 0; +} + +/** Our rendezvous request priority queue is too full; keep the first + * pqueue_high_level/2 entries and discard the rest. + */ +static void +trim_rend_pqueue(hs_pow_service_state_t *pow_state, time_t now) +{ + smartlist_t *old_pqueue = pow_state->rend_request_pqueue; + smartlist_t *new_pqueue = pow_state->rend_request_pqueue = smartlist_new(); + + log_info(LD_REND, "Rendezvous request priority queue has " + "reached capacity (%d). Discarding the bottom half.", + smartlist_len(old_pqueue)); + + while (smartlist_len(old_pqueue) && + smartlist_len(new_pqueue) < pow_state->pqueue_high_level/2) { + /* while there are still old ones, and the new one isn't full yet */ + pending_rend_t *req = + smartlist_pqueue_pop(old_pqueue, + compare_rend_request_by_effort_, + offsetof(pending_rend_t, idx)); + if (queued_rend_request_is_too_old(req, now)) { + log_info(LD_REND, "While trimming, rend request has been pending " + "for too long; discarding."); + + pow_state->max_trimmed_effort = MAX(pow_state->max_trimmed_effort, + req->rdv_data.pow_effort); + + free_pending_rend(req); + } else { + smartlist_pqueue_add(new_pqueue, + compare_rend_request_by_effort_, + offsetof(pending_rend_t, idx), req); + } + } + + /* Ok, we have rescued all the entries we want to keep. The rest are + * all excess. */ + SMARTLIST_FOREACH_BEGIN(old_pqueue, pending_rend_t *, req) { + pow_state->max_trimmed_effort = MAX(pow_state->max_trimmed_effort, + req->rdv_data.pow_effort); + free_pending_rend(req); + } SMARTLIST_FOREACH_END(req); + smartlist_free(old_pqueue); +} + +/** Count up how many pending outgoing (CIRCUIT_PURPOSE_S_CONNECT_REND) + * circuits there are for this service. Used in the PoW rate limiting + * world to decide whether it's time to launch any new ones. + */ +static int +count_service_rp_circuits_pending(hs_service_t *service) +{ + origin_circuit_t *ocirc = NULL; + int count = 0; + while ((ocirc = circuit_get_next_by_purpose(ocirc, + CIRCUIT_PURPOSE_S_CONNECT_REND))) { + /* Count up circuits that are v3 and for this service. */ + if (ocirc->hs_ident != NULL && + ed25519_pubkey_eq(ô->hs_ident->identity_pk, + &service->keys.identity_pk)) { + count++; + } + } + return count; +} + +/** Peek at the top entry on the pending rend pqueue, which must not be empty. + * If its level of effort is at least what we're suggesting for that service + * right now, return 1, else return 0. + */ +int +top_of_rend_pqueue_is_worthwhile(hs_pow_service_state_t *pow_state) +{ + tor_assert(pow_state->rend_request_pqueue); + tor_assert(smartlist_len(pow_state->rend_request_pqueue)); + + pending_rend_t *req = + smartlist_get(pow_state->rend_request_pqueue, 0); + + if (req->rdv_data.pow_effort >= pow_state->suggested_effort) + return 1; + + return 0; +} + +/** Abandon and free all pending rend requests, leaving the pqueue empty. */ +void +rend_pqueue_clear(hs_pow_service_state_t *pow_state) +{ + tor_assert(pow_state->rend_request_pqueue); + while (smartlist_len(pow_state->rend_request_pqueue)) { + pending_rend_t *req = smartlist_pop_last(pow_state->rend_request_pqueue); + free_pending_rend(req); + } +} + +/** What is the threshold of in-progress (CIRCUIT_PURPOSE_S_CONNECT_REND) + * rendezvous responses above which we won't launch new low-effort rendezvous + * responses? (Intro2 cells with suitable PoW effort are not affected + * by this threshold.) */ +#define MAX_CHEAP_REND_CIRCUITS_IN_PROGRESS 16 + +static void +handle_rend_pqueue_cb(mainloop_event_t *ev, void *arg) +{ + hs_service_t *service = arg; + hs_pow_service_state_t *pow_state = service->state.pow_state; + time_t now = time(NULL); + int in_flight = count_service_rp_circuits_pending(service); + + (void) ev; /* Not using the returned event, make compiler happy. */ + + log_info(LD_REND, "Considering launching more rendezvous responses. " + "%d in-flight, %d pending.", + in_flight, + smartlist_len(pow_state->rend_request_pqueue)); + + /* Process only one rend request per callback, so that this work will not + * be prioritized over other event loop callbacks. We may need to retry + * in order to find one request that's still viable. */ + while (smartlist_len(pow_state->rend_request_pqueue) > 0) { + + /* first, peek at the top result to see if we want to pop it */ + if (in_flight >= MAX_CHEAP_REND_CIRCUITS_IN_PROGRESS && + !top_of_rend_pqueue_is_worthwhile(pow_state)) { + /* We have queued requests, but they are all low priority, and also + * we have too many in-progress rendezvous responses. Don't launch + * any more. Schedule ourselves to reassess in a bit. */ + log_info(LD_REND, "Next request to launch is low priority, and " + "%d in-flight already. Waiting to launch more.", in_flight); + const struct timeval delay_tv = { 0, 100000 }; + mainloop_event_schedule(pow_state->pop_pqueue_ev, &delay_tv); + return; /* done here! no cleanup needed. */ + } + + if (pow_state->using_pqueue_bucket) { + token_bucket_ctr_refill(&pow_state->pqueue_bucket, + (uint32_t) monotime_coarse_absolute_sec()); + + if (token_bucket_ctr_get(&pow_state->pqueue_bucket) > 0) { + token_bucket_ctr_dec(&pow_state->pqueue_bucket, 1); + } else { + /* Waiting for pqueue rate limit to refill, come back later */ + const struct timeval delay_tv = { 0, 100000 }; + mainloop_event_schedule(pow_state->pop_pqueue_ev, &delay_tv); + return; + } + } + + /* Pop next request by effort. */ + pending_rend_t *req = + smartlist_pqueue_pop(pow_state->rend_request_pqueue, + compare_rend_request_by_effort_, + offsetof(pending_rend_t, idx)); + + hs_metrics_pow_pqueue_rdv(service, + smartlist_len(pow_state->rend_request_pqueue)); + + log_info(LD_REND, "Dequeued pending rendezvous request with effort: %u. " + "Waited %d. " + "Remaining requests: %u", + req->rdv_data.pow_effort, + (int)(now - req->enqueued_ts), + smartlist_len(pow_state->rend_request_pqueue)); + + if (queued_rend_request_is_too_old(req, now)) { + log_info(LD_REND, "Top rend request has been pending for too long; " + "discarding and moving to the next one."); + free_pending_rend(req); + continue; /* do not increment count, this one's free */ + } + + /* Launch the rendezvous circuit. */ + launch_rendezvous_point_circuit(service, &req->ip_auth_pubkey, + &req->ip_enc_key_kp, &req->rdv_data, now); + free_pending_rend(req); + + ++pow_state->rend_handled; + ++in_flight; + break; + } + + /* If there are still some pending rendezvous circuits in the pqueue then + * reschedule the event in order to continue handling them. */ + if (smartlist_len(pow_state->rend_request_pqueue) > 0) { + mainloop_event_activate(pow_state->pop_pqueue_ev); + + if (smartlist_len(pow_state->rend_request_pqueue) >= + pow_state->pqueue_low_level) { + pow_state->had_queue = 1; + } + } +} + +/** Given the information needed to launch a rendezvous circuit and an + * effort value, enqueue the rendezvous request in the service's PoW priority + * queue with the effort being the priority. + * + * Return 0 if we successfully enqueued the request else -1. */ +static int +enqueue_rend_request(const hs_service_t *service, hs_service_intro_point_t *ip, + hs_cell_introduce2_data_t *data, time_t now) +{ + hs_pow_service_state_t *pow_state = NULL; + pending_rend_t *req = NULL; + + tor_assert(service); + tor_assert(ip); + tor_assert(data); + + /* Ease our lives */ + pow_state = service->state.pow_state; + + req = tor_malloc_zero(sizeof(pending_rend_t)); + + /* Copy over the rendezvous request the needed data to launch a circuit. */ + ed25519_pubkey_copy(&req->ip_auth_pubkey, &ip->auth_key_kp.pubkey); + memcpy(&req->ip_enc_key_kp, &ip->enc_key_kp, sizeof(req->ip_enc_key_kp)); + memcpy(&req->rdv_data, &data->rdv_data, sizeof(req->rdv_data)); + /* Invalidate the link specifier pointer in the introduce2 data so it + * doesn't get freed under us. */ + data->rdv_data.link_specifiers = NULL; + req->idx = -1; + req->enqueued_ts = now; + + /* Enqueue the rendezvous request. */ + smartlist_pqueue_add(pow_state->rend_request_pqueue, + compare_rend_request_by_effort_, + offsetof(pending_rend_t, idx), req); + + hs_metrics_pow_pqueue_rdv(service, + smartlist_len(pow_state->rend_request_pqueue)); + + log_info(LD_REND, "Enqueued rendezvous request with effort: %u. " + "Queued requests: %u", + req->rdv_data.pow_effort, + smartlist_len(pow_state->rend_request_pqueue)); + + /* Initialize the priority queue event if it hasn't been done so already. */ + if (pow_state->pop_pqueue_ev == NULL) { + pow_state->pop_pqueue_ev = + mainloop_event_postloop_new(handle_rend_pqueue_cb, (void *)service); + } + + /* Activate event, we just enqueued a rendezvous request. */ + mainloop_event_activate(pow_state->pop_pqueue_ev); + + /* See if there are so many cells queued that we need to cull. */ + if (smartlist_len(pow_state->rend_request_pqueue) >= + pow_state->pqueue_high_level) { + trim_rend_pqueue(pow_state, now); + hs_metrics_pow_pqueue_rdv(service, + smartlist_len(pow_state->rend_request_pqueue)); + } + + return 0; +} + /* ========== */ /* Public API */ /* ========== */ @@ -830,7 +1157,7 @@ origin_circuit_t *circ) { size_t payload_len; - uint8_t payload[RELAY_PAYLOAD_SIZE] = {0}; + uint8_t payload[RELAY_PAYLOAD_SIZE_MAX] = {0}; tor_assert(service); tor_assert(circ); @@ -864,13 +1191,17 @@ if (relay_send_command_from_edge(CONTROL_CELL_ID, TO_CIRCUIT(circ), RELAY_COMMAND_RENDEZVOUS1, - (const char *) payload, payload_len, + (const char *) payload, + payload_len, circ->cpath->prev) < 0) { /* On error, circuit is closed. */ log_warn(LD_REND, "Unable to send RENDEZVOUS1 cell on circuit %u " "for service %s", TO_CIRCUIT(circ)->n_circ_id, safe_str_client(service->onion_address)); + + hs_metrics_failed_rdv(&service->keys.identity_pk, + HS_METRICS_ERR_RDV_RENDEZVOUS1); goto done; } @@ -880,6 +1211,8 @@ sizeof(circ->hs_ident->rendezvous_ntor_key_seed), 1) < 0) { log_warn(LD_GENERAL, "Failed to setup circ"); + + hs_metrics_failed_rdv(&service->keys.identity_pk, HS_METRICS_ERR_RDV_E2E); goto done; } @@ -980,6 +1313,7 @@ int ret = -1; time_t elapsed; hs_cell_introduce2_data_t data; + time_t now = time(NULL); tor_assert(service); tor_assert(circ); @@ -993,23 +1327,28 @@ data.enc_kp = &ip->enc_key_kp; data.payload = payload; data.payload_len = payload_len; - data.link_specifiers = smartlist_new(); data.replay_cache = ip->replay_cache; - data.cc_enabled = 0; - - if (get_subcredential_for_handling_intro2_cell(service, - &data, subcredential)) { + data.rdv_data.link_specifiers = smartlist_new(); + data.rdv_data.cc_enabled = 0; + data.rdv_data.pow_effort = 0; + + if (get_subcredential_for_handling_intro2_cell(service, &data, + subcredential)) { + hs_metrics_reject_intro_req(service, + HS_METRICS_ERR_INTRO_REQ_SUBCREDENTIAL); goto done; } - if (hs_cell_parse_introduce2(&data, circ, service) < 0) { + if (hs_cell_parse_introduce2(&data, circ, service, ip) < 0) { + hs_metrics_reject_intro_req(service, HS_METRICS_ERR_INTRO_REQ_INTRODUCE2); goto done; } /* Check whether we've seen this REND_COOKIE before to detect repeats. */ if (replaycache_add_test_and_elapsed( service->state.replay_cache_rend_cookie, - data.rendezvous_cookie, sizeof(data.rendezvous_cookie), + data.rdv_data.rendezvous_cookie, + sizeof(data.rdv_data.rendezvous_cookie), &elapsed)) { /* A Tor client will send a new INTRODUCE1 cell with the same REND_COOKIE * as its previous one if its intro circ times out while in state @@ -1020,6 +1359,8 @@ log_info(LD_REND, "We received an INTRODUCE2 cell with same REND_COOKIE " "field %ld seconds ago. Dropping cell.", (long int) elapsed); + hs_metrics_reject_intro_req(service, + HS_METRICS_ERR_INTRO_REQ_INTRODUCE2_REPLAY); goto done; } @@ -1027,13 +1368,33 @@ * so increment our counter that we've seen one on this intro point. */ ip->introduce2_count++; + /* Add the rendezvous request to the priority queue if PoW defenses are + * enabled, otherwise rendezvous as usual. */ + if (have_module_pow() && service->config.has_pow_defenses_enabled) { + log_info(LD_REND, + "Adding introduction request to pqueue with effort: %u", + data.rdv_data.pow_effort); + if (enqueue_rend_request(service, ip, &data, now) < 0) { + goto done; + } + + /* Track the total effort in valid requests received this period */ + service->state.pow_state->total_effort += data.rdv_data.pow_effort; + + /* Successfully added rend circuit to priority queue. */ + ret = 0; + goto done; + } + /* Launch rendezvous circuit with the onion key and rend cookie. */ - launch_rendezvous_point_circuit(service, ip, &data); + launch_rendezvous_point_circuit(service, &ip->auth_key_kp.pubkey, + &ip->enc_key_kp, &data.rdv_data, now); /* Success. */ ret = 0; done: - link_specifier_smartlist_free(data.link_specifiers); + /* Note that if PoW defenses are enabled, this is NULL. */ + link_specifier_smartlist_free(data.rdv_data.link_specifiers); memwipe(&data, 0, sizeof(data)); return ret; } @@ -1080,11 +1441,12 @@ hs_circ_send_introduce1(origin_circuit_t *intro_circ, origin_circuit_t *rend_circ, const hs_desc_intro_point_t *ip, - const hs_subcredential_t *subcredential) + const hs_subcredential_t *subcredential, + const hs_pow_solution_t *pow_solution) { int ret = -1; ssize_t payload_len; - uint8_t payload[RELAY_PAYLOAD_SIZE] = {0}; + uint8_t payload[RELAY_PAYLOAD_SIZE_MAX] = {0}; hs_cell_introduce1_data_t intro1_data; tor_assert(intro_circ); @@ -1114,6 +1476,9 @@ goto close; } + /* Set the PoW solution if any. */ + intro1_data.pow_solution = pow_solution; + /* If the rend circ was set up for congestion control, add that to the * intro data, to signal it in an extension */ if (TO_CIRCUIT(rend_circ)->ccontrol) { @@ -1165,7 +1530,7 @@ hs_circ_send_establish_rendezvous(origin_circuit_t *circ) { ssize_t cell_len = 0; - uint8_t cell[RELAY_PAYLOAD_SIZE] = {0}; + uint8_t cell[RELAY_PAYLOAD_SIZE_MAX] = {0}; tor_assert(circ); tor_assert(TO_CIRCUIT(circ)->purpose == CIRCUIT_PURPOSE_C_ESTABLISH_REND); diff -Nru tor-0.4.7.16/src/feature/hs/hs_circuit.h tor-0.4.9.6/src/feature/hs/hs_circuit.h --- tor-0.4.7.16/src/feature/hs/hs_circuit.h 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/feature/hs/hs_circuit.h 2026-03-25 14:30:34.000000000 +0000 @@ -12,8 +12,29 @@ #include "core/or/or.h" #include "lib/crypt_ops/crypto_ed25519.h" +#include "feature/hs/hs_cell.h" #include "feature/hs/hs_service.h" +/** Pending rendezvous request. This is put in a service priority queue. */ +typedef struct pending_rend_t { + /* Intro point authentication pubkey. */ + ed25519_public_key_t ip_auth_pubkey; + /* Intro point encryption keypair for the "ntor" type. */ + curve25519_keypair_t ip_enc_key_kp; + + /* Rendezvous data for the circuit. */ + hs_cell_intro_rdv_data_t rdv_data; + + /** Position of element in the heap */ + int idx; + + /** When was this request enqueued. */ + time_t enqueued_ts; +} pending_rend_t; + +int top_of_rend_pqueue_is_worthwhile(hs_pow_service_state_t *pow_state); +void rend_pqueue_clear(hs_pow_service_state_t *pow_state); + /* Cleanup function when the circuit is closed or freed. */ void hs_circ_cleanup_on_close(circuit_t *circ); void hs_circ_cleanup_on_free(circuit_t *circ); @@ -55,7 +76,8 @@ int hs_circ_send_introduce1(origin_circuit_t *intro_circ, origin_circuit_t *rend_circ, const hs_desc_intro_point_t *ip, - const struct hs_subcredential_t *subcredential); + const struct hs_subcredential_t *subcredential, + const hs_pow_solution_t *pow_solution); int hs_circ_send_establish_rendezvous(origin_circuit_t *circ); /* e2e circuit API. */ @@ -83,11 +105,12 @@ const curve25519_public_key_t *server_pk, const struct hs_ntor_rend_cell_keys_t *keys); -struct hs_cell_introduce2_data_t; MOCK_DECL(STATIC void, launch_rendezvous_point_circuit,(const hs_service_t *service, - const hs_service_intro_point_t *ip, - const struct hs_cell_introduce2_data_t *data)); + const ed25519_public_key_t *ip_auth_pubkey, + const curve25519_keypair_t *ip_enc_key_kp, + const hs_cell_intro_rdv_data_t *rdv_data, + time_t now)); #endif /* defined(HS_CIRCUIT_PRIVATE) */ diff -Nru tor-0.4.7.16/src/feature/hs/hs_client.c tor-0.4.9.6/src/feature/hs/hs_client.c --- tor-0.4.7.16/src/feature/hs/hs_client.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/feature/hs/hs_client.c 2026-03-25 14:30:34.000000000 +0000 @@ -541,7 +541,7 @@ /** Find a descriptor intro point object that matches the given ident in the * given descriptor desc. Return NULL if not found. */ -static const hs_desc_intro_point_t * +const hs_desc_intro_point_t * find_desc_intro_point_by_ident(const hs_ident_circuit_t *ident, const hs_descriptor_t *desc) { @@ -549,6 +549,7 @@ tor_assert(ident); tor_assert(desc); + tor_assert_nonfatal(!ed25519_public_key_is_zero(&ident->intro_auth_pk)); SMARTLIST_FOREACH_BEGIN(desc->encrypted_data.intro_points, const hs_desc_intro_point_t *, ip) { @@ -600,14 +601,75 @@ return ret_ip; } +/** Phase two for client-side introducing: + * Send an INTRODUCE1 cell along the intro circuit and populate the rend + * circuit identifier with the needed key material for the e2e encryption. + */ +int +send_introduce1(origin_circuit_t *intro_circ, + origin_circuit_t *rend_circ, + const hs_descriptor_t *desc, + hs_pow_solution_t *pow_solution, + const hs_desc_intro_point_t *ip) +{ + const ed25519_public_key_t *service_identity_pk = + &intro_circ->hs_ident->identity_pk; + + /* Send the INTRODUCE1 cell. */ + if (hs_circ_send_introduce1(intro_circ, rend_circ, ip, + &desc->subcredential, pow_solution) < 0) { + if (TO_CIRCUIT(intro_circ)->marked_for_close) { + /* If the introduction circuit was closed, we were unable to send the + * cell for some reasons. In any case, the intro circuit has to be + * closed by the above function. We'll return a transient error so tor + * can recover and pick a new intro point. To avoid picking that same + * intro point, we'll note down the intro point failure so it doesn't + * get reused. */ + hs_cache_client_intro_state_note(service_identity_pk, + &intro_circ->hs_ident->intro_auth_pk, + INTRO_POINT_FAILURE_GENERIC); + } + /* It is also possible that the rendezvous circuit was closed due to being + * unable to use the rendezvous point node_t so in that case, we also want + * to recover and let tor pick a new one. */ + return -1; /* transient failure */ + } + + /* Cell has been sent successfully. + * Now, we wait for an ACK or NAK on this circuit. */ + circuit_change_purpose(TO_CIRCUIT(intro_circ), + CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT); + /* Set timestamp_dirty, because circuit_expire_building expects it to + * specify when a circuit entered the _C_INTRODUCE_ACK_WAIT state. */ + TO_CIRCUIT(intro_circ)->timestamp_dirty = time(NULL); + pathbias_count_use_attempt(intro_circ); + + return 0; /* Success. */ +} + +/** Set a client-side cap on the highest effort of PoW we will try to + * tackle. If asked for higher, we solve it at this cap. */ +#define CLIENT_MAX_POW_EFFORT 10000 + +/** Set a client-side minimum effort. If the client is choosing to increase + * effort on retry, it will always pick a value >= this lower limit. */ +#define CLIENT_MIN_RETRY_POW_EFFORT 8 + +/** Client effort will double on every retry until this level is hit */ +#define CLIENT_POW_EFFORT_DOUBLE_UNTIL 1000 + +/** After we reach DOUBLE_UNTIL, client effort is multiplied by this amount + * on every retry until we reach MAX_POW_EFFORT. */ +#define CLIENT_POW_RETRY_MULTIPLIER (1.5f) + /** Send an INTRODUCE1 cell along the intro circuit and populate the rend * circuit identifier with the needed key material for the e2e encryption. * Return 0 on success, -1 if there is a transient error such that an action * has been taken to recover and -2 if there is a permanent error indicating * that both circuits were closed. */ static int -send_introduce1(origin_circuit_t *intro_circ, - origin_circuit_t *rend_circ) +consider_sending_introduce1(origin_circuit_t *intro_circ, + origin_circuit_t *rend_circ) { int status; char onion_address[HS_SERVICE_ADDR_LEN_BASE32 + 1]; @@ -624,9 +686,15 @@ * version number but for now there is none because it's all v3. */ hs_build_address(service_identity_pk, HS_VERSION_THREE, onion_address); - log_info(LD_REND, "Sending INTRODUCE1 cell to service %s on circuit %u", + log_info(LD_REND, "Considering sending INTRODUCE1 cell to service %s " + "on circuit %u", safe_str_client(onion_address), TO_CIRCUIT(intro_circ)->n_circ_id); + /* if it's already waiting on the cpuworker farm, don't queue it again */ + if (intro_circ->hs_currently_solving_pow) { + goto tran_err; + } + /* 1) Get descriptor from our cache. */ const hs_descriptor_t *desc = hs_cache_lookup_as_client(service_identity_pk); @@ -644,8 +712,8 @@ goto tran_err; } - /* Check if the rendevous circuit was setup WITHOUT congestion control but if - * it is enabled and the service supports it. This can happen, see + /* Check if the rendezvous circuit was setup WITHOUT congestion control, + * but if it is enabled and the service supports it. This can happen, see * setup_rendezvous_circ_congestion_control() and so close rendezvous circuit * so another one can be created. */ if (TO_CIRCUIT(rend_circ)->ccontrol == NULL && congestion_control_enabled() @@ -668,41 +736,84 @@ goto perm_err; } - /* Send the INTRODUCE1 cell. */ - if (hs_circ_send_introduce1(intro_circ, rend_circ, ip, - &desc->subcredential) < 0) { - if (TO_CIRCUIT(intro_circ)->marked_for_close) { - /* If the introduction circuit was closed, we were unable to send the - * cell for some reasons. In any case, the intro circuit has to be - * closed by the above function. We'll return a transient error so tor - * can recover and pick a new intro point. To avoid picking that same - * intro point, we'll note down the intro point failure so it doesn't - * get reused. */ - hs_cache_client_intro_state_note(service_identity_pk, - &intro_circ->hs_ident->intro_auth_pk, - INTRO_POINT_FAILURE_GENERIC); - } - /* It is also possible that the rendezvous circuit was closed due to being - * unable to use the rendezvous point node_t so in that case, we also want - * to recover and let tor pick a new one. */ - goto tran_err; - } - - /* Cell has been sent successfully. Copy the introduction point - * authentication and encryption key in the rendezvous circuit identifier so - * we can compute the ntor keys when we receive the RENDEZVOUS2 cell. */ + /* Copy the introduction point authentication and encryption key + * in the rendezvous circuit identifier so we can compute the ntor keys + * when we receive the RENDEZVOUS2 cell. */ memcpy(&rend_circ->hs_ident->intro_enc_pk, &ip->enc_key, sizeof(rend_circ->hs_ident->intro_enc_pk)); - ed25519_pubkey_copy(&rend_circ->hs_ident->intro_auth_pk, - &intro_circ->hs_ident->intro_auth_pk); - /* Now, we wait for an ACK or NAK on this circuit. */ - circuit_change_purpose(TO_CIRCUIT(intro_circ), - CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT); - /* Set timestamp_dirty, because circuit_expire_building expects it to - * specify when a circuit entered the _C_INTRODUCE_ACK_WAIT state. */ - TO_CIRCUIT(intro_circ)->timestamp_dirty = time(NULL); - pathbias_count_use_attempt(intro_circ); + /* Optionally choose to solve a client puzzle for this connection. This + * is only available if we have PoW support at compile time, and if the + * service has provided a PoW seed in its descriptor. The puzzle is enabled + * any time effort is nonzero, which can be recommended by the service or + * self-imposed as a result of previous timeouts. + */ + if (have_module_pow() && desc->encrypted_data.pow_params) { + hs_pow_solver_inputs_t pow_inputs = { + .effort = desc->encrypted_data.pow_params->suggested_effort, + .CompiledProofOfWorkHash = get_options()->CompiledProofOfWorkHash + }; + ed25519_pubkey_copy(&pow_inputs.service_blinded_id, + &desc->plaintext_data.blinded_pubkey); + memcpy(pow_inputs.seed, desc->encrypted_data.pow_params->seed, + sizeof pow_inputs.seed); + log_debug(LD_REND, "PoW params present in descriptor, suggested_effort=%u", + pow_inputs.effort); + + if (pow_inputs.effort > CLIENT_MAX_POW_EFFORT) { + log_notice(LD_REND, "Onion service suggested effort %d which is " + "higher than we want to solve. Solving at %d instead.", + pow_inputs.effort, CLIENT_MAX_POW_EFFORT); + pow_inputs.effort = CLIENT_MAX_POW_EFFORT; + } + + const hs_cache_intro_state_t *state = + hs_cache_client_intro_state_find(&intro_circ->hs_ident->identity_pk, + &intro_circ->hs_ident->intro_auth_pk); + uint32_t unreachable_count = state ? state->unreachable_count : 0; + if (state) { + log_debug(LD_REND, "hs_cache state during PoW consideration, " + "error=%d timed_out=%d unreachable_count=%u", + state->error, state->timed_out, state->unreachable_count); + } + uint64_t new_effort = pow_inputs.effort; + for (unsigned n_retry = 0; n_retry < unreachable_count; n_retry++) { + if (new_effort >= CLIENT_MAX_POW_EFFORT) { + break; + } + if (new_effort < CLIENT_POW_EFFORT_DOUBLE_UNTIL) { + new_effort <<= 1; + } else { + new_effort = (uint64_t) (CLIENT_POW_RETRY_MULTIPLIER * new_effort); + } + new_effort = MAX((uint64_t)CLIENT_MIN_RETRY_POW_EFFORT, new_effort); + new_effort = MIN((uint64_t)CLIENT_MAX_POW_EFFORT, new_effort); + } + if (pow_inputs.effort != (uint32_t)new_effort) { + log_info(LD_REND, "Increasing PoW effort from %d to %d after intro " + "point unreachable_count=%d", + pow_inputs.effort, (int)new_effort, unreachable_count); + pow_inputs.effort = (uint32_t)new_effort; + } + + if (pow_inputs.effort > 0) { + /* send it to the client-side pow cpuworker for solving. */ + intro_circ->hs_currently_solving_pow = 1; + if (hs_pow_queue_work(intro_circ->global_identifier, + rend_circ->hs_ident->rendezvous_cookie, + &pow_inputs) != 0) { + log_warn(LD_REND, "Failed to enqueue PoW request"); + } + + /* can't proceed with the intro1 cell yet, so yield back to the + * main loop */ + goto tran_err; + } + } + + /* move on to the next phase: actually try to send it */ + if (send_introduce1(intro_circ, rend_circ, desc, NULL, ip) < 0) + goto tran_err; /* Success. */ status = 0; @@ -732,8 +843,8 @@ * * Return 0 if everything went well, otherwise return -1 in the case of errors. */ -static int -setup_intro_circ_auth_key(origin_circuit_t *circ) +int +hs_client_setup_intro_circ_auth_key(origin_circuit_t *circ) { const hs_descriptor_t *desc; const hs_desc_intro_point_t *ip; @@ -779,13 +890,6 @@ log_info(LD_REND, "Introduction circuit %u has opened. Attaching streams.", (unsigned int) TO_CIRCUIT(circ)->n_circ_id); - /* This is an introduction circuit so we'll attach the correct - * authentication key to the circuit identifier so it can be identified - * properly later on. */ - if (setup_intro_circ_auth_key(circ) < 0) { - return; - } - connection_ap_attach_pending(1); } @@ -1344,6 +1448,9 @@ err: circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_TORPROTOCOL); end: + memwipe(auth_mac, 0, sizeof(auth_mac)); + memwipe(handshake_info, 0, sizeof(handshake_info)); + memwipe(&server_pk, 0, sizeof(server_pk)); memwipe(&keys, 0, sizeof(keys)); return ret; } @@ -1390,9 +1497,20 @@ /* Check if fetching a desc for this HS is useful to us right now */ { const hs_descriptor_t *cached_desc = NULL; + int has_usable_intro = false; + int has_expired_hs_pow = false; + cached_desc = hs_cache_lookup_as_client(identity_pk); - if (cached_desc && hs_client_any_intro_points_usable(identity_pk, - cached_desc)) { + if (cached_desc) { + has_usable_intro = hs_client_any_intro_points_usable(identity_pk, + cached_desc); + if (cached_desc->encrypted_data.pow_params) { + has_expired_hs_pow = + cached_desc->encrypted_data.pow_params->expiration_time < + approx_time(); + } + } + if (has_usable_intro && !has_expired_hs_pow) { log_info(LD_GENERAL, "We would fetch a v3 hidden service descriptor " "but we already have a usable descriptor."); status = HS_CLIENT_FETCH_HAVE_DESC; @@ -1972,6 +2090,7 @@ orig_circ = CONST_TO_ORIGIN_CIRCUIT(circ); tor_assert(orig_circ->hs_ident); + const ed25519_public_key_t *intro_pk = &orig_circ->hs_ident->intro_auth_pk; has_timed_out = (circ->marked_for_close_orig_reason == END_CIRC_REASON_TIMEOUT); @@ -1986,22 +2105,22 @@ safe_str_client(ed25519_fmt(&orig_circ->hs_ident->identity_pk)), safe_str_client(build_state_get_exit_nickname(orig_circ->build_state)), failure); + tor_assert_nonfatal(!ed25519_public_key_is_zero(intro_pk)); hs_cache_client_intro_state_note(&orig_circ->hs_ident->identity_pk, - &orig_circ->hs_ident->intro_auth_pk, - failure); + intro_pk, failure); break; case CIRCUIT_PURPOSE_C_INTRODUCING: if (has_timed_out || !orig_circ->build_state) { break; } + tor_assert_nonfatal(!ed25519_public_key_is_zero(intro_pk)); failure = INTRO_POINT_FAILURE_UNREACHABLE; log_info(LD_REND, "Failed v3 intro circ for service %s to intro point %s " "(while building circuit). Marking as unreachable.", safe_str_client(ed25519_fmt(&orig_circ->hs_ident->identity_pk)), safe_str_client(build_state_get_exit_nickname(orig_circ->build_state))); hs_cache_client_intro_state_note(&orig_circ->hs_ident->identity_pk, - &orig_circ->hs_ident->intro_auth_pk, - failure); + intro_pk, failure); break; default: break; @@ -2143,7 +2262,7 @@ hs_client_send_introduce1(origin_circuit_t *intro_circ, origin_circuit_t *rend_circ) { - return send_introduce1(intro_circ, rend_circ); + return consider_sending_introduce1(intro_circ, rend_circ); } /** Called when the client circuit circ has been established. It can be either diff -Nru tor-0.4.7.16/src/feature/hs/hs_client.h tor-0.4.9.6/src/feature/hs/hs_client.h --- tor-0.4.7.16/src/feature/hs/hs_client.h 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/feature/hs/hs_client.h 2026-03-25 14:30:34.000000000 +0000 @@ -78,6 +78,10 @@ int flags; } hs_client_service_authorization_t; +const hs_desc_intro_point_t * +find_desc_intro_point_by_ident(const hs_ident_circuit_t *ident, + const hs_descriptor_t *desc); + hs_client_register_auth_status_t hs_client_register_auth_credentials(hs_client_service_authorization_t *creds); @@ -100,6 +104,12 @@ const ed25519_public_key_t *onion_identity_pk, const smartlist_t *hsdirs); +int send_introduce1(origin_circuit_t *intro_circ, + origin_circuit_t *rend_circ, + const hs_descriptor_t *desc, + hs_pow_solution_t *pow_solution, + const hs_desc_intro_point_t *ip); + hs_desc_decode_status_t hs_client_decode_descriptor( const char *desc_str, const ed25519_public_key_t *service_identity_pk, @@ -109,6 +119,8 @@ int hs_client_refetch_hsdesc(const ed25519_public_key_t *identity_pk); void hs_client_dir_info_changed(void); +int hs_client_setup_intro_circ_auth_key(origin_circuit_t *circ); + int hs_client_send_introduce1(origin_circuit_t *intro_circ, origin_circuit_t *rend_circ); diff -Nru tor-0.4.7.16/src/feature/hs/hs_common.c tor-0.4.9.6/src/feature/hs/hs_common.c --- tor-0.4.7.16/src/feature/hs/hs_common.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/feature/hs/hs_common.c 2026-03-25 14:30:34.000000000 +0000 @@ -432,7 +432,7 @@ * thus will be ignored for the param construction. * * The result is put in param_out. */ -static void +STATIC void build_blinded_key_param(const ed25519_public_key_t *pubkey, const uint8_t *secret, size_t secret_len, uint64_t period_num, uint64_t period_length, @@ -1680,13 +1680,13 @@ 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(&ap.addr), ap.port); + "it: %s:%u", safe_str(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, + (have_ed25519_id) ? &ed25519_pk : NULL, onion_key, &ap.addr, ap.port, NULL, false); done: return info; diff -Nru tor-0.4.7.16/src/feature/hs/hs_common.h tor-0.4.9.6/src/feature/hs/hs_common.h --- tor-0.4.7.16/src/feature/hs/hs_common.h 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/feature/hs/hs_common.h 2026-03-25 14:30:34.000000000 +0000 @@ -49,13 +49,6 @@ /** String prefix for the signature of ESTABLISH_INTRO */ #define ESTABLISH_INTRO_SIG_PREFIX "Tor establish-intro cell v1" -/** The default HS time period length */ -#define HS_TIME_PERIOD_LENGTH_DEFAULT 1440 /* 1440 minutes == one day */ -/** The minimum time period length as seen in prop224 section [TIME-PERIODS] */ -#define HS_TIME_PERIOD_LENGTH_MIN 30 /* minutes */ -/** The minimum time period length as seen in prop224 section [TIME-PERIODS] */ -#define HS_TIME_PERIOD_LENGTH_MAX (60 * 24 * 10) /* 10 days or 14400 minutes */ - /** Prefix of the onion address checksum. */ #define HS_SERVICE_ADDR_CHECKSUM_PREFIX ".onion checksum" /** Length of the checksum prefix minus the NUL terminated byte. */ @@ -83,7 +76,7 @@ /** The default HS time period length */ #define HS_TIME_PERIOD_LENGTH_DEFAULT 1440 /* 1440 minutes == one day */ /** The minimum time period length as seen in prop224 section [TIME-PERIODS] */ -#define HS_TIME_PERIOD_LENGTH_MIN 30 /* minutes */ +#define HS_TIME_PERIOD_LENGTH_MIN 5 /* minutes */ /** The minimum time period length as seen in prop224 section [TIME-PERIODS] */ #define HS_TIME_PERIOD_LENGTH_MAX (60 * 24 * 10) /* 10 days or 14400 minutes */ /** The time period rotation offset as seen in prop224 section @@ -256,7 +249,14 @@ #ifdef HS_COMMON_PRIVATE +struct ed25519_public_key_t; + STATIC void get_disaster_srv(uint64_t time_period_num, uint8_t *srv_out); +STATIC void build_blinded_key_param( + const struct ed25519_public_key_t *pubkey, + const uint8_t *secret, size_t secret_len, + uint64_t period_num, uint64_t period_length, + uint8_t *param_out); /** The period for which a hidden service directory cannot be queried for * the same descriptor ID again. */ diff -Nru tor-0.4.7.16/src/feature/hs/hs_config.c tor-0.4.9.6/src/feature/hs/hs_config.c --- tor-0.4.7.16/src/feature/hs/hs_config.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/feature/hs/hs_config.c 2026-03-25 14:30:34.000000000 +0000 @@ -320,6 +320,19 @@ config->intro_dos_burst_per_sec, config->intro_dos_rate_per_sec); goto invalid; } + if (config->has_pow_defenses_enabled && + (config->pow_queue_burst < config->pow_queue_rate)) { + log_warn(LD_CONFIG, "Hidden service PoW queue burst (%" PRIu32 ") can " + "not be smaller than the rate value (%" PRIu32 ").", + config->pow_queue_burst, config->pow_queue_rate); + goto invalid; + } + if (config->has_pow_defenses_enabled && !have_module_pow()) { + log_warn(LD_CONFIG, "Hidden service proof-of-work defenses are enabled " + "in our configuration but this build of tor does not " + "include the required 'pow' module."); + goto invalid; + } /* Valid. */ return 0; @@ -351,7 +364,7 @@ if (hs_opts->HiddenServiceExportCircuitID) { int ok; config->circuit_id_protocol = - helper_parse_circuit_id_protocol("HiddenServcieExportCircuitID", + helper_parse_circuit_id_protocol("HiddenServiceExportCircuitID", hs_opts->HiddenServiceExportCircuitID, &ok); if (!ok) { @@ -392,6 +405,20 @@ } } + /* Are the PoW anti-DoS defenses enabled? */ + config->has_pow_defenses_enabled = hs_opts->HiddenServicePoWDefensesEnabled; + config->pow_queue_rate = hs_opts->HiddenServicePoWQueueRate; + config->pow_queue_burst = hs_opts->HiddenServicePoWQueueBurst; + + log_info(LD_REND, "Service PoW defenses are %s", + config->has_pow_defenses_enabled ? "enabled" : "disabled"); + if (config->has_pow_defenses_enabled) { + log_info(LD_REND, "Service PoW queue rate set to: %" PRIu32, + config->pow_queue_rate); + log_info(LD_REND, "Service PoW queue burst set to: %" PRIu32, + config->pow_queue_burst); + } + /* We do not load the key material for the service at this stage. This is * done later once tor can confirm that it is in a running state. */ diff -Nru tor-0.4.7.16/src/feature/hs/hs_config.h tor-0.4.9.6/src/feature/hs/hs_config.h --- tor-0.4.7.16/src/feature/hs/hs_config.h 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/feature/hs/hs_config.h 2026-03-25 14:30:34.000000000 +0000 @@ -25,6 +25,11 @@ #define HS_CONFIG_V3_DOS_DEFENSE_BURST_PER_SEC_MIN 0 #define HS_CONFIG_V3_DOS_DEFENSE_BURST_PER_SEC_MAX INT32_MAX +/* Default values for the HS anti-DoS PoW defenses. */ +#define HS_CONFIG_V3_POW_DEFENSES_DEFAULT 0 +#define HS_CONFIG_V3_POW_QUEUE_RATE 250 +#define HS_CONFIG_V3_POW_QUEUE_BURST 2500 + /* API */ int hs_config_service_all(const or_options_t *options, int validate_only); diff -Nru tor-0.4.7.16/src/feature/hs/hs_descriptor.c tor-0.4.9.6/src/feature/hs/hs_descriptor.c --- tor-0.4.7.16/src/feature/hs/hs_descriptor.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/feature/hs/hs_descriptor.c 2026-03-25 14:30:34.000000000 +0000 @@ -68,6 +68,7 @@ #include "feature/dirparse/parsecommon.h" #include "feature/hs/hs_cache.h" #include "feature/hs/hs_config.h" +#include "feature/hs/hs_pow.h" #include "feature/nodelist/torcert.h" /* tor_cert_encode_ed22519() */ #include "lib/memarea/memarea.h" #include "lib/crypt_ops/crypto_format.h" @@ -96,6 +97,7 @@ #define str_ip_legacy_key_cert "legacy-key-cert" #define str_intro_point_start "\n" str_intro_point " " #define str_flow_control "flow-control" +#define str_pow_params "pow-params" /* Constant string value for the construction to encrypt the encrypted data * section. */ #define str_enc_const_superencryption "hsdir-superencrypted-data" @@ -117,6 +119,16 @@ { 0, NULL } }; +/** PoW supported types. */ +static const struct { + hs_pow_desc_type_t type; + const char *identifier; +} pow_types[] = { + { HS_POW_DESC_V1, "v1"}, + /* Indicate end of array. */ + { 0, NULL } +}; + /** Descriptor ruleset. */ static token_rule_t hs_desc_v3_token_table[] = { T1_START(str_hs_desc, R_HS_DESCRIPTOR, EQ(1), NO_OBJ), @@ -143,6 +155,7 @@ T01(str_intro_auth_required, R3_INTRO_AUTH_REQUIRED, GE(1), NO_OBJ), T01(str_single_onion, R3_SINGLE_ONION_SERVICE, ARGS, NO_OBJ), T01(str_flow_control, R3_FLOW_CONTROL, GE(2), NO_OBJ), + T0N(str_pow_params, R3_POW_PARAMS, GE(1), NO_OBJ), END_OF_TABLE }; @@ -758,6 +771,13 @@ smartlist_add_asprintf(lines, "%s %d\n", str_create2_formats, ONION_HANDSHAKE_TYPE_NTOR); +#ifdef TOR_UNIT_TESTS + if (desc->encrypted_data.test_extra_plaintext) { + smartlist_add(lines, + tor_strdup(desc->encrypted_data.test_extra_plaintext)); + } +#endif + if (desc->encrypted_data.intro_auth_types && smartlist_len(desc->encrypted_data.intro_auth_types)) { /* Put the authentication-required line. */ @@ -777,6 +797,31 @@ protover_get_supported(PRT_FLOWCTRL), congestion_control_sendme_inc()); } + + /* Add PoW parameters if present. */ + if (desc->encrypted_data.pow_params) { + /* Base64 the seed */ + size_t seed_b64_len = base64_encode_size(HS_POW_SEED_LEN, 0) + 1; + char *seed_b64 = tor_malloc_zero(seed_b64_len); + int ret = base64_encode(seed_b64, seed_b64_len, + (char *)desc->encrypted_data.pow_params->seed, + HS_POW_SEED_LEN, 0); + /* Return length doesn't count the NUL byte. */ + tor_assert((size_t) ret == (seed_b64_len - 1)); + + /* Convert the expiration time to space-less ISO format. */ + char time_buf[ISO_TIME_LEN + 1]; + format_iso_time_nospace(time_buf, + desc->encrypted_data.pow_params->expiration_time); + + /* Add "pow-params" line to descriptor encoding. */ + smartlist_add_asprintf(lines, "%s %s %s %u %s\n", str_pow_params, + pow_types[desc->encrypted_data.pow_params->type].identifier, + seed_b64, + desc->encrypted_data.pow_params->suggested_effort, + time_buf); + tor_free(seed_b64); + } } /* Build the introduction point(s) section. */ @@ -2053,6 +2098,91 @@ return ret; } +/** Given a list of tokens for PoW params, decode it as a v1 + * hs_pow_desc_params_t. + * + * Each token's args MUST contain at least 1 element. + * + * On success, return 0, and set pow_params_out to a new set of + * parameters (or to NULL if there were no v1 parameters). Return -1 on + * failure. + */ +static int +decode_pow_params(const smartlist_t *toks, + hs_pow_desc_params_t **pow_params_out) +{ + bool found_v1 = false; + int ret = -1; + tor_assert(pow_params_out); + *pow_params_out = NULL; + + if (!toks) + return 0; + + SMARTLIST_FOREACH_BEGIN(toks, const directory_token_t *, tok) { + tor_assert(tok->n_args >= 1); + + if (strcmp(tok->args[0], "v1")) { + // Unrecognized type; skip it. + continue; + } + + if (found_v1) { + log_warn(LD_REND, "Duplicate v1 PoW entries in descriptor."); + goto done; + } + found_v1 = true; + if (tok->n_args < 4) { + log_warn(LD_REND, "Insufficient arguments for v1 PoW entry."); + goto done; + } + + hs_pow_desc_params_t *pow_params = tor_malloc_zero(sizeof(*pow_params)); + *pow_params_out = pow_params; + pow_params->type = HS_POW_DESC_V1; + + if (base64_decode((char *)pow_params->seed, sizeof(pow_params->seed), + tok->args[1], strlen(tok->args[1])) != + sizeof(pow_params->seed)) { + log_warn(LD_REND, "Unparseable seed %s in PoW params", + escaped(tok->args[1])); + goto done; + } + + int ok; + unsigned long effort = + tor_parse_ulong(tok->args[2], 10, 0, UINT32_MAX, &ok, NULL); + if (!ok) { + log_warn(LD_REND, "Unparseable suggested effort %s in PoW params", + escaped(tok->args[2])); + goto done; + } + pow_params->suggested_effort = (uint32_t)effort; + + /* Parse the expiration time of the PoW params. */ + time_t expiration_time = 0; + if (parse_iso_time_nospace(tok->args[3], &expiration_time)) { + log_warn(LD_REND, "Unparseable expiration time %s in PoW params", + escaped(tok->args[3])); + goto done; + } + /* Validation of this time is done in client_desc_has_arrived() so we can + * trigger a fetch if expired. */ + pow_params->expiration_time = expiration_time; + + } SMARTLIST_FOREACH_END(tok); + + /* Success. */ + ret = 0; + + done: + if (ret < 0 && *pow_params_out) { + tor_free(*pow_params_out); // sets it to NULL + } + + return ret; +} + /** Decode descriptor plaintext data for version 3. Given a list of tokens, an * allocated plaintext object that will be populated and the encoded * descriptor with its length. The last one is needed for signature @@ -2364,6 +2494,16 @@ desc_encrypted_out->sendme_inc = sendme_inc; } + /* Get PoW if any. */ + { + smartlist_t *pow_toks = find_all_by_keyword(tokens, R3_POW_PARAMS); + int r = decode_pow_params(pow_toks, &desc_encrypted_out->pow_params); + smartlist_free(pow_toks); + if (r < 0) { + goto err; + } + } + /* Initialize the descriptor's introduction point list before we start * decoding. Having 0 intro point is valid. Then decode them all. */ desc_encrypted_out->intro_points = smartlist_new(); @@ -2704,9 +2844,15 @@ } /* Try to decode what we just encoded. Symmetry is nice!, but it is - * symmetric only if the client auth is disabled. That is, the descriptor - * cookie will be NULL. */ - if (!descriptor_cookie) { + * symmetric only if the client auth is disabled (That is, the descriptor + * cookie will be NULL) and the test-only mock plaintext isn't in use. */ + bool do_round_trip_test = !descriptor_cookie; +#ifdef TOR_UNIT_TESTS + if (desc->encrypted_data.test_extra_plaintext) { + do_round_trip_test = false; + } +#endif + if (do_round_trip_test) { ret = hs_desc_decode_descriptor(*encoded_out, &desc->subcredential, NULL, NULL); if (BUG(ret != HS_DESC_DECODE_OK)) { @@ -2776,6 +2922,7 @@ smartlist_free(desc->intro_points); } tor_free(desc->flow_control_pv); + tor_free(desc->pow_params); memwipe(desc, 0, sizeof(*desc)); } diff -Nru tor-0.4.7.16/src/feature/hs/hs_descriptor.h tor-0.4.9.6/src/feature/hs/hs_descriptor.h --- tor-0.4.7.16/src/feature/hs/hs_descriptor.h 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/feature/hs/hs_descriptor.h 2026-03-25 14:30:34.000000000 +0000 @@ -15,6 +15,7 @@ #include "trunnel/ed25519_cert.h" /* needed for trunnel */ #include "feature/nodelist/torcert.h" #include "core/crypto/hs_ntor.h" /* for hs_subcredential_t */ +#include "feature/hs/hs_pow.h" /* Trunnel */ struct link_specifier_t; @@ -171,8 +172,18 @@ char *flow_control_pv; uint8_t sendme_inc; + /** PoW parameters. If NULL, it is not present. */ + hs_pow_desc_params_t *pow_params; + /** A list of intro points. Contains hs_desc_intro_point_t objects. */ smartlist_t *intro_points; + +#ifdef TOR_UNIT_TESTS + /** In unit tests only, we can include additional arbitrary plaintext. + * This is used to test parser validation by adding invalid inner data to + * descriptors that are otherwise correct and correctly encrypted. */ + const char *test_extra_plaintext; +#endif } hs_desc_encrypted_data_t; /** The superencrypted data section of a descriptor. Obviously the data in diff -Nru tor-0.4.7.16/src/feature/hs/hs_dos.c tor-0.4.9.6/src/feature/hs/hs_dos.c --- tor-0.4.7.16/src/feature/hs/hs_dos.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/feature/hs/hs_dos.c 2026-03-25 14:30:34.000000000 +0000 @@ -28,6 +28,7 @@ #include "feature/relay/routermode.h" #include "lib/evloop/token_bucket.h" +#include "lib/time/compat_time.h" #include "feature/hs/hs_dos.h" @@ -143,7 +144,7 @@ token_bucket_ctr_init(&circ->introduce2_bucket, consensus_param_introduce_rate_per_sec, consensus_param_introduce_burst_per_sec, - (uint32_t) approx_time()); + (uint32_t) monotime_coarse_absolute_sec()); } /** Called when the consensus has changed. We might have new consensus @@ -188,7 +189,7 @@ /* Refill INTRODUCE2 bucket. */ token_bucket_ctr_refill(&s_intro_circ->introduce2_bucket, - (uint32_t) approx_time()); + (uint32_t) monotime_coarse_absolute_sec()); /* Decrement the bucket for this valid INTRODUCE1 cell we just got. Don't * underflow else we end up with a too big of a bucket. */ diff -Nru tor-0.4.7.16/src/feature/hs/hs_ident.c tor-0.4.9.6/src/feature/hs/hs_ident.c --- tor-0.4.7.16/src/feature/hs/hs_ident.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/feature/hs/hs_ident.c 2026-03-25 14:30:34.000000000 +0000 @@ -62,6 +62,16 @@ tor_free(ident); } +/** Return a newly allocated HS directory connection identifier that is meant + * for the server side (HSDir). Only the blinded key is known by the HSDir. */ +hs_ident_dir_conn_t * +hs_ident_server_dir_conn_new(const ed25519_public_key_t *blinded_pk) +{ + hs_ident_dir_conn_t *ident = tor_malloc_zero(sizeof(*ident)); + ed25519_pubkey_copy(&ident->blinded_pk, blinded_pk); + return ident; +} + /** Initialized the allocated ident object with identity_pk and blinded_pk. * None of them can be NULL since a valid directory connection identifier must * have all fields set. */ diff -Nru tor-0.4.7.16/src/feature/hs/hs_ident.h tor-0.4.9.6/src/feature/hs/hs_ident.h --- tor-0.4.7.16/src/feature/hs/hs_ident.h 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/feature/hs/hs_ident.h 2026-03-25 14:30:34.000000000 +0000 @@ -128,6 +128,8 @@ void hs_ident_dir_conn_init(const ed25519_public_key_t *identity_pk, const ed25519_public_key_t *blinded_pk, hs_ident_dir_conn_t *ident); +hs_ident_dir_conn_t *hs_ident_server_dir_conn_new( + const ed25519_public_key_t *blinded_pk); /* Edge connection identifier API. */ hs_ident_edge_conn_t *hs_ident_edge_conn_new( diff -Nru tor-0.4.7.16/src/feature/hs/hs_intropoint.c tor-0.4.9.6/src/feature/hs/hs_intropoint.c --- tor-0.4.7.16/src/feature/hs/hs_intropoint.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/feature/hs/hs_intropoint.c 2026-03-25 14:30:34.000000000 +0000 @@ -15,8 +15,10 @@ #include "core/or/circuituse.h" #include "core/or/relay.h" #include "feature/rend/rendmid.h" +#include "feature/relay/relay_metrics.h" #include "feature/stats/rephist.h" #include "lib/crypt_ops/crypto_format.h" +#include "lib/time/compat_time.h" /* Trunnel */ #include "trunnel/ed25519_cert.h" @@ -316,7 +318,7 @@ token_bucket_ctr_init(&circ->introduce2_bucket, (uint32_t) intro2_rate_per_sec, (uint32_t) intro2_burst_per_sec, - (uint32_t) approx_time()); + (uint32_t) monotime_coarse_absolute_sec()); log_info(LD_REND, "Intro point DoS defenses enabled. Rate is %" PRIu64 " and Burst is %" PRIu64, intro2_rate_per_sec, intro2_burst_per_sec); @@ -418,6 +420,7 @@ /* Check that the circuit is in shape to become an intro point */ if (!hs_intro_circuit_is_suitable_for_establish_intro(circ)) { + relay_increment_est_intro_action(EST_INTRO_UNSUITABLE_CIRCUIT); goto err; } @@ -425,6 +428,7 @@ ssize_t parsing_result = trn_cell_establish_intro_parse(&parsed_cell, request, request_len); if (parsing_result < 0) { + relay_increment_est_intro_action(EST_INTRO_MALFORMED); log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "Rejecting %s ESTABLISH_INTRO cell.", parsing_result == -1 ? "invalid" : "truncated"); @@ -435,6 +439,7 @@ (uint8_t *) circ->rend_circ_nonce, sizeof(circ->rend_circ_nonce)); if (cell_ok < 0) { + relay_increment_est_intro_action(EST_INTRO_MALFORMED); log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "Failed to verify ESTABLISH_INTRO cell."); goto err; @@ -443,9 +448,11 @@ /* This cell is legit. Take the appropriate actions. */ cell_ok = handle_verified_establish_intro_cell(circ, parsed_cell); if (cell_ok < 0) { + relay_increment_est_intro_action(EST_INTRO_CIRCUIT_DEAD); goto err; } + relay_increment_est_intro_action(EST_INTRO_SUCCESS); /* We are done! */ retval = 0; goto done; @@ -504,6 +511,7 @@ tor_assert(request); if (request_len == 0) { + relay_increment_est_intro_action(EST_INTRO_MALFORMED); log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "Empty ESTABLISH_INTRO cell."); goto err; } @@ -516,10 +524,12 @@ case TRUNNEL_HS_INTRO_AUTH_KEY_TYPE_LEGACY1: /* Likely version 2 onion service which is now obsolete. Avoid a * protocol warning considering they still exists on the network. */ + relay_increment_est_intro_action(EST_INTRO_MALFORMED); goto err; case TRUNNEL_HS_INTRO_AUTH_KEY_TYPE_ED25519: return handle_establish_intro(circ, request, request_len); default: + relay_increment_est_intro_action(EST_INTRO_MALFORMED); log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "Unrecognized AUTH_KEY_TYPE %u.", first_byte); goto err; @@ -643,6 +653,7 @@ ssize_t cell_size = trn_cell_introduce1_parse(&parsed_cell, request, request_len); if (cell_size < 0) { + relay_increment_intro1_action(INTRO1_MALFORMED); log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "Rejecting %s INTRODUCE1 cell. Responding with NACK.", cell_size == -1 ? "invalid" : "truncated"); @@ -653,6 +664,7 @@ /* Once parsed validate the cell format. */ if (validate_introduce1_parsed_cell(parsed_cell) < 0) { + relay_increment_intro1_action(INTRO1_MALFORMED); /* Inform client that the INTRODUCE1 has bad format. */ status = TRUNNEL_HS_INTRO_ACK_STATUS_BAD_FORMAT; goto send_ack; @@ -664,6 +676,7 @@ get_auth_key_from_cell(&auth_key, RELAY_COMMAND_INTRODUCE1, parsed_cell); service_circ = hs_circuitmap_get_intro_circ_v3_relay_side(&auth_key); if (service_circ == NULL) { + relay_increment_intro1_action(INTRO1_UNKNOWN_SERVICE); char b64_key[ED25519_BASE64_LEN + 1]; ed25519_public_to_base64(b64_key, &auth_key); log_info(LD_REND, "No intro circuit found for INTRODUCE1 cell " @@ -679,6 +692,7 @@ /* Before sending, lets make sure this cell can be sent on the service * circuit asking the DoS defenses. */ if (!hs_dos_can_send_intro2(service_circ)) { + relay_increment_intro1_action(INTRO1_RATE_LIMITED); char *msg; static ratelim_t rlimit = RATELIM_INIT(5 * 60); if ((msg = rate_limit_log(&rlimit, approx_time()))) { @@ -695,13 +709,14 @@ if (relay_send_command_from_edge(CONTROL_CELL_ID, TO_CIRCUIT(service_circ), RELAY_COMMAND_INTRODUCE2, (char *) request, request_len, NULL)) { - log_warn(LD_PROTOCOL, "Unable to send INTRODUCE2 cell to the service."); + relay_increment_intro1_action(INTRO1_CIRCUIT_DEAD); /* Inform the client that we can't relay the cell. Use the unknown ID * status code since it means that we do not know the service. */ status = TRUNNEL_HS_INTRO_ACK_STATUS_UNKNOWN_ID; goto send_ack; } + relay_increment_intro1_action(INTRO1_SUCCESS); /* Success! Send an INTRODUCE_ACK success status onto the client circuit. */ status = TRUNNEL_HS_INTRO_ACK_STATUS_SUCCESS; ret = 0; @@ -732,6 +747,7 @@ } if (circ->already_received_introduce1) { + relay_increment_intro1_action(INTRO1_CIRCUIT_REUSED); log_fn(LOG_PROTOCOL_WARN, LD_REND, "Blocking multiple introductions on the same circuit. " "Someone might be trying to attack a hidden service through " @@ -741,6 +757,7 @@ /* Disallow single hop client circuit. */ if (circ->p_chan && channel_is_client(circ->p_chan)) { + relay_increment_intro1_action(INTRO1_SINGLE_HOP); log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "Single hop client was rejected while trying to introduce. " "Closing circuit."); @@ -762,6 +779,7 @@ /* A cell that can't hold a DIGEST_LEN is invalid. */ if (request_len < DIGEST_LEN) { + relay_increment_intro1_action(INTRO1_MALFORMED); log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "Invalid INTRODUCE1 cell length."); goto err; } diff -Nru tor-0.4.7.16/src/feature/hs/hs_metrics.c tor-0.4.9.6/src/feature/hs/hs_metrics.c --- tor-0.4.7.16/src/feature/hs/hs_metrics.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/feature/hs/hs_metrics.c 2026-03-25 14:30:34.000000000 +0000 @@ -13,6 +13,7 @@ #include "lib/malloc/malloc.h" #include "lib/container/smartlist.h" #include "lib/metrics/metrics_store.h" +#include "lib/log/util_bug.h" #include "feature/hs/hs_metrics.h" #include "feature/hs/hs_metrics_entry.h" @@ -29,51 +30,125 @@ return buf; } -/** Initialize a metrics store for the given service. +/** Add a new metric to the metrics store of the service. * - * Essentially, this goes over the base_metrics array and adds them all to the - * store set with their label(s) if any. */ + * metric is the index of the metric in the base_metrics array. + */ static void -init_store(hs_service_t *service) +add_metric_with_labels(hs_service_t *service, hs_metrics_key_t metric, + bool port_as_label, uint16_t port) { metrics_store_t *store; + const char **error_reasons = NULL; + size_t num_error_reasons = 0; tor_assert(service); + if (BUG(metric >= base_metrics_size)) + return; + store = service->metrics.store; + /* Check whether the current metric is an error metric, because error metrics + * require an additional `reason` label. */ + switch (metric) { + case HS_METRICS_NUM_REJECTED_INTRO_REQ: + error_reasons = hs_metrics_intro_req_error_reasons; + num_error_reasons = hs_metrics_intro_req_error_reasons_size; + break; + case HS_METRICS_NUM_FAILED_RDV: + error_reasons = hs_metrics_rend_error_reasons; + num_error_reasons = hs_metrics_rend_error_reasons_size; + break; + /* Fall through for all other metrics, as they don't need a + * reason label. */ + case HS_METRICS_NUM_INTRODUCTIONS: FALLTHROUGH; + case HS_METRICS_APP_WRITE_BYTES: FALLTHROUGH; + case HS_METRICS_APP_READ_BYTES: FALLTHROUGH; + case HS_METRICS_NUM_ESTABLISHED_RDV: FALLTHROUGH; + case HS_METRICS_NUM_RDV: FALLTHROUGH; + case HS_METRICS_NUM_ESTABLISHED_INTRO: FALLTHROUGH; + case HS_METRICS_POW_NUM_PQUEUE_RDV: FALLTHROUGH; + case HS_METRICS_POW_SUGGESTED_EFFORT: FALLTHROUGH; + case HS_METRICS_INTRO_CIRC_BUILD_TIME: FALLTHROUGH; + case HS_METRICS_REND_CIRC_BUILD_TIME: FALLTHROUGH; + default: + break; + } + + /* We don't need a reason label for this metric */ + if (!num_error_reasons) { + metrics_store_entry_t *entry = metrics_store_add( + store, base_metrics[metric].type, base_metrics[metric].name, + base_metrics[metric].help, base_metrics[metric].bucket_count, + base_metrics[metric].buckets); + + metrics_store_entry_add_label(entry, + metrics_format_label("onion", service->onion_address)); + + if (port_as_label) { + metrics_store_entry_add_label(entry, + metrics_format_label("port", port_to_str(port))); + } + + return; + } + + tor_assert(error_reasons); + + /* Add entries with reason as label. We need one metric line per + * reason. */ + for (size_t i = 0; i < num_error_reasons; ++i) { + metrics_store_entry_t *entry = + metrics_store_add(store, base_metrics[metric].type, + base_metrics[metric].name, + base_metrics[metric].help, + base_metrics[metric].bucket_count, + base_metrics[metric].buckets); + /* Add labels to the entry. */ + metrics_store_entry_add_label(entry, + metrics_format_label("onion", service->onion_address)); + metrics_store_entry_add_label(entry, + metrics_format_label("reason", error_reasons[i])); + + if (port_as_label) { + metrics_store_entry_add_label(entry, + metrics_format_label("port", port_to_str(port))); + } + } +} + +/** Initialize a metrics store for the given service. + * + * Essentially, this goes over the base_metrics array and adds them all to the + * store set with their label(s) if any. */ +static void +init_store(hs_service_t *service) +{ + tor_assert(service); + for (size_t i = 0; i < base_metrics_size; ++i) { /* Add entries with port as label. We need one metric line per port. */ if (base_metrics[i].port_as_label && service->config.ports) { SMARTLIST_FOREACH_BEGIN(service->config.ports, const hs_port_config_t *, p) { - metrics_store_entry_t *entry = - metrics_store_add(store, base_metrics[i].type, base_metrics[i].name, - base_metrics[i].help); - - /* Add labels to the entry. */ - metrics_store_entry_add_label(entry, - metrics_format_label("onion", service->onion_address)); - metrics_store_entry_add_label(entry, - metrics_format_label("port", port_to_str(p->virtual_port))); + add_metric_with_labels(service, base_metrics[i].key, true, + p->virtual_port); } SMARTLIST_FOREACH_END(p); } else { - metrics_store_entry_t *entry = - metrics_store_add(store, base_metrics[i].type, base_metrics[i].name, - base_metrics[i].help); - metrics_store_entry_add_label(entry, - metrics_format_label("onion", service->onion_address)); + add_metric_with_labels(service, base_metrics[i].key, false, 0); } } } /** Update the metrics key entry in the store in the given service. The port, - * if non 0, is used to find the correct metrics entry. The value n is the - * value used to update the entry. */ + * if non 0, and the reason label, if non NULL, are used to find the correct + * metrics entry. The value n is the value used to update the entry. */ void hs_metrics_update_by_service(const hs_metrics_key_t key, - hs_service_t *service, const uint16_t port, - int64_t n) + const hs_service_t *service, + uint16_t port, const char *reason, + int64_t n, int64_t obs, bool reset) { tor_assert(service); @@ -89,29 +164,47 @@ * XXX: This is not the most optimal due to the string format. Maybe at some * point turn this into a kvline and a map in a metric entry? */ SMARTLIST_FOREACH_BEGIN(entries, metrics_store_entry_t *, entry) { - if (port == 0 || - metrics_store_entry_has_label(entry, - metrics_format_label("port", port_to_str(port)))) { - metrics_store_entry_update(entry, n); + if ((port == 0 || + metrics_store_entry_has_label( + entry, metrics_format_label("port", port_to_str(port)))) && + ((!reason || metrics_store_entry_has_label( + entry, metrics_format_label("reason", reason))))) { + if (reset) { + metrics_store_entry_reset(entry); + } + + if (metrics_store_entry_is_histogram(entry)) { + metrics_store_hist_entry_update(entry, n, obs); + } else { + metrics_store_entry_update(entry, n); + } + break; } } SMARTLIST_FOREACH_END(entry); } /** Update the metrics key entry in the store of a service identified by the - * given identity public key. The port, if non 0, is used to find the correct - * metrics entry. The value n is the value used to update the entry. + * given identity public key. The port, if non 0, and the reason label, if non + * NULL, are used to find the correct metrics entry. The value n is the value + * used to update the entry. * * This is used by callsite that have access to the key but not the service * object so an extra lookup is done to find the service. */ void hs_metrics_update_by_ident(const hs_metrics_key_t key, const ed25519_public_key_t *ident_pk, - const uint16_t port, int64_t n) + const uint16_t port, const char *reason, + int64_t n, int64_t obs, bool reset) { hs_service_t *service; - tor_assert(ident_pk); + if (!ident_pk) { + /* We can end up here in case this is used from a failure/closing path for + * which we might not have any identity key attacehed to a circuit or + * connection yet. Simply don't assume we have one. */ + return; + } service = hs_service_find(ident_pk); if (!service) { @@ -121,7 +214,7 @@ * service and thus the only way to know is to lookup the service. */ return; } - hs_metrics_update_by_service(key, service, port, n); + hs_metrics_update_by_service(key, service, port, reason, n, obs, reset); } /** Return a list of all the onion service metrics stores. This is the diff -Nru tor-0.4.7.16/src/feature/hs/hs_metrics.h tor-0.4.9.6/src/feature/hs/hs_metrics.h --- tor-0.4.7.16/src/feature/hs/hs_metrics.h 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/feature/hs/hs_metrics.h 2026-03-25 14:30:34.000000000 +0000 @@ -26,45 +26,87 @@ /* Metrics Update. */ void hs_metrics_update_by_ident(const hs_metrics_key_t key, const ed25519_public_key_t *ident_pk, - const uint16_t port, int64_t n); + const uint16_t port, const char *reason, + int64_t n, int64_t obs, bool reset); void hs_metrics_update_by_service(const hs_metrics_key_t key, - hs_service_t *service, const uint16_t port, - int64_t n); + const hs_service_t *service, + uint16_t port, const char *reason, + int64_t n, int64_t obs, bool reset); /** New introducion request received. */ -#define hs_metrics_new_introduction(s) \ - hs_metrics_update_by_service(HS_METRICS_NUM_INTRODUCTIONS, (s), 0, 1) +#define hs_metrics_new_introduction(s) \ + hs_metrics_update_by_service(HS_METRICS_NUM_INTRODUCTIONS, (s), \ + 0, NULL, 1, 0, false) + +/** Introducion request rejected. */ +#define hs_metrics_reject_intro_req(s, reason) \ + hs_metrics_update_by_service(HS_METRICS_NUM_REJECTED_INTRO_REQ, (s), 0, \ + (reason), 1, 0, false) /** Number of bytes written to the application from the service. */ -#define hs_metrics_app_write_bytes(i, port, n) \ - hs_metrics_update_by_ident(HS_METRICS_APP_WRITE_BYTES, (i), (port), (n)) +#define hs_metrics_app_write_bytes(i, port, n) \ + hs_metrics_update_by_ident(HS_METRICS_APP_WRITE_BYTES, (i), (port), NULL, \ + (n), 0, false) /** Number of bytes read from the application to the service. */ -#define hs_metrics_app_read_bytes(i, port, n) \ - hs_metrics_update_by_ident(HS_METRICS_APP_READ_BYTES, (i), (port), (n)) +#define hs_metrics_app_read_bytes(i, port, n) \ + hs_metrics_update_by_ident(HS_METRICS_APP_READ_BYTES, (i), \ + (port), NULL, (n), 0, false) /** Newly established rendezvous. This is called as soon as the circuit purpose * is REND_JOINED which is when the RENDEZVOUS2 cell is sent. */ -#define hs_metrics_new_established_rdv(s) \ - hs_metrics_update_by_service(HS_METRICS_NUM_ESTABLISHED_RDV, (s), 0, 1) +#define hs_metrics_new_established_rdv(s) \ + hs_metrics_update_by_service(HS_METRICS_NUM_ESTABLISHED_RDV, (s), \ + 0, NULL, 1, 0, false) + +/** New rendezvous circuit failure. */ +#define hs_metrics_failed_rdv(i, reason) \ + hs_metrics_update_by_ident(HS_METRICS_NUM_FAILED_RDV, (i), \ + 0, (reason), 1, 0, false) /** Established rendezvous closed. This is called when the circuit in * REND_JOINED state is marked for close. */ -#define hs_metrics_close_established_rdv(i) \ - hs_metrics_update_by_ident(HS_METRICS_NUM_ESTABLISHED_RDV, (i), 0, -1) +#define hs_metrics_close_established_rdv(i) \ + hs_metrics_update_by_ident(HS_METRICS_NUM_ESTABLISHED_RDV, (i), \ + 0, NULL, -1, 0, false) /** New rendezvous circuit being launched. */ #define hs_metrics_new_rdv(i) \ - hs_metrics_update_by_ident(HS_METRICS_NUM_RDV, (i), 0, 1) + hs_metrics_update_by_ident(HS_METRICS_NUM_RDV, (i), 0, NULL, 1, 0, false) + +/** Update depth of rendezvous pqueue any time new work is enqueued. */ +#define hs_metrics_pow_pqueue_rdv(s, n) \ + hs_metrics_update_by_service(HS_METRICS_POW_NUM_PQUEUE_RDV, (s), 0, \ + NULL, (n), 0, true) + +/** Update the suggested effort we include in proof-of-work state */ +#define hs_metrics_pow_suggested_effort(s, n) \ + hs_metrics_update_by_service(HS_METRICS_POW_SUGGESTED_EFFORT, (s), 0, \ + NULL, (n), 0, true) /** New introduction circuit has been established. This is called when the * INTRO_ESTABLISHED has been received by the service. */ -#define hs_metrics_new_established_intro(s) \ - hs_metrics_update_by_service(HS_METRICS_NUM_ESTABLISHED_INTRO, (s), 0, 1) +#define hs_metrics_new_established_intro(s) \ + hs_metrics_update_by_service(HS_METRICS_NUM_ESTABLISHED_INTRO, (s), 0, \ + NULL, 1, 0, false) /** Established introduction circuit closes. This is called when * INTRO_ESTABLISHED circuit is marked for close. */ -#define hs_metrics_close_established_intro(i) \ - hs_metrics_update_by_ident(HS_METRICS_NUM_ESTABLISHED_INTRO, (i), 0, -1) +#define hs_metrics_close_established_intro(i) \ + hs_metrics_update_by_ident(HS_METRICS_NUM_ESTABLISHED_INTRO, (i), 0, NULL, \ + -1, 0, false) + +/** Record an introduction circuit build time duration. This is called + * when the INTRO_ESTABLISHED has been received by the service. */ +#define hs_metrics_intro_circ_build_time(s, obs) \ + hs_metrics_update_by_service(HS_METRICS_INTRO_CIRC_BUILD_TIME, (s), 0, \ + NULL, 1, obs, false) + +/** Record a rendezvous circuit build time duration. This is called as soon as + * the circuit purpose is REND_JOINED which is when the RENDEZVOUS2 cell is + * sent. */ +#define hs_metrics_rdv_circ_build_time(s, obs) \ + hs_metrics_update_by_service(HS_METRICS_REND_CIRC_BUILD_TIME, (s), 0, NULL, \ + 1, obs, false) #endif /* !defined(TOR_FEATURE_HS_HS_METRICS_H) */ diff -Nru tor-0.4.7.16/src/feature/hs/hs_metrics_entry.c tor-0.4.9.6/src/feature/hs/hs_metrics_entry.c --- tor-0.4.7.16/src/feature/hs/hs_metrics_entry.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/feature/hs/hs_metrics_entry.c 2026-03-25 14:30:34.000000000 +0000 @@ -8,12 +8,37 @@ #define HS_METRICS_ENTRY_PRIVATE +#include + #include "orconfig.h" #include "lib/cc/compat_compiler.h" +#include "lib/log/log.h" +#include "lib/log/util_bug.h" #include "feature/hs/hs_metrics_entry.h" +/* Histogram time buckets (in milliseconds). */ +static const int64_t hs_metrics_circ_build_time_buckets[] = +{ + 1000, /* 1s */ + 5000, /* 5s */ + 10000, /* 10s */ + 30000, /* 30s */ + 60000 /* 60s */ +}; + +// TODO: Define a constant for ARRAY_LENGTH(hs_metrics_circ_build_time_buckets) +// and use where it applicable. +// +// This is commented out because it doesn't compile with gcc versions < 8.1 +// or with MSVC ("initializer element is not constant"). +// +// See ticket#40773 and https://gcc.gnu.org/bugzilla/show_bug.cgi?id=69960#c18 +// +/*static const size_t hs_metrics_circ_build_time_buckets_size =*/ +/*ARRAY_LENGTH(hs_metrics_circ_build_time_buckets);*/ + /** The base metrics that is a static array of metrics that are added to every * single new stores. * @@ -45,13 +70,19 @@ .key = HS_METRICS_NUM_ESTABLISHED_RDV, .type = METRICS_TYPE_GAUGE, .name = METRICS_NAME(hs_rdv_established_count), - .help = "Total number of established rendezvous circuit", + .help = "Total number of established rendezvous circuits", }, { .key = HS_METRICS_NUM_RDV, .type = METRICS_TYPE_COUNTER, .name = METRICS_NAME(hs_rdv_num_total), - .help = "Total number of rendezvous circuit created", + .help = "Total number of rendezvous circuits created", + }, + { + .key = HS_METRICS_NUM_FAILED_RDV, + .type = METRICS_TYPE_COUNTER, + .name = METRICS_NAME(hs_rdv_error_count), + .help = "Total number of rendezvous circuit errors", }, { .key = HS_METRICS_NUM_ESTABLISHED_INTRO, @@ -59,7 +90,69 @@ .name = METRICS_NAME(hs_intro_established_count), .help = "Total number of established introduction circuit", }, + { + .key = HS_METRICS_NUM_REJECTED_INTRO_REQ, + .type = METRICS_TYPE_COUNTER, + .name = METRICS_NAME(hs_intro_rejected_intro_req_count), + .help = "Total number of rejected introduction circuits", + }, + { + .key = HS_METRICS_INTRO_CIRC_BUILD_TIME, + .type = METRICS_TYPE_HISTOGRAM, + .name = METRICS_NAME(hs_intro_circ_build_time), + .buckets = hs_metrics_circ_build_time_buckets, + .bucket_count = ARRAY_LENGTH(hs_metrics_circ_build_time_buckets), + .help = "The introduction circuit build time in milliseconds", + }, + { + .key = HS_METRICS_REND_CIRC_BUILD_TIME, + .type = METRICS_TYPE_HISTOGRAM, + .name = METRICS_NAME(hs_rend_circ_build_time), + .buckets = hs_metrics_circ_build_time_buckets, + .bucket_count = ARRAY_LENGTH(hs_metrics_circ_build_time_buckets), + .help = "The rendezvous circuit build time in milliseconds", + }, + { + .key = HS_METRICS_POW_NUM_PQUEUE_RDV, + .type = METRICS_TYPE_GAUGE, + .name = METRICS_NAME(hs_rdv_pow_pqueue_count), + .help = "Number of requests waiting in the proof of work priority queue", + }, + { + .key = HS_METRICS_POW_SUGGESTED_EFFORT, + .type = METRICS_TYPE_GAUGE, + .name = METRICS_NAME(hs_pow_suggested_effort), + .help = "Suggested effort for requests with a proof of work client puzzle", + }, }; /** Size of base_metrics array that is number of entries. */ const size_t base_metrics_size = ARRAY_LENGTH(base_metrics); + +/** Possible values for the reason label of the + * hs_intro_rejected_intro_req_count metric. */ +const char *hs_metrics_intro_req_error_reasons[] = +{ + HS_METRICS_ERR_INTRO_REQ_BAD_AUTH_KEY, + HS_METRICS_ERR_INTRO_REQ_INTRODUCE2, + HS_METRICS_ERR_INTRO_REQ_SUBCREDENTIAL, + HS_METRICS_ERR_INTRO_REQ_INTRODUCE2_REPLAY, +}; + +/** The number of entries in the hs_metrics_intro_req_error_reasons array. */ +const size_t hs_metrics_intro_req_error_reasons_size = + ARRAY_LENGTH(hs_metrics_intro_req_error_reasons); + +/** Possible values for the reason label of the hs_rdv_error_count metric. */ +const char *hs_metrics_rend_error_reasons[] = +{ + HS_METRICS_ERR_RDV_RP_CONN_FAILURE, + HS_METRICS_ERR_RDV_PATH, + HS_METRICS_ERR_RDV_RENDEZVOUS1, + HS_METRICS_ERR_RDV_E2E, + HS_METRICS_ERR_RDV_RETRY, +}; + +/** The number of entries in the hs_metrics_rend_error_reasons array. */ +const size_t hs_metrics_rend_error_reasons_size = + ARRAY_LENGTH(hs_metrics_rend_error_reasons); diff -Nru tor-0.4.7.16/src/feature/hs/hs_metrics_entry.h tor-0.4.9.6/src/feature/hs/hs_metrics_entry.h --- tor-0.4.7.16/src/feature/hs/hs_metrics_entry.h 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/feature/hs/hs_metrics_entry.h 2026-03-25 14:30:34.000000000 +0000 @@ -13,6 +13,33 @@ #include "lib/metrics/metrics_common.h" +/* Possible values for the reason label of the + * hs_intro_rejected_intro_req_count metric. */ +/** The hidden service received an unknown introduction auth key. */ +#define HS_METRICS_ERR_INTRO_REQ_BAD_AUTH_KEY "bad_auth_key" +/** The hidden service received a malformed INTRODUCE2 cell. */ +#define HS_METRICS_ERR_INTRO_REQ_INTRODUCE2 "invalid_introduce2" +/** The hidden service does not have the necessary subcredential. */ +#define HS_METRICS_ERR_INTRO_REQ_SUBCREDENTIAL "subcredential" +/** The hidden service received an INTRODUCE2 replay. */ +#define HS_METRICS_ERR_INTRO_REQ_INTRODUCE2_REPLAY "replay" + +/* Possible values for the reason label of the hs_rdv_error_count metric. */ +/** The hidden service failed to connect to the rendezvous point. */ +#define HS_METRICS_ERR_RDV_RP_CONN_FAILURE "rp_conn_failure" +/** The hidden service failed to build a circuit to the rendezvous point due + * to an invalid selected path. */ +#define HS_METRICS_ERR_RDV_PATH "invalid_path" +/** The hidden service failed to send the RENDEZVOUS1 cell on rendezvous + * circuit. */ +#define HS_METRICS_ERR_RDV_RENDEZVOUS1 "rendezvous1" +/** The hidden service failed to set up an end-to-end rendezvous circuit to + * the client. */ +#define HS_METRICS_ERR_RDV_E2E "e2e_circ" +/** The hidden service reattempted to connect to the rendezvous point by + * launching a new circuit to it, but failed */ +#define HS_METRICS_ERR_RDV_RETRY "retry" + /** Metrics key which are used as an index in the main base metrics array. */ typedef enum { /** Number of introduction requests. */ @@ -21,12 +48,24 @@ HS_METRICS_APP_WRITE_BYTES = 1, /** Number of bytes read from application to onion service. */ HS_METRICS_APP_READ_BYTES = 2, - /** Number of established rendezsvous. */ + /** Number of established rendezvous. */ HS_METRICS_NUM_ESTABLISHED_RDV = 3, - /** Number of rendezsvous circuits created. */ + /** Number of rendezvous circuits created. */ HS_METRICS_NUM_RDV = 4, + /** Number of failed rendezvous. */ + HS_METRICS_NUM_FAILED_RDV = 5, /** Number of established introducton points. */ - HS_METRICS_NUM_ESTABLISHED_INTRO = 5, + HS_METRICS_NUM_ESTABLISHED_INTRO = 6, + /** Number of rejected introducton requests. */ + HS_METRICS_NUM_REJECTED_INTRO_REQ = 7, + /** Introduction circuit build time in milliseconds. */ + HS_METRICS_INTRO_CIRC_BUILD_TIME = 8, + /** Rendezvous circuit build time in milliseconds. */ + HS_METRICS_REND_CIRC_BUILD_TIME = 9, + /** Number of requests waiting in the proof of work priority queue. */ + HS_METRICS_POW_NUM_PQUEUE_RDV = 10, + /** Suggested effort for requests with a proof of work client puzzle. */ + HS_METRICS_POW_SUGGESTED_EFFORT = 11, } hs_metrics_key_t; /** The metadata of an HS metrics. */ @@ -39,6 +78,10 @@ const char *name; /* Metrics output help comment. */ const char *help; + /* The buckets, if the metric type is METRICS_TYPE_HISTOGRAM. */ + const int64_t *buckets; + /* The number of buckets, if the metric type is METRICS_TYPE_HISTOGRAM. */ + size_t bucket_count; /* True iff a port label should be added to the metrics entry. */ bool port_as_label; } hs_metrics_entry_t; @@ -46,6 +89,11 @@ extern const hs_metrics_entry_t base_metrics[]; extern const size_t base_metrics_size; -#endif /* defined(HS_METRICS_ENTRY_PRIVATE) */ +extern const char *hs_metrics_intro_req_error_reasons[]; +extern const size_t hs_metrics_intro_req_error_reasons_size; +extern const char *hs_metrics_rend_error_reasons[]; +extern const size_t hs_metrics_rend_error_reasons_size; + +#endif /* defined(HS_METRICS_ENTRY_PRIVATE) */ #endif /* !defined(TOR_FEATURE_HS_METRICS_ENTRY_H) */ diff -Nru tor-0.4.7.16/src/feature/hs/hs_options.inc tor-0.4.9.6/src/feature/hs/hs_options.inc --- tor-0.4.7.16/src/feature/hs/hs_options.inc 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/feature/hs/hs_options.inc 2026-03-25 14:30:34.000000000 +0000 @@ -31,5 +31,8 @@ CONF_VAR(HiddenServiceEnableIntroDoSRatePerSec, POSINT, 0, "25") CONF_VAR(HiddenServiceEnableIntroDoSBurstPerSec, POSINT, 0, "200") CONF_VAR(HiddenServiceOnionBalanceInstance, BOOL, 0, "0") +CONF_VAR(HiddenServicePoWDefensesEnabled, BOOL, 0, "0") +CONF_VAR(HiddenServicePoWQueueRate, POSINT, 0, "250") +CONF_VAR(HiddenServicePoWQueueBurst, POSINT, 0, "2500") END_CONF_STRUCT(hs_opts_t) diff -Nru tor-0.4.7.16/src/feature/hs/hs_pow.c tor-0.4.9.6/src/feature/hs/hs_pow.c --- tor-0.4.7.16/src/feature/hs/hs_pow.c 1970-01-01 00:00:00.000000000 +0000 +++ tor-0.4.9.6/src/feature/hs/hs_pow.c 2026-03-25 14:30:34.000000000 +0000 @@ -0,0 +1,569 @@ +/* Copyright (c) 2017-2020, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file hs_pow.c + * \brief Contains code to handle proof-of-work computations + * when a hidden service is defending against DoS attacks. + **/ + +#include + +#include "core/or/or.h" +#include "app/config/config.h" +#include "ext/ht.h" +#include "ext/compat_blake2.h" +#include "core/or/circuitlist.h" +#include "core/or/origin_circuit_st.h" +#include "ext/equix/include/equix.h" +#include "feature/hs/hs_cache.h" +#include "feature/hs/hs_descriptor.h" +#include "feature/hs/hs_circuitmap.h" +#include "feature/hs/hs_client.h" +#include "feature/hs/hs_pow.h" +#include "lib/crypt_ops/crypto_rand.h" +#include "lib/crypt_ops/crypto_format.h" +#include "lib/arch/bytes.h" +#include "lib/cc/ctassert.h" +#include "core/mainloop/cpuworker.h" +#include "lib/evloop/workqueue.h" +#include "lib/time/compat_time.h" + +/** Replay cache set up */ +/** Cache entry for (nonce, seed) replay protection. */ +typedef struct nonce_cache_entry_t { + HT_ENTRY(nonce_cache_entry_t) node; + struct { + uint8_t nonce[HS_POW_NONCE_LEN]; + uint8_t seed_head[HS_POW_SEED_HEAD_LEN]; + } bytes; +} nonce_cache_entry_t; + +/** Return true if the two (nonce, seed) replay cache entries are the same */ +static inline int +nonce_cache_entries_eq_(const struct nonce_cache_entry_t *entry1, + const struct nonce_cache_entry_t *entry2) +{ + return fast_memeq(&entry1->bytes, &entry2->bytes, sizeof entry1->bytes); +} + +/** Hash function to hash the (nonce, seed) tuple entry. */ +static inline unsigned +nonce_cache_entry_hash_(const struct nonce_cache_entry_t *ent) +{ + return (unsigned)siphash24g(&ent->bytes, sizeof ent->bytes); +} + +static HT_HEAD(nonce_cache_table_ht, nonce_cache_entry_t) + nonce_cache_table = HT_INITIALIZER(); + +HT_PROTOTYPE(nonce_cache_table_ht, nonce_cache_entry_t, node, + nonce_cache_entry_hash_, nonce_cache_entries_eq_); + +HT_GENERATE2(nonce_cache_table_ht, nonce_cache_entry_t, node, + nonce_cache_entry_hash_, nonce_cache_entries_eq_, 0.6, + tor_reallocarray_, tor_free_); + +/** This is a callback used to check replay cache entries against a provided + * seed head, or NULL to operate on the entire cache. Matching entries return + * 1 and their internal cache entry is freed, non-matching entries return 0. */ +static int +nonce_cache_entry_match_seed_and_free(nonce_cache_entry_t *ent, void *data) +{ + if (data == NULL || + fast_memeq(ent->bytes.seed_head, data, HS_POW_SEED_HEAD_LEN)) { + tor_free(ent); + return 1; + } + return 0; +} + +/** Helper: Increment a given nonce and set it in the challenge at the right + * offset. Use by the solve function. */ +static inline void +increment_and_set_nonce(uint8_t *nonce, uint8_t *challenge) +{ + for (unsigned i = 0; i < HS_POW_NONCE_LEN; i++) { + uint8_t prev = nonce[i]; + if (++nonce[i] > prev) { + break; + } + } + memcpy(challenge + HS_POW_NONCE_OFFSET, nonce, HS_POW_NONCE_LEN); +} + +/* Helper: Build EquiX challenge (P || ID || C || N || INT_32(E)) and return + * a newly allocated buffer containing it. */ +static uint8_t * +build_equix_challenge(const ed25519_public_key_t *blinded_id, + const uint8_t *seed, const uint8_t *nonce, + const uint32_t effort) +{ + size_t offset = 0; + uint8_t *challenge = tor_malloc_zero(HS_POW_CHALLENGE_LEN); + + CTASSERT(HS_POW_ID_LEN == sizeof *blinded_id); + tor_assert_nonfatal(!ed25519_public_key_is_zero(blinded_id)); + + log_debug(LD_REND, + "Constructing EquiX challenge with " + "blinded service id %s, effort: %d", + safe_str_client(ed25519_fmt(blinded_id)), + effort); + + memcpy(challenge + offset, HS_POW_PSTRING, HS_POW_PSTRING_LEN); + offset += HS_POW_PSTRING_LEN; + memcpy(challenge + offset, blinded_id, HS_POW_ID_LEN); + offset += HS_POW_ID_LEN; + memcpy(challenge + offset, seed, HS_POW_SEED_LEN); + offset += HS_POW_SEED_LEN; + tor_assert(HS_POW_NONCE_OFFSET == offset); + memcpy(challenge + offset, nonce, HS_POW_NONCE_LEN); + offset += HS_POW_NONCE_LEN; + set_uint32(challenge + offset, tor_htonl(effort)); + offset += HS_POW_EFFORT_LEN; + tor_assert(HS_POW_CHALLENGE_LEN == offset); + + return challenge; +} + +/** Helper: Return true iff the given challenge and solution for the given + * effort do validate as in: R * E <= UINT32_MAX. */ +static bool +validate_equix_challenge(const uint8_t *challenge, + const uint8_t *solution_bytes, + const uint32_t effort) +{ + /* Fail if R * E > UINT32_MAX. */ + uint8_t hash_result[HS_POW_HASH_LEN]; + blake2b_state b2_state; + + if (BUG(blake2b_init(&b2_state, HS_POW_HASH_LEN) < 0)) { + return false; + } + + /* Construct: blake2b(C || N || E || S) */ + blake2b_update(&b2_state, challenge, HS_POW_CHALLENGE_LEN); + blake2b_update(&b2_state, solution_bytes, HS_POW_EQX_SOL_LEN); + blake2b_final(&b2_state, hash_result, HS_POW_HASH_LEN); + + /* Scale to 64 bit so we can avoid 32 bit overflow. */ + uint64_t RE = tor_htonl(get_uint32(hash_result)) * (uint64_t) effort; + + return RE <= UINT32_MAX; +} + +/** Helper: Convert equix_solution to a byte array in little-endian order */ +static void +pack_equix_solution(const equix_solution *sol_in, + uint8_t *bytes_out) +{ + for (unsigned i = 0; i < EQUIX_NUM_IDX; i++) { + bytes_out[i*2+0] = (uint8_t)sol_in->idx[i]; + bytes_out[i*2+1] = (uint8_t)(sol_in->idx[i] >> 8); + } +} + +/** Helper: Build an equix_solution from its corresponding byte array. */ +static void +unpack_equix_solution(const uint8_t *bytes_in, + equix_solution *sol_out) +{ + for (unsigned i = 0; i < EQUIX_NUM_IDX; i++) { + sol_out->idx[i] = (uint16_t)bytes_in[i*2+0] | + (uint16_t)bytes_in[i*2+1] << 8; + } +} + +/** Helper: Map the CompiledProofOfWorkHash configuration option to its + * corresponding equix_ctx_flags bit. */ +static equix_ctx_flags +hs_pow_equix_option_flags(int CompiledProofOfWorkHash) +{ + if (CompiledProofOfWorkHash == 0) { + return 0; + } else if (CompiledProofOfWorkHash == 1) { + return EQUIX_CTX_MUST_COMPILE; + } else { + tor_assert_nonfatal(CompiledProofOfWorkHash == -1); + return EQUIX_CTX_TRY_COMPILE; + } +} + +/** Solve the EquiX/blake2b PoW scheme using the parameters in pow_params, and + * store the solution in pow_solution_out. Returns 0 on success and -1 + * otherwise. Called by a client, from a cpuworker thread. */ +int +hs_pow_solve(const hs_pow_solver_inputs_t *pow_inputs, + hs_pow_solution_t *pow_solution_out) +{ + int ret = -1; + uint8_t nonce[HS_POW_NONCE_LEN]; + uint8_t *challenge = NULL; + equix_ctx *ctx = NULL; + + tor_assert(pow_inputs); + tor_assert(pow_solution_out); + const uint32_t effort = pow_inputs->effort; + + /* Generate a random nonce N. */ + crypto_rand((char *)nonce, sizeof nonce); + + /* Build EquiX challenge string */ + challenge = build_equix_challenge(&pow_inputs->service_blinded_id, + pow_inputs->seed, nonce, effort); + + /* This runs on a cpuworker, let's not access global get_options(). + * Instead, the particular options we need are captured in pow_inputs. */ + ctx = equix_alloc(EQUIX_CTX_SOLVE | + hs_pow_equix_option_flags(pow_inputs->CompiledProofOfWorkHash)); + if (!ctx) { + goto end; + } + + uint8_t sol_bytes[HS_POW_EQX_SOL_LEN]; + monotime_t start_time; + monotime_get(&start_time); + log_info(LD_REND, "Solving proof of work (effort %u)", effort); + + for (;;) { + /* Calculate solutions to S = equix_solve(C || N || E), */ + equix_solutions_buffer buffer; + equix_result result; + result = equix_solve(ctx, challenge, HS_POW_CHALLENGE_LEN, &buffer); + switch (result) { + + case EQUIX_OK: + for (unsigned i = 0; i < buffer.count; i++) { + pack_equix_solution(&buffer.sols[i], sol_bytes); + + /* Check an Equi-X solution against the effort threshold */ + if (validate_equix_challenge(challenge, sol_bytes, effort)) { + /* Store the nonce N. */ + memcpy(pow_solution_out->nonce, nonce, HS_POW_NONCE_LEN); + /* Store the effort E. */ + pow_solution_out->effort = effort; + /* We only store the first 4 bytes of the seed C. */ + memcpy(pow_solution_out->seed_head, pow_inputs->seed, + sizeof(pow_solution_out->seed_head)); + /* Store the solution S */ + memcpy(&pow_solution_out->equix_solution, + sol_bytes, sizeof sol_bytes); + + monotime_t end_time; + monotime_get(&end_time); + int64_t duration_usec = monotime_diff_usec(&start_time, &end_time); + log_info(LD_REND, "Proof of work solution (effort %u) found " + "using %s implementation in %u.%06u seconds", + effort, + (EQUIX_SOLVER_DID_USE_COMPILER & buffer.flags) + ? "compiled" : "interpreted", + (unsigned)(duration_usec / 1000000), + (unsigned)(duration_usec % 1000000)); + + /* Indicate success and we are done. */ + ret = 0; + goto end; + } + } + break; + + case EQUIX_FAIL_CHALLENGE: + /* This happens occasionally due to HashX rejecting some program + * configurations. For our purposes here it's the same as count==0. + * Increment the nonce and try again. */ + break; + + case EQUIX_FAIL_COMPILE: + /* The interpreter is disabled and the compiler failed */ + log_warn(LD_REND, "Proof of work solver failed, " + "compile error with no fallback enabled."); + goto end; + + /* These failures are not applicable to equix_solve, but included for + * completeness and to satisfy exhaustive enum warnings. */ + case EQUIX_FAIL_ORDER: + case EQUIX_FAIL_PARTIAL_SUM: + case EQUIX_FAIL_FINAL_SUM: + /* And these really should not happen, and indicate + * programming errors if they do. */ + case EQUIX_FAIL_NO_SOLVER: + case EQUIX_FAIL_INTERNAL: + default: + tor_assert_nonfatal_unreached(); + goto end; + } + + /* No solutions for this nonce and/or none that passed the effort + * threshold, increment and try again. */ + increment_and_set_nonce(nonce, challenge); + } + + end: + tor_free(challenge); + equix_free(ctx); + return ret; +} + +/** Verify the solution in pow_solution using the service's current PoW + * parameters found in pow_state. Returns 0 on success and -1 otherwise. Called + * by the service. */ +int +hs_pow_verify(const ed25519_public_key_t *service_blinded_id, + const hs_pow_service_state_t *pow_state, + const hs_pow_solution_t *pow_solution) +{ + int ret = -1; + uint8_t *challenge = NULL; + nonce_cache_entry_t search, *entry = NULL; + equix_ctx *ctx = NULL; + const uint8_t *seed = NULL; + + tor_assert(pow_state); + tor_assert(pow_solution); + tor_assert(service_blinded_id); + tor_assert_nonfatal(!ed25519_public_key_is_zero(service_blinded_id)); + + /* Find a valid seed C that starts with the seed head. Fail if no such seed + * exists. */ + if (fast_memeq(pow_state->seed_current, pow_solution->seed_head, + HS_POW_SEED_HEAD_LEN)) { + seed = pow_state->seed_current; + } else if (fast_memeq(pow_state->seed_previous, pow_solution->seed_head, + HS_POW_SEED_HEAD_LEN)) { + seed = pow_state->seed_previous; + } else { + log_warn(LD_REND, "Seed head didn't match either seed."); + goto done; + } + + /* Fail if N = POW_NONCE is present in the replay cache. */ + memcpy(search.bytes.nonce, pow_solution->nonce, HS_POW_NONCE_LEN); + memcpy(search.bytes.seed_head, pow_solution->seed_head, + HS_POW_SEED_HEAD_LEN); + entry = HT_FIND(nonce_cache_table_ht, &nonce_cache_table, &search); + if (entry) { + log_warn(LD_REND, "Found (nonce, seed) tuple in the replay cache."); + goto done; + } + + /* Build the challenge with the params we have. */ + challenge = build_equix_challenge(service_blinded_id, seed, + pow_solution->nonce, pow_solution->effort); + + if (!validate_equix_challenge(challenge, pow_solution->equix_solution, + pow_solution->effort)) { + log_warn(LD_REND, "Verification of challenge effort in PoW failed."); + goto done; + } + + ctx = equix_alloc(EQUIX_CTX_VERIFY | + hs_pow_equix_option_flags(get_options()->CompiledProofOfWorkHash)); + if (!ctx) { + goto done; + } + + /* Fail if equix_verify() != EQUIX_OK */ + equix_solution equix_sol; + unpack_equix_solution(pow_solution->equix_solution, &equix_sol); + equix_result result = equix_verify(ctx, challenge, HS_POW_CHALLENGE_LEN, + &equix_sol); + if (result != EQUIX_OK) { + log_warn(LD_REND, "Verification of EquiX solution in PoW failed."); + goto done; + } + + /* PoW verified successfully. */ + ret = 0; + + /* Add the (nonce, seed) tuple to the replay cache. */ + entry = tor_malloc_zero(sizeof(nonce_cache_entry_t)); + memcpy(entry->bytes.nonce, pow_solution->nonce, HS_POW_NONCE_LEN); + memcpy(entry->bytes.seed_head, pow_solution->seed_head, + HS_POW_SEED_HEAD_LEN); + HT_INSERT(nonce_cache_table_ht, &nonce_cache_table, entry); + + done: + tor_free(challenge); + equix_free(ctx); + return ret; +} + +/** Remove entries from the (nonce, seed) replay cache which are for the seed + * beginning with seed_head. If seed_head is NULL, remove all cache entries. */ +void +hs_pow_remove_seed_from_cache(const uint8_t *seed_head) +{ + /* If nonce_cache_entry_has_seed returns 1, the entry is removed. */ + HT_FOREACH_FN(nonce_cache_table_ht, &nonce_cache_table, + nonce_cache_entry_match_seed_and_free, (void*)seed_head); +} + +/** Free a given PoW service state. */ +void +hs_pow_free_service_state(hs_pow_service_state_t *state) +{ + if (state == NULL) { + return; + } + rend_pqueue_clear(state); + tor_assert(smartlist_len(state->rend_request_pqueue) == 0); + smartlist_free(state->rend_request_pqueue); + mainloop_event_free(state->pop_pqueue_ev); + tor_free(state); +} + +/* ===== + Thread workers + =====*/ + +/** + * An object passed to a worker thread that will try to solve the pow. + */ +typedef struct pow_worker_job_t { + + /** Inputs for the PoW solver (seed, chosen effort) */ + hs_pow_solver_inputs_t pow_inputs; + + /** State: we'll look these up to figure out how to proceed after. */ + uint32_t intro_circ_identifier; + uint8_t rend_circ_cookie[HS_REND_COOKIE_LEN]; + + /** Output: The worker thread will malloc and write its answer here, + * or set it to NULL if it produced no useful answer. */ + hs_pow_solution_t *pow_solution_out; + +} pow_worker_job_t; + +/** + * Worker function. This function runs inside a worker thread and receives + * a pow_worker_job_t as its input. + */ +static workqueue_reply_t +pow_worker_threadfn(void *state_, void *work_) +{ + (void)state_; + pow_worker_job_t *job = work_; + job->pow_solution_out = tor_malloc_zero(sizeof(hs_pow_solution_t)); + + if (hs_pow_solve(&job->pow_inputs, job->pow_solution_out)) { + tor_free(job->pow_solution_out); + job->pow_solution_out = NULL; /* how we signal that we came up empty */ + } + return WQ_RPL_REPLY; +} + +/** + * Helper: release all storage held in job. + */ +static void +pow_worker_job_free(pow_worker_job_t *job) +{ + if (!job) + return; + tor_free(job->pow_solution_out); + tor_free(job); +} + +/** + * Worker function: This function runs in the main thread, and receives + * a pow_worker_job_t that the worker thread has already processed. + */ +static void +pow_worker_replyfn(void *work_) +{ + tor_assert(in_main_thread()); + tor_assert(work_); + + pow_worker_job_t *job = work_; + + /* Look up the circuits that we're going to use this pow in. + * There's room for improvement here. We already had a fast mapping to + * rend circuits from some kind of identifier that we can keep in a + * pow_worker_job_t, but we don't have that index for intro circs at this + * time. If the linear search in circuit_get_by_global_id() is ever a + * noticeable bottleneck we should add another map. + */ + origin_circuit_t *intro_circ = + circuit_get_by_global_id(job->intro_circ_identifier); + origin_circuit_t *rend_circ = + hs_circuitmap_get_established_rend_circ_client_side(job->rend_circ_cookie); + + /* try to re-create desc and ip */ + const ed25519_public_key_t *service_identity_pk = NULL; + const hs_descriptor_t *desc = NULL; + const hs_desc_intro_point_t *ip = NULL; + if (intro_circ) + service_identity_pk = &intro_circ->hs_ident->identity_pk; + if (service_identity_pk) + desc = hs_cache_lookup_as_client(service_identity_pk); + if (desc) + ip = find_desc_intro_point_by_ident(intro_circ->hs_ident, desc); + + if (intro_circ && rend_circ && service_identity_pk && desc && ip && + job->pow_solution_out) { + + /* successful pow solve, and circs still here */ + log_info(LD_REND, "Got a PoW solution we like! Shipping it!"); + + /* Set flag to reflect that the HS we are attempting to rendezvous has PoW + * defenses enabled, and as such we will need to be more lenient with + * timing out while waiting for the service-side circuit to be built. */ + rend_circ->hs_with_pow_circ = 1; + + /* Remember the PoW effort we chose, for client-side rend circuits. */ + rend_circ->hs_pow_effort = job->pow_inputs.effort; + + // and then send that intro cell + if (send_introduce1(intro_circ, rend_circ, + desc, job->pow_solution_out, ip) < 0) { + /* if it failed, mark the intro point as ready to start over */ + intro_circ->hs_currently_solving_pow = 0; + } + + } else { + if (!job->pow_solution_out) { + log_warn(LD_REND, "PoW cpuworker returned with no solution"); + } else { + log_info(LD_REND, "PoW solution completed but we can " + "no longer locate its circuit"); + } + if (intro_circ) { + intro_circ->hs_currently_solving_pow = 0; + } + } + + pow_worker_job_free(job); +} + +/** + * Queue the job of solving the pow in a worker thread. + */ +int +hs_pow_queue_work(uint32_t intro_circ_identifier, + const uint8_t *rend_circ_cookie, + const hs_pow_solver_inputs_t *pow_inputs) +{ + tor_assert(in_main_thread()); + tor_assert(rend_circ_cookie); + tor_assert(pow_inputs); + tor_assert_nonfatal( + !ed25519_public_key_is_zero(&pow_inputs->service_blinded_id)); + + pow_worker_job_t *job = tor_malloc_zero(sizeof(*job)); + job->intro_circ_identifier = intro_circ_identifier; + memcpy(&job->rend_circ_cookie, rend_circ_cookie, + sizeof job->rend_circ_cookie); + memcpy(&job->pow_inputs, pow_inputs, sizeof job->pow_inputs); + + workqueue_entry_t *work; + work = cpuworker_queue_work(WQ_PRI_LOW, + pow_worker_threadfn, + pow_worker_replyfn, + job); + if (!work) { + pow_worker_job_free(job); + return -1; + } + return 0; +} diff -Nru tor-0.4.7.16/src/feature/hs/hs_pow.h tor-0.4.9.6/src/feature/hs/hs_pow.h --- tor-0.4.7.16/src/feature/hs/hs_pow.h 1970-01-01 00:00:00.000000000 +0000 +++ tor-0.4.9.6/src/feature/hs/hs_pow.h 2026-03-25 14:30:34.000000000 +0000 @@ -0,0 +1,228 @@ +/* Copyright (c) 2019-2020, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file hs_pow.h + * \brief Header file containing PoW denial of service defenses for the HS + * subsystem for all versions. + **/ + +#ifndef TOR_HS_POW_H +#define TOR_HS_POW_H + +#include "lib/evloop/compat_libevent.h" +#include "lib/evloop/token_bucket.h" +#include "lib/smartlist_core/smartlist_core.h" +#include "lib/crypt_ops/crypto_ed25519.h" + +/* Service updates the suggested effort every HS_UPDATE_PERIOD seconds. + * This parameter controls how often we can change hs descriptor data to + * update suggested_effort, but it also controls the frequency of our + * opportunities to increase or decrease effort. Lower values react to + * attacks faster, higher values may be more stable. + * Can this move to torrc? (Or the consensus?) The hs_cache timings are + * related, and they're also hardcoded. +*/ +#define HS_UPDATE_PERIOD 300 + +/** Length of random nonce (N) used in the PoW scheme. */ +#define HS_POW_NONCE_LEN 16 +/** Length of an E-quiX solution (S) in bytes. */ +#define HS_POW_EQX_SOL_LEN 16 +/** Length of blake2b hash result (R) used in the PoW scheme. */ +#define HS_POW_HASH_LEN 4 +/** Length of algorithm personalization string (P) used in the PoW scheme */ +#define HS_POW_PSTRING_LEN 16 +/** Algorithm personalization string (P) */ +#define HS_POW_PSTRING "Tor hs intro v1\0" +/** Length of the blinded public ID for the onion service (ID) */ +#define HS_POW_ID_LEN 32 +/** Length of random seed used in the PoW scheme. */ +#define HS_POW_SEED_LEN 32 +/** Length of seed identification heading in the PoW scheme. */ +#define HS_POW_SEED_HEAD_LEN 4 +/** Length of an effort value */ +#define HS_POW_EFFORT_LEN sizeof(uint32_t) +/** Offset of the nonce value within the challenge string */ +#define HS_POW_NONCE_OFFSET \ + (HS_POW_PSTRING_LEN + HS_POW_ID_LEN + HS_POW_SEED_LEN) +/** Length of a PoW challenge. Construction as per prop327 is: + * (P || ID || C || N || INT_32(E)) + */ +#define HS_POW_CHALLENGE_LEN \ + (HS_POW_PSTRING_LEN + HS_POW_ID_LEN + \ + HS_POW_SEED_LEN + HS_POW_NONCE_LEN + HS_POW_EFFORT_LEN) + +/** Type of PoW in the descriptor. */ +typedef enum { + HS_POW_DESC_V1 = 1, +} hs_pow_desc_type_t; + +/** Proof-of-Work parameters for DoS defense located in a descriptor. */ +typedef struct hs_pow_desc_params_t { + /** Type of PoW system being used. */ + hs_pow_desc_type_t type; + + /** Random 32-byte seed used as input the the PoW hash function */ + uint8_t seed[HS_POW_SEED_LEN]; + + /** Specifies effort value that clients should aim for when contacting the + * service. */ + uint32_t suggested_effort; + + /** Timestamp after which the above seed expires. */ + time_t expiration_time; +} hs_pow_desc_params_t; + +/** The inputs to the PoW solver, derived from the descriptor data and the + * client's per-connection effort choices. */ +typedef struct hs_pow_solver_inputs_t { + /** Seed value from a current descriptor */ + uint8_t seed[HS_POW_SEED_LEN]; + /** Blinded public ID for the onion service this puzzle is bound to */ + ed25519_public_key_t service_blinded_id; + /** Effort chosen by the client. May be higher or lower than + * suggested_effort in the descriptor. */ + uint32_t effort; + /** Configuration option, choice of hash implementation. AUTOBOOL. */ + int CompiledProofOfWorkHash; +} hs_pow_solver_inputs_t; + +/** State and parameters of PoW defenses, stored in the service state. */ +typedef struct hs_pow_service_state_t { + /* If PoW defenses are enabled this is a priority queue containing acceptable + * requests that are awaiting rendezvous circuits to built, where priority is + * based on the amount of effort that was exerted in the PoW. */ + smartlist_t *rend_request_pqueue; + + /* Low level mark for pqueue size. Below this length it's considered to be + * effectively empty when calculating effort adjustments. */ + int pqueue_low_level; + + /* High level mark for pqueue size. When the queue is this length we will + * trim it down to pqueue_high_level/2. */ + int pqueue_high_level; + + /* Event callback for dequeueing rend requests, paused when the queue is + * empty or rate limited. */ + mainloop_event_t *pop_pqueue_ev; + + /* Token bucket for rate limiting the priority queue */ + token_bucket_ctr_t pqueue_bucket; + + /* The current seed being used in the PoW defenses. */ + uint8_t seed_current[HS_POW_SEED_LEN]; + + /* The previous seed that was used in the PoW defenses. We accept solutions + * for both the current and previous seed. */ + uint8_t seed_previous[HS_POW_SEED_LEN]; + + /* The time at which the current seed expires and rotates for a new one. */ + time_t expiration_time; + + /* The suggested effort that clients should use in order for their request to + * be serviced in a timely manner. */ + uint32_t suggested_effort; + + /* The maximum effort of a request we've had to trim, this update period */ + uint32_t max_trimmed_effort; + + /* The following values are used when calculating and updating the suggested + * effort every HS_UPDATE_PERIOD seconds. */ + + /* Number of intro requests the service handled since last update. */ + uint32_t rend_handled; + /* The next time at which to update the suggested effort. */ + time_t next_effort_update; + /* Sum of effort of all valid requests received since the last update. */ + uint64_t total_effort; + + /* Did we have elements waiting in the queue during this period? */ + bool had_queue; + /* Are we using pqueue_bucket to rate limit the pqueue? */ + bool using_pqueue_bucket; + +} hs_pow_service_state_t; + +/* Struct to store a solution to the PoW challenge. */ +typedef struct hs_pow_solution_t { + /* The nonce chosen to satisfy the PoW challenge's conditions. */ + uint8_t nonce[HS_POW_NONCE_LEN]; + + /* The effort used in this solution. */ + uint32_t effort; + + /* A prefix of the seed used in this solution, so it can be identified. */ + uint8_t seed_head[HS_POW_SEED_HEAD_LEN]; + + /* The Equi-X solution used in this PoW solution. */ + uint8_t equix_solution[HS_POW_EQX_SOL_LEN]; +} hs_pow_solution_t; + +#ifdef HAVE_MODULE_POW +#define have_module_pow() (1) + +/* API */ +int hs_pow_solve(const hs_pow_solver_inputs_t *pow_inputs, + hs_pow_solution_t *pow_solution_out); + +int hs_pow_verify(const ed25519_public_key_t *service_blinded_id, + const hs_pow_service_state_t *pow_state, + const hs_pow_solution_t *pow_solution); + +void hs_pow_remove_seed_from_cache(const uint8_t *seed_head); +void hs_pow_free_service_state(hs_pow_service_state_t *state); + +int hs_pow_queue_work(uint32_t intro_circ_identifier, + const uint8_t *rend_circ_cookie, + const hs_pow_solver_inputs_t *pow_inputs); + +#else /* !defined(HAVE_MODULE_POW) */ +#define have_module_pow() (0) + +static inline int +hs_pow_solve(const hs_pow_solver_inputs_t *pow_inputs, + hs_pow_solution_t *pow_solution_out) +{ + (void)pow_inputs; + (void)pow_solution_out; + return -1; +} + +static inline int +hs_pow_verify(const ed25519_public_key_t *service_blinded_id, + const hs_pow_service_state_t *pow_state, + const hs_pow_solution_t *pow_solution) +{ + (void)service_blinded_id; + (void)pow_state; + (void)pow_solution; + return -1; +} + +static inline void +hs_pow_remove_seed_from_cache(const uint8_t *seed_head) +{ + (void)seed_head; +} + +static inline void +hs_pow_free_service_state(hs_pow_service_state_t *state) +{ + (void)state; +} + +static inline int +hs_pow_queue_work(uint32_t intro_circ_identifier, + const uint8_t *rend_circ_cookie, + const hs_pow_solver_inputs_t *pow_inputs) +{ + (void)intro_circ_identifier; + (void)rend_circ_cookie; + (void)pow_inputs; + return -1; +} + +#endif /* defined(HAVE_MODULE_POW) */ + +#endif /* !defined(TOR_HS_POW_H) */ diff -Nru tor-0.4.7.16/src/feature/hs/hs_service.c tor-0.4.9.6/src/feature/hs/hs_service.c --- tor-0.4.7.16/src/feature/hs/hs_service.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/feature/hs/hs_service.c 2026-03-25 14:30:34.000000000 +0000 @@ -33,6 +33,8 @@ #include "lib/crypt_ops/crypto_ope.h" #include "lib/crypt_ops/crypto_rand.h" #include "lib/crypt_ops/crypto_util.h" +#include "lib/time/tvdiff.h" +#include "lib/time/compat_time.h" #include "feature/hs/hs_circuit.h" #include "feature/hs/hs_common.h" @@ -42,6 +44,7 @@ #include "feature/hs/hs_ident.h" #include "feature/hs/hs_intropoint.h" #include "feature/hs/hs_metrics.h" +#include "feature/hs/hs_metrics_entry.h" #include "feature/hs/hs_service.h" #include "feature/hs/hs_stats.h" #include "feature/hs/hs_ob.h" @@ -144,7 +147,7 @@ sizeof(service->keys.identity_pk.pubkey)); } -/** This is _the_ global hash map of hidden services which indexed the service +/** This is _the_ global hash map of hidden services which indexes the services * contained in it by master public identity key which is roughly the onion * address of the service. */ static struct hs_service_ht *hs_service_map; @@ -170,9 +173,7 @@ } /** Query the given service map with a public key and return a service object - * if found else NULL. It is also possible to set a directory path in the - * search query. If pk is NULL, then it will be set to zero indicating the - * hash table to compare the directory path instead. */ + * if found else NULL. */ STATIC hs_service_t * find_service(hs_service_ht *map, const ed25519_public_key_t *pk) { @@ -262,6 +263,63 @@ c->has_dos_defense_enabled = HS_CONFIG_V3_DOS_DEFENSE_DEFAULT; c->intro_dos_rate_per_sec = HS_CONFIG_V3_DOS_DEFENSE_RATE_PER_SEC_DEFAULT; c->intro_dos_burst_per_sec = HS_CONFIG_V3_DOS_DEFENSE_BURST_PER_SEC_DEFAULT; + /* PoW default options. */ + c->has_pow_defenses_enabled = HS_CONFIG_V3_POW_DEFENSES_DEFAULT; + c->pow_queue_rate = HS_CONFIG_V3_POW_QUEUE_RATE; + c->pow_queue_burst = HS_CONFIG_V3_POW_QUEUE_BURST; +} + +/** Initialize PoW defenses */ +static void +initialize_pow_defenses(hs_service_t *service) +{ + service->state.pow_state = tor_malloc_zero(sizeof(hs_pow_service_state_t)); + + /* Make life easier */ + hs_pow_service_state_t *pow_state = service->state.pow_state; + + pow_state->rend_request_pqueue = smartlist_new(); + pow_state->pop_pqueue_ev = NULL; + + /* If we are using the pqueue rate limiter, calculate min and max queue + * levels based on those programmed rates. If not, we have generic + * defaults */ + pow_state->pqueue_low_level = 16; + pow_state->pqueue_high_level = 16384; + + if (service->config.pow_queue_rate > 0 && + service->config.pow_queue_burst >= service->config.pow_queue_rate) { + pow_state->using_pqueue_bucket = 1; + token_bucket_ctr_init(&pow_state->pqueue_bucket, + service->config.pow_queue_rate, + service->config.pow_queue_burst, + (uint32_t) monotime_coarse_absolute_sec()); + + pow_state->pqueue_low_level = MAX(8, service->config.pow_queue_rate / 4); + pow_state->pqueue_high_level = + service->config.pow_queue_burst + + service->config.pow_queue_rate * MAX_REND_TIMEOUT * 2; + } + + /* We recalculate and update the suggested effort every HS_UPDATE_PERIOD + * seconds. */ + pow_state->suggested_effort = 0; + pow_state->rend_handled = 0; + pow_state->total_effort = 0; + pow_state->next_effort_update = (time(NULL) + HS_UPDATE_PERIOD); + + /* Generate the random seeds. We generate both as we don't want the previous + * seed to be predictable even if it doesn't really exist yet, and it needs + * to be different to the current nonce for the replay cache scrubbing to + * function correctly. */ + log_info(LD_REND, "Generating both PoW seeds..."); + crypto_rand((char *)&pow_state->seed_current, HS_POW_SEED_LEN); + crypto_rand((char *)&pow_state->seed_previous, HS_POW_SEED_LEN); + + pow_state->expiration_time = + (time(NULL) + + crypto_rand_int_range(HS_SERVICE_POW_SEED_ROTATE_TIME_MIN, + HS_SERVICE_POW_SEED_ROTATE_TIME_MAX)); } /** From a service configuration object config, clear everything from it @@ -354,11 +412,6 @@ static int32_t get_intro_point_min_lifetime(void) { -#define MIN_INTRO_POINT_LIFETIME_TESTING 10 - if (get_options()->TestingTorNetwork) { - return MIN_INTRO_POINT_LIFETIME_TESTING; - } - /* The [0, 2147483647] range is quite large to accommodate anything we decide * in the future. */ return networkstatus_get_param(NULL, "hs_intro_min_lifetime", @@ -371,11 +424,6 @@ static int32_t get_intro_point_max_lifetime(void) { -#define MAX_INTRO_POINT_LIFETIME_TESTING 30 - if (get_options()->TestingTorNetwork) { - return MAX_INTRO_POINT_LIFETIME_TESTING; - } - /* The [0, 2147483647] range is quite large to accommodate anything we decide * in the future. */ return networkstatus_get_param(NULL, "hs_intro_max_lifetime", @@ -2107,7 +2155,7 @@ continue; } - /* Reaching this point means we are pass bootup so at runtime. We should + /* Reaching this point means we are past bootup so at runtime. We should * *never* have an empty current descriptor. If the next descriptor is * empty, we'll try to build it for the next time period. This only * happens when we rotate meaning that we are guaranteed to have a new SRV @@ -2129,7 +2177,7 @@ /** Randomly pick a node to become an introduction point but not present in the * given exclude_nodes list. The chosen node is put in the exclude list * regardless of success or not because in case of failure, the node is simply - * unsusable from that point on. + * unusable from that point on. * * If direct_conn is set, try to pick a node that our local firewall/policy * allows us to connect to directly. If we can't find any, return NULL. @@ -2147,7 +2195,7 @@ const node_t *node; hs_service_intro_point_t *ip = NULL; /* Normal 3-hop introduction point flags. */ - router_crn_flags_t flags = CRN_NEED_UPTIME | CRN_NEED_DESC; + router_crn_flags_t flags = CRN_NEED_UPTIME | CRN_NEED_DESC | CRN_FOR_HS; /* Single onion flags. */ router_crn_flags_t direct_flags = flags | CRN_PREF_ADDR | CRN_DIRECT_CONN; @@ -2250,6 +2298,14 @@ safe_str_client(service->onion_address)); goto done; } + + /* Save a copy of the specific version of the blinded ID that we + * use to reach this intro point. Needed to validate proof-of-work + * solutions that are bound to this specific service. */ + tor_assert(desc->desc); + ed25519_pubkey_copy(&ip->blinded_id, + &desc->desc->plaintext_data.blinded_pubkey); + /* Valid intro point object, add it to the descriptor current map. */ service_intro_point_add(desc->intro_points.map, ip); } @@ -2367,6 +2423,88 @@ } FOR_EACH_SERVICE_END; } +/** Update or initialise PoW parameters in the descriptors if they do not + * reflect the current state of the PoW defenses. If the defenses have been + * disabled then remove the PoW parameters from the descriptors. */ +static void +update_all_descriptors_pow_params(time_t now) +{ + FOR_EACH_SERVICE_BEGIN(service) { + int descs_updated = 0; + hs_pow_service_state_t *pow_state = service->state.pow_state; + hs_desc_encrypted_data_t *encrypted; + uint32_t previous_effort; + + /* If PoW defenses have been disabled after previously being enabled, i.e + * via config change and SIGHUP, we need to remove the PoW parameters from + * the descriptors so clients stop attempting to solve the puzzle. */ + FOR_EACH_DESCRIPTOR_BEGIN(service, desc) { + if (!service->config.has_pow_defenses_enabled && + desc->desc->encrypted_data.pow_params) { + log_info(LD_REND, "PoW defenses have been disabled, clearing " + "pow_params from a descriptor."); + tor_free(desc->desc->encrypted_data.pow_params); + /* Schedule for upload here as we can skip the following checks as PoW + * defenses are disabled. */ + service_desc_schedule_upload(desc, now, 1); + } + } FOR_EACH_DESCRIPTOR_END; + + /* Skip remaining checks if this service does not have PoW defenses + * enabled. */ + if (!service->config.has_pow_defenses_enabled) { + continue; + } + + FOR_EACH_DESCRIPTOR_BEGIN(service, desc) { + encrypted = &desc->desc->encrypted_data; + /* If this is a new service or PoW defenses were just enabled we need to + * initialise pow_params in the descriptors. If this runs the next if + * statement will run and set the correct values. */ + if (!encrypted->pow_params) { + log_info(LD_REND, "Initializing pow_params in descriptor..."); + encrypted->pow_params = tor_malloc_zero(sizeof(hs_pow_desc_params_t)); + } + + /* Update the descriptor any time the seed rotates, using expiration + * time as a proxy for parameters not including the suggested_effort, + * which gets special treatment below. */ + if (encrypted->pow_params->expiration_time != + pow_state->expiration_time) { + encrypted->pow_params->type = 0; /* use first version in the list */ + memcpy(encrypted->pow_params->seed, &pow_state->seed_current, + HS_POW_SEED_LEN); + encrypted->pow_params->suggested_effort = pow_state->suggested_effort; + encrypted->pow_params->expiration_time = pow_state->expiration_time; + descs_updated = 1; + } + + /* Services SHOULD NOT upload a new descriptor if the suggested + * effort value changes by less than 15 percent. */ + previous_effort = encrypted->pow_params->suggested_effort; + if (pow_state->suggested_effort < previous_effort * 0.85 || + previous_effort * 1.15 < pow_state->suggested_effort) { + log_info(LD_REND, "Suggested effort changed significantly, " + "updating descriptors..."); + encrypted->pow_params->suggested_effort = pow_state->suggested_effort; + descs_updated = 1; + } else if (previous_effort != pow_state->suggested_effort) { + /* The change in suggested effort was not significant enough to + * warrant updating the descriptors, return 0 to reflect they are + * unchanged. */ + log_info(LD_REND, "Change in suggested effort didn't warrant " + "updating descriptors."); + } + } FOR_EACH_DESCRIPTOR_END; + + if (descs_updated) { + FOR_EACH_DESCRIPTOR_BEGIN(service, desc) { + service_desc_schedule_upload(desc, now, 1); + } FOR_EACH_DESCRIPTOR_END; + } + } FOR_EACH_SERVICE_END; +} + /** Return true iff the given intro point has expired that is it has been used * for too long or we've reached our max seen INTRODUCE2 cell. */ STATIC int @@ -2420,7 +2558,7 @@ goto end; } - /* Pass this point, even though we might be over the retry limit, we check + /* Past 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. */ @@ -2508,6 +2646,131 @@ smartlist_free(ips_to_free); } +/** Rotate the seeds used in the proof-of-work defenses. */ +static void +rotate_pow_seeds(hs_service_t *service, time_t now) +{ + /* Make life easier */ + hs_pow_service_state_t *pow_state = service->state.pow_state; + + log_info(LD_REND, + "Current seed expired. Scrubbing replay cache, rotating PoW " + "seeds, generating new seed and updating descriptors."); + + /* Before we overwrite the previous seed lets scrub entries corresponding + * to it in the nonce replay cache. */ + hs_pow_remove_seed_from_cache(pow_state->seed_previous); + + /* Keep track of the current seed that we are now rotating. */ + memcpy(pow_state->seed_previous, pow_state->seed_current, HS_POW_SEED_LEN); + + /* Generate a new random seed to use from now on. Make sure the seed head + * is different to that of the previous seed. The following while loop + * will run at least once as the seeds will initially be equal. */ + while (fast_memeq(pow_state->seed_previous, pow_state->seed_current, + HS_POW_SEED_HEAD_LEN)) { + crypto_rand((char *)pow_state->seed_current, HS_POW_SEED_LEN); + } + + /* Update the expiration time for the new seed. */ + pow_state->expiration_time = + (now + + crypto_rand_int_range(HS_SERVICE_POW_SEED_ROTATE_TIME_MIN, + HS_SERVICE_POW_SEED_ROTATE_TIME_MAX)); + + { + char fmt_next_time[ISO_TIME_LEN + 1]; + format_local_iso_time(fmt_next_time, pow_state->expiration_time); + log_debug(LD_REND, "PoW state expiration time set to: %s", fmt_next_time); + } +} + +/** Every HS_UPDATE_PERIOD seconds, and while PoW defenses are enabled, the + * service updates its suggested effort for PoW solutions as SUGGESTED_EFFORT = + * TOTAL_EFFORT / (SVC_BOTTOM_CAPACITY * HS_UPDATE_PERIOD) where TOTAL_EFFORT + * is the sum of the effort of all valid requests that have been received since + * the suggested_effort was last updated. */ +static void +update_suggested_effort(hs_service_t *service, time_t now) +{ + /* Make life easier */ + hs_pow_service_state_t *pow_state = service->state.pow_state; + + /* Calculate the new suggested effort, using an additive-increase + * multiplicative-decrease estimation scheme. */ + enum { + NONE, + INCREASE, + DECREASE + } aimd_event = NONE; + + if (pow_state->max_trimmed_effort > pow_state->suggested_effort) { + /* Increase when we notice that high-effort requests are trimmed */ + aimd_event = INCREASE; + } else if (pow_state->had_queue) { + if (smartlist_len(pow_state->rend_request_pqueue) > 0 && + top_of_rend_pqueue_is_worthwhile(pow_state)) { + /* Increase when the top of queue is high-effort */ + aimd_event = INCREASE; + } + } else if (smartlist_len(pow_state->rend_request_pqueue) < + pow_state->pqueue_low_level) { + /* Dec when the queue is empty now and had_queue wasn't set this period */ + aimd_event = DECREASE; + } + + switch (aimd_event) { + case INCREASE: + if (pow_state->suggested_effort < UINT32_MAX) { + pow_state->suggested_effort = MAX(pow_state->suggested_effort + 1, + (uint32_t)(pow_state->total_effort / + pow_state->rend_handled)); + } + break; + case DECREASE: + pow_state->suggested_effort = 2*pow_state->suggested_effort/3; + break; + case NONE: + break; + } + + hs_metrics_pow_suggested_effort(service, pow_state->suggested_effort); + + log_debug(LD_REND, "Recalculated suggested effort: %u", + pow_state->suggested_effort); + + /* Reset the total effort sum and number of rends for this update period. */ + pow_state->total_effort = 0; + pow_state->rend_handled = 0; + pow_state->max_trimmed_effort = 0; + pow_state->had_queue = 0; + pow_state->next_effort_update = now + HS_UPDATE_PERIOD; +} + +/** Run PoW defenses housekeeping. This MUST be called if the defenses are + * actually enabled for the given service. */ +static void +pow_housekeeping(hs_service_t *service, time_t now) +{ + /* If the service is starting off or just been reset we need to + * initialize the state of the defenses. */ + if (!service->state.pow_state) { + initialize_pow_defenses(service); + } + + /* If the current PoW seed has expired then generate a new current + * seed, storing the old one in seed_previous. */ + if (now >= service->state.pow_state->expiration_time) { + rotate_pow_seeds(service, now); + } + + /* Update the suggested effort if HS_UPDATE_PERIOD seconds have passed + * since we last did so. */ + if (now >= service->state.pow_state->next_effort_update) { + update_suggested_effort(service, now); + } +} + /** Set the next rotation time of the descriptors for the given service for the * time now. */ static void @@ -2652,6 +2915,12 @@ set_rotation_time(service); } + /* Check if we need to initialize or update PoW parameters, if the + * defenses are enabled. */ + if (have_module_pow() && service->config.has_pow_defenses_enabled) { + pow_housekeeping(service, now); + } + /* Cleanup invalid intro points from the service descriptor. */ cleanup_intro_points(service, now); @@ -2685,6 +2954,11 @@ * points. Missing introduction points will be picked in this function which * is useful for newly built descriptors. */ update_all_descriptors_intro_points(now); + + if (have_module_pow()) { + /* Update the PoW params if needed. */ + update_all_descriptors_pow_params(now); + } } /** For the given service, launch any intro point circuits that could be @@ -2757,13 +3031,6 @@ tor_assert(service->config.num_intro_points <= HS_CONFIG_V3_MAX_INTRO_POINTS); -/** For a testing network, allow to do it for the maximum amount so circuit - * creation and rotation and so on can actually be tested without limit. */ -#define MAX_INTRO_POINT_CIRCUIT_RETRIES_TESTING -1 - if (get_options()->TestingTorNetwork) { - return MAX_INTRO_POINT_CIRCUIT_RETRIES_TESTING; - } - num_wanted_ip = service->config.num_intro_points; /* The calculation is as follow. We have a number of intro points that we @@ -2997,9 +3264,8 @@ } /** Encode and sign the service descriptor desc and upload it to the - * responsible hidden service directories. If for_next_period is true, the set - * of directories are selected using the next hsdir_index. This does nothing - * if PublishHidServDescriptors is false. */ + * responsible hidden service directories. + * This does nothing if PublishHidServDescriptors is false. */ STATIC void upload_descriptor_to_all(const hs_service_t *service, hs_service_descriptor_t *desc) @@ -3414,6 +3680,11 @@ * will even out the metric. */ if (TO_CIRCUIT(circ)->purpose == CIRCUIT_PURPOSE_S_REND_JOINED) { hs_metrics_new_established_rdv(service); + + struct timeval now; + tor_gettimeofday(&now); + int64_t duration = tv_mdiff(&TO_CIRCUIT(circ)->timestamp_began, &now); + hs_metrics_rdv_circ_build_time(service, duration); } goto done; @@ -3467,8 +3738,13 @@ goto err; } + struct timeval now; + tor_gettimeofday(&now); + int64_t duration = tv_mdiff(&TO_CIRCUIT(circ)->timestamp_began, &now); + /* Update metrics. */ hs_metrics_new_established_intro(service); + hs_metrics_intro_circ_build_time(service, duration); log_info(LD_REND, "Successfully received an INTRO_ESTABLISHED cell " "on circuit %u for service %s", @@ -3511,6 +3787,9 @@ "an INTRODUCE2 cell on circuit %u for service %s", TO_CIRCUIT(circ)->n_circ_id, safe_str_client(service->onion_address)); + + hs_metrics_reject_intro_req(service, + HS_METRICS_ERR_INTRO_REQ_BAD_AUTH_KEY); goto err; } /* If we have an IP object, we MUST have a descriptor object. */ @@ -3527,6 +3806,7 @@ return 0; err: + return -1; } @@ -3784,6 +4064,9 @@ hs_service_add_ephemeral(ed25519_secret_key_t *sk, smartlist_t *ports, int max_streams_per_rdv_circuit, int max_streams_close_circuit, + int pow_defenses_enabled, + uint32_t pow_queue_rate, + uint32_t pow_queue_burst, smartlist_t *auth_clients_v3, char **address_out) { hs_service_add_ephemeral_status_t ret; @@ -3803,6 +4086,9 @@ service->config.is_ephemeral = 1; smartlist_free(service->config.ports); service->config.ports = ports; + service->config.has_pow_defenses_enabled = pow_defenses_enabled; + service->config.pow_queue_rate = pow_queue_rate; + service->config.pow_queue_burst = pow_queue_burst; /* Handle the keys. */ memcpy(&service->keys.identity_sk, sk, sizeof(service->keys.identity_sk)); @@ -4352,6 +4638,9 @@ service_descriptor_free(desc); } FOR_EACH_DESCRIPTOR_END; + /* Free the state of the PoW defenses. */ + hs_pow_free_service_state(service->state.pow_state); + /* Free service configuration. */ service_clear_config(&service->config); diff -Nru tor-0.4.7.16/src/feature/hs/hs_service.h tor-0.4.9.6/src/feature/hs/hs_service.h --- tor-0.4.7.16/src/feature/hs/hs_service.h 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/feature/hs/hs_service.h 2026-03-25 14:30:34.000000000 +0000 @@ -35,6 +35,11 @@ /** Maximum interval for uploading next descriptor (in seconds). */ #define HS_SERVICE_NEXT_UPLOAD_TIME_MAX (120 * 60) +/** PoW seed expiration time is set to RAND_TIME(now+7200, 900) + * seconds. */ +#define HS_SERVICE_POW_SEED_ROTATE_TIME_MIN (7200 - 900) +#define HS_SERVICE_POW_SEED_ROTATE_TIME_MAX (7200) + /** Collected metrics for a specific service. */ typedef struct hs_service_metrics_t { /** Store containing the metrics values. */ @@ -57,6 +62,10 @@ /** Encryption keypair for the "ntor" type. */ curve25519_keypair_t enc_key_kp; + /** Blinded public ID for this service, from this intro point's + * active time period. */ + ed25519_public_key_t blinded_id; + /** Legacy key if that intro point doesn't support v3. This should be used if * the base object legacy flag is set. */ crypto_pk_t *legacy_key; @@ -104,7 +113,7 @@ digest256map_t *map; /** Contains node's identity key digest that were introduction point for this - * descriptor but were retried to many times. We keep those so we avoid + * descriptor but were retried too many times. We keep those so we avoid * re-picking them over and over for a circuit retry period. * XXX: Once we have #22173, change this to only use ed25519 identity. */ digestmap_t *failed_id; @@ -257,6 +266,11 @@ uint32_t intro_dos_rate_per_sec; uint32_t intro_dos_burst_per_sec; + /** True iff PoW anti-DoS defenses are enabled. */ + unsigned int has_pow_defenses_enabled : 1; + uint32_t pow_queue_rate; + uint32_t pow_queue_burst; + /** If set, contains the Onion Balance master ed25519 public key (taken from * an .onion addresses) that this tor instance serves as backend. */ smartlist_t *ob_master_pubkeys; @@ -291,6 +305,10 @@ hs_subcredential_t *ob_subcreds; /* Number of OB subcredentials */ size_t n_ob_subcreds; + + /** State of the PoW defenses, which may be enabled dynamically. NULL if not + * defined for this service. */ + hs_pow_service_state_t *pow_state; } hs_service_state_t; /** Representation of a service running on this tor instance. */ @@ -371,6 +389,9 @@ hs_service_add_ephemeral(ed25519_secret_key_t *sk, smartlist_t *ports, int max_streams_per_rdv_circuit, int max_streams_close_circuit, + int pow_defenses_enabled, + uint32_t pow_queue_rate, + uint32_t pow_queue_burst, smartlist_t *auth_clients_v3, char **address_out); int hs_service_del_ephemeral(const char *address); diff -Nru tor-0.4.7.16/src/feature/hs/include.am tor-0.4.9.6/src/feature/hs/include.am --- tor-0.4.7.16/src/feature/hs/include.am 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/feature/hs/include.am 2026-03-25 14:30:34.000000000 +0000 @@ -1,6 +1,6 @@ # ADD_C_FILE: INSERT SOURCES HERE. -LIBTOR_APP_A_SOURCES += \ +LIBTOR_APP_A_SOURCES += \ src/feature/hs/hs_cache.c \ src/feature/hs/hs_cell.c \ src/feature/hs/hs_circuit.c \ @@ -13,13 +13,21 @@ src/feature/hs/hs_dos.c \ src/feature/hs/hs_ident.c \ src/feature/hs/hs_intropoint.c \ - src/feature/hs/hs_metrics.c \ + src/feature/hs/hs_metrics.c \ src/feature/hs/hs_ob.c \ src/feature/hs/hs_service.c \ src/feature/hs/hs_stats.c \ - src/feature/hs/hs_sys.c \ + src/feature/hs/hs_sys.c \ src/feature/hs/hs_metrics_entry.c +# Proof of Work module +MODULE_POW_SOURCES = \ + src/feature/hs/hs_pow.c + +if BUILD_MODULE_POW +LIBTOR_APP_A_SOURCES += $(MODULE_POW_SOURCES) +endif + # ADD_C_FILE: INSERT HEADERS HERE. noinst_HEADERS += \ src/feature/hs/hs_cache.h \ @@ -34,12 +42,13 @@ src/feature/hs/hs_dos.h \ src/feature/hs/hs_ident.h \ src/feature/hs/hs_intropoint.h \ - src/feature/hs/hs_metrics.h \ + src/feature/hs/hs_metrics.h \ src/feature/hs/hs_ob.h \ src/feature/hs/hs_opts_st.h \ src/feature/hs/hs_options.inc \ + src/feature/hs/hs_pow.h \ src/feature/hs/hs_service.h \ src/feature/hs/hs_stats.h \ src/feature/hs/hsdir_index_st.h \ - src/feature/hs/hs_sys.h \ + src/feature/hs/hs_sys.h \ src/feature/hs/hs_metrics_entry.h diff -Nru tor-0.4.7.16/src/feature/hs_common/include.am tor-0.4.9.6/src/feature/hs_common/include.am --- tor-0.4.7.16/src/feature/hs_common/include.am 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/feature/hs_common/include.am 2026-03-25 14:30:34.000000000 +0000 @@ -1,7 +1,7 @@ # ADD_C_FILE: INSERT SOURCES HERE. LIBTOR_APP_A_SOURCES += \ - src/feature/hs_common/replaycache.c \ + src/feature/hs_common/replaycache.c \ src/feature/hs_common/shared_random_client.c # ADD_C_FILE: INSERT HEADERS HERE. diff -Nru tor-0.4.7.16/src/feature/metrics/include.am tor-0.4.9.6/src/feature/metrics/include.am --- tor-0.4.7.16/src/feature/metrics/include.am 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/feature/metrics/include.am 2026-03-25 14:30:34.000000000 +0000 @@ -1,10 +1,10 @@ # ADD_C_FILE: INSERT SOURCES HERE. -LIBTOR_APP_A_SOURCES += \ +LIBTOR_APP_A_SOURCES += \ src/feature/metrics/metrics.c \ src/feature/metrics/metrics_sys.c # ADD_C_FILE: INSERT HEADERS HERE. -noinst_HEADERS += \ +noinst_HEADERS += \ src/feature/metrics/metrics.h \ src/feature/metrics/metrics_sys.h diff -Nru tor-0.4.7.16/src/feature/nodelist/fmt_routerstatus.c tor-0.4.9.6/src/feature/nodelist/fmt_routerstatus.c --- tor-0.4.7.16/src/feature/nodelist/fmt_routerstatus.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/feature/nodelist/fmt_routerstatus.c 2026-03-25 14:30:34.000000000 +0000 @@ -26,6 +26,9 @@ /** Helper: write the router-status information in rs into a newly * allocated character buffer. Use the same format as in network-status * documents. If version is non-NULL, add a "v" line for the platform. + * If declared_publish_time is nonnegative, we declare it as the + * publication time. Otherwise we look for a publication time in vrs, + * and fall back to a default (not useful) publication time. * * Return 0 on success, -1 on failure. * @@ -38,12 +41,14 @@ * NS_V3_VOTE - Output a complete V3 NS vote. If vrs is present, * it contains additional information for the vote. * NS_CONTROL_PORT - Output a NS document for the control port. + * */ char * routerstatus_format_entry(const routerstatus_t *rs, const char *version, const char *protocols, routerstatus_format_type_t format, - const vote_routerstatus_t *vrs) + const vote_routerstatus_t *vrs, + time_t declared_publish_time) { char *summary; char *result = NULL; @@ -53,11 +58,18 @@ char digest64[BASE64_DIGEST_LEN+1]; smartlist_t *chunks = smartlist_new(); + if (declared_publish_time >= 0) { + format_iso_time(published, declared_publish_time); + } else if (vrs) { + format_iso_time(published, vrs->published_on); + } else { + strlcpy(published, "2038-01-01 00:00:00", sizeof(published)); + } + const char *ip_str = fmt_addr(&rs->ipv4_addr); if (ip_str[0] == '\0') goto err; - format_iso_time(published, rs->published_on); digest_to_base64(identity64, rs->identity_digest); digest_to_base64(digest64, rs->descriptor_digest); diff -Nru tor-0.4.7.16/src/feature/nodelist/fmt_routerstatus.h tor-0.4.9.6/src/feature/nodelist/fmt_routerstatus.h --- tor-0.4.7.16/src/feature/nodelist/fmt_routerstatus.h 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/feature/nodelist/fmt_routerstatus.h 2026-03-25 14:30:34.000000000 +0000 @@ -35,6 +35,7 @@ const char *version, const char *protocols, routerstatus_format_type_t format, - const vote_routerstatus_t *vrs); + const vote_routerstatus_t *vrs, + time_t declared_publish_time); #endif /* !defined(TOR_FMT_ROUTERSTATUS_H) */ diff -Nru tor-0.4.7.16/src/feature/nodelist/include.am tor-0.4.9.6/src/feature/nodelist/include.am --- tor-0.4.7.16/src/feature/nodelist/include.am 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/feature/nodelist/include.am 2026-03-25 14:30:34.000000000 +0000 @@ -1,6 +1,6 @@ # ADD_C_FILE: INSERT SOURCES HERE. -LIBTOR_APP_A_SOURCES += \ +LIBTOR_APP_A_SOURCES += \ src/feature/nodelist/authcert.c \ src/feature/nodelist/describe.c \ src/feature/nodelist/dirlist.c \ @@ -30,7 +30,7 @@ src/feature/nodelist/networkstatus.h \ src/feature/nodelist/networkstatus_sr_info_st.h \ src/feature/nodelist/networkstatus_st.h \ - src/feature/nodelist/networkstatus_voter_info_st.h \ + src/feature/nodelist/networkstatus_voter_info_st.h\ src/feature/nodelist/nickname.h \ src/feature/nodelist/node_st.h \ src/feature/nodelist/nodefamily.h \ diff -Nru tor-0.4.7.16/src/feature/nodelist/microdesc.c tor-0.4.9.6/src/feature/nodelist/microdesc.c --- tor-0.4.7.16/src/feature/nodelist/microdesc.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/feature/nodelist/microdesc.c 2026-03-25 14:30:34.000000000 +0000 @@ -626,7 +626,7 @@ (*mdp)->digest, DIGEST256_LEN)) { rs_match = "Microdesc digest in RS matches"; } else { - rs_match = "Microdesc digest in RS does match"; + rs_match = "Microdesc digest in RS does not match"; } if (ns) { /* This should be impossible, but let's see! */ @@ -909,14 +909,16 @@ //tor_assert(md->held_in_map == 0); //tor_assert(md->held_by_nodes == 0); - if (md->onion_pkey) - tor_free(md->onion_pkey); tor_free(md->onion_curve25519_pkey); tor_free(md->ed25519_identity_pkey); if (md->body && md->saved_location != SAVED_IN_CACHE) tor_free(md->body); nodefamily_free(md->family); + if (md->family_ids) { + SMARTLIST_FOREACH(md->family_ids, char *, cp, tor_free(cp)); + smartlist_free(md->family_ids); + } short_policy_free(md->exit_policy); short_policy_free(md->ipv6_exit_policy); diff -Nru tor-0.4.7.16/src/feature/nodelist/microdesc_st.h tor-0.4.9.6/src/feature/nodelist/microdesc_st.h --- tor-0.4.7.16/src/feature/nodelist/microdesc_st.h 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/feature/nodelist/microdesc_st.h 2026-03-25 14:30:34.000000000 +0000 @@ -16,6 +16,7 @@ struct ed25519_public_key_t; struct nodefamily_t; struct short_policy_t; +struct smartlist_t; #include "ext/ht.h" @@ -63,14 +64,6 @@ /* Fields in the microdescriptor. */ - /** - * Public RSA TAP key for onions, ASN.1 encoded. We store this - * in its encoded format since storing it as a crypto_pk_t uses - * significantly more memory. */ - char *onion_pkey; - /** Length of onion_pkey, in bytes. */ - size_t onion_pkey_len; - /** As routerinfo_t.onion_curve25519_pkey */ struct curve25519_public_key_t *onion_curve25519_pkey; /** Ed25519 identity key, if included. */ @@ -81,6 +74,11 @@ uint16_t ipv6_orport; /** As routerinfo_t.family, with readable members parsed. */ struct nodefamily_t *family; + /** A list of strings representing router family IDs. + * May be null; Copied from family-ids. + * (Happy families only.) */ + struct smartlist_t *family_ids; + /** IPv4 exit policy summary */ struct short_policy_t *exit_policy; /** IPv6 exit policy summary */ diff -Nru tor-0.4.7.16/src/feature/nodelist/networkstatus.c tor-0.4.9.6/src/feature/nodelist/networkstatus.c --- tor-0.4.7.16/src/feature/nodelist/networkstatus.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/feature/nodelist/networkstatus.c 2026-03-25 14:30:34.000000000 +0000 @@ -51,6 +51,7 @@ #include "core/or/circuitmux.h" #include "core/or/circuitmux_ewma.h" #include "core/or/circuitstats.h" +#include "core/or/conflux_params.h" #include "core/or/connection_edge.h" #include "core/or/connection_or.h" #include "core/or/dos.h" @@ -1616,7 +1617,6 @@ a->is_hs_dir != b->is_hs_dir || a->is_staledesc != b->is_staledesc || a->has_bandwidth != b->has_bandwidth || - a->published_on != b->published_on || a->ipv6_orport != b->ipv6_orport || a->is_v2_dir != b->is_v2_dir || a->bandwidth_kb != b->bandwidth_kb || @@ -1712,6 +1712,7 @@ flow_control_new_consensus_params(c); hs_service_new_consensus_params(c); dns_new_consensus_params(c); + conflux_params_new_consensus(c); /* Maintenance of our L2 guard list */ maintain_layer2_guards(); @@ -1953,7 +1954,7 @@ int free_consensus = 1; /* Free 'c' at the end of the function */ int checked_protocols_already = 0; - if (flav < 0) { + if (flav < 0 || flav >= N_CONSENSUS_FLAVORS) { /* XXXX we don't handle unrecognized flavors yet. */ log_warn(LD_BUG, "Unrecognized consensus flavor %s", flavor); return -2; @@ -1981,6 +1982,7 @@ if ((int)c->flavor != flav) { /* This wasn't the flavor we thought we were getting. */ + tor_assert(c->flavor < N_CONSENSUS_FLAVORS); if (require_flavor) { log_warn(LD_DIR, "Got consensus with unexpected flavor %s (wanted %s)", networkstatus_get_flavor_name(c->flavor), flavor); @@ -2139,6 +2141,10 @@ } current_md_consensus = c; free_consensus = 0; /* avoid free */ + } else { + tor_assert_nonfatal_unreached(); + result = -2; + goto done; } waiting = &consensus_waiting_for_certs[flav]; @@ -2372,7 +2378,7 @@ networkstatus_getinfo_helper_single(const routerstatus_t *rs) { return routerstatus_format_entry(rs, NULL, NULL, NS_CONTROL_PORT, - NULL); + NULL, -1); } /** @@ -2404,7 +2410,6 @@ 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); @@ -2451,7 +2456,9 @@ if (ri->purpose != purpose) continue; set_routerstatus_from_routerinfo(&rs, node, ri); - smartlist_add(statuses, networkstatus_getinfo_helper_single(&rs)); + char *text = routerstatus_format_entry( + &rs, NULL, NULL, NS_CONTROL_PORT, NULL, ri->cache_info.published_on); + smartlist_add(statuses, text); } SMARTLIST_FOREACH_END(ri); answer = smartlist_join_strings(statuses, "", 0, NULL); @@ -2622,15 +2629,12 @@ int client_would_use_router(const routerstatus_t *rs, time_t now) { + (void) now; if (!rs->is_flagged_running) { /* If we had this router descriptor, we wouldn't even bother using it. * (Fetching and storing depends on by we_want_to_fetch_flavor().) */ return 0; } - if (rs->published_on + OLD_ROUTER_DESC_MAX_AGE < now) { - /* We'd drop it immediately for being too old. */ - return 0; - } if (!routerstatus_version_supports_extend2_cells(rs, 1)) { /* We'd ignore it because it doesn't support EXTEND2 cells. * If we don't know the version, download the descriptor so we can diff -Nru tor-0.4.7.16/src/feature/nodelist/node_select.h tor-0.4.9.6/src/feature/nodelist/node_select.h --- tor-0.4.7.16/src/feature/nodelist/node_select.h 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/feature/nodelist/node_select.h 2026-03-25 14:30:34.000000000 +0000 @@ -29,11 +29,13 @@ /* On clients, if choosing a node for a direct connection, only provide * nodes that satisfy ClientPreferIPv6OR. */ CRN_PREF_ADDR = 1<<5, - /* On clients, only provide nodes with HSRend=2 protocol version which - * is required for hidden service version 3. */ - CRN_RENDEZVOUS_V3 = 1<<6, + /* On clients, indicate that we need a HS related circuit (IP, HSDir, or RP). + * This is used in order to avoid certain nodes for these purposes. */ + CRN_FOR_HS = 1<<6, /* On clients, only provide nodes that can initiate IPv6 extends. */ CRN_INITIATE_IPV6_EXTEND = 1<<7, + /* On clients, only provide nodes that support Conflux (Relay=5). */ + CRN_CONFLUX = 1<<8, } router_crn_flags_t; /** Possible ways to weight routers when choosing one randomly. See diff -Nru tor-0.4.7.16/src/feature/nodelist/node_st.h tor-0.4.9.6/src/feature/nodelist/node_st.h --- tor-0.4.7.16/src/feature/nodelist/node_st.h 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/feature/nodelist/node_st.h 2026-03-25 14:30:34.000000000 +0000 @@ -74,6 +74,9 @@ unsigned int is_middle_only:1; unsigned int is_hs_dir:1; /**< True iff this router is a hidden service * directory according to the authorities. */ + unsigned int strip_guard:1; /**< True iff we should strip the Guard flag. */ + unsigned int strip_hsdir:1; /**< True iff we should strip the HSDir flag. */ + unsigned int strip_v2dir:1; /**< True iff we should strip the V2Dir flag. */ /* Local info: warning state. */ diff -Nru tor-0.4.7.16/src/feature/nodelist/nodelist.c tor-0.4.9.6/src/feature/nodelist/nodelist.c --- tor-0.4.7.16/src/feature/nodelist/nodelist.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/feature/nodelist/nodelist.c 2026-03-25 14:30:34.000000000 +0000 @@ -680,6 +680,32 @@ return ESTIMATED_ADDRESS_PER_NODE; } +/** + * If true, we use relays' listed family members in order to + * determine which relays are in the same family. + */ +static int use_family_lists = 1; +/** + * If true, we use relays' validated family IDs in order to + * determine which relays are in the same family. + */ +static int use_family_ids = 1; + +/** + * Update consensus parameters relevant to nodelist operations. + * + * We need to cache these values rather than searching for them every time + * we check whether two relays are in the same family. + **/ +static void +nodelist_update_consensus_params(const networkstatus_t *ns) +{ + use_family_lists = networkstatus_get_param(ns, "use-family-lists", + 1, 0, 1); // default, low, high + use_family_ids = networkstatus_get_param(ns, "use-family-ids", + 1, 0, 1); // default, low, high +} + /** Tell the nodelist that the current usable consensus is ns. * This makes the nodelist change all of the routerstatus entries for * the nodes, drop nodes that no longer have enough info to get used, @@ -698,6 +724,8 @@ SMARTLIST_FOREACH(the_nodelist->nodes, node_t *, node, node->rs = NULL); + nodelist_update_consensus_params(ns); + /* Conservatively estimate that every node will have 2 addresses (v4 and * v6). Then we add the number of configured trusted authorities we have. */ int estimated_addresses = smartlist_len(ns->routerstatus_list) * @@ -733,15 +761,21 @@ } node_set_country(node); - /* If we're not an authdir, believe others. */ - if (!authdir) { + /* Set node's flags based on rs's flags. */ + { node->is_valid = rs->is_valid; node->is_running = rs->is_flagged_running; node->is_fast = rs->is_fast; node->is_stable = rs->is_stable; node->is_possible_guard = rs->is_possible_guard; node->is_exit = rs->is_exit; - node->is_bad_exit = rs->is_bad_exit; + if (!authdir) { + /* Authdirs treat is_bad_exit specially in that they only assign + * it when the descriptor arrives. So when a dir auth is reading + * the flags from an existing consensus, don't believe the bit + * here, else it will get stuck 'on' forever. */ + node->is_bad_exit = rs->is_bad_exit; + } node->is_hs_dir = rs->is_hs_dir; node->ipv6_preferred = 0; if (reachable_addr_prefer_ipv6_orport(options) && @@ -787,15 +821,6 @@ } } -/** Return 1 iff node has Exit flag and no BadExit flag. - * Otherwise, return 0. - */ -int -node_is_good_exit(const node_t *node) -{ - return node->is_exit && ! node->is_bad_exit; -} - /** Helper: return true iff a node has a usable amount of information*/ static inline int node_is_usable(const node_t *node) @@ -1205,7 +1230,7 @@ /** Dummy object that should be unreturnable. Used to ensure that * node_get_protover_summary_flags() always returns non-NULL. */ static const protover_summary_flags_t zero_protover_flags = { - 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 }; /** Return the protover_summary_flags for a given node. */ @@ -1341,6 +1366,15 @@ } } +/** Return true iff the given node supports conflux (Relay=5) */ +bool +node_supports_conflux(const node_t *node) +{ + tor_assert(node); + + return node_get_protover_summary_flags(node)->supports_conflux; +} + /** Return the RSA ID key's SHA1 digest for the provided node. */ const uint8_t * node_get_rsa_id_digest(const node_t *node) @@ -1464,13 +1498,13 @@ node_is_dir(const node_t *node) { if (node->rs) { - routerstatus_t * rs = node->rs; + routerstatus_t *rs = node->rs; /* This is true if supports_tunnelled_dir_requests is true which * indicates that we support directory request tunnelled or through the * DirPort. */ return rs->is_v2_dir; } else if (node->ri) { - routerinfo_t * ri = node->ri; + routerinfo_t *ri = node->ri; /* Both tunnelled request is supported or DirPort is set. */ return ri->supports_tunnelled_dir_requests; } else { @@ -2025,37 +2059,6 @@ return NULL; } -/* Return a newly allocacted RSA onion public key taken from the given node. - * - * Return NULL if node is NULL or no RSA onion public key can be found. It is - * the caller responsibility to free the returned object. */ -crypto_pk_t * -node_get_rsa_onion_key(const node_t *node) -{ - crypto_pk_t *pk = NULL; - const char *onion_pkey; - size_t onion_pkey_len; - - if (!node) { - goto end; - } - - if (node->ri) { - onion_pkey = node->ri->onion_pkey; - onion_pkey_len = node->ri->onion_pkey_len; - } else if (node->rs && node->md) { - onion_pkey = node->md->onion_pkey; - onion_pkey_len = node->md->onion_pkey_len; - } else { - /* No descriptor or microdescriptor. */ - goto end; - } - pk = router_get_rsa_onion_pkey(onion_pkey, onion_pkey_len); - - end: - return pk; -} - /** Refresh the country code of ri. This function MUST be called on * each router when the GeoIP database is reloaded, and on all new routers. */ void @@ -2136,7 +2139,7 @@ /** Return true iff n1's declared family contains n2. */ STATIC int -node_family_contains(const node_t *n1, const node_t *n2) +node_family_list_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); @@ -2151,7 +2154,7 @@ * Return true iff node has declared a nonempty family. **/ STATIC bool -node_has_declared_family(const node_t *node) +node_has_declared_family_list(const node_t *node) { if (node->ri && node->ri->declared_family && smartlist_len(node->ri->declared_family)) { @@ -2166,12 +2169,44 @@ } /** + * Return the listed family IDs of `a`, if it has any. + */ +static const smartlist_t * +node_get_family_ids(const node_t *node) +{ + if (node->ri && node->ri->family_ids) { + return node->ri->family_ids; + } else if (node->md && node->md->family_ids) { + return node->md->family_ids; + } else { + return NULL; + } +} + +/** + * Return true iff `a` and `b` have any family ID in common. + **/ +static bool +nodes_have_common_family_id(const node_t *a, const node_t *b) +{ + const smartlist_t *ids_a = node_get_family_ids(a); + const smartlist_t *ids_b = node_get_family_ids(b); + if (ids_a == NULL || ids_b == NULL) + return false; + SMARTLIST_FOREACH(ids_a, const char *, id, { + if (smartlist_contains_string(ids_b, id)) + 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) +node_lookup_declared_family_list(smartlist_t *out, const node_t *node) { if (node->ri && node->ri->declared_family && smartlist_len(node->ri->declared_family)) { @@ -2211,9 +2246,17 @@ return 1; } - /* Are they in the same family because the agree they are? */ - if (node_family_contains(node1, node2) && - node_family_contains(node2, node1)) { + /* Are they in the same family because they agree they are? */ + if (use_family_lists && + node_family_list_contains(node1, node2) && + node_family_list_contains(node2, node1)) { + return 1; + } + + /* Are they in the same family because they have a common + * verified family ID? */ + if (use_family_ids && + nodes_have_common_family_id(node1, node2)) { return 1; } @@ -2273,20 +2316,31 @@ /* Now, add all nodes in the declared family of this node, if they * also declare this node to be in their family. */ - if (node_has_declared_family(node)) { + if (use_family_lists && + node_has_declared_family_list(node)) { smartlist_t *declared_family = smartlist_new(); - node_lookup_declared_family(declared_family, node); + node_lookup_declared_family_list(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 node_t *, node2) { - if (node_family_contains(node2, node)) { + if (node_family_list_contains(node2, node)) { smartlist_add(sl, (void*)node2); } } SMARTLIST_FOREACH_END(node2); smartlist_free(declared_family); } + /* Now add all the nodes that share a verified family ID with this node. */ + if (use_family_ids && + node_get_family_ids(node)) { + SMARTLIST_FOREACH(all_nodes, const node_t *, node2, { + if (nodes_have_common_family_id(node, node2)) { + smartlist_add(sl, (void *)node2); + } + }); + } + /* If the user declared any families locally, honor those too. */ if (options->NodeFamilySets) { SMARTLIST_FOREACH(options->NodeFamilySets, const routerset_t *, rs, { diff -Nru tor-0.4.7.16/src/feature/nodelist/nodelist.h tor-0.4.9.6/src/feature/nodelist/nodelist.h --- tor-0.4.7.16/src/feature/nodelist/nodelist.h 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/feature/nodelist/nodelist.h 2026-03-25 14:30:34.000000000 +0000 @@ -54,7 +54,6 @@ void node_get_verbose_nickname_by_id(const char *id_digest, char *verbose_name_out); int node_is_dir(const node_t *node); -int node_is_good_exit(const node_t *node); int node_has_any_descriptor(const node_t *node); int node_has_preferred_descriptor(const node_t *node, int for_direct_connect); @@ -84,6 +83,7 @@ bool node_supports_initiating_ipv6_extends(const node_t *node); bool node_supports_accepting_ipv6_extends(const node_t *node, bool need_canonical_ipv6_conn); +bool node_supports_conflux(const node_t *node); const uint8_t *node_get_rsa_id_digest(const node_t *node); MOCK_DECL(smartlist_t *,node_get_link_specifier_smartlist,(const node_t *node, @@ -108,7 +108,6 @@ int node_has_curve25519_onion_key(const node_t *node); 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(const smartlist_t *, nodelist_get_list, (void)); @@ -170,9 +169,10 @@ STATIC int node_nickname_matches(const node_t *node, const char *nickname); STATIC int node_in_nickname_smartlist(const smartlist_t *lst, const node_t *node); -STATIC int node_family_contains(const node_t *n1, const node_t *n2); -STATIC bool node_has_declared_family(const node_t *node); -STATIC void node_lookup_declared_family(smartlist_t *out, const node_t *node); +STATIC int node_family_list_contains(const node_t *n1, const node_t *n2); +STATIC bool node_has_declared_family_list(const node_t *node); +STATIC void node_lookup_declared_family_list(smartlist_t *out, + const node_t *node); #ifdef TOR_UNIT_TESTS diff -Nru tor-0.4.7.16/src/feature/nodelist/routerinfo_st.h tor-0.4.9.6/src/feature/nodelist/routerinfo_st.h --- tor-0.4.7.16/src/feature/nodelist/routerinfo_st.h 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/feature/nodelist/routerinfo_st.h 2026-03-25 14:30:34.000000000 +0000 @@ -15,6 +15,7 @@ #include "feature/nodelist/signed_descriptor_st.h" struct curve25519_public_key_t; +struct smartlist_t; /** Information about another onion router in the network. */ struct routerinfo_t { @@ -33,10 +34,13 @@ /** * Public RSA TAP key for onions, ASN.1 encoded. We store this * in its encoded format since storing it as a crypto_pk_t uses - * significantly more memory. */ - char *onion_pkey; + * significantly more memory. + * + * This may be absent. + */ + char *tap_onion_pkey; /** Length of onion_pkey, in bytes. */ - size_t onion_pkey_len; + size_t tap_onion_pkey_len; crypto_pk_t *identity_pkey; /**< Public RSA key for signing. */ /** Public curve25519 key for onions */ @@ -64,6 +68,10 @@ long uptime; /**< How many seconds the router claims to have been up */ smartlist_t *declared_family; /**< Nicknames of router which this router * claims are its family. */ + /** A list of strings representing router family IDs. + * May be null. Extracted from family-certs. + * (Happy families only.) */ + struct smartlist_t *family_ids; char *contact_info; /**< Declared contact info for this router. */ unsigned int is_hibernating:1; /**< Whether the router claims to be * hibernating */ diff -Nru tor-0.4.7.16/src/feature/nodelist/routerlist.c tor-0.4.9.6/src/feature/nodelist/routerlist.c --- tor-0.4.7.16/src/feature/nodelist/routerlist.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/feature/nodelist/routerlist.c 2026-03-25 14:30:34.000000000 +0000 @@ -243,7 +243,6 @@ int r = -1; off_t offset = 0; smartlist_t *signed_descriptors = NULL; - int nocache=0; size_t total_expected_len = 0; int had_any; int force = flags & RRS_FORCE; @@ -304,7 +303,6 @@ goto done; } if (sd->do_not_cache) { - ++nocache; continue; } c = tor_malloc(sizeof(sized_chunk_t)); @@ -558,8 +556,9 @@ const bool need_desc = (flags & CRN_NEED_DESC) != 0; const bool pref_addr = (flags & CRN_PREF_ADDR) != 0; const bool direct_conn = (flags & CRN_DIRECT_CONN) != 0; - const bool rendezvous_v3 = (flags & CRN_RENDEZVOUS_V3) != 0; const bool initiate_ipv6_extend = (flags & CRN_INITIATE_IPV6_EXTEND) != 0; + const bool need_conflux = (flags & CRN_CONFLUX) != 0; + const bool for_hs = (flags & CRN_FOR_HS) != 0; const or_options_t *options = get_options(); const bool check_reach = @@ -589,11 +588,10 @@ * 0.3.1.0-alpha. */ if (node_allows_single_hop_exits(node)) return false; - /* Exclude relays that can not become a rendezvous for a hidden service - * version 3. */ - if (rendezvous_v3 && - !node_supports_v3_rendezvous_point(node)) + /* Exclude relay that don't do conflux if requested. */ + if (need_conflux && !node_supports_conflux(node)) { return false; + } /* Choose a node with an OR address that matches the firewall rules */ if (direct_conn && check_reach && !reachable_addr_allows_node(node, @@ -602,6 +600,10 @@ return false; if (initiate_ipv6_extend && !node_supports_initiating_ipv6_extends(node)) return false; + /* MiddleOnly node should never be used for HS endpoints (IP, RP, HSDir). */ + if (for_hs && node->is_middle_only) { + return false; + } return true; } @@ -927,8 +929,8 @@ tor_free(router->platform); tor_free(router->protocol_list); tor_free(router->contact_info); - if (router->onion_pkey) - tor_free(router->onion_pkey); + if (router->tap_onion_pkey) + tor_free(router->tap_onion_pkey); tor_free(router->onion_curve25519_pkey); if (router->identity_pkey) crypto_pk_free(router->identity_pkey); @@ -937,6 +939,10 @@ SMARTLIST_FOREACH(router->declared_family, char *, s, tor_free(s)); smartlist_free(router->declared_family); } + if (router->family_ids) { + SMARTLIST_FOREACH(router->family_ids, char *, cp, tor_free(cp)); + smartlist_free(router->family_ids); + } addr_policy_list_free(router->exit_policy); short_policy_free(router->ipv6_exit_policy); @@ -1924,11 +1930,9 @@ retain = digestset_new(n_max_retain); } - cutoff = now - OLD_ROUTER_DESC_MAX_AGE; /* Retain anything listed in the consensus. */ if (consensus) { SMARTLIST_FOREACH(consensus->routerstatus_list, routerstatus_t *, rs, - if (rs->published_on >= cutoff) digestset_add(retain, rs->descriptor_digest)); } @@ -2653,7 +2657,7 @@ digestmap_t *map = NULL; smartlist_t *no_longer_old = smartlist_new(); smartlist_t *downloadable = smartlist_new(); - routerstatus_t *source = NULL; + const routerstatus_t *source = NULL; int authdir = authdir_mode(options); int n_delayed=0, n_have=0, n_would_reject=0, n_wouldnt_use=0, n_inprogress=0, n_in_oldrouters=0; @@ -2669,10 +2673,17 @@ networkstatus_voter_info_t *voter = smartlist_get(consensus->voters, 0); tor_assert(voter); ds = trusteddirserver_get_by_v3_auth_digest(voter->identity_digest); - if (ds) - source = &(ds->fake_status); - else + if (ds) { + source = router_get_consensus_status_by_id(ds->digest); + if (!source) { + /* prefer to use the address in the consensus, but fall back to + * the hard-coded trusted_dir_server address if we don't have a + * consensus or this digest isn't in our consensus. */ + source = &ds->fake_status; + } + } else { log_warn(LD_DIR, "couldn't lookup source from vote?"); + } } map = digestmap_new(); @@ -2721,17 +2732,20 @@ continue; /* We would never use it ourself. */ } if (is_vote && source) { - char time_bufnew[ISO_TIME_LEN+1]; - char time_bufold[ISO_TIME_LEN+1]; + char old_digest_buf[HEX_DIGEST_LEN+1]; + const char *old_digest = "none"; const routerinfo_t *oldrouter; oldrouter = router_get_by_id_digest(rs->identity_digest); - format_iso_time(time_bufnew, rs->published_on); - if (oldrouter) - format_iso_time(time_bufold, oldrouter->cache_info.published_on); + if (oldrouter) { + base16_encode(old_digest_buf, sizeof(old_digest_buf), + oldrouter->cache_info.signed_descriptor_digest, + DIGEST_LEN); + old_digest = old_digest_buf; + } log_info(LD_DIR, "Learned about %s (%s vs %s) from %s's vote (%s)", routerstatus_describe(rs), - time_bufnew, - oldrouter ? time_bufold : "none", + hex_str(rs->descriptor_digest, DIGEST_LEN), + old_digest, source->nickname, oldrouter ? "known" : "unknown"); } smartlist_add(downloadable, rs->descriptor_digest); @@ -2946,6 +2960,24 @@ /** We allow uptime to vary from how much it ought to be by this much. */ #define ROUTER_ALLOW_UPTIME_DRIFT (6*60*60) +/** Return true iff r1 and r2 have the same TAP onion keys. */ +static int +router_tap_onion_keys_eq(const routerinfo_t *r1, const routerinfo_t *r2) +{ + if (r1->tap_onion_pkey_len != r2->tap_onion_pkey_len) + return 0; + + if ((r1->tap_onion_pkey == NULL) && (r2->tap_onion_pkey == NULL)) { + return 1; + } else if ((r1->tap_onion_pkey != NULL) && (r2->tap_onion_pkey != NULL)) { + return tor_memeq(r1->tap_onion_pkey, r2->tap_onion_pkey, + r1->tap_onion_pkey_len); + } else { + /* One is NULL; one is not. */ + return 0; + } +} + /** Return true iff the only differences between r1 and r2 are such that * would not cause a recent (post 0.1.1.6) dirserver to republish. */ @@ -2971,8 +3003,7 @@ r1->ipv6_orport != r2->ipv6_orport || r1->ipv4_dirport != r2->ipv4_dirport || r1->purpose != r2->purpose || - r1->onion_pkey_len != r2->onion_pkey_len || - !tor_memeq(r1->onion_pkey, r2->onion_pkey, r1->onion_pkey_len) || + !router_tap_onion_keys_eq(r1,r2) || !crypto_pk_eq_keys(r1->identity_pkey, r2->identity_pkey) || strcasecmp(r1->platform, r2->platform) || (r1->contact_info && !r2->contact_info) || /* contact_info is optional */ diff -Nru tor-0.4.7.16/src/feature/nodelist/routerstatus_st.h tor-0.4.9.6/src/feature/nodelist/routerstatus_st.h --- tor-0.4.7.16/src/feature/nodelist/routerstatus_st.h 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/feature/nodelist/routerstatus_st.h 2026-03-25 14:30:34.000000000 +0000 @@ -21,7 +21,6 @@ * routerstatus_has_visibly_changed and the printing function * routerstatus_format_entry in NS_CONTROL_PORT mode. */ - time_t published_on; /**< When was this router published? */ char nickname[MAX_NICKNAME_LEN+1]; /**< The nickname this router says it * has. */ char identity_digest[DIGEST_LEN]; /**< Digest of the router's identity diff -Nru tor-0.4.7.16/src/feature/nodelist/torcert.h tor-0.4.9.6/src/feature/nodelist/torcert.h --- tor-0.4.7.16/src/feature/nodelist/torcert.h 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/feature/nodelist/torcert.h 2026-03-25 14:30:34.000000000 +0000 @@ -22,6 +22,7 @@ #define CERT_TYPE_AUTH_HS_IP_KEY 0x09 #define CERT_TYPE_ONION_ID 0x0A #define CERT_TYPE_CROSS_HS_IP_KEYS 0x0B +#define CERT_TYPE_FAMILY_V_IDENTITY 0x0C #define CERT_FLAG_INCLUDE_SIGNING_KEY 0x1 diff -Nru tor-0.4.7.16/src/feature/nodelist/vote_routerstatus_st.h tor-0.4.9.6/src/feature/nodelist/vote_routerstatus_st.h --- tor-0.4.7.16/src/feature/nodelist/vote_routerstatus_st.h 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/feature/nodelist/vote_routerstatus_st.h 2026-03-25 14:30:34.000000000 +0000 @@ -18,6 +18,7 @@ struct vote_routerstatus_t { routerstatus_t status; /**< Underlying 'status' object for this router. * Flags are redundant. */ + time_t published_on; /**< When was this router published? */ /** How many known-flags are allowed in a vote? This is the width of * the flags field of vote_routerstatus_t */ #define MAX_KNOWN_FLAGS_IN_VOTE 64 diff -Nru tor-0.4.7.16/src/feature/relay/circuitbuild_relay.c tor-0.4.9.6/src/feature/relay/circuitbuild_relay.c --- tor-0.4.7.16/src/feature/relay/circuitbuild_relay.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/feature/relay/circuitbuild_relay.c 2026-03-25 14:30:34.000000000 +0000 @@ -389,7 +389,6 @@ circ->n_hop = extend_info_new(NULL /*nickname*/, (const char*)ec->node_id, &ec->ed_pubkey, - NULL, /*onion_key*/ NULL, /*curve25519_key*/ &chosen_ap->addr, chosen_ap->port, @@ -422,15 +421,14 @@ * Return -1 if we want to warn and tear down the circuit, else return 0. */ int -circuit_extend(struct cell_t *cell, struct circuit_t *circ) +circuit_extend(const relay_msg_t *rmsg, struct circuit_t *circ) { channel_t *n_chan; - relay_header_t rh; extend_cell_t ec; const char *msg = NULL; int should_launch = 0; - IF_BUG_ONCE(!cell) { + IF_BUG_ONCE(!rmsg) { return -1; } @@ -441,11 +439,13 @@ if (circuit_extend_state_valid_helper(circ) < 0) return -1; - relay_header_unpack(&rh, cell->payload); + /* We no longer accept EXTEND messages; only EXTEND2. */ + if (rmsg->command == RELAY_COMMAND_EXTEND) { + /* TODO: Should we log this? */ + return -1; + } - if (extend_cell_parse(&ec, rh.command, - cell->payload+RELAY_HEADER_SIZE, - rh.length) < 0) { + if (extend_cell_parse(&ec, rmsg->command, rmsg->body, rmsg->length) < 0) { log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "Can't parse extend cell. Closing circuit."); return -1; @@ -535,6 +535,7 @@ int onionskin_answer(struct or_circuit_t *circ, const created_cell_t *created_cell, + relay_crypto_alg_t crypto_alg, const char *keys, size_t keys_len, const uint8_t *rend_circ_nonce) { @@ -556,8 +557,6 @@ return -1; } - tor_assert(keys_len == CPATH_KEY_MATERIAL_LEN); - if (created_cell_format(&cell, created_cell) < 0) { log_warn(LD_BUG,"couldn't format created cell (type=%d, len=%d).", (int)created_cell->cell_type, (int)created_cell->handshake_len); @@ -567,10 +566,8 @@ circuit_set_state(TO_CIRCUIT(circ), CIRCUIT_STATE_OPEN); - log_debug(LD_CIRC,"init digest forward 0x%.8x, backward 0x%.8x.", - (unsigned int)get_uint32(keys), - (unsigned int)get_uint32(keys+20)); - if (relay_crypto_init(&circ->crypto, keys, keys_len, 0, 0)<0) { + if (relay_crypto_init(crypto_alg, + &circ->crypto, keys, keys_len)<0) { log_warn(LD_BUG,"Circuit initialization failed."); return -1; } @@ -579,8 +576,10 @@ int used_create_fast = (created_cell->cell_type == CELL_CREATED_FAST); - append_cell_to_circuit_queue(TO_CIRCUIT(circ), - circ->p_chan, &cell, CELL_DIRECTION_IN, 0); + if (append_cell_to_circuit_queue(TO_CIRCUIT(circ), circ->p_chan, + &cell, CELL_DIRECTION_IN, 0) < 0) { + return -1; + } log_debug(LD_CIRC,"Finished sending '%s' cell.", used_create_fast ? "created_fast" : "created"); diff -Nru tor-0.4.7.16/src/feature/relay/circuitbuild_relay.h tor-0.4.9.6/src/feature/relay/circuitbuild_relay.h --- tor-0.4.7.16/src/feature/relay/circuitbuild_relay.h 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/feature/relay/circuitbuild_relay.h 2026-03-25 14:30:34.000000000 +0000 @@ -14,6 +14,8 @@ #include "lib/cc/torint.h" #include "lib/log/log.h" +#include "core/or/relay_msg_st.h" +#include "core/crypto/relay_crypto.h" #include "app/config/config.h" @@ -34,19 +36,20 @@ #ifdef HAVE_MODULE_RELAY -int circuit_extend(struct cell_t *cell, struct circuit_t *circ); +int circuit_extend(const relay_msg_t *msg, struct circuit_t *circ); int onionskin_answer(struct or_circuit_t *circ, const struct created_cell_t *created_cell, + relay_crypto_alg_t crypto_alg, const char *keys, size_t keys_len, const uint8_t *rend_circ_nonce); #else /* !defined(HAVE_MODULE_RELAY) */ static inline int -circuit_extend(struct cell_t *cell, struct circuit_t *circ) +circuit_extend(const relay_msg_t *msg, struct circuit_t *circ) { - (void)cell; + (void)msg; (void)circ; circuitbuild_warn_client_extend(); return -1; @@ -55,11 +58,13 @@ static inline int onionskin_answer(struct or_circuit_t *circ, const struct created_cell_t *created_cell, + relay_crypto_alg_t crypto_alg, const char *keys, size_t keys_len, const uint8_t *rend_circ_nonce) { (void)circ; (void)created_cell; + (void)crypto_alg; (void)keys; (void)keys_len; (void)rend_circ_nonce; diff -Nru tor-0.4.7.16/src/feature/relay/dns.c tor-0.4.9.6/src/feature/relay/dns.c --- tor-0.4.7.16/src/feature/relay/dns.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/feature/relay/dns.c 2026-03-25 14:30:34.000000000 +0000 @@ -71,6 +71,7 @@ #include "core/or/edge_connection_st.h" #include "core/or/or_circuit_st.h" +#include "core/or/conflux_util.h" #include "ht.h" @@ -85,6 +86,13 @@ * that the resolver is wedged? */ #define RESOLVE_MAX_TIMEOUT 300 +/** The clipped TTL sent back in the RESOLVED cell for every DNS queries. + * + * See https://gitlab.torproject.org/tpo/core/tor/-/issues/40979 for a thorough + * explanation but this is first and foremost a security fix in order to avoid + * an exit DNS cache oracle. */ +#define RESOLVED_CLIPPED_TTL (60) + /** Our evdns_base; this structure handles all our name lookups. */ static struct evdns_base *the_evdns_base = NULL; @@ -507,12 +515,13 @@ send_resolved_cell,(edge_connection_t *conn, uint8_t answer_type, const cached_resolve_t *resolved)) { - char buf[RELAY_PAYLOAD_SIZE], *cp = buf; + // (We use the minimum here to ensure that we never + // generate a too-big message.) + char buf[RELAY_PAYLOAD_SIZE_MIN], *cp = buf; size_t buflen = 0; - uint32_t ttl; + uint32_t ttl = RESOLVED_CLIPPED_TTL; buf[0] = answer_type; - ttl = conn->address_ttl; switch (answer_type) { @@ -562,6 +571,12 @@ connection_edge_send_command(conn, RELAY_COMMAND_RESOLVED, buf, buflen); } +void +dns_send_resolved_error_cell(edge_connection_t *conn, uint8_t answer_type) +{ + send_resolved_cell(conn, answer_type, NULL); +} + /** Send a response to the RESOLVE request of a connection for an in-addr.arpa * address on connection conn which yielded the result hostname. * The answer type will be RESOLVED_HOSTNAME. @@ -574,17 +589,18 @@ send_resolved_hostname_cell,(edge_connection_t *conn, const char *hostname)) { - char buf[RELAY_PAYLOAD_SIZE]; + char buf[RELAY_PAYLOAD_SIZE_MAX]; size_t buflen; - uint32_t ttl; + uint32_t ttl = RESOLVED_CLIPPED_TTL; if (BUG(!hostname)) return; size_t namelen = strlen(hostname); - tor_assert(namelen < 256); - ttl = conn->address_ttl; + if (BUG(namelen >= 256)) { + return; + } buf[0] = RESOLVED_TYPE_HOSTNAME; buf[1] = (uint8_t)namelen; @@ -650,6 +666,7 @@ * connected cell. */ exitconn->next_stream = oncirc->n_streams; oncirc->n_streams = exitconn; + conflux_update_n_streams(oncirc, exitconn); } break; case 0: @@ -658,6 +675,7 @@ exitconn->base_.state = EXIT_CONN_STATE_RESOLVING; exitconn->next_stream = oncirc->resolving_streams; oncirc->resolving_streams = exitconn; + conflux_update_resolving_streams(oncirc, exitconn); break; case -2: case -1: @@ -768,11 +786,11 @@ if (!is_reverse || !is_resolve) { if (!is_reverse) - log_info(LD_EXIT, "Bad .in-addr.arpa address \"%s\"; sending error.", + log_info(LD_EXIT, "Bad .in-addr.arpa address %s; sending error.", escaped_safe_str(exitconn->base_.address)); else if (!is_resolve) log_info(LD_EXIT, - "Attempt to connect to a .in-addr.arpa address \"%s\"; " + "Attempt to connect to a .in-addr.arpa address %s; " "sending error.", escaped_safe_str(exitconn->base_.address)); @@ -1175,8 +1193,8 @@ * resolution. * * Do this by sending a RELAY_RESOLVED cell (if the pending stream had sent us - * RELAY_RESOLVE cell), or by launching an exit connection (if the pending - * stream had send us a RELAY_BEGIN cell). + * a RELAY_RESOLVE cell), or by launching an exit connection (if the pending + * stream had sent us a RELAY_BEGIN cell). */ static void inform_pending_connections(cached_resolve_t *resolve) @@ -1234,6 +1252,7 @@ pend->conn->next_stream = TO_OR_CIRCUIT(circ)->n_streams; pend->conn->on_circuit = circ; TO_OR_CIRCUIT(circ)->n_streams = pend->conn; + conflux_update_n_streams(TO_OR_CIRCUIT(circ), pend->conn); connection_exit_connect(pend->conn); } else { @@ -1459,7 +1478,7 @@ * the query itself timed out in transit. */ SET("timeout:", get_consensus_param_exit_dns_timeout()); - /* This tells libevent to attemps up to X times a DNS query if the previous + /* This tells libevent to attempt up to X times a DNS query if the previous * one failed to complete within N second. We believe that this should be * enough to catch temporary hiccups on the first query. But after that, it * should signal us that it won't be able to resolve it. */ diff -Nru tor-0.4.7.16/src/feature/relay/dns.h tor-0.4.9.6/src/feature/relay/dns.h --- tor-0.4.7.16/src/feature/relay/dns.h 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/feature/relay/dns.h 2026-03-25 14:30:34.000000000 +0000 @@ -20,6 +20,8 @@ void connection_dns_remove(edge_connection_t *conn); void assert_connection_edge_not_dns_pending(edge_connection_t *conn); int dns_resolve(edge_connection_t *exitconn); +void dns_send_resolved_error_cell(edge_connection_t *conn, + uint8_t answer_type); int dns_seems_to_be_broken(void); int dns_seems_to_be_broken_for_ipv6(void); void dns_reset_correctness_checks(void); @@ -36,6 +38,8 @@ #else /* !defined(HAVE_MODULE_RELAY) */ #define dns_init() (0) +#define dns_send_resolved_error_cell(conn, answer_type) \ + ((void)(conn), (void)(answer_type)) #define dns_seems_to_be_broken() (0) #define has_dns_init_failed() (0) #define dns_cache_total_allocation() (0) diff -Nru tor-0.4.7.16/src/feature/relay/ext_orport.c tor-0.4.9.6/src/feature/relay/ext_orport.c --- tor-0.4.7.16/src/feature/relay/ext_orport.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/feature/relay/ext_orport.c 2026-03-25 14:30:34.000000000 +0000 @@ -285,6 +285,9 @@ EXT_OR_PORT_AUTH_NONCE_LEN); } + memwipe(server_hash, 0, sizeof(server_hash)); + memwipe(server_nonce, 0, sizeof(server_nonce)); + *reply_out = reply; *reply_len_out = reply_len; diff -Nru tor-0.4.7.16/src/feature/relay/include.am tor-0.4.9.6/src/feature/relay/include.am --- tor-0.4.7.16/src/feature/relay/include.am 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/feature/relay/include.am 2026-03-25 14:30:34.000000000 +0000 @@ -11,7 +11,7 @@ MODULE_RELAY_SOURCES = \ src/feature/relay/circuitbuild_relay.c \ src/feature/relay/dns.c \ - src/feature/relay/ext_orport.c \ + src/feature/relay/ext_orport.c \ src/feature/relay/routermode.c \ src/feature/relay/relay_config.c \ src/feature/relay/relay_handshake.c \ @@ -31,7 +31,7 @@ src/feature/relay/onion_queue.h \ src/feature/relay/relay_config.h \ src/feature/relay/relay_handshake.h \ - src/feature/relay/relay_metrics.h \ + src/feature/relay/relay_metrics.h \ src/feature/relay/relay_periodic.h \ src/feature/relay/relay_sys.h \ src/feature/relay/relay_find_addr.h \ diff -Nru tor-0.4.7.16/src/feature/relay/onion_queue.c tor-0.4.9.6/src/feature/relay/onion_queue.c --- tor-0.4.7.16/src/feature/relay/onion_queue.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/feature/relay/onion_queue.c 2026-03-25 14:30:34.000000000 +0000 @@ -50,10 +50,6 @@ #define ONION_QUEUE_MAX_DELAY_MIN 1 #define ONION_QUEUE_MAX_DELAY_MAX INT32_MAX -#define NUM_NTORS_PER_TAP_DEFAULT 10 -#define NUM_NTORS_PER_TAP_MIN 1 -#define NUM_NTORS_PER_TAP_MAX 100000 - /** Type for a linked list of circuits that are waiting for a free CPU worker * to process a waiting onion handshake. */ typedef struct onion_queue_t { @@ -84,17 +80,9 @@ static void onion_queue_entry_remove(onion_queue_t *victim); /** Consensus parameters. */ -static int32_t ns_num_ntors_per_tap = NUM_NTORS_PER_TAP_DEFAULT; static time_t ns_onion_queue_wait_cutoff = ONION_QUEUE_WAIT_CUTOFF_DEFAULT; static uint32_t ns_onion_queue_max_delay = ONION_QUEUE_MAX_DELAY_DEFAULT; -/** Return the number of ntors per tap from the cached parameter. */ -static inline int32_t -get_num_ntors_per_tap(void) -{ - return ns_num_ntors_per_tap; -} - /** Return the onion queue wait cutoff value from the cached parameter. */ static inline time_t get_onion_queue_wait_cutoff(void) @@ -115,7 +103,7 @@ /** * We combine ntorv3 and ntor into the same queue, so we must - * use this function to covert the cell type to a queue index. + * use this function to convert the cell type to a queue index. */ static inline uint16_t onionskin_type_to_queue(uint16_t type) @@ -146,8 +134,12 @@ const or_options_t *options = get_options(); int num_cpus; uint64_t max_onion_queue_delay; - uint64_t tap_usec, ntor_usec; - uint64_t ntor_during_tap_usec, tap_during_ntor_usec; + uint64_t ntor_usec; + + /* We never allow TAP. */ + if (type == ONION_HANDSHAKE_TYPE_TAP) { + return 0; + } /* If we've got fewer than 50 entries, we always have room for one more. */ if (ol_entries[type] < 50) @@ -164,44 +156,15 @@ /* Compute how many microseconds we'd expect to need to clear all * onionskins in various combinations of the queues. */ - /* How long would it take to process all the TAP cells in the queue? */ - tap_usec = estimated_usec_for_onionskins( - ol_entries[ONION_HANDSHAKE_TYPE_TAP], - ONION_HANDSHAKE_TYPE_TAP) / num_cpus; - /* How long would it take to process all the NTor cells in the queue? */ ntor_usec = estimated_usec_for_onionskins( ol_entries[ONION_HANDSHAKE_TYPE_NTOR], ONION_HANDSHAKE_TYPE_NTOR) / num_cpus; - /* How long would it take to process the tap cells that we expect to - * process while draining the ntor queue? */ - tap_during_ntor_usec = estimated_usec_for_onionskins( - MIN(ol_entries[ONION_HANDSHAKE_TYPE_TAP], - ol_entries[ONION_HANDSHAKE_TYPE_NTOR] / get_num_ntors_per_tap()), - ONION_HANDSHAKE_TYPE_TAP) / num_cpus; - - /* How long would it take to process the ntor cells that we expect to - * process while draining the tap queue? */ - ntor_during_tap_usec = estimated_usec_for_onionskins( - MIN(ol_entries[ONION_HANDSHAKE_TYPE_NTOR], - ol_entries[ONION_HANDSHAKE_TYPE_TAP] * get_num_ntors_per_tap()), - ONION_HANDSHAKE_TYPE_NTOR) / num_cpus; - /* See whether that exceeds MaxOnionQueueDelay. If so, we can't queue * this. */ if (type == ONION_HANDSHAKE_TYPE_NTOR && - (ntor_usec + tap_during_ntor_usec) / 1000 > max_onion_queue_delay) - return 0; - - if (type == ONION_HANDSHAKE_TYPE_TAP && - (tap_usec + ntor_during_tap_usec) / 1000 > max_onion_queue_delay) - return 0; - - /* If we support the ntor handshake, then don't let TAP handshakes use - * more than 2/3 of the space on the queue. */ - if (type == ONION_HANDSHAKE_TYPE_TAP && - tap_usec / 1000 > max_onion_queue_delay * 2 / 3) + (ntor_usec / 1000) > max_onion_queue_delay) return 0; return 1; @@ -292,38 +255,7 @@ static uint16_t decide_next_handshake_type(void) { - /* The number of times we've chosen ntor lately when both were available. */ - static int recently_chosen_ntors = 0; - - if (!ol_entries[ONION_HANDSHAKE_TYPE_NTOR]) - return ONION_HANDSHAKE_TYPE_TAP; /* no ntors? try tap */ - - if (!ol_entries[ONION_HANDSHAKE_TYPE_TAP]) { - - /* Nick wants us to prioritize new tap requests when there aren't - * any in the queue and we've processed k ntor cells since the last - * tap cell. This strategy is maybe a good idea, since it starves tap - * less in the case where tap is rare, or maybe a poor idea, since it - * makes the new tap cell unfairly jump in front of ntor cells that - * got here first. In any case this edge case will only become relevant - * once tap is rare. We should reevaluate whether we like this decision - * once tap gets more rare. */ - if (ol_entries[ONION_HANDSHAKE_TYPE_NTOR] && - recently_chosen_ntors <= get_num_ntors_per_tap()) - ++recently_chosen_ntors; - - return ONION_HANDSHAKE_TYPE_NTOR; /* no taps? try ntor */ - } - - /* They both have something queued. Pick ntor if we haven't done that - * too much lately. */ - if (++recently_chosen_ntors <= get_num_ntors_per_tap()) { - return ONION_HANDSHAKE_TYPE_NTOR; - } - - /* Else, it's time to let tap have its turn. */ - recently_chosen_ntors = 0; - return ONION_HANDSHAKE_TYPE_TAP; + return ONION_HANDSHAKE_TYPE_NTOR; } /** Remove the highest priority item from ol_list[] and return it, or @@ -445,10 +377,4 @@ ONION_QUEUE_WAIT_CUTOFF_DEFAULT, ONION_QUEUE_WAIT_CUTOFF_MIN, ONION_QUEUE_WAIT_CUTOFF_MAX); - - ns_num_ntors_per_tap = - networkstatus_get_param(ns, "NumNTorsPerTAP", - NUM_NTORS_PER_TAP_DEFAULT, - NUM_NTORS_PER_TAP_MIN, - NUM_NTORS_PER_TAP_MAX); } diff -Nru tor-0.4.7.16/src/feature/relay/relay_config.c tor-0.4.9.6/src/feature/relay/relay_config.c --- tor-0.4.7.16/src/feature/relay/relay_config.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/feature/relay/relay_config.c 2026-03-25 14:30:34.000000000 +0000 @@ -21,6 +21,7 @@ #include "lib/meminfo/meminfo.h" #include "lib/osinfo/uname.h" #include "lib/process/setuid.h" +#include "lib/crypt_ops/crypto_format.h" /* Required for dirinfo_type_t in or_options_t */ #include "core/or/or.h" @@ -30,9 +31,11 @@ #include "core/mainloop/cpuworker.h" #include "core/mainloop/mainloop.h" #include "core/or/connection_or.h" +#include "core/or/policies.h" #include "core/or/port_cfg_st.h" #include "feature/hibernate/hibernate.h" +#include "feature/hs/hs_service.h" #include "feature/nodelist/nickname.h" #include "feature/stats/geoip_stats.h" #include "feature/stats/predict_ports.h" @@ -691,7 +694,7 @@ * - "any" * - "https" * - "email" - * - "moat" + * - "settings" * * If the option string is unrecognised, a warning will be logged and 0 is * returned. If the option string contains an invalid character, -1 is @@ -704,7 +707,7 @@ return 0; const char *RECOGNIZED[] = { - "none", "any", "https", "email", "moat" + "none", "any", "https", "email", "settings" }; unsigned i; for (i = 0; i < ARRAY_LENGTH(RECOGNIZED); ++i) { @@ -942,7 +945,8 @@ if (accounting_parse_options(options, 1)<0) REJECT("Failed to parse accounting options. See logs for details."); - if (options->AccountingMax) { + if (options->AccountingMax && + !hs_service_non_anonymous_mode_enabled(options)) { if (options->RendConfigLines && server_mode(options)) { log_warn(LD_CONFIG, "Using accounting with a hidden service and an " "ORPort is risky: your hidden service(s) and your public " @@ -1118,7 +1122,8 @@ if (BUG(!msg)) return -1; - if (server_mode(options) && options->RendConfigLines) + if (server_mode(options) && options->RendConfigLines && + !hs_service_non_anonymous_mode_enabled(options)) log_warn(LD_CONFIG, "Tor is currently configured as a relay and a hidden service. " "That's not very secure: you should probably run your hidden service " @@ -1147,6 +1152,13 @@ REJECT("BridgeRelay is 1, ORPort is not set. This is an invalid " "combination."); + if (options->BridgeRelay == 1 && !(options->ExitRelay == 0 || + policy_using_default_exit_options(options))) { + log_warn(LD_CONFIG, "BridgeRelay is 1, but ExitRelay is 1 or an " + "ExitPolicy is configured. Tor will start, but it will not " + "function as an exit relay."); + } + if (server_mode(options)) { char *dircache_msg = NULL; if (have_enough_mem_for_dircache(options, 0, &dircache_msg)) { @@ -1169,6 +1181,24 @@ options->MyFamily_lines, "MyFamily", msg)) return -1; + if (options->FamilyId_lines) { + options->FamilyIds = smartlist_new(); + config_line_t *line; + for (line = options->FamilyId_lines; line; line = line->next) { + if (!strcmp(line->value, "*")) { + options->AllFamilyIdsExpected = true; + continue; + } + + ed25519_public_key_t pk; + if (ed25519_public_from_base64(&pk, line->value) < 0) { + tor_asprintf(msg, "Invalid FamilyId %s", line->value); + return -1; + } + smartlist_add(options->FamilyIds, tor_memdup(&pk, sizeof(pk))); + } + } + if (options->ConstrainedSockets) { if (options->DirPort_set) { /* Providing cached directory entries while system TCP buffers are scarce @@ -1263,6 +1293,7 @@ YES_IF_CHANGED_STRING(ContactInfo); YES_IF_CHANGED_STRING(BridgeDistribution); YES_IF_CHANGED_LINELIST(MyFamily); + YES_IF_CHANGED_LINELIST(FamilyId_lines); YES_IF_CHANGED_STRING(AccountingStart); YES_IF_CHANGED_INT(AccountingMax); YES_IF_CHANGED_INT(AccountingRule); @@ -1324,12 +1355,6 @@ "Worker-related options changed. Rotating workers."); const int server_mode_turned_on = server_mode(options) && !server_mode(old_options); - const int dir_server_mode_turned_on = - dir_server_mode(options) && !dir_server_mode(old_options); - - if (server_mode_turned_on || dir_server_mode_turned_on) { - cpu_init(); - } if (server_mode_turned_on) { ip_address_changed(0); diff -Nru tor-0.4.7.16/src/feature/relay/relay_find_addr.c tor-0.4.9.6/src/feature/relay/relay_find_addr.c --- tor-0.4.7.16/src/feature/relay/relay_find_addr.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/feature/relay/relay_find_addr.c 2026-03-25 14:30:34.000000000 +0000 @@ -78,7 +78,7 @@ /* Do not believe anyone who says our address is their address. */ log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "A relay endpoint %s is telling us that their address is ours.", - fmt_addr(peer_addr)); + safe_str(fmt_addr(peer_addr))); return; } @@ -212,17 +212,19 @@ return; } const node_t *node = node_get_by_id(rs->identity_digest); - if (!node) { + extend_info_t *ei = NULL; + if (node) { + ei = extend_info_from_node(node, 1, false); + } + if (!node || !ei) { /* This can happen if we are still in the early starting stage where no * descriptors we actually fetched and thus we have the routerstatus_t * for the authority but not its descriptor which is needed to build a * circuit and thus learn our address. */ - log_info(LD_GENERAL, "Can't build a circuit to an authority. Unable to " - "learn for now our address from them."); - return; - } - extend_info_t *ei = extend_info_from_node(node, 1, false); - if (BUG(!ei)) { + log_info(LD_GENERAL, + "Trying to learn our IP address by connecting to an " + "authority, but can't build a circuit to one yet. Will try " + "again soon."); return; } diff -Nru tor-0.4.7.16/src/feature/relay/relay_handshake.c tor-0.4.9.6/src/feature/relay/relay_handshake.c --- tor-0.4.7.16/src/feature/relay/relay_handshake.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/feature/relay/relay_handshake.c 2026-03-25 14:30:34.000000000 +0000 @@ -183,27 +183,17 @@ return 0; } -#ifdef TOR_UNIT_TESTS -int testing__connection_or_pretend_TLSSECRET_is_supported = 0; -#else -#define testing__connection_or_pretend_TLSSECRET_is_supported 0 -#endif - /** Return true iff challenge_type is an AUTHCHALLENGE type that * we can send and receive. */ int authchallenge_type_is_supported(uint16_t challenge_type) { switch (challenge_type) { - case AUTHTYPE_RSA_SHA256_TLSSECRET: -#ifdef HAVE_WORKING_TOR_TLS_GET_TLSSECRETS - return 1; -#else - return testing__connection_or_pretend_TLSSECRET_is_supported; -#endif case AUTHTYPE_ED25519_SHA256_RFC5705: return 1; - case AUTHTYPE_RSA_SHA256_RFC5705: + + case AUTHTYPE_RSA_SHA256_TLSSECRET: // obsolete. + case AUTHTYPE_RSA_SHA256_RFC5705: // never implemented. default: return 0; } @@ -243,11 +233,6 @@ tor_assert(sizeof(ac->challenge) == 32); crypto_rand((char*)ac->challenge, sizeof(ac->challenge)); - if (authchallenge_type_is_supported(AUTHTYPE_RSA_SHA256_TLSSECRET)) - auth_challenge_cell_add_methods(ac, AUTHTYPE_RSA_SHA256_TLSSECRET); - /* Disabled, because everything that supports this method also supports - * the much-superior ED25519_SHA256_RFC5705 */ - /* auth_challenge_cell_add_methods(ac, AUTHTYPE_RSA_SHA256_RFC5705); */ if (authchallenge_type_is_supported(AUTHTYPE_ED25519_SHA256_RFC5705)) auth_challenge_cell_add_methods(ac, AUTHTYPE_ED25519_SHA256_RFC5705); auth_challenge_cell_set_n_methods(ac, @@ -283,42 +268,36 @@ * determined by the rest of the handshake, and which match the provided value * exactly. * - * If server is false and signing_key is NULL, calculate the + * If server is false and ed_signing_key is NULL, calculate the * first V3_AUTH_BODY_LEN bytes of the authenticator (that is, everything * that should be signed), but don't actually sign it. * - * If server is false and signing_key is provided, calculate the - * entire authenticator, signed with signing_key. + * If server is false and ed_signing_key is provided, + * calculate the + * entire authenticator, signed with ed_signing_key. * * Return the length of the cell body on success, and -1 on failure. */ var_cell_t * connection_or_compute_authenticate_cell_body(or_connection_t *conn, const int authtype, - crypto_pk_t *signing_key, const ed25519_keypair_t *ed_signing_key, int server) { auth1_t *auth = NULL; - auth_ctx_t *ctx = auth_ctx_new(); var_cell_t *result = NULL; - int old_tlssecrets_algorithm = 0; const char *authtype_str = NULL; - int is_ed = 0; - /* assert state is reasonable XXXX */ switch (authtype) { case AUTHTYPE_RSA_SHA256_TLSSECRET: - authtype_str = "AUTH0001"; - old_tlssecrets_algorithm = 1; - break; case AUTHTYPE_RSA_SHA256_RFC5705: - authtype_str = "AUTH0002"; + /* These are unsupported; we should never reach this point. */ + tor_assert_nonfatal_unreached_once(); + return NULL; break; case AUTHTYPE_ED25519_SHA256_RFC5705: authtype_str = "AUTH0003"; - is_ed = 1; break; default: tor_assert(0); @@ -326,7 +305,6 @@ } auth = auth1_new(); - ctx->is_ed = is_ed; /* Type: 8 bytes. */ memcpy(auth1_getarray_type(auth), authtype_str, 8); @@ -355,7 +333,7 @@ memcpy(auth->sid, server_id, 32); } - if (is_ed) { + { const ed25519_public_key_t *my_ed_id, *their_ed_id; if (!conn->handshake_state->certs->ed_id_sign) { log_warn(LD_OR, "Ed authenticate without Ed ID cert from peer."); @@ -367,8 +345,8 @@ const uint8_t *cid_ed = (server ? their_ed_id : my_ed_id)->pubkey; const uint8_t *sid_ed = (server ? my_ed_id : their_ed_id)->pubkey; - memcpy(auth->u1_cid_ed, cid_ed, ED25519_PUBKEY_LEN); - memcpy(auth->u1_sid_ed, sid_ed, ED25519_PUBKEY_LEN); + memcpy(auth->cid_ed, cid_ed, ED25519_PUBKEY_LEN); + memcpy(auth->sid_ed, sid_ed, ED25519_PUBKEY_LEN); } { @@ -408,15 +386,8 @@ tor_x509_cert_free(cert); } - /* HMAC of clientrandom and serverrandom using master key : 32 octets */ - if (old_tlssecrets_algorithm) { - if (tor_tls_get_tlssecrets(conn->tls, auth->tlssecrets) < 0) { - log_fn(LOG_PROTOCOL_WARN, LD_OR, "Somebody asked us for an older TLS " - "authentication method (AUTHTYPE_RSA_SHA256_TLSSECRET) " - "which we don't support."); - goto err; - } - } else { + /* RFC5709 key exporter material : 32 octets */ + { char label[128]; tor_snprintf(label, sizeof(label), "EXPORTER FOR TOR TLS CLIENT BINDING %s", authtype_str); @@ -436,11 +407,9 @@ * checks it. That's followed by 16 bytes of nonce. */ crypto_rand((char*)auth->rand, 24); - ssize_t maxlen = auth1_encoded_len(auth, ctx); - if (ed_signing_key && is_ed) { + ssize_t maxlen = auth1_encoded_len(auth); + if (ed_signing_key) { maxlen += ED25519_SIG_LEN; - } else if (signing_key && !is_ed) { - maxlen += crypto_pk_keysize(signing_key); } const int AUTH_CELL_HEADER_LEN = 4; /* 2 bytes of type, 2 bytes of length */ @@ -452,7 +421,7 @@ result->command = CELL_AUTHENTICATE; set_uint16(result->payload, htons(authtype)); - if ((len = auth1_encode(out, outlen, auth, ctx)) < 0) { + if ((len = auth1_encode(out, outlen, auth)) < 0) { /* LCOV_EXCL_START */ log_warn(LD_BUG, "Unable to encode signed part of AUTH1 data."); goto err; @@ -461,7 +430,7 @@ if (server) { auth1_t *tmp = NULL; - ssize_t len2 = auth1_parse(&tmp, out, len, ctx); + ssize_t len2 = auth1_parse(&tmp, out, len); if (!tmp) { /* LCOV_EXCL_START */ log_warn(LD_BUG, "Unable to parse signed part of AUTH1 data that " @@ -481,7 +450,7 @@ goto done; } - if (ed_signing_key && is_ed) { + if (ed_signing_key) { ed25519_signature_t sig; if (ed25519_sign(&sig, out, len, ed_signing_key) < 0) { /* LCOV_EXCL_START */ @@ -491,25 +460,9 @@ } auth1_setlen_sig(auth, ED25519_SIG_LEN); memcpy(auth1_getarray_sig(auth), sig.sig, ED25519_SIG_LEN); - - } else if (signing_key && !is_ed) { - auth1_setlen_sig(auth, crypto_pk_keysize(signing_key)); - - char d[32]; - crypto_digest256(d, (char*)out, len, DIGEST_SHA256); - int siglen = crypto_pk_private_sign(signing_key, - (char*)auth1_getarray_sig(auth), - auth1_getlen_sig(auth), - d, 32); - if (siglen < 0) { - log_warn(LD_OR, "Unable to sign AUTH1 data."); - goto err; - } - - auth1_setlen_sig(auth, siglen); } - len = auth1_encode(out, outlen, auth, ctx); + len = auth1_encode(out, outlen, auth); if (len < 0) { /* LCOV_EXCL_START */ log_warn(LD_BUG, "Unable to encode signed AUTH1 data."); @@ -527,7 +480,6 @@ result = NULL; done: auth1_free(auth); - auth_ctx_free(ctx); return result; } @@ -537,13 +489,8 @@ connection_or_send_authenticate_cell,(or_connection_t *conn, int authtype)) { var_cell_t *cell; - crypto_pk_t *pk = tor_tls_get_my_client_auth_key(); /* XXXX make sure we're actually supposed to send this! */ - if (!pk) { - log_warn(LD_BUG, "Can't compute authenticate cell: no client auth key"); - return -1; - } if (! authchallenge_type_is_supported(authtype)) { log_warn(LD_BUG, "Tried to send authenticate cell with unknown " "authentication type %d", authtype); @@ -552,7 +499,6 @@ cell = connection_or_compute_authenticate_cell_body(conn, authtype, - pk, get_current_auth_keypair(), 0 /* not server */); if (! cell) { diff -Nru tor-0.4.7.16/src/feature/relay/relay_handshake.h tor-0.4.9.6/src/feature/relay/relay_handshake.h --- tor-0.4.7.16/src/feature/relay/relay_handshake.h 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/feature/relay/relay_handshake.h 2026-03-25 14:30:34.000000000 +0000 @@ -21,7 +21,6 @@ var_cell_t *connection_or_compute_authenticate_cell_body( or_connection_t *conn, const int authtype, - crypto_pk_t *signing_key, const struct ed25519_keypair_t *ed_signing_key, int server); @@ -56,13 +55,11 @@ connection_or_compute_authenticate_cell_body( or_connection_t *conn, const int authtype, - crypto_pk_t *signing_key, const struct ed25519_keypair_t *ed_signing_key, int server) { (void)conn; (void)authtype; - (void)signing_key; (void)ed_signing_key; (void)server; tor_assert_nonfatal_unreached(); diff -Nru tor-0.4.7.16/src/feature/relay/relay_metrics.c tor-0.4.9.6/src/feature/relay/relay_metrics.c --- tor-0.4.7.16/src/feature/relay/relay_metrics.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/feature/relay/relay_metrics.c 2026-03-25 14:30:34.000000000 +0000 @@ -13,6 +13,7 @@ #include "core/or/or.h" #include "core/mainloop/connection.h" #include "core/mainloop/mainloop.h" +#include "core/or/command.h" #include "core/or/congestion_control_common.h" #include "core/or/congestion_control_vegas.h" #include "core/or/congestion_control_flow.h" @@ -32,8 +33,10 @@ #include "feature/nodelist/nodelist.h" #include "feature/nodelist/node_st.h" #include "feature/nodelist/routerstatus_st.h" +#include "feature/nodelist/torcert.h" #include "feature/relay/relay_metrics.h" #include "feature/relay/router.h" +#include "feature/relay/routerkeys.h" #include "feature/stats/rephist.h" #include @@ -52,9 +55,18 @@ static void fill_onionskins_values(void); static void fill_oom_values(void); static void fill_streams_values(void); +static void fill_relay_circ_proto_violation(void); +static void fill_relay_destroy_cell(void); +static void fill_relay_drop_cell(void); static void fill_relay_flags(void); static void fill_tcp_exhaustion_values(void); static void fill_traffic_values(void); +static void fill_signing_cert_expiry(void); + +static void fill_est_intro_cells(void); +static void fill_est_rend_cells(void); +static void fill_intro1_cells(void); +static void fill_rend1_cells(void); /** The base metrics that is a static array of metrics added to the metrics * store. @@ -174,6 +186,62 @@ .help = "Total number of circuits", .fill_fn = fill_circuits_values, }, + { + .key = RELAY_METRICS_SIGNING_CERT_EXPIRY, + .type = METRICS_TYPE_GAUGE, + .name = METRICS_NAME(relay_signing_cert_expiry_timestamp), + .help = "Timestamp at which the current online keys will expire", + .fill_fn = fill_signing_cert_expiry, + }, + { + .key = RELAY_METRICS_NUM_EST_REND, + .type = METRICS_TYPE_COUNTER, + .name = METRICS_NAME(relay_est_rend_total), + .help = "Total number of EST_REND cells we received", + .fill_fn = fill_est_rend_cells, + }, + { + .key = RELAY_METRICS_NUM_EST_INTRO, + .type = METRICS_TYPE_COUNTER, + .name = METRICS_NAME(relay_est_intro_total), + .help = "Total number of EST_INTRO cells we received", + .fill_fn = fill_est_intro_cells, + }, + { + .key = RELAY_METRICS_NUM_INTRO1_CELLS, + .type = METRICS_TYPE_COUNTER, + .name = METRICS_NAME(relay_intro1_total), + .help = "Total number of INTRO1 cells we received", + .fill_fn = fill_intro1_cells, + }, + { + .key = RELAY_METRICS_NUM_REND1_CELLS, + .type = METRICS_TYPE_COUNTER, + .name = METRICS_NAME(relay_rend1_total), + .help = "Total number of REND1 cells we received", + .fill_fn = fill_rend1_cells, + }, + { + .key = RELAY_METRICS_CIRC_DESTROY_CELL, + .type = METRICS_TYPE_COUNTER, + .name = METRICS_NAME(relay_destroy_cell_total), + .help = "Total number of DESTROY cell we received", + .fill_fn = fill_relay_destroy_cell, + }, + { + .key = RELAY_METRICS_CIRC_PROTO_VIOLATION, + .type = METRICS_TYPE_COUNTER, + .name = METRICS_NAME(relay_circ_proto_violation_total), + .help = "Total number of circuit protocol violation", + .fill_fn = fill_relay_circ_proto_violation, + }, + { + .key = RELAY_METRICS_CIRC_DROP_CELL, + .type = METRICS_TYPE_COUNTER, + .name = METRICS_NAME(relay_drop_cell_total), + .help = "Total number of DROP cell we received", + .fill_fn = fill_relay_drop_cell, + }, }; static const size_t num_base_metrics = ARRAY_LENGTH(base_metrics); @@ -222,8 +290,8 @@ { const relay_metrics_entry_t *rentry = &base_metrics[RELAY_METRICS_NUM_CIRCUITS]; - metrics_store_entry_t *sentry = - metrics_store_add(the_store, rentry->type, rentry->name, rentry->help); + metrics_store_entry_t *sentry = metrics_store_add( + the_store, rentry->type, rentry->name, rentry->help, 0, NULL); metrics_store_entry_add_label(sentry, metrics_format_label("state", "opened")); @@ -255,57 +323,57 @@ const relay_metrics_entry_t *rentry = &base_metrics[RELAY_METRICS_RELAY_FLAGS]; - metrics_store_entry_t *sentry = - metrics_store_add(the_store, rentry->type, rentry->name, rentry->help); + metrics_store_entry_t *sentry = metrics_store_add( + the_store, rentry->type, rentry->name, rentry->help, 0, NULL); metrics_store_entry_add_label(sentry, metrics_format_label("type", "Fast")); metrics_store_entry_update(sentry, is_fast); sentry = metrics_store_add(the_store, rentry->type, rentry->name, - rentry->help); + rentry->help, 0, NULL); metrics_store_entry_add_label(sentry, metrics_format_label("type", "Exit")); metrics_store_entry_update(sentry, is_exit); sentry = metrics_store_add(the_store, rentry->type, rentry->name, - rentry->help); + rentry->help, 0, NULL); metrics_store_entry_add_label(sentry, metrics_format_label("type", "Authority")); metrics_store_entry_update(sentry, is_authority); sentry = metrics_store_add(the_store, rentry->type, rentry->name, - rentry->help); + rentry->help, 0, NULL); metrics_store_entry_add_label(sentry, metrics_format_label("type", "Stable")); metrics_store_entry_update(sentry, is_stable); sentry = metrics_store_add(the_store, rentry->type, rentry->name, - rentry->help); + rentry->help, 0, NULL); metrics_store_entry_add_label(sentry, metrics_format_label("type", "HSDir")); metrics_store_entry_update(sentry, is_hs_dir); sentry = metrics_store_add(the_store, rentry->type, rentry->name, - rentry->help); + rentry->help, 0, NULL); metrics_store_entry_add_label(sentry, metrics_format_label("type", "Running")); metrics_store_entry_update(sentry, is_running); sentry = metrics_store_add(the_store, rentry->type, rentry->name, - rentry->help); + rentry->help, 0, NULL); metrics_store_entry_add_label(sentry, metrics_format_label("type", "V2Dir")); metrics_store_entry_update(sentry, is_v2_dir); sentry = metrics_store_add(the_store, rentry->type, rentry->name, - rentry->help); + rentry->help, 0, NULL); metrics_store_entry_add_label(sentry, metrics_format_label("type", "Sybil")); metrics_store_entry_update(sentry, is_sybil); sentry = metrics_store_add(the_store, rentry->type, rentry->name, - rentry->help); + rentry->help, 0, NULL); metrics_store_entry_add_label(sentry, metrics_format_label("type", "Guard")); metrics_store_entry_update(sentry, is_guard); @@ -317,15 +385,15 @@ { const relay_metrics_entry_t *rentry = &base_metrics[RELAY_METRICS_NUM_TRAFFIC]; - metrics_store_entry_t *sentry = - metrics_store_add(the_store, rentry->type, rentry->name, rentry->help); + metrics_store_entry_t *sentry = metrics_store_add( + the_store, rentry->type, rentry->name, rentry->help, 0, NULL); metrics_store_entry_add_label(sentry, metrics_format_label("direction", "read")); metrics_store_entry_update(sentry, get_bytes_read()); sentry = metrics_store_add(the_store, rentry->type, rentry->name, - rentry->help); + rentry->help, 0, NULL); metrics_store_entry_add_label(sentry, metrics_format_label("direction", "written")); metrics_store_entry_update(sentry, get_bytes_written()); @@ -336,60 +404,66 @@ fill_dos_values(void) { const relay_metrics_entry_t *rentry = &base_metrics[RELAY_METRICS_NUM_DOS]; - metrics_store_entry_t *sentry = - metrics_store_add(the_store, rentry->type, rentry->name, rentry->help); + metrics_store_entry_t *sentry = metrics_store_add( + the_store, rentry->type, rentry->name, rentry->help, 0, NULL); metrics_store_entry_add_label(sentry, metrics_format_label("type", "circuit_rejected")); metrics_store_entry_update(sentry, dos_get_num_cc_rejected()); sentry = metrics_store_add(the_store, rentry->type, rentry->name, - rentry->help); + rentry->help, 0, NULL); metrics_store_entry_add_label(sentry, metrics_format_label("type", "circuit_killed_max_cell")); metrics_store_entry_update(sentry, stats_n_circ_max_cell_reached); sentry = metrics_store_add(the_store, rentry->type, rentry->name, - rentry->help); + rentry->help, 0, NULL); metrics_store_entry_add_label(sentry, metrics_format_label("type", "circuit_killed_max_cell_outq")); metrics_store_entry_update(sentry, stats_n_circ_max_cell_outq_reached); sentry = metrics_store_add(the_store, rentry->type, rentry->name, - rentry->help); + rentry->help, 0, NULL); metrics_store_entry_add_label(sentry, metrics_format_label("type", "marked_address")); metrics_store_entry_update(sentry, dos_get_num_cc_marked_addr()); sentry = metrics_store_add(the_store, rentry->type, rentry->name, - rentry->help); + rentry->help, 0, NULL); metrics_store_entry_add_label(sentry, metrics_format_label("type", "marked_address_maxq")); metrics_store_entry_update(sentry, dos_get_num_cc_marked_addr_maxq()); sentry = metrics_store_add(the_store, rentry->type, rentry->name, - rentry->help); + rentry->help, 0, NULL); metrics_store_entry_add_label(sentry, metrics_format_label("type", "conn_rejected")); metrics_store_entry_update(sentry, dos_get_num_conn_addr_connect_rejected()); sentry = metrics_store_add(the_store, rentry->type, rentry->name, - rentry->help); + rentry->help, 0, NULL); metrics_store_entry_add_label(sentry, metrics_format_label("type", "concurrent_conn_rejected")); metrics_store_entry_update(sentry, dos_get_num_conn_addr_rejected()); sentry = metrics_store_add(the_store, rentry->type, rentry->name, - rentry->help); + rentry->help, 0, NULL); metrics_store_entry_add_label(sentry, metrics_format_label("type", "single_hop_refused")); metrics_store_entry_update(sentry, dos_get_num_single_hop_refused()); sentry = metrics_store_add(the_store, rentry->type, rentry->name, - rentry->help); + rentry->help, 0, NULL); metrics_store_entry_add_label(sentry, metrics_format_label("type", "introduce2_rejected")); metrics_store_entry_update(sentry, hs_dos_get_intro2_rejected_count()); + + sentry = metrics_store_add(the_store, rentry->type, rentry->name, + rentry->help, 0, NULL); + metrics_store_entry_add_label(sentry, + metrics_format_label("type", "stream_rejected")); + metrics_store_entry_update(sentry, dos_get_num_stream_rejected()); } /** Fill function for the RELAY_METRICS_CC_COUNTERS metric. */ @@ -399,8 +473,8 @@ const relay_metrics_entry_t *rentry = &base_metrics[RELAY_METRICS_CC_COUNTERS]; - metrics_store_entry_t *sentry = - metrics_store_add(the_store, rentry->type, rentry->name, rentry->help); + metrics_store_entry_t *sentry = metrics_store_add( + the_store, rentry->type, rentry->name, rentry->help, 0, NULL); metrics_store_entry_add_label(sentry, metrics_format_label("state", "starvation")); metrics_store_entry_add_label(sentry, @@ -408,7 +482,7 @@ metrics_store_entry_update(sentry, congestion_control_get_num_rtt_reset()); sentry = metrics_store_add(the_store, rentry->type, rentry->name, - rentry->help); + rentry->help, 0, NULL); metrics_store_entry_add_label(sentry, metrics_format_label("state", "clock_stalls")); metrics_store_entry_add_label(sentry, @@ -417,7 +491,7 @@ congestion_control_get_num_clock_stalls()); sentry = metrics_store_add(the_store, rentry->type, rentry->name, - rentry->help); + rentry->help, 0, NULL); metrics_store_entry_add_label(sentry, metrics_format_label("state", "flow_control")); metrics_store_entry_add_label(sentry, @@ -426,7 +500,7 @@ cc_stats_flow_num_xoff_sent); sentry = metrics_store_add(the_store, rentry->type, rentry->name, - rentry->help); + rentry->help, 0, NULL); metrics_store_entry_add_label(sentry, metrics_format_label("state", "flow_control")); metrics_store_entry_add_label(sentry, @@ -435,7 +509,7 @@ cc_stats_flow_num_xon_sent); sentry = metrics_store_add(the_store, rentry->type, rentry->name, - rentry->help); + rentry->help, 0, NULL); metrics_store_entry_add_label(sentry, metrics_format_label("state", "cc_limits")); metrics_store_entry_add_label(sentry, @@ -443,7 +517,7 @@ metrics_store_entry_update(sentry, cc_stats_vegas_above_delta); sentry = metrics_store_add(the_store, rentry->type, rentry->name, - rentry->help); + rentry->help, 0, NULL); metrics_store_entry_add_label(sentry, metrics_format_label("state", "cc_limits")); metrics_store_entry_add_label(sentry, @@ -451,7 +525,7 @@ metrics_store_entry_update(sentry, cc_stats_vegas_above_ss_cwnd_max); sentry = metrics_store_add(the_store, rentry->type, rentry->name, - rentry->help); + rentry->help, 0, NULL); metrics_store_entry_add_label(sentry, metrics_format_label("state", "cc_limits")); metrics_store_entry_add_label(sentry, @@ -459,7 +533,7 @@ metrics_store_entry_update(sentry, cc_stats_vegas_below_ss_inc_floor); sentry = metrics_store_add(the_store, rentry->type, rentry->name, - rentry->help); + rentry->help, 0, NULL); metrics_store_entry_add_label(sentry, metrics_format_label("state", "cc_circuits")); metrics_store_entry_add_label(sentry, @@ -467,7 +541,7 @@ metrics_store_entry_update(sentry, cc_stats_circs_created); sentry = metrics_store_add(the_store, rentry->type, rentry->name, - rentry->help); + rentry->help, 0, NULL); metrics_store_entry_add_label(sentry, metrics_format_label("state", "cc_circuits")); metrics_store_entry_add_label(sentry, @@ -475,7 +549,7 @@ metrics_store_entry_update(sentry, cc_stats_circs_closed); sentry = metrics_store_add(the_store, rentry->type, rentry->name, - rentry->help); + rentry->help, 0, NULL); metrics_store_entry_add_label(sentry, metrics_format_label("state", "cc_circuits")); metrics_store_entry_add_label(sentry, @@ -490,8 +564,8 @@ const relay_metrics_entry_t *rentry = &base_metrics[RELAY_METRICS_CC_GAUGES]; - metrics_store_entry_t *sentry = - metrics_store_add(the_store, rentry->type, rentry->name, rentry->help); + metrics_store_entry_t *sentry = metrics_store_add( + the_store, rentry->type, rentry->name, rentry->help, 0, NULL); metrics_store_entry_add_label(sentry, metrics_format_label("state", "slow_start_exit")); metrics_store_entry_add_label(sentry, @@ -500,7 +574,7 @@ tor_llround(cc_stats_vegas_exit_ss_cwnd_ma)); sentry = metrics_store_add(the_store, rentry->type, rentry->name, - rentry->help); + rentry->help, 0, NULL); metrics_store_entry_add_label(sentry, metrics_format_label("state", "slow_start_exit")); metrics_store_entry_add_label(sentry, @@ -509,7 +583,7 @@ tor_llround(cc_stats_vegas_exit_ss_bdp_ma)); sentry = metrics_store_add(the_store, rentry->type, rentry->name, - rentry->help); + rentry->help, 0, NULL); metrics_store_entry_add_label(sentry, metrics_format_label("state", "slow_start_exit")); metrics_store_entry_add_label(sentry, @@ -518,7 +592,7 @@ tor_llround(cc_stats_vegas_exit_ss_inc_ma)); sentry = metrics_store_add(the_store, rentry->type, rentry->name, - rentry->help); + rentry->help, 0, NULL); metrics_store_entry_add_label(sentry, metrics_format_label("state", "on_circ_close")); metrics_store_entry_add_label(sentry, @@ -527,7 +601,7 @@ tor_llround(cc_stats_circ_close_cwnd_ma)); sentry = metrics_store_add(the_store, rentry->type, rentry->name, - rentry->help); + rentry->help, 0, NULL); metrics_store_entry_add_label(sentry, metrics_format_label("state", "on_circ_close")); metrics_store_entry_add_label(sentry, @@ -536,7 +610,7 @@ tor_llround(cc_stats_circ_close_ss_cwnd_ma)); sentry = metrics_store_add(the_store, rentry->type, rentry->name, - rentry->help); + rentry->help, 0, NULL); metrics_store_entry_add_label(sentry, metrics_format_label("state", "buffers")); metrics_store_entry_add_label(sentry, @@ -545,7 +619,7 @@ tor_llround(cc_stats_flow_xon_outbuf_ma)); sentry = metrics_store_add(the_store, rentry->type, rentry->name, - rentry->help); + rentry->help, 0, NULL); metrics_store_entry_add_label(sentry, metrics_format_label("state", "buffers")); metrics_store_entry_add_label(sentry, @@ -554,7 +628,7 @@ tor_llround(cc_stats_flow_xoff_outbuf_ma)); sentry = metrics_store_add(the_store, rentry->type, rentry->name, - rentry->help); + rentry->help, 0, NULL); metrics_store_entry_add_label(sentry, metrics_format_label("state", "cc_backoff")); metrics_store_entry_add_label(sentry, @@ -563,7 +637,7 @@ tor_llround(cc_stats_vegas_csig_blocked_ma)); sentry = metrics_store_add(the_store, rentry->type, rentry->name, - rentry->help); + rentry->help, 0, NULL); metrics_store_entry_add_label(sentry, metrics_format_label("state", "cc_backoff")); metrics_store_entry_add_label(sentry, @@ -572,7 +646,7 @@ tor_llround(cc_stats_vegas_gamma_drop_ma)); sentry = metrics_store_add(the_store, rentry->type, rentry->name, - rentry->help); + rentry->help, 0, NULL); metrics_store_entry_add_label(sentry, metrics_format_label("state", "cc_backoff")); metrics_store_entry_add_label(sentry, @@ -581,7 +655,7 @@ tor_llround(cc_stats_vegas_delta_drop_ma)); sentry = metrics_store_add(the_store, rentry->type, rentry->name, - rentry->help); + rentry->help, 0, NULL); metrics_store_entry_add_label(sentry, metrics_format_label("state", "cc_backoff")); metrics_store_entry_add_label(sentry, @@ -590,7 +664,7 @@ tor_llround(cc_stats_vegas_ss_csig_blocked_ma)); sentry = metrics_store_add(the_store, rentry->type, rentry->name, - rentry->help); + rentry->help, 0, NULL); metrics_store_entry_add_label(sentry, metrics_format_label("state", "cc_cwnd_update")); metrics_store_entry_add_label(sentry, @@ -599,7 +673,7 @@ tor_llround(cc_stats_vegas_csig_alpha_ma)); sentry = metrics_store_add(the_store, rentry->type, rentry->name, - rentry->help); + rentry->help, 0, NULL); metrics_store_entry_add_label(sentry, metrics_format_label("state", "cc_cwnd_update")); metrics_store_entry_add_label(sentry, @@ -608,7 +682,7 @@ tor_llround(cc_stats_vegas_csig_beta_ma)); sentry = metrics_store_add(the_store, rentry->type, rentry->name, - rentry->help); + rentry->help, 0, NULL); metrics_store_entry_add_label(sentry, metrics_format_label("state", "cc_cwnd_update")); metrics_store_entry_add_label(sentry, @@ -617,7 +691,7 @@ tor_llround(cc_stats_vegas_csig_delta_ma)); sentry = metrics_store_add(the_store, rentry->type, rentry->name, - rentry->help); + rentry->help, 0, NULL); metrics_store_entry_add_label(sentry, metrics_format_label("state", "cc_estimates")); metrics_store_entry_add_label(sentry, @@ -626,7 +700,7 @@ tor_llround(cc_stats_vegas_ss_queue_ma)); sentry = metrics_store_add(the_store, rentry->type, rentry->name, - rentry->help); + rentry->help, 0, NULL); metrics_store_entry_add_label(sentry, metrics_format_label("state", "cc_estimates")); metrics_store_entry_add_label(sentry, @@ -635,7 +709,7 @@ tor_llround(cc_stats_vegas_queue_ma)); sentry = metrics_store_add(the_store, rentry->type, rentry->name, - rentry->help); + rentry->help, 0, NULL); metrics_store_entry_add_label(sentry, metrics_format_label("state", "cc_estimates")); metrics_store_entry_add_label(sentry, @@ -659,16 +733,16 @@ { const relay_metrics_entry_t *rentry = &base_metrics[RELAY_METRICS_NUM_STREAMS]; - metrics_store_entry_t *sentry = - metrics_store_add(the_store, rentry->type, rentry->name, rentry->help); + metrics_store_entry_t *sentry = metrics_store_add( + the_store, rentry->type, rentry->name, rentry->help, 0, NULL); fill_single_stream_value(sentry, RELAY_COMMAND_BEGIN); sentry = metrics_store_add(the_store, rentry->type, rentry->name, - rentry->help); + rentry->help, 0, NULL); fill_single_stream_value(sentry, RELAY_COMMAND_BEGIN_DIR); sentry = metrics_store_add(the_store, rentry->type, rentry->name, - rentry->help); + rentry->help, 0, NULL); fill_single_stream_value(sentry, RELAY_COMMAND_RESOLVE); } @@ -704,31 +778,31 @@ if (i == 10) { continue; } - metrics_store_entry_t *sentry = - metrics_store_add(the_store, rentry->type, rentry->name, rentry->help); + metrics_store_entry_t *sentry = metrics_store_add( + the_store, rentry->type, rentry->name, rentry->help, 0, NULL); fill_single_connection_value(sentry, i, "initiated", "created", AF_INET, rep_hist_get_conn_created(false, i, AF_INET)); sentry = metrics_store_add(the_store, rentry->type, rentry->name, - rentry->help); + rentry->help, 0, NULL); fill_single_connection_value(sentry, i, "initiated", "created", AF_INET6, rep_hist_get_conn_created(false, i, AF_INET6)); sentry = metrics_store_add(the_store, rentry->type, rentry->name, - rentry->help); + rentry->help, 0, NULL); fill_single_connection_value(sentry, i, "received", "created", AF_INET, rep_hist_get_conn_created(true, i, AF_INET)); sentry = metrics_store_add(the_store, rentry->type, rentry->name, - rentry->help); + rentry->help, 0, NULL); fill_single_connection_value(sentry, i, "received", "created", AF_INET6, rep_hist_get_conn_created(true, i, AF_INET6)); sentry = metrics_store_add(the_store, rentry->type, rentry->name, - rentry->help); + rentry->help, 0, NULL); fill_single_connection_value(sentry, i, "received", "rejected", AF_INET, rep_hist_get_conn_rejected(i, AF_INET)); sentry = metrics_store_add(the_store, rentry->type, rentry->name, - rentry->help); + rentry->help, 0, NULL); fill_single_connection_value(sentry, i, "received", "rejected", AF_INET6, rep_hist_get_conn_rejected(i, AF_INET6)); @@ -748,21 +822,21 @@ if (i == 10) { continue; } - metrics_store_entry_t *sentry = - metrics_store_add(the_store, rentry->type, rentry->name, rentry->help); + metrics_store_entry_t *sentry = metrics_store_add( + the_store, rentry->type, rentry->name, rentry->help, 0, NULL); fill_single_connection_value(sentry, i, "initiated", "opened", AF_INET, rep_hist_get_conn_opened(false, i, AF_INET)); sentry = metrics_store_add(the_store, rentry->type, rentry->name, - rentry->help); + rentry->help, 0, NULL); fill_single_connection_value(sentry, i, "initiated", "opened", AF_INET6, rep_hist_get_conn_opened(false, i, AF_INET6)); sentry = metrics_store_add(the_store, rentry->type, rentry->name, - rentry->help); + rentry->help, 0, NULL); fill_single_connection_value(sentry, i, "received", "opened", AF_INET, rep_hist_get_conn_opened(true, i, AF_INET)); sentry = metrics_store_add(the_store, rentry->type, rentry->name, - rentry->help); + rentry->help, 0, NULL); fill_single_connection_value(sentry, i, "received", "opened", AF_INET6, rep_hist_get_conn_opened(true, i, AF_INET6)); } @@ -777,7 +851,7 @@ &base_metrics[RELAY_METRICS_NUM_TCP_EXHAUSTION]; sentry = metrics_store_add(the_store, rentry->type, rentry->name, - rentry->help); + rentry->help, 0, NULL); metrics_store_entry_update(sentry, rep_hist_get_n_tcp_exhaustion()); } @@ -835,7 +909,7 @@ for (size_t j = 0; j < num_errors; j++) { sentry = metrics_store_add(the_store, rentry->type, rentry->name, - rentry->help); + rentry->help, 0, NULL); metrics_store_entry_add_label(sentry, record_label); metrics_store_entry_add_label(sentry, metrics_format_label("reason", errors[j].name)); @@ -849,7 +923,7 @@ /* Put in the DNS errors, unfortunately not per-type for now. */ for (size_t j = 0; j < num_errors; j++) { sentry = metrics_store_add(the_store, rentry->type, rentry->name, - rentry->help); + rentry->help, 0, NULL); metrics_store_entry_add_label(sentry, metrics_format_label("reason", errors[j].name)); metrics_store_entry_update(sentry, @@ -873,7 +947,7 @@ char *record_label = tor_strdup(metrics_format_label("record", dns_types[i].name)); sentry = metrics_store_add(the_store, rentry->type, rentry->name, - rentry->help); + rentry->help, 0, NULL); metrics_store_entry_add_label(sentry, record_label); metrics_store_entry_update(sentry, rep_hist_get_n_dns_request(dns_types[i].type)); @@ -882,7 +956,7 @@ #endif sentry = metrics_store_add(the_store, rentry->type, rentry->name, - rentry->help); + rentry->help, 0, NULL); metrics_store_entry_update(sentry, rep_hist_get_n_dns_request(0)); } @@ -895,13 +969,13 @@ &base_metrics[RELAY_METRICS_NUM_GLOBAL_RW_LIMIT]; sentry = metrics_store_add(the_store, rentry->type, rentry->name, - rentry->help); + rentry->help, 0, NULL); metrics_store_entry_add_label(sentry, metrics_format_label("side", "read")); metrics_store_entry_update(sentry, rep_hist_get_n_read_limit_reached()); sentry = metrics_store_add(the_store, rentry->type, rentry->name, - rentry->help); + rentry->help, 0, NULL); metrics_store_entry_add_label(sentry, metrics_format_label("side", "write")); metrics_store_entry_update(sentry, rep_hist_get_n_write_limit_reached()); @@ -916,13 +990,13 @@ &base_metrics[RELAY_METRICS_NUM_SOCKETS]; sentry = metrics_store_add(the_store, rentry->type, rentry->name, - rentry->help); + rentry->help, 0, NULL); metrics_store_entry_add_label(sentry, metrics_format_label("state", "opened")); metrics_store_entry_update(sentry, get_n_open_sockets()); sentry = metrics_store_add(the_store, rentry->type, rentry->name, - rentry->help); + rentry->help, 0, NULL); metrics_store_entry_update(sentry, get_max_sockets()); } @@ -940,7 +1014,7 @@ char *type_label = tor_strdup(metrics_format_label("type", handshake_type_to_str(t))); sentry = metrics_store_add(the_store, rentry->type, rentry->name, - rentry->help); + rentry->help, 0, NULL); metrics_store_entry_add_label(sentry, type_label); metrics_store_entry_add_label(sentry, metrics_format_label("action", "processed")); @@ -948,7 +1022,7 @@ rep_hist_get_circuit_n_handshake_assigned(t)); sentry = metrics_store_add(the_store, rentry->type, rentry->name, - rentry->help); + rentry->help, 0, NULL); metrics_store_entry_add_label(sentry, type_label); metrics_store_entry_add_label(sentry, metrics_format_label("action", "dropped")); @@ -967,30 +1041,236 @@ &base_metrics[RELAY_METRICS_NUM_OOM_BYTES]; sentry = metrics_store_add(the_store, rentry->type, rentry->name, - rentry->help); + rentry->help, 0, NULL); metrics_store_entry_add_label(sentry, metrics_format_label("subsys", "cell")); metrics_store_entry_update(sentry, oom_stats_n_bytes_removed_cell); sentry = metrics_store_add(the_store, rentry->type, rentry->name, - rentry->help); + rentry->help, 0, NULL); metrics_store_entry_add_label(sentry, metrics_format_label("subsys", "dns")); metrics_store_entry_update(sentry, oom_stats_n_bytes_removed_dns); sentry = metrics_store_add(the_store, rentry->type, rentry->name, - rentry->help); + rentry->help, 0, NULL); metrics_store_entry_add_label(sentry, metrics_format_label("subsys", "geoip")); metrics_store_entry_update(sentry, oom_stats_n_bytes_removed_geoip); sentry = metrics_store_add(the_store, rentry->type, rentry->name, - rentry->help); + rentry->help, 0, NULL); metrics_store_entry_add_label(sentry, metrics_format_label("subsys", "hsdir")); metrics_store_entry_update(sentry, oom_stats_n_bytes_removed_hsdir); } +/** Fill function for the RELAY_METRICS_SIGNING_CERT_EXPIRY metrics. */ +static void +fill_signing_cert_expiry(void) +{ + metrics_store_entry_t *sentry; + const tor_cert_t *signing_key; + const relay_metrics_entry_t *rentry = + &base_metrics[RELAY_METRICS_SIGNING_CERT_EXPIRY]; + + if (get_options()->OfflineMasterKey) { + signing_key = get_master_signing_key_cert(); + if (signing_key) { + sentry = metrics_store_add(the_store, rentry->type, rentry->name, + rentry->help, 0, NULL); + metrics_store_entry_update(sentry, signing_key->valid_until); + } + } +} + +static uint64_t est_intro_actions[EST_INTRO_ACTION_COUNT] = {0}; + +void +relay_increment_est_intro_action(est_intro_action_t action) +{ + est_intro_actions[action]++; +} + +static void +fill_est_intro_cells(void) +{ + metrics_store_entry_t *sentry; + const relay_metrics_entry_t *rentry = + &base_metrics[RELAY_METRICS_NUM_EST_INTRO]; + + static struct { + const char *name; + est_intro_action_t key; + } actions[] = { + {.name = "success", .key = EST_INTRO_SUCCESS}, + {.name = "malformed", .key = EST_INTRO_MALFORMED}, + {.name = "unsuitable_circuit", .key = EST_INTRO_UNSUITABLE_CIRCUIT}, + {.name = "circuit_dead", .key = EST_INTRO_CIRCUIT_DEAD}, + }; + static const size_t num_actions = ARRAY_LENGTH(actions); + + for (size_t i = 0; i < num_actions; ++i) { + sentry = metrics_store_add(the_store, rentry->type, rentry->name, + rentry->help, 0, NULL); + metrics_store_entry_add_label( + sentry, metrics_format_label("action", actions[i].name)); + metrics_store_entry_update(sentry, + (long)est_intro_actions[actions[i].key]); + } +} + +static uint64_t est_rend_actions[EST_REND_ACTION_COUNT] = {0}; + +void +relay_increment_est_rend_action(est_rend_action_t action) +{ + est_rend_actions[action]++; +} + +static void +fill_est_rend_cells(void) +{ + metrics_store_entry_t *sentry; + const relay_metrics_entry_t *rentry = + &base_metrics[RELAY_METRICS_NUM_EST_REND]; + + static struct { + const char *name; + est_rend_action_t key; + } actions[] = { + {.name = "success", .key = EST_REND_SUCCESS}, + {.name = "unsuitable_circuit", .key = EST_REND_UNSUITABLE_CIRCUIT}, + {.name = "single_hop", .key = EST_REND_SINGLE_HOP}, + {.name = "malformed", .key = EST_REND_MALFORMED}, + {.name = "duplicate_cookie", .key = EST_REND_DUPLICATE_COOKIE}, + {.name = "circuit_dead", .key = EST_REND_CIRCUIT_DEAD}, + }; + static const size_t num_actions = ARRAY_LENGTH(actions); + + for (size_t i = 0; i < num_actions; ++i) { + sentry = metrics_store_add(the_store, rentry->type, rentry->name, + rentry->help, 0, NULL); + metrics_store_entry_add_label( + sentry, metrics_format_label("action", actions[i].name)); + metrics_store_entry_update(sentry, (long)est_rend_actions[actions[i].key]); + } +} + +static uint64_t intro1_actions[INTRO1_ACTION_COUNT] = {0}; + +void +relay_increment_intro1_action(intro1_action_t action) +{ + intro1_actions[action]++; +} + +static void +fill_intro1_cells(void) +{ + metrics_store_entry_t *sentry; + const relay_metrics_entry_t *rentry = + &base_metrics[RELAY_METRICS_NUM_INTRO1_CELLS]; + + static struct { + const char *name; + intro1_action_t key; + } actions[] = { + {.name = "success", .key = INTRO1_SUCCESS}, + {.name = "circuit_dead", .key = INTRO1_CIRCUIT_DEAD}, + {.name = "malformed", .key = INTRO1_MALFORMED}, + {.name = "unknown_service", .key = INTRO1_UNKNOWN_SERVICE}, + {.name = "rate_limited", .key = INTRO1_RATE_LIMITED}, + {.name = "circuit_reused", .key = INTRO1_CIRCUIT_REUSED}, + {.name = "single_hop", .key = INTRO1_SINGLE_HOP}, + }; + static const size_t num_actions = ARRAY_LENGTH(actions); + + for (size_t i = 0; i < num_actions; ++i) { + sentry = metrics_store_add(the_store, rentry->type, rentry->name, + rentry->help, 0, NULL); + metrics_store_entry_add_label( + sentry, metrics_format_label("action", actions[i].name)); + metrics_store_entry_update(sentry, (long)intro1_actions[actions[i].key]); + } +} + +static uint64_t rend1_actions[REND1_ACTION_COUNT] = {0}; + +void +relay_increment_rend1_action(rend1_action_t action) +{ + rend1_actions[action]++; +} + +static void +fill_rend1_cells(void) +{ + metrics_store_entry_t *sentry; + const relay_metrics_entry_t *rentry = + &base_metrics[RELAY_METRICS_NUM_REND1_CELLS]; + + static struct { + const char *name; + rend1_action_t key; + } actions[] = { + {.name = "success", .key = REND1_SUCCESS}, + {.name = "unsuitable_circuit", .key = REND1_UNSUITABLE_CIRCUIT}, + {.name = "malformed", .key = REND1_MALFORMED}, + {.name = "unknown_cookie", .key = REND1_UNKNOWN_COOKIE}, + {.name = "circuit_dead", .key = REND1_CIRCUIT_DEAD}, + }; + static const size_t num_actions = ARRAY_LENGTH(actions); + + for (size_t i = 0; i < num_actions; ++i) { + sentry = metrics_store_add(the_store, rentry->type, rentry->name, + rentry->help, 0, NULL); + metrics_store_entry_add_label( + sentry, metrics_format_label("action", actions[i].name)); + metrics_store_entry_update(sentry, (long)rend1_actions[actions[i].key]); + } +} + +/** Fill the metrics store for the RELAY_METRICS_CIRC_DESTROY_CELL counter. */ +static void +fill_relay_destroy_cell(void) +{ + metrics_store_entry_t *sentry; + const relay_metrics_entry_t *rentry = + &base_metrics[RELAY_METRICS_CIRC_DESTROY_CELL]; + + sentry = metrics_store_add(the_store, rentry->type, rentry->name, + rentry->help, 0, NULL); + metrics_store_entry_update(sentry, + (int64_t) stats_n_destroy_cells_processed); +} + +/** Fill the metrics store for the RELAY_METRICS_CIRC_DROP_CELL counter. */ +static void +fill_relay_drop_cell(void) +{ + metrics_store_entry_t *sentry; + const relay_metrics_entry_t *rentry = + &base_metrics[RELAY_METRICS_CIRC_DROP_CELL]; + + sentry = metrics_store_add(the_store, rentry->type, rentry->name, + rentry->help, 0, NULL); + metrics_store_entry_update(sentry, rep_hist_get_drop_cell_received_count()); +} + +/** Fill the metrics store for the RELAY_METRICS_CIRC_PROTO_VIOLATION. */ +static void +fill_relay_circ_proto_violation(void) +{ + metrics_store_entry_t *sentry; + const relay_metrics_entry_t *rentry = + &base_metrics[RELAY_METRICS_CIRC_PROTO_VIOLATION]; + + sentry = metrics_store_add(the_store, rentry->type, rentry->name, + rentry->help, 0, NULL); + metrics_store_entry_update(sentry, circ_n_proto_violation); +} + /** Reset the global store and fill it with all the metrics from base_metrics * and their associated values. * diff -Nru tor-0.4.7.16/src/feature/relay/relay_metrics.h tor-0.4.9.6/src/feature/relay/relay_metrics.h --- tor-0.4.7.16/src/feature/relay/relay_metrics.h 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/feature/relay/relay_metrics.h 2026-03-25 14:30:34.000000000 +0000 @@ -47,6 +47,22 @@ RELAY_METRICS_RELAY_FLAGS, /** Numer of circuits. */ RELAY_METRICS_NUM_CIRCUITS, + /** Timestamp at which the current online keys will expire. */ + RELAY_METRICS_SIGNING_CERT_EXPIRY, + /** Number of times we received an EST_REND cell */ + RELAY_METRICS_NUM_EST_REND, + /** Number of times we received an EST_INTRO cell */ + RELAY_METRICS_NUM_EST_INTRO, + /** Number of times we received an INTRO1 cell */ + RELAY_METRICS_NUM_INTRO1_CELLS, + /** Number of times we received a REND1 cell */ + RELAY_METRICS_NUM_REND1_CELLS, + /** Number of circuit closed by receiving a DESTROY cell. */ + RELAY_METRICS_CIRC_DESTROY_CELL, + /** Number of circuits closed due to protocol violation. */ + RELAY_METRICS_CIRC_PROTO_VIOLATION, + /** Number of drop cell seen. */ + RELAY_METRICS_CIRC_DROP_CELL, } relay_metrics_key_t; /** The metadata of a relay metric. */ @@ -70,4 +86,54 @@ /* Accessors. */ const smartlist_t *relay_metrics_get_stores(void); +typedef enum { + EST_INTRO_SUCCESS, + EST_INTRO_MALFORMED, + EST_INTRO_UNSUITABLE_CIRCUIT, + EST_INTRO_CIRCUIT_DEAD, + + EST_INTRO_ACTION_COUNT +} est_intro_action_t; + +void relay_increment_est_intro_action(est_intro_action_t); + +typedef enum { + EST_REND_SUCCESS, + EST_REND_UNSUITABLE_CIRCUIT, + EST_REND_SINGLE_HOP, + EST_REND_MALFORMED, + EST_REND_DUPLICATE_COOKIE, + EST_REND_CIRCUIT_DEAD, + + EST_REND_ACTION_COUNT +} est_rend_action_t; + +void relay_increment_est_rend_action(est_rend_action_t); + +typedef enum { + INTRO1_SUCCESS, + INTRO1_CIRCUIT_DEAD, + INTRO1_MALFORMED, + INTRO1_UNKNOWN_SERVICE, + INTRO1_RATE_LIMITED, + INTRO1_CIRCUIT_REUSED, + INTRO1_SINGLE_HOP, + + INTRO1_ACTION_COUNT +} intro1_action_t; + +void relay_increment_intro1_action(intro1_action_t); + +typedef enum { + REND1_SUCCESS, + REND1_UNSUITABLE_CIRCUIT, + REND1_MALFORMED, + REND1_UNKNOWN_COOKIE, + REND1_CIRCUIT_DEAD, + + REND1_ACTION_COUNT +} rend1_action_t; + +void relay_increment_rend1_action(rend1_action_t); + #endif /* !defined(TOR_FEATURE_RELAY_RELAY_METRICS_H) */ diff -Nru tor-0.4.7.16/src/feature/relay/relay_periodic.c tor-0.4.9.6/src/feature/relay/relay_periodic.c --- tor-0.4.7.16/src/feature/relay/relay_periodic.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/feature/relay/relay_periodic.c 2026-03-25 14:30:34.000000000 +0000 @@ -102,7 +102,9 @@ } log_info(LD_GENERAL,"Rotating onion key."); - rotate_onion_key(); + if (!rotate_onion_key()) { + return ONION_KEY_CONSENSUS_CHECK_INTERVAL; + } cpuworkers_rotate_keyinfo(); if (!router_rebuild_descriptor(1)) { log_info(LD_CONFIG, "Couldn't rebuild router descriptor"); @@ -239,7 +241,7 @@ log_warn(LD_CONFIG, "Your server has not managed to confirm reachability for " "its ORPort(s) at %s%s%s. Relays do not publish " - "descriptors until their ORPort and DirPort are " + "descriptors until their ORPort(s) are " "reachable. Please check your firewalls, ports, address, " "/etc/hosts file, etc.", where4?where4:"", diff -Nru tor-0.4.7.16/src/feature/relay/relay_stub.c tor-0.4.9.6/src/feature/relay/relay_stub.c --- tor-0.4.7.16/src/feature/relay/relay_stub.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/feature/relay/relay_stub.c 2026-03-25 14:30:34.000000000 +0000 @@ -12,6 +12,7 @@ #include "orconfig.h" #include "feature/relay/relay_sys.h" #include "lib/subsys/subsys.h" +#include "feature/relay/relay_metrics.h" const struct subsys_fns_t sys_relay = { .name = "relay", @@ -19,3 +20,27 @@ .supported = false, .level = RELAY_SUBSYS_LEVEL, }; + +void +relay_increment_est_intro_action(est_intro_action_t action) +{ + (void)action; +} + +void +relay_increment_est_rend_action(est_rend_action_t action) +{ + (void)action; +} + +void +relay_increment_intro1_action(intro1_action_t action) +{ + (void)action; +} + +void +relay_increment_rend1_action(rend1_action_t action) +{ + (void)action; +} diff -Nru tor-0.4.7.16/src/feature/relay/router.c tor-0.4.9.6/src/feature/relay/router.c --- tor-0.4.7.16/src/feature/relay/router.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/feature/relay/router.c 2026-03-25 14:30:34.000000000 +0000 @@ -211,8 +211,13 @@ mark_my_descriptor_dirty("set onion key"); } -/** Return the current onion key. Requires that the onion key has been - * loaded or generated. */ +/** Return the current TAP onion key. Requires that the onion key has been + * loaded or generated. + * + * Note that this key is no longer used for anything; we only keep it around + * because (as of June 2024) other Tor instances all expect to find it in + * our routerdescs. + **/ MOCK_IMPL(crypto_pk_t *, get_onion_key,(void)) { @@ -220,6 +225,25 @@ return onionkey; } +/** + * Return true iff we should include our TAP onion key in our router + * descriptor. + */ +static int +should_publish_tap_onion_key(void) +{ +#define SHOULD_PUBLISH_TAP_MIN 0 +#define SHOULD_PUBLISH_TAP_MAX 1 + /* Note that we err on the side of publishing. */ +#define SHOULD_PUBLISH_TAP_DFLT 1 + + return networkstatus_get_param(NULL, + "publish-dummy-tap-key", + SHOULD_PUBLISH_TAP_DFLT, + SHOULD_PUBLISH_TAP_MIN, + SHOULD_PUBLISH_TAP_MAX); +} + /** Store a full copy of the current onion key into *key, and a full * copy of the most recent onion key into *last. Store NULL into * a pointer if the corresponding key does not exist. @@ -358,6 +382,7 @@ log_err(LD_BUG, "Couldn't compute our own identity key digest."); tor_assert(0); } + pt_update_bridge_lines(); } #ifdef TOR_UNIT_TESTS @@ -482,8 +507,10 @@ * - schedule all previous cpuworkers to shut down _after_ processing * pending work. (This will cause fresh cpuworkers to be generated.) * - generate and upload a fresh routerinfo. + * + * Return true on success, else false on error. */ -void +bool rotate_onion_key(void) { char *fname, *fname_prev; @@ -491,6 +518,7 @@ or_state_t *state = get_or_state(); curve25519_keypair_t new_curve25519_keypair; time_t now; + bool result = false; fname = get_keydir_fname("secret_onion_key"); fname_prev = get_keydir_fname("secret_onion_key.old"); /* There isn't much point replacing an old key with an empty file */ @@ -540,6 +568,7 @@ tor_mutex_release(key_lock); mark_my_descriptor_dirty("rotated onion key"); or_state_mark_dirty(state, get_options()->AvoidDiskWrites ? now+3600 : 0); + result = true; goto done; error: log_warn(LD_GENERAL, "Couldn't rotate onion key."); @@ -549,6 +578,7 @@ memwipe(&new_curve25519_keypair, 0, sizeof(new_curve25519_keypair)); tor_free(fname); tor_free(fname_prev); + return result; } /** Log greeting message that points to new relay lifecycle document the @@ -847,6 +877,7 @@ STATIC void router_announce_bridge_status_page(void) { +#ifdef ENABLE_MODULE_RELAY char fingerprint[FINGERPRINT_LEN + 1]; if (crypto_pk_get_hashed_fingerprint(get_server_identity_key(), @@ -860,6 +891,7 @@ log_notice(LD_GENERAL, "You can check the status of your bridge relay at " "https://bridges.torproject.org/status?id=%s", fingerprint); +#endif } /** Compute fingerprint (or hashed fingerprint if hashed is 1) and write @@ -911,9 +943,9 @@ goto done; } - log_notice(LD_GENERAL, "Your Tor %s identity key %s fingerprint is '%s %s'", + log_notice(LD_GENERAL, "Your Tor %s identity key %sfingerprint is '%s %s'", hashed ? "bridge's hashed" : "server's", - ed25519_identity ? "ed25519" : "", + ed25519_identity ? "ed25519 " : "", options->Nickname, fingerprint); result = 0; @@ -1036,6 +1068,11 @@ if (new_signing_key < 0) return -1; + if (options->command == CMD_RUN_TOR) { + if (load_family_id_keys(options, networkstatus_get_latest_consensus()) < 0) + return -1; + } + /* 2. Read onion key. Make it if none is found. */ keydir = get_keydir_fname("secret_onion_key"); log_info(LD_GENERAL,"Reading/making onion key \"%s\"...",keydir); @@ -1249,13 +1286,12 @@ /** Helper: Return 1 if we have sufficient resources for serving directory * requests, return 0 otherwise. - * dir_port is either 0 or the configured DirPort number. * If AccountingMax is set less than our advertised bandwidth, then don't * serve requests. Likewise, if our advertised bandwidth is less than * MIN_BW_TO_ADVERTISE_DIRSERVER, don't bother trying to serve requests. */ static int -router_should_be_dirserver(const or_options_t *options, int dir_port) +router_should_be_dirserver(const or_options_t *options) { static int advertising=1; /* start out assuming we will advertise */ int new_choice=1; @@ -1264,7 +1300,8 @@ if (accounting_is_enabled(options) && get_options()->AccountingRule != ACCT_IN) { /* Don't spend bytes for directory traffic if we could end up hibernating, - * but allow DirPort otherwise. Some relay operators set AccountingMax + * but allow being a dir cache otherwise. + * Some relay operators set AccountingMax * because they're confused or to get statistics. Directory traffic has a * much larger effect on output than input so there is no reason to turn it * off if using AccountingRule in. */ @@ -1276,10 +1313,9 @@ "seconds long. Raising to 1."); interval_length = 1; } - log_info(LD_GENERAL, "Calculating whether to advertise %s: effective " - "bwrate: %u, AccountingMax: %"PRIu64", " + log_info(LD_GENERAL, "Calculating whether to advertise begindir: " + "effective bwrate: %u, AccountingMax: %"PRIu64", " "accounting interval length %d", - dir_port ? "dirport" : "begindir", effective_bw, (options->AccountingMax), interval_length); @@ -1299,14 +1335,11 @@ if (advertising != new_choice) { if (new_choice == 1) { - if (dir_port > 0) - log_notice(LD_DIR, "Advertising DirPort as %d", dir_port); - else - log_notice(LD_DIR, "Advertising directory service support"); + log_notice(LD_DIR, "Advertising directory service support"); } else { tor_assert(reason); - log_notice(LD_DIR, "Not advertising Dir%s (Reason: %s)", - dir_port ? "Port" : "ectory Service support", reason); + log_notice(LD_DIR, "Not advertising Directory Service support " + "(Reason: %s)", reason); } advertising = new_choice; } @@ -1315,17 +1348,13 @@ } /** Look at a variety of factors, and return 0 if we don't want to - * advertise the fact that we have a DirPort open or begindir support, else + * advertise the fact that we have begindir support, else * return 1. * - * Where dir_port or supports_tunnelled_dir_requests are not relevant, they - * must be 0. - * * Log a helpful message if we change our mind about whether to publish. */ static int decide_to_advertise_dir_impl(const or_options_t *options, - uint16_t dir_port, int supports_tunnelled_dir_requests) { /* Part one: reasons to publish or not publish that aren't @@ -1333,24 +1362,21 @@ * or because they're normal behavior. */ /* short circuit the rest of the function */ - if (!dir_port && !supports_tunnelled_dir_requests) + if (!supports_tunnelled_dir_requests) return 0; if (authdir_mode(options)) /* always publish */ return 1; if (net_is_disabled()) return 0; - if (dir_port && !routerconf_find_dir_port(options, dir_port)) - return 0; - if (supports_tunnelled_dir_requests && - !routerconf_find_or_port(options, AF_INET)) + if (!routerconf_find_or_port(options, AF_INET)) return 0; /* Part two: consider config options that could make us choose to * publish or not publish that the user might find surprising. */ - return router_should_be_dirserver(options, dir_port); + return router_should_be_dirserver(options); } -/** Front-end to decide_to_advertise_dir_impl(): return 0 if we don't want to +/** Return 0 if we don't want to * advertise the fact that we have a DirPort open, else return the * DirPort we want to advertise. */ @@ -1368,8 +1394,7 @@ router_should_advertise_begindir(const or_options_t *options, int supports_tunnelled_dir_requests) { - /* dir_port is not relevant, pass 0 */ - return decide_to_advertise_dir_impl(options, 0, + return decide_to_advertise_dir_impl(options, supports_tunnelled_dir_requests); } @@ -1398,17 +1423,14 @@ static bool publish_even_when_ipv6_orport_unreachable = false; /** Decide if we're a publishable server. We are a publishable server if: + * - We are an authoritative directory server, or if * - We don't have the ClientOnly option set * and * - We have the PublishServerDescriptor option set to non-empty * and * - We have ORPort set * and - * - We believe our ORPort and DirPort (if present) are reachable from - * the outside; or - * - We believe our ORPort is reachable from the outside, and we can't - * check our DirPort because the consensus has no exits; or - * - We are an authoritative directory server. + * - We believe our ORPort is reachable from the outside. */ static int decide_if_publishable_server(void) @@ -1441,13 +1463,7 @@ return 0; } } - if (router_have_consensus_path() == CONSENSUS_PATH_INTERNAL) { - /* All set: there are no exits in the consensus (maybe this is a tiny - * test network), so we can't check our DirPort reachability. */ - return 1; - } else { - return router_dirport_seems_reachable(options); - } + return 1; /* everything looks good! publish. */ } /** Initiate server descriptor upload as reasonable (if server is publishable, @@ -2133,9 +2149,12 @@ ri->supports_tunnelled_dir_requests = directory_permits_begindir_requests(options); ri->cache_info.published_on = time(NULL); - /* get_onion_key() must invoke from main thread */ - router_set_rsa_onion_pkey(get_onion_key(), &ri->onion_pkey, - &ri->onion_pkey_len); + + if (should_publish_tap_onion_key()) { + /* get_onion_key() must invoke from main thread */ + router_set_rsa_onion_pkey(get_onion_key(), &ri->tap_onion_pkey, + &ri->tap_onion_pkey_len); + } ri->onion_curve25519_pkey = tor_memdup(&get_current_curve25519_keypair()->pubkey, @@ -2496,6 +2515,21 @@ publish_even_when_ipv4_orport_unreachable = ar; publish_even_when_ipv6_orport_unreachable = ar || ar6; + + warn_about_family_id_config(get_options(), ns); +} + +/** + * Return true if the parameters in `ns` say that we should publish + * a legacy family list. + * + * Use the latest networkstatus (or returns the default) if `ns` is NULL. + */ +bool +should_publish_family_list(const networkstatus_t *ns) +{ + return networkstatus_get_param(ns, "publish-family-list", + 1, 0, 1); // default, min, max } /** Mark our descriptor out of data iff the IPv6 omit status flag is flipped @@ -2554,8 +2588,6 @@ rs = networkstatus_vote_find_entry(ns, server_identitykey_digest); if (rs == NULL) retry_fast_reason = "not listed in consensus"; - else if (rs->published_on < slow_cutoff) - retry_fast_reason = "version listed in consensus is quite old"; else if (rs->is_staledesc && ns->valid_after > desc_clean_since) retry_fast_reason = "listed as stale in consensus"; } @@ -2774,7 +2806,7 @@ char published[ISO_TIME_LEN+1]; char fingerprint[FINGERPRINT_LEN+1]; char *extra_info_line = NULL; - size_t onion_pkeylen, identity_pkeylen; + size_t onion_pkeylen=0, identity_pkeylen; char *family_line = NULL; char *extra_or_address = NULL; const or_options_t *options = get_options(); @@ -2832,12 +2864,14 @@ } /* PEM-encode the onion key */ - rsa_pubkey = router_get_rsa_onion_pkey(router->onion_pkey, - router->onion_pkey_len); - if (crypto_pk_write_public_key_to_string(rsa_pubkey, - &onion_pkey,&onion_pkeylen)<0) { - log_warn(LD_BUG,"write onion_pkey to string failed!"); - goto err; + rsa_pubkey = router_get_rsa_onion_pkey(router->tap_onion_pkey, + router->tap_onion_pkey_len); + if (rsa_pubkey) { + if (crypto_pk_write_public_key_to_string(rsa_pubkey, + &onion_pkey,&onion_pkeylen)<0) { + log_warn(LD_BUG,"write onion_pkey to string failed!"); + goto err; + } } /* PEM-encode the identity key */ @@ -2848,7 +2882,7 @@ } /* Cross-certify with RSA key */ - if (tap_key && router->cache_info.signing_key_cert && + if (tap_key && rsa_pubkey && router->cache_info.signing_key_cert && router->cache_info.signing_key_cert->signing_key_included) { char buf[256]; int tap_cc_len = 0; @@ -2973,7 +3007,7 @@ "uptime %ld\n" "bandwidth %d %d %d\n" "%s%s" - "onion-key\n%s" + "%s%s" "signing-key\n%s" "%s%s" "%s%s%s", @@ -2994,13 +3028,43 @@ extra_info_line ? extra_info_line : "", (options->DownloadExtraInfo || options->V3AuthoritativeDir) ? "caches-extra-info\n" : "", - onion_pkey, identity_pkey, + onion_pkey?"onion-key\n":"", onion_pkey?onion_pkey:"", + identity_pkey, rsa_tap_cc_line ? rsa_tap_cc_line : "", ntor_cc_line ? ntor_cc_line : "", family_line, we_are_hibernating() ? "hibernating 1\n" : "", "hidden-service-dir\n"); + SMARTLIST_FOREACH_BEGIN(get_current_family_id_keys(), + const ed25519_keypair_t *, k_family_id) { + // TODO PROP321: We may want this to be configurable; + // we can probably use a smaller value. +#define FAMILY_CERT_LIFETIME (30*86400) + tor_cert_t *family_cert = tor_cert_create_ed25519( + k_family_id, + CERT_TYPE_FAMILY_V_IDENTITY, + // (this is the identity key "KP_relayid_ed") + &router->cache_info.signing_key_cert->signing_key, + router->cache_info.published_on, + FAMILY_CERT_LIFETIME, CERT_FLAG_INCLUDE_SIGNING_KEY); + char family_cert_base64[256]; + if (base64_encode(family_cert_base64, sizeof(family_cert_base64), + (const char*) family_cert->encoded, + family_cert->encoded_len, BASE64_ENCODE_MULTILINE) < 0) { + log_err(LD_BUG, "Base64 encoding family cert failed!?"); + tor_cert_free(family_cert); + goto err; + } + smartlist_add_asprintf(chunks, + "family-cert\n" + "-----BEGIN FAMILY CERT-----\n" + "%s" + "-----END FAMILY CERT-----\n", + family_cert_base64); + tor_cert_free(family_cert); + } SMARTLIST_FOREACH_END(k_family_id); + if (options->ContactInfo && strlen(options->ContactInfo)) { const char *ci = options->ContactInfo; if (strchr(ci, '\n') || strchr(ci, '\r')) diff -Nru tor-0.4.7.16/src/feature/relay/router.h tor-0.4.9.6/src/feature/relay/router.h --- tor-0.4.7.16/src/feature/relay/router.h 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/feature/relay/router.h 2026-03-25 14:30:34.000000000 +0000 @@ -45,7 +45,7 @@ crypto_pk_t *get_my_v3_legacy_signing_key(void); void dup_onion_keys(crypto_pk_t **key, crypto_pk_t **last); void expire_old_onion_keys(void); -void rotate_onion_key(void); +bool rotate_onion_key(void); void v3_authority_check_key_expiry(void); int get_onion_key_lifetime(void); int get_onion_key_grace_period(void); @@ -81,6 +81,8 @@ int should_refuse_unknown_exits(const or_options_t *options); void router_new_consensus_params(const networkstatus_t *); +bool should_publish_family_list(const networkstatus_t *ns); + void router_upload_dir_desc_to_dirservers(int force); void mark_my_descriptor_dirty_if_too_old(time_t now); void mark_my_descriptor_dirty(const char *reason); diff -Nru tor-0.4.7.16/src/feature/relay/routerkeys.c tor-0.4.9.6/src/feature/relay/routerkeys.c --- tor-0.4.7.16/src/feature/relay/routerkeys.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/feature/relay/routerkeys.c 2026-03-25 14:30:34.000000000 +0000 @@ -14,6 +14,8 @@ * (TODO: The keys in router.c should go here too.) */ +#define ROUTERKEYS_PRIVATE + #include "core/or/or.h" #include "app/config/config.h" #include "feature/relay/router.h" @@ -21,8 +23,11 @@ #include "feature/relay/routermode.h" #include "feature/keymgt/loadkey.h" #include "feature/nodelist/torcert.h" +#include "feature/nodelist/networkstatus_st.h" +#include "feature/dirauth/dirvote.h" #include "lib/crypt_ops/crypto_util.h" +#include "lib/crypt_ops/crypto_format.h" #include "lib/tls/tortls.h" #include "lib/tls/x509.h" @@ -44,6 +49,9 @@ static size_t rsa_ed_crosscert_len = 0; static time_t rsa_ed_crosscert_expiration = 0; +// list of ed25519_keypair_t +static smartlist_t *family_id_keys = NULL; + /** * Running as a server: load, reload, or refresh our ed25519 keys and * certificates, creating and saving new ones as needed. @@ -674,6 +682,344 @@ return auth_key_cert; } +/** + * Suffix for the filenames in which we expect to find a family ID key. + */ +#define FAMILY_KEY_SUFFIX ".secret_family_key" + +/** + * Return true if `fname` is a possible filename of a family ID key. + * + * Family ID key filenames are FAMILY_KEY_FNAME, followed optionally + * by "." and a positive integer. + */ +STATIC bool +is_family_key_fname(const char *fname) +{ + return 0 == strcmpend(fname, FAMILY_KEY_SUFFIX); +} + +/** Return true if `id` is configured in `options`. */ +static bool +family_key_id_is_expected(const or_options_t *options, + const ed25519_public_key_t *id) +{ + if (options->AllFamilyIdsExpected) + return true; + + SMARTLIST_FOREACH(options->FamilyIds, const ed25519_public_key_t *, k, { + if (ed25519_pubkey_eq(k, id)) + return true; + }); + return false; +} + +/** Return true if the key for `id` has been loaded. */ +static bool +family_key_is_present(const ed25519_public_key_t *id) +{ + if (!family_id_keys) + return false; + + SMARTLIST_FOREACH(family_id_keys, const ed25519_keypair_t *, kp, { + if (ed25519_pubkey_eq(&kp->pubkey, id)) + return true; + }); + return false; +} + +/** + * Tag to use on family key files. + */ +#define FAMILY_KEY_FILE_TAG "fmly-id" + +/** Return a list of all the possible family-key files in `keydir`. + * Return NULL on error. + * + * (Unlike list_family_key_files, this function does not use a cached + * list when the seccomp2 sandbox is enabled.) */ +static smartlist_t * +list_family_key_files_impl(const char *keydir) +{ + smartlist_t *files = tor_listdir(keydir); + smartlist_t *result = smartlist_new(); + + if (!files) { + log_warn(LD_OR, "Unable to list contents of directory %s", keydir); + goto err; + } + + SMARTLIST_FOREACH_BEGIN(files, const char *, fn) { + if (!is_family_key_fname(fn)) + continue; + + smartlist_add_asprintf(result, "%s%s%s", keydir, PATH_SEPARATOR, fn); + } SMARTLIST_FOREACH_END(fn); + + goto done; + err: + SMARTLIST_FOREACH(result, char *, cp, tor_free(cp)); + smartlist_free(result); // sets result to NULL. + done: + if (files) { + SMARTLIST_FOREACH(files, char *, cp, tor_free(cp)); + smartlist_free(files); + } + + return result; +} + +/** + * A list of files returned by list_family_key_files_impl. + * Used when the seccomp2 sandbox is enabled. + */ +static smartlist_t *cached_family_key_file_list = NULL; + +/** Return a list of all the possible family-key files in `keydir`. + * Return NULL on error. + */ +smartlist_t * +list_family_key_files(const or_options_t *options, + const char *keydir) +{ + if (options->Sandbox) { + if (!cached_family_key_file_list) + cached_family_key_file_list = list_family_key_files_impl(keydir); + if (!cached_family_key_file_list) + return NULL; + + smartlist_t *result = smartlist_new(); + SMARTLIST_FOREACH(cached_family_key_file_list, char *, fn, + smartlist_add_strdup(result, fn)); + return result; + } + + return list_family_key_files_impl(keydir); +} + +/** + * Look for all the family keys in `keydir`, load them into + * family_id_keys. + */ +STATIC int +load_family_id_keys_impl(const or_options_t *options, + const char *keydir) +{ + if (BUG(!options) || BUG(!keydir)) + return -1; + + smartlist_t *key_files = list_family_key_files(options, keydir); + smartlist_t *new_keys = NULL; + ed25519_keypair_t *kp_tmp = NULL; + char *tag_tmp = NULL; + int r = -1; + + if (key_files == NULL) { + goto end; // already warned. + } + + new_keys = smartlist_new(); + SMARTLIST_FOREACH_BEGIN(key_files, const char *, fn) { + kp_tmp = tor_malloc_zero(sizeof(*kp_tmp)); + // TODO: If we ever allow cert provisioning here, + // use ed_key_init_from_file() instead. + if (ed25519_seckey_read_from_file(&kp_tmp->seckey, &tag_tmp, fn) < 0) { + log_warn(LD_OR, "%s was not an ed25519 secret key.", fn); + goto end; + } + if (0 != strcmp(tag_tmp, FAMILY_KEY_FILE_TAG)) { + log_warn(LD_OR, "%s was not a family ID key.", fn); + goto end; + } + if (ed25519_public_key_generate(&kp_tmp->pubkey, &kp_tmp->seckey) < 0) { + log_warn(LD_OR, "Unable to generate public key for %s", fn); + goto end; + } + + if (family_key_id_is_expected(options, &kp_tmp->pubkey)) { + smartlist_add(new_keys, kp_tmp); + kp_tmp = NULL; // prevent double-free + } else { + log_warn(LD_OR, "Found secret family key in %s " + "with unexpected FamilyID %s", + fn, ed25519_fmt(&kp_tmp->pubkey)); + } + + ed25519_keypair_free(kp_tmp); + tor_free(tag_tmp); + } SMARTLIST_FOREACH_END(fn); + + set_family_id_keys(new_keys); + new_keys = NULL; // prevent double-free + r = 0; + end: + if (key_files) { + SMARTLIST_FOREACH(key_files, char *, cp, tor_free(cp)); + smartlist_free(key_files); + } + if (new_keys) { + SMARTLIST_FOREACH(new_keys, ed25519_keypair_t *, kp, + ed25519_keypair_free(kp)); + smartlist_free(new_keys); + } + tor_free(tag_tmp); + ed25519_keypair_free(kp_tmp); + return r; +} + +/** + * Create a new family ID key, and store it in `fname`. + * + * If pk_out is provided, set it to the generated public key. + **/ +int +create_family_id_key(const char *fname, ed25519_public_key_t *pk_out) +{ + int r = -1; + ed25519_keypair_t *kp = tor_malloc_zero(sizeof(ed25519_keypair_t)); + + /* Refuse to overwrite an existing family key */ + if (file_status(fname) == FN_FILE) { + log_warn(LD_GENERAL, + "Family key file '%s' already exists. " + "Refusing to overwrite existing family key.", + fname); + goto done; + } + + if (ed25519_keypair_generate(kp, 1) < 0) { + log_warn(LD_BUG, "Can't generate ed25519 key!"); + goto done; + } + + if (ed25519_seckey_write_to_file(&kp->seckey, + fname, FAMILY_KEY_FILE_TAG)<0) { + log_warn(LD_BUG, "Can't write key to file."); + goto done; + } + + if (pk_out) { + ed25519_pubkey_copy(pk_out, &kp->pubkey); + } + + r = 0; + + done: + ed25519_keypair_free(kp); + return r; +} + +/** + * If configured to do so, load our family keys from the key directory. + * Otherwise, clear the family keys. + * + * Additionally, warn about inconsistencies between family options. + * If `ns` is provided, provide additional warnings. + * + * `options` is required; `ns` may be NULL. + */ +int +load_family_id_keys(const or_options_t *options, + const networkstatus_t *ns) +{ + if (options->FamilyIds) { + if (load_family_id_keys_impl(options, options->FamilyKeyDirectory) < 0) + return -1; + + bool any_missing = false; + SMARTLIST_FOREACH_BEGIN(options->FamilyIds, + const ed25519_public_key_t *, id) { + if (!family_key_is_present(id)) { + log_err(LD_OR, "No key was found for listed FamilyID %s", + ed25519_fmt(id)); + any_missing = true; + } + } SMARTLIST_FOREACH_END(id); + if (any_missing) + return -1; + + log_info(LD_OR, "Found %d family ID keys", + smartlist_len(get_current_family_id_keys())); + } else { + set_family_id_keys(NULL); + } + warn_about_family_id_config(options, ns); + return 0; +} + +#define FAMILY_INFO_URL \ + "https://community.torproject.org/relay/setup/post-install/family-ids/" + +/** Generate warnings as appropriate about our family ID configuration. + * + * `options` is required; `ns` may be NULL. + */ +void +warn_about_family_id_config(const or_options_t *options, + const networkstatus_t *ns) +{ + static int have_warned_absent_myfamily = 0; + static int have_warned_absent_familykeys = 0; + + if (options->FamilyIds) { + if (!have_warned_absent_myfamily && + !options->MyFamily && ns && should_publish_family_list(ns)) { + log_warn(LD_OR, + "FamilyId was configured, but MyFamily was not. " + "FamilyId is good, but the Tor network still requires " + "MyFamily while clients are migrating to use family " + "keys instead."); + have_warned_absent_myfamily = 1; + } + } else { + if (!have_warned_absent_familykeys && + options->MyFamily && + ns && ns->consensus_method >= MIN_METHOD_FOR_FAMILY_IDS) { + log_notice(LD_OR, + "MyFamily was configured, but FamilyId was not. " + "It's a good time to start migrating your relays " + "to use family keys. " + "See "FAMILY_INFO_URL " for instructions."); + have_warned_absent_familykeys = 1; + } + } +} + +/** + * Return a list of our current family id keypairs, + * as a list of `ed25519_keypair_t`. + * + * Never returns NULL. + * + * TODO PROP321: Right now this is only used in testing; + * when we add relay support we'll need a way to actually + * read these keys from disk. + **/ +const smartlist_t * +get_current_family_id_keys(void) +{ + if (family_id_keys == NULL) + family_id_keys = smartlist_new(); + return family_id_keys; +} + +/** + * Replace our list of family ID keys with `family_id_keys`, + * which must be a list of `ed25519_keypair_t`. + * + * Takes ownership of its input. + */ +STATIC void +set_family_id_keys(smartlist_t *keys) +{ + if (family_id_keys) { + SMARTLIST_FOREACH(family_id_keys, ed25519_keypair_t *, kp, + ed25519_keypair_free(kp)); + smartlist_free(family_id_keys); + } + family_id_keys = keys; +} + void get_master_rsa_crosscert(const uint8_t **cert_out, size_t *size_out) @@ -746,11 +1092,18 @@ ed25519_keypair_free(master_identity_key); ed25519_keypair_free(master_signing_key); ed25519_keypair_free(current_auth_key); + set_family_id_keys(NULL); + tor_cert_free(signing_key_cert); tor_cert_free(link_cert_cert); tor_cert_free(auth_key_cert); tor_free(rsa_ed_crosscert); + if (cached_family_key_file_list) { + SMARTLIST_FOREACH(cached_family_key_file_list, char *, cp, tor_free(cp)); + smartlist_free(cached_family_key_file_list); + } + master_identity_key = master_signing_key = NULL; current_auth_key = NULL; signing_key_cert = link_cert_cert = auth_key_cert = NULL; diff -Nru tor-0.4.7.16/src/feature/relay/routerkeys.h tor-0.4.9.6/src/feature/relay/routerkeys.h --- tor-0.4.7.16/src/feature/relay/routerkeys.h 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/feature/relay/routerkeys.h 2026-03-25 14:30:34.000000000 +0000 @@ -21,6 +21,10 @@ const struct tor_cert_st *get_current_link_cert_cert(void); const struct tor_cert_st *get_current_auth_key_cert(void); +smartlist_t *list_family_key_files(const or_options_t *options, + const char *keydir); +const smartlist_t *get_current_family_id_keys(void); + void get_master_rsa_crosscert(const uint8_t **cert_out, size_t *size_out); @@ -39,6 +43,11 @@ int log_cert_expiration(void); int load_ed_keys(const or_options_t *options, time_t now); +int load_family_id_keys(const or_options_t *options, + const networkstatus_t *ns); +int create_family_id_key(const char *fname, ed25519_public_key_t *pk_out); +void warn_about_family_id_config(const or_options_t *options, + const networkstatus_t *ns); int should_make_new_ed_keys(const or_options_t *options, const time_t now); int generate_ed_link_cert(const or_options_t *options, time_t now, int force); @@ -53,7 +62,6 @@ static inline void * relay_key_is_unavailable_(void) { - tor_assert_nonfatal_unreached(); return NULL; } #define relay_key_is_unavailable(type) \ @@ -83,6 +91,10 @@ ((void)(options), (void)(now), (void)(force), 0) #define should_make_new_ed_keys(options, now) \ ((void)(options), (void)(now), 0) +#define warn_about_family_id_config(options,ns) \ + ((void)(options), (void)(ns)) +#define get_current_family_id_keys() \ + (smartlist_new()) // These can get removed once router.c becomes relay-only. static inline struct tor_cert_st * @@ -121,6 +133,10 @@ * CMD_KEYGEN. */ #define load_ed_keys(x,y) \ (puts("Not available: Tor has been compiled without relay support"), 0) +#define load_family_id_keys(x,y) \ + (puts("Not available: Tor has been compiled without relay support"), 0) +#define create_family_id_key(x,y) \ + (puts("Not available: Tor has been compiled without relay support"), -1) #endif /* defined(HAVE_MODULE_RELAY) */ @@ -129,4 +145,11 @@ void init_mock_ed_keys(const crypto_pk_t *rsa_identity_key); #endif +#ifdef ROUTERKEYS_PRIVATE +STATIC void set_family_id_keys(smartlist_t *keys); +STATIC bool is_family_key_fname(const char *fname); +STATIC int load_family_id_keys_impl(const or_options_t *options, + const char *keydir); +#endif + #endif /* !defined(TOR_ROUTERKEYS_H) */ diff -Nru tor-0.4.7.16/src/feature/relay/selftest.c tor-0.4.9.6/src/feature/relay/selftest.c --- tor-0.4.7.16/src/feature/relay/selftest.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/feature/relay/selftest.c 2026-03-25 14:30:34.000000000 +0000 @@ -130,16 +130,6 @@ return true; } -/** Relay DirPorts are no longer used (though authorities are). In either case, - * reachability self test is done anymore, since network re-entry towards an - * authority DirPort is not allowed. Thus, consider it always reachable. */ -int -router_dirport_seems_reachable(const or_options_t *options) -{ - (void) options; - return 1; -} - /** See if we currently believe our ORPort to be unreachable. If so, return 1 * else return 0. */ static int @@ -201,7 +191,6 @@ static extend_info_t * extend_info_from_router(const routerinfo_t *r, int family) { - crypto_pk_t *rsa_pubkey; extend_info_t *info; tor_addr_port_t ap; @@ -224,15 +213,14 @@ /* We don't have an ORPort for the requested family. */ return NULL; } - rsa_pubkey = router_get_rsa_onion_pkey(r->onion_pkey, r->onion_pkey_len); info = extend_info_new(r->nickname, r->cache_info.identity_digest, ed_id_key, - rsa_pubkey, r->onion_curve25519_pkey, + r->onion_curve25519_pkey, &ap.addr, ap.port, /* TODO-324: Should self-test circuits use * congestion control? */ NULL, false); - crypto_pk_free(rsa_pubkey); + return info; } diff -Nru tor-0.4.7.16/src/feature/relay/selftest.h tor-0.4.9.6/src/feature/relay/selftest.h --- tor-0.4.7.16/src/feature/relay/selftest.h 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/feature/relay/selftest.h 2026-03-25 14:30:34.000000000 +0000 @@ -20,8 +20,6 @@ int router_orport_seems_reachable( const struct or_options_t *options, int family); -int router_dirport_seems_reachable( - const struct or_options_t *options); void router_do_reachability_checks(void); void router_perform_bandwidth_test(int num_circs, time_t now); diff -Nru tor-0.4.7.16/src/feature/rend/include.am tor-0.4.9.6/src/feature/rend/include.am --- tor-0.4.7.16/src/feature/rend/include.am 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/feature/rend/include.am 2026-03-25 14:30:34.000000000 +0000 @@ -5,6 +5,6 @@ src/feature/rend/rendmid.c # ADD_C_FILE: INSERT HEADERS HERE. -noinst_HEADERS += \ - src/feature/rend/rendcommon.h \ +noinst_HEADERS += \ + src/feature/rend/rendcommon.h \ src/feature/rend/rendmid.h diff -Nru tor-0.4.7.16/src/feature/rend/rendcommon.c tor-0.4.9.6/src/feature/rend/rendcommon.c --- tor-0.4.7.16/src/feature/rend/rendcommon.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/feature/rend/rendcommon.c 2026-03-25 14:30:34.000000000 +0000 @@ -40,7 +40,14 @@ int r = -2; if (CIRCUIT_IS_ORIGIN(circ)) { origin_circ = TO_ORIGIN_CIRCUIT(circ); - if (!layer_hint || layer_hint != origin_circ->cpath->prev) { + + /* Opened onion service circuit receiving cell MUST have an hs_ident as it + * is the underlying assumption else we can't process the cell. If this is + * the case, we can't recover so close the circuit. */ + if (BUG(!origin_circ->hs_ident)) { + circuit_mark_for_close(circ, END_CIRC_REASON_INTERNAL); + origin_circ = NULL; + } else if (!layer_hint || layer_hint != origin_circ->cpath->prev) { log_fn(LOG_PROTOCOL_WARN, LD_APP, "Relay cell (rend purpose %d) from wrong hop on origin circ", command); diff -Nru tor-0.4.7.16/src/feature/rend/rendmid.c tor-0.4.9.6/src/feature/rend/rendmid.c --- tor-0.4.7.16/src/feature/rend/rendmid.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/feature/rend/rendmid.c 2026-03-25 14:30:34.000000000 +0000 @@ -19,6 +19,7 @@ #include "feature/hs/hs_circuitmap.h" #include "feature/hs/hs_dos.h" #include "feature/hs/hs_intropoint.h" +#include "feature/relay/relay_metrics.h" #include "core/or/or_circuit_st.h" @@ -36,6 +37,7 @@ (unsigned)circ->p_circ_id); if (circ->base_.purpose != CIRCUIT_PURPOSE_OR) { + relay_increment_est_rend_action(EST_REND_UNSUITABLE_CIRCUIT); log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "Tried to establish rendezvous on non-OR circuit with purpose %s", circuit_purpose_to_string(circ->base_.purpose)); @@ -46,6 +48,7 @@ * attempt to establish rendezvous points directly to us. */ if (channel_is_client(circ->p_chan) && dos_should_refuse_single_hop_client()) { + relay_increment_est_rend_action(EST_REND_SINGLE_HOP); /* Note it down for the heartbeat log purposes. */ dos_note_refuse_single_hop_client(); /* Silent drop so the client has to time out before moving on. */ @@ -53,18 +56,21 @@ } if (circ->base_.n_chan) { + relay_increment_est_rend_action(EST_REND_UNSUITABLE_CIRCUIT); log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "Tried to establish rendezvous on non-edge circuit"); goto err; } if (request_len != REND_COOKIE_LEN) { + relay_increment_est_rend_action(EST_REND_MALFORMED); log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "Invalid length on ESTABLISH_RENDEZVOUS."); goto err; } if (hs_circuitmap_get_rend_circ_relay_side(request)) { + relay_increment_est_rend_action(EST_REND_DUPLICATE_COOKIE); log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "Duplicate rendezvous cookie in ESTABLISH_RENDEZVOUS."); goto err; @@ -74,11 +80,13 @@ if (relay_send_command_from_edge(0,TO_CIRCUIT(circ), RELAY_COMMAND_RENDEZVOUS_ESTABLISHED, "", 0, NULL)<0) { + relay_increment_est_rend_action(EST_REND_CIRCUIT_DEAD); log_warn(LD_PROTOCOL, "Couldn't send RENDEZVOUS_ESTABLISHED cell."); /* Stop right now, the circuit has been closed. */ return -1; } + relay_increment_est_rend_action(EST_REND_SUCCESS); circuit_change_purpose(TO_CIRCUIT(circ), CIRCUIT_PURPOSE_REND_POINT_WAITING); hs_circuitmap_register_rend_circ_relay_side(circ, request); @@ -108,6 +116,7 @@ int reason = END_CIRC_REASON_INTERNAL; if (circ->base_.purpose != CIRCUIT_PURPOSE_OR || circ->base_.n_chan) { + relay_increment_rend1_action(REND1_UNSUITABLE_CIRCUIT); log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "Tried to complete rendezvous on non-OR or non-edge circuit %u.", (unsigned)circ->p_circ_id); @@ -116,6 +125,7 @@ } if (request_len < REND_COOKIE_LEN) { + relay_increment_rend1_action(REND1_MALFORMED); log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "Rejecting RENDEZVOUS1 cell with bad length (%d) on circuit %u.", (int)request_len, (unsigned)circ->p_circ_id); @@ -135,6 +145,7 @@ * client gives up on a rendezvous circuit after sending INTRODUCE1, but * before the onion service sends the RENDEZVOUS1 cell. */ + relay_increment_rend1_action(REND1_UNKNOWN_COOKIE); log_fn(LOG_DEBUG, LD_PROTOCOL, "Rejecting RENDEZVOUS1 cell with unrecognized rendezvous cookie %s.", hexid); @@ -155,6 +166,7 @@ RELAY_COMMAND_RENDEZVOUS2, (char*)(request+REND_COOKIE_LEN), request_len-REND_COOKIE_LEN, NULL)) { + relay_increment_rend1_action(REND1_CIRCUIT_DEAD); log_warn(LD_GENERAL, "Unable to send RENDEZVOUS2 cell to client on circuit %u.", (unsigned)rend_circ->p_circ_id); @@ -162,6 +174,7 @@ return -1; } + relay_increment_rend1_action(REND1_SUCCESS); /* Join the circuits. */ log_info(LD_REND, "Completing rendezvous: circuit %u joins circuit %u (cookie %s)", diff -Nru tor-0.4.7.16/src/feature/stats/geoip_stats.c tor-0.4.9.6/src/feature/stats/geoip_stats.c --- tor-0.4.7.16/src/feature/stats/geoip_stats.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/feature/stats/geoip_stats.c 2026-03-25 14:30:34.000000000 +0000 @@ -305,6 +305,7 @@ geoip_client_action_t action) { clientmap_entry_t lookup; + memset(&lookup, 0, sizeof(lookup)); tor_assert(addr); @@ -389,8 +390,8 @@ * statuses? */ static uint32_t ns_v3_responses[GEOIP_NS_RESPONSE_NUM]; -/** Note that we've rejected a client's request for a v3 network status - * for reason reason at time now. */ +/** Note how we have handled a client's request for a v3 network status: + * with reason at time now. */ void geoip_note_ns_response(geoip_ns_response_t response) { @@ -996,7 +997,8 @@ tor_asprintf(&result, "dirreq-stats-end %s (%d s)\n" "dirreq-v3-ips %s\n" "dirreq-v3-reqs %s\n" - "dirreq-v3-resp ok=%u,not-enough-sigs=%u,unavailable=%u," + "dirreq-v3-resp " + "served=%u,ok=%u,not-enough-sigs=%u,unavailable=%u," "not-found=%u,not-modified=%u,busy=%u\n" "dirreq-v3-direct-dl %s\n" "dirreq-v3-tunneled-dl %s\n", @@ -1004,6 +1006,7 @@ (unsigned) (now - start_of_dirreq_stats_interval), v3_ips_string ? v3_ips_string : "", v3_reqs_string ? v3_reqs_string : "", + ns_v3_responses[GEOIP_SERVED], ns_v3_responses[GEOIP_SUCCESS], ns_v3_responses[GEOIP_REJECT_NOT_ENOUGH_SIGS], ns_v3_responses[GEOIP_REJECT_UNAVAILABLE], diff -Nru tor-0.4.7.16/src/feature/stats/geoip_stats.h tor-0.4.9.6/src/feature/stats/geoip_stats.h --- tor-0.4.7.16/src/feature/stats/geoip_stats.h 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/feature/stats/geoip_stats.h 2026-03-25 14:30:34.000000000 +0000 @@ -20,12 +20,12 @@ * the others, we're not. */ typedef enum { - /** We've noticed a connection as a bridge relay or entry guard. */ + /** An incoming ORPort connection */ GEOIP_CLIENT_CONNECT = 0, /** We've served a networkstatus consensus as a directory server. */ GEOIP_CLIENT_NETWORKSTATUS = 1, } geoip_client_action_t; -/** Indicates either a positive reply or a reason for rejectng a network +/** Indicates either a positive reply or a reason for rejecting a network * status request that will be included in geoip statistics. */ typedef enum { /** Request is answered successfully. */ @@ -41,8 +41,11 @@ GEOIP_REJECT_NOT_MODIFIED = 4, /** Directory is busy. */ GEOIP_REJECT_BUSY = 5, + /** We began to serve the request, and when we feel we have finished + * serving it we will note this with a GEOIP_SUCCESS call too. */ + GEOIP_SERVED = 6, } geoip_ns_response_t; -#define GEOIP_NS_RESPONSE_NUM 6 +#define GEOIP_NS_RESPONSE_NUM 7 /** Directory requests that we are measuring can be either direct or * tunneled. */ diff -Nru tor-0.4.7.16/src/feature/stats/include.am tor-0.4.9.6/src/feature/stats/include.am --- tor-0.4.7.16/src/feature/stats/include.am 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/feature/stats/include.am 2026-03-25 14:30:34.000000000 +0000 @@ -9,7 +9,7 @@ # ADD_C_FILE: INSERT HEADERS HERE. noinst_HEADERS += \ - src/feature/stats/bw_array_st.h \ + src/feature/stats/bw_array_st.h \ src/feature/stats/bwhist.h \ src/feature/stats/connstats.h \ src/feature/stats/geoip_stats.h \ diff -Nru tor-0.4.7.16/src/feature/stats/rephist.c tor-0.4.9.6/src/feature/stats/rephist.c --- tor-0.4.7.16/src/feature/stats/rephist.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/feature/stats/rephist.c 2026-03-25 14:30:34.000000000 +0000 @@ -280,6 +280,9 @@ /** DNS query statistics store. It covers all type of queries. */ static dns_stats_t dns_all_stats; +/** Counter of the total number of DROP cell received. */ +static uint64_t relay_circ_n_drop_cell_received = 0; + /** Return the point to the DNS statistics store. Ignore the type for now * because of a libevent problem. */ static inline dns_stats_t * @@ -2290,19 +2293,14 @@ /** Keep track of the onionskin requests for an assessment period. */ static overload_onionskin_assessment_t overload_onionskin_assessment; -/** - * We combine ntorv3 and ntor into the same stat, so we must - * use this function to covert the cell type to a stat index. +/** This function ensures that we clamp the maximum value of the given input + * type to NTOR in case the input is out of range. */ static inline uint16_t onionskin_type_to_stat(uint16_t type) { - if (type == ONION_HANDSHAKE_TYPE_NTOR_V3) { - return ONION_HANDSHAKE_TYPE_NTOR; - } - if (BUG(type > MAX_ONION_STAT_TYPE)) { - return MAX_ONION_STAT_TYPE; // use ntor if out of range + return MAX_ONION_STAT_TYPE; // use ntor_v3 if out of range } return type; @@ -2315,7 +2313,7 @@ * the stats are reset back to 0 and the assessment time period updated. * * This is called when a ntor handshake is _requested_ because we want to avoid - * to have an assymetric situation where requested counter is reset to 0 but + * to have an asymmetric situation where requested counter is reset to 0 but * then a drop happens leading to the drop counter being incremented while the * requested counter is 0. */ static void @@ -2371,7 +2369,8 @@ onion_handshakes_requested[stat]++; /* Only relays get to record requested onionskins. */ - if (stat == ONION_HANDSHAKE_TYPE_NTOR) { + if (stat == ONION_HANDSHAKE_TYPE_NTOR || + stat == ONION_HANDSHAKE_TYPE_NTOR_V3) { /* Assess if we've reached the overload general signal. */ overload_general_onionskin_assessment(); @@ -2398,7 +2397,8 @@ stats_n_onionskin_dropped[stat]++; /* Only relays get to record requested onionskins. */ - if (stat == ONION_HANDSHAKE_TYPE_NTOR) { + if (stat == ONION_HANDSHAKE_TYPE_NTOR || + stat == ONION_HANDSHAKE_TYPE_NTOR_V3) { /* Note the dropped ntor in the overload assessment object. */ overload_onionskin_assessment.n_ntor_dropped++; } @@ -2438,11 +2438,13 @@ { (void)now; log_notice(LD_HEARTBEAT, "Circuit handshake stats since last time: " - "%d/%d TAP, %d/%d NTor.", + "%d/%d TAP, %d/%d NTor, %d/%d NTor (v3).", onion_handshakes_assigned[ONION_HANDSHAKE_TYPE_TAP], onion_handshakes_requested[ONION_HANDSHAKE_TYPE_TAP], onion_handshakes_assigned[ONION_HANDSHAKE_TYPE_NTOR], - onion_handshakes_requested[ONION_HANDSHAKE_TYPE_NTOR]); + onion_handshakes_requested[ONION_HANDSHAKE_TYPE_NTOR], + onion_handshakes_assigned[ONION_HANDSHAKE_TYPE_NTOR_V3], + onion_handshakes_requested[ONION_HANDSHAKE_TYPE_NTOR_V3]); memset(onion_handshakes_assigned, 0, sizeof(onion_handshakes_assigned)); memset(onion_handshakes_requested, 0, sizeof(onion_handshakes_requested)); } @@ -2816,6 +2818,8 @@ switch (type) { case PADDING_TYPE_DROP: padding_current.write_drop_cell_count++; + /* Padding stats get reset thus why we have two counters. */ + relay_circ_n_drop_cell_received++; break; case PADDING_TYPE_CELL: padding_current.write_pad_cell_count++; @@ -3023,6 +3027,13 @@ OVERLOAD_ONIONSKIN_NTOR_PERIOD_SECS_MAX); } +/** Relay Only: return the total number of DROP cell received. */ +uint64_t +rep_hist_get_drop_cell_received_count(void) +{ + return relay_circ_n_drop_cell_received; +} + #ifdef TOR_UNIT_TESTS /* only exists for unit tests: get HSv2 stats object */ const hs_v2_stats_t * diff -Nru tor-0.4.7.16/src/feature/stats/rephist.h tor-0.4.9.6/src/feature/stats/rephist.h --- tor-0.4.7.16/src/feature/stats/rephist.h 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/feature/stats/rephist.h 2026-03-25 14:30:34.000000000 +0000 @@ -102,8 +102,8 @@ void rep_hist_consensus_has_changed(const networkstatus_t *ns); /** We combine ntor and ntorv3 stats, so we have 3 stat types: - * tap, fast, and ntor. The max type is ntor (2) */ -#define MAX_ONION_STAT_TYPE ONION_HANDSHAKE_TYPE_NTOR + * tap, fast, and ntor. The max type is ntor_v3 (3) */ +#define MAX_ONION_STAT_TYPE MAX_ONION_HANDSHAKE_TYPE extern uint64_t rephist_total_alloc; extern uint32_t rephist_total_num; @@ -192,6 +192,8 @@ uint64_t rep_hist_get_n_read_limit_reached(void); uint64_t rep_hist_get_n_write_limit_reached(void); +uint64_t rep_hist_get_drop_cell_received_count(void); + #ifdef TOR_UNIT_TESTS struct hs_v2_stats_t; const struct hs_v2_stats_t *rep_hist_get_hs_v2_stats(void); diff -Nru tor-0.4.7.16/src/include.am tor-0.4.9.6/src/include.am --- tor-0.4.7.16/src/include.am 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/include.am 2026-03-25 14:30:34.000000000 +0000 @@ -87,6 +87,5 @@ include src/test/include.am include src/tools/include.am -include src/win32/include.am include src/config/include.am include src/test/fuzz/include.am diff -Nru tor-0.4.7.16/src/lib/cc/compat_compiler.h tor-0.4.9.6/src/lib/cc/compat_compiler.h --- tor-0.4.7.16/src/lib/cc/compat_compiler.h 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/lib/cc/compat_compiler.h 2026-03-25 14:30:34.000000000 +0000 @@ -79,6 +79,12 @@ #define FALLTHROUGH #endif +#if defined(HAVE_ATTR_NONSTRING) +#define NONSTRING __attribute__((nonstring)) +#else +#define NONSTRING +#endif + /* What GCC do we have? */ #ifdef __GNUC__ #define GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__) diff -Nru tor-0.4.7.16/src/lib/compress/compress.c tor-0.4.9.6/src/lib/compress/compress.c --- tor-0.4.7.16/src/lib/compress/compress.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/lib/compress/compress.c 2026-03-25 14:30:34.000000000 +0000 @@ -53,9 +53,12 @@ * MAX_UNCOMPRESSION_FACTOR. Within those parameters, there's a reasonably * large range of possible values. IMO, anything over 8 is probably safe; IMO * anything under 50 is probably sufficient. + * + * 2025-10-01: (ahf) Bumped to 5 MB to avoid the situation described in + * tor#40739. */ #define MAX_UNCOMPRESSION_FACTOR 25 -#define CHECK_FOR_COMPRESSION_BOMB_AFTER (1024*64) +#define CHECK_FOR_COMPRESSION_BOMB_AFTER (5 * 1024 * 1024) /** @} */ /** Return true if uncompressing an input of size in_size to an input of @@ -66,7 +69,17 @@ if (size_in == 0 || size_out < CHECK_FOR_COMPRESSION_BOMB_AFTER) return 0; - return (size_out / size_in > MAX_UNCOMPRESSION_FACTOR); + double compression_factor = (double)size_out / size_in; + if (compression_factor > MAX_UNCOMPRESSION_FACTOR) { + log_warn(LD_GENERAL, + "Detected possible compression bomb with " + "input size = %"TOR_PRIuSZ" and output size = %"TOR_PRIuSZ" " + "(compression factor = %.2f)", + size_in, size_out, compression_factor); + return 1; + } + + return 0; } /** Guess the size that in_len will be after compression or diff -Nru tor-0.4.7.16/src/lib/conf/include.am tor-0.4.9.6/src/lib/conf/include.am --- tor-0.4.7.16/src/lib/conf/include.am 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/lib/conf/include.am 2026-03-25 14:30:34.000000000 +0000 @@ -1,7 +1,7 @@ # ADD_C_FILE: INSERT HEADERS HERE. noinst_HEADERS += \ - src/lib/conf/confdecl.h \ - src/lib/conf/conftesting.h \ - src/lib/conf/conftypes.h \ + src/lib/conf/confdecl.h \ + src/lib/conf/conftesting.h \ + src/lib/conf/conftypes.h \ src/lib/conf/confmacros.h diff -Nru tor-0.4.7.16/src/lib/confmgt/include.am tor-0.4.9.6/src/lib/confmgt/include.am --- tor-0.4.7.16/src/lib/confmgt/include.am 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/lib/confmgt/include.am 2026-03-25 14:30:34.000000000 +0000 @@ -6,10 +6,10 @@ # ADD_C_FILE: INSERT SOURCES HERE. src_lib_libtor_confmgt_a_SOURCES = \ - src/lib/confmgt/confmgt.c \ - src/lib/confmgt/structvar.c \ - src/lib/confmgt/type_defs.c \ - src/lib/confmgt/typedvar.c \ + src/lib/confmgt/confmgt.c \ + src/lib/confmgt/structvar.c \ + src/lib/confmgt/type_defs.c \ + src/lib/confmgt/typedvar.c \ src/lib/confmgt/unitparse.c src_lib_libtor_confmgt_testing_a_SOURCES = \ diff -Nru tor-0.4.7.16/src/lib/crypt_ops/aes.h tor-0.4.9.6/src/lib/crypt_ops/aes.h --- tor-0.4.7.16/src/lib/crypt_ops/aes.h 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/lib/crypt_ops/aes.h 2026-03-25 14:30:34.000000000 +0000 @@ -15,17 +15,31 @@ #include "lib/cc/torint.h" #include "lib/malloc/malloc.h" +#include "lib/testsupport/testsupport.h" typedef struct aes_cnt_cipher_t aes_cnt_cipher_t; aes_cnt_cipher_t* aes_new_cipher(const uint8_t *key, const uint8_t *iv, int key_bits); +void aes_cipher_set_iv_aligned(aes_cnt_cipher_t *cipher_, const uint8_t *iv); +void aes_cipher_set_key(aes_cnt_cipher_t *cipher_, + const uint8_t *key, int key_bits); void aes_cipher_free_(aes_cnt_cipher_t *cipher); #define aes_cipher_free(cipher) \ FREE_AND_NULL(aes_cnt_cipher_t, aes_cipher_free_, (cipher)) void aes_crypt_inplace(aes_cnt_cipher_t *cipher, char *data, size_t len); -int evaluate_evp_for_aes(int force_value); -int evaluate_ctr_for_aes(void); +#ifdef USE_AES_RAW +typedef struct aes_raw_t aes_raw_t; + +aes_raw_t *aes_raw_new(const uint8_t *key, int key_bits, bool encrypt); +void aes_raw_set_key(aes_raw_t **cipher, const uint8_t *key, + int key_bits, bool encrypt); +void aes_raw_free_(aes_raw_t *cipher); +#define aes_raw_free(cipher) \ + FREE_AND_NULL(aes_raw_t, aes_raw_free_, (cipher)) +void aes_raw_encrypt(const aes_raw_t *cipher, uint8_t *block); +void aes_raw_decrypt(const aes_raw_t *cipher, uint8_t *block); +#endif #endif /* !defined(TOR_AES_H) */ diff -Nru tor-0.4.7.16/src/lib/crypt_ops/aes_nss.c tor-0.4.9.6/src/lib/crypt_ops/aes_nss.c --- tor-0.4.7.16/src/lib/crypt_ops/aes_nss.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/lib/crypt_ops/aes_nss.c 2026-03-25 14:30:34.000000000 +0000 @@ -9,6 +9,9 @@ * \brief Use NSS to implement AES_CTR. **/ +#define USE_AES_RAW +#define TOR_AES_PRIVATE + #include "orconfig.h" #include "lib/crypt_ops/aes.h" #include "lib/crypt_ops/crypto_nss_mgt.h" @@ -20,9 +23,18 @@ #include ENABLE_GCC_WARNING("-Wstrict-prototypes") -aes_cnt_cipher_t * -aes_new_cipher(const uint8_t *key, const uint8_t *iv, - int key_bits) +struct aes_cnt_cipher_t { + PK11Context *context; + // We need to keep a copy of the key here since we can't set the IV only. + // It would be nice to fix that, but NSS doesn't see a huge number of + // users. + uint8_t kbytes; + uint8_t key[32]; +}; + +static PK11Context * +aes_new_cipher_internal(const uint8_t *key, const uint8_t *iv, + int key_bits) { const CK_MECHANISM_TYPE ckm = CKM_AES_CTR; SECItem keyItem = { .type = siBuffer, @@ -65,7 +77,18 @@ PK11_FreeSlot(slot); tor_assert(result); - return (aes_cnt_cipher_t *)result; + return result; +} + +aes_cnt_cipher_t * +aes_new_cipher(const uint8_t *key, const uint8_t *iv, + int key_bits) +{ + aes_cnt_cipher_t *cipher = tor_malloc_zero(sizeof(*cipher)); + cipher->context = aes_new_cipher_internal(key, iv, key_bits); + cipher->kbytes = key_bits / 8; + memcpy(cipher->key, key, cipher->kbytes); + return cipher; } void @@ -73,7 +96,34 @@ { if (!cipher) return; - PK11_DestroyContext((PK11Context*) cipher, PR_TRUE); + PK11_DestroyContext(cipher->context, PR_TRUE); + memwipe(cipher, 0, sizeof(*cipher)); + tor_free(cipher); +} + +void +aes_cipher_set_iv_aligned(aes_cnt_cipher_t *cipher, const uint8_t *iv) +{ + // For NSS, I could not find a method to change the IV + // of an existing context. Maybe I missed one? + PK11_DestroyContext(cipher->context, PR_TRUE); + cipher->context = aes_new_cipher_internal(cipher->key, iv, + 8*(int)cipher->kbytes); +} + +void +aes_cipher_set_key(aes_cnt_cipher_t *cipher, + const uint8_t *key, int key_bits) +{ + const uint8_t iv[16] = {0}; + // For NSS, I could not find a method to change the key + // of an existing context. Maybe I missed one? + PK11_DestroyContext(cipher->context, PR_TRUE); + memwipe(cipher->key, 0, sizeof(cipher->key)); + + cipher->context = aes_new_cipher_internal(key, iv, key_bits); + cipher->kbytes = key_bits / 8; + memcpy(cipher->key, key, cipher->kbytes); } void @@ -82,25 +132,90 @@ tor_assert(len_ <= INT_MAX); SECStatus s; - PK11Context *ctx = (PK11Context*)cipher; unsigned char *data = (unsigned char *)data_; int len = (int) len_; int result_len = 0; - s = PK11_CipherOp(ctx, data, &result_len, len, data, len); + s = PK11_CipherOp(cipher->context, data, &result_len, len, data, len); tor_assert(s == SECSuccess); tor_assert(result_len == len); } -int -evaluate_evp_for_aes(int force_value) +aes_raw_t * +aes_raw_new(const uint8_t *key, int key_bits, bool encrypt) { - (void)force_value; - return 0; -} + const CK_MECHANISM_TYPE ckm = CKM_AES_ECB; + SECItem keyItem = { .type = siBuffer, // ???? + .data = (unsigned char *)key, + .len = (key_bits / 8) }; + SECItem ivItem = { .type = siBuffer, + .data = NULL, + .len = 0 }; + PK11SlotInfo *slot = NULL; + PK11SymKey *keyObj = NULL; + SECItem *ivObj = NULL; + PK11Context *result = NULL; + + slot = PK11_GetBestSlot(ckm, NULL); + if (!slot) + goto err; + + CK_ATTRIBUTE_TYPE mode = encrypt ? CKA_ENCRYPT : CKA_DECRYPT; + + keyObj = PK11_ImportSymKey(slot, ckm, PK11_OriginUnwrap, + mode, &keyItem, NULL); + if (!keyObj) + goto err; + + ivObj = PK11_ParamFromIV(ckm, &ivItem); + if (!ivObj) + goto err; + + PORT_SetError(SEC_ERROR_IO); + result = PK11_CreateContextBySymKey(ckm, mode, keyObj, ivObj); + + err: -int -evaluate_ctr_for_aes(void) + if (ivObj) + SECITEM_FreeItem(ivObj, PR_TRUE); + if (keyObj) + PK11_FreeSymKey(keyObj); + if (slot) + PK11_FreeSlot(slot); + + tor_assert(result); + return (aes_raw_t *)result; +} +void +aes_raw_free_(aes_raw_t *cipher_) +{ + if (!cipher_) + return; + PK11Context *ctx = (PK11Context*)cipher_; + PK11_DestroyContext(ctx, PR_TRUE); +} +void +aes_raw_set_key(aes_raw_t **cipher, const uint8_t *key, + int key_bits, bool encrypt) +{ + // For NSS, I could not find a method to change the key + // of an existing context. + aes_raw_free(*cipher); + *cipher = aes_raw_new(key, key_bits, encrypt); +} +void +aes_raw_encrypt(const aes_raw_t *cipher, uint8_t *block) +{ + SECStatus s; + PK11Context *ctx = (PK11Context*)cipher; + int result_len = 0; + s = PK11_CipherOp(ctx, block, &result_len, 16, block, 16); + tor_assert(s == SECSuccess); + tor_assert(result_len == 16); +} +void +aes_raw_decrypt(const aes_raw_t *cipher, uint8_t *block) { - return 0; + /* This is the same function call for NSS. */ + aes_raw_encrypt(cipher, block); } diff -Nru tor-0.4.7.16/src/lib/crypt_ops/aes_openssl.c tor-0.4.9.6/src/lib/crypt_ops/aes_openssl.c --- tor-0.4.7.16/src/lib/crypt_ops/aes_openssl.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/lib/crypt_ops/aes_openssl.c 2026-03-25 14:30:34.000000000 +0000 @@ -9,6 +9,9 @@ * \brief Use OpenSSL to implement AES_CTR. **/ +#define USE_AES_RAW +#define TOR_AES_PRIVATE + #include "orconfig.h" #include "lib/crypt_ops/aes.h" #include "lib/crypt_ops/crypto_util.h" @@ -24,10 +27,6 @@ #include #include "lib/crypt_ops/crypto_openssl_mgt.h" -#if OPENSSL_VERSION_NUMBER < OPENSSL_V_SERIES(1,0,0) -#error "We require OpenSSL >= 1.0.0" -#endif - DISABLE_GCC_WARNING("-Wredundant-decls") #include @@ -42,36 +41,43 @@ #include "lib/log/log.h" #include "lib/ctime/di_ops.h" -#ifdef OPENSSL_NO_ENGINE -/* Android's OpenSSL seems to have removed all of its Engine support. */ -#define DISABLE_ENGINES +/* Cached values of our EVP_CIPHER items. If we don't pre-fetch them, + * then EVP_CipherInit calls EVP_CIPHER_fetch itself, + * which is surprisingly expensive. + */ +static const EVP_CIPHER *aes128ctr = NULL; +static const EVP_CIPHER *aes192ctr = NULL; +static const EVP_CIPHER *aes256ctr = NULL; +static const EVP_CIPHER *aes128ecb = NULL; +static const EVP_CIPHER *aes192ecb = NULL; +static const EVP_CIPHER *aes256ecb = NULL; + +#if OPENSSL_VERSION_NUMBER >= OPENSSL_V_NOPATCH(3,0,0) \ + && !defined(LIBRESSL_VERSION_NUMBER) +#define RESOLVE_CIPHER(c) \ + EVP_CIPHER_fetch(NULL, OBJ_nid2sn(EVP_CIPHER_get_nid(c)), "") +#else +#define RESOLVE_CIPHER(c) (c) #endif -/* We have five strategies for implementing AES counter mode. - * - * Best with x86 and x86_64: Use EVP_aes_*_ctr() and EVP_EncryptUpdate(). - * This is possible with OpenSSL 1.0.1, where the counter-mode implementation - * can use bit-sliced or vectorized AES or AESNI as appropriate. - * - * Otherwise: Pick the best possible AES block implementation that OpenSSL - * gives us, and the best possible counter-mode implementation, and combine - * them. +/** + * Pre-fetch the versions of every AES cipher with its associated provider. */ -#if OPENSSL_VERSION_NUMBER >= OPENSSL_V_NOPATCH(1,1,0) - -/* With newer OpenSSL versions, the older fallback modes don't compile. So - * don't use them, even if we lack specific acceleration. */ - -#define USE_EVP_AES_CTR - -#elif OPENSSL_VERSION_NUMBER >= OPENSSL_V_NOPATCH(1,0,1) && \ - (defined(__i386) || defined(__i386__) || defined(_M_IX86) || \ - defined(__x86_64) || defined(__x86_64__) || \ - defined(_M_AMD64) || defined(_M_X64) || defined(__INTEL__)) - -#define USE_EVP_AES_CTR - -#endif /* OPENSSL_VERSION_NUMBER >= OPENSSL_V_NOPATCH(1,1,0) || ... */ +static void +init_ciphers(void) +{ + aes128ctr = RESOLVE_CIPHER(EVP_aes_128_ctr()); + aes192ctr = RESOLVE_CIPHER(EVP_aes_192_ctr()); + aes256ctr = RESOLVE_CIPHER(EVP_aes_256_ctr()); + aes128ecb = RESOLVE_CIPHER(EVP_aes_128_ecb()); + aes192ecb = RESOLVE_CIPHER(EVP_aes_192_ecb()); + aes256ecb = RESOLVE_CIPHER(EVP_aes_256_ecb()); +} +#define INIT_CIPHERS() STMT_BEGIN { \ + if (PREDICT_UNLIKELY(NULL == aes128ctr)) { \ + init_ciphers(); \ + } \ + } STMT_END /* We have 2 strategies for getting the AES block cipher: Via OpenSSL's * AES_encrypt function, or via OpenSSL's EVP_EncryptUpdate function. @@ -92,19 +98,18 @@ * make sure that we have a fixed version.) */ -#ifdef USE_EVP_AES_CTR - /* We don't actually define the struct here. */ aes_cnt_cipher_t * aes_new_cipher(const uint8_t *key, const uint8_t *iv, int key_bits) { + INIT_CIPHERS(); EVP_CIPHER_CTX *cipher = EVP_CIPHER_CTX_new(); const EVP_CIPHER *c = NULL; switch (key_bits) { - case 128: c = EVP_aes_128_ctr(); break; - case 192: c = EVP_aes_192_ctr(); break; - case 256: c = EVP_aes_256_ctr(); break; + case 128: c = aes128ctr; break; + case 192: c = aes192ctr; break; + case 256: c = aes256ctr; break; default: tor_assert_unreached(); // LCOV_EXCL_LINE } EVP_EncryptInit(cipher, c, key, iv); @@ -116,12 +121,46 @@ if (!cipher_) return; EVP_CIPHER_CTX *cipher = (EVP_CIPHER_CTX *) cipher_; -#ifdef OPENSSL_1_1_API EVP_CIPHER_CTX_reset(cipher); + EVP_CIPHER_CTX_free(cipher); +} + +/** Changes the key of the cipher; + * sets the IV to 0. + */ +void +aes_cipher_set_key(aes_cnt_cipher_t *cipher_, const uint8_t *key, int key_bits) +{ + EVP_CIPHER_CTX *cipher = (EVP_CIPHER_CTX *) cipher_; + uint8_t iv[16] = {0}; + const EVP_CIPHER *c = NULL; + switch (key_bits) { + case 128: c = aes128ctr; break; + case 192: c = aes192ctr; break; + case 256: c = aes256ctr; break; + default: tor_assert_unreached(); // LCOV_EXCL_LINE + } + + // No need to call EVP_CIPHER_CTX_Reset here; EncryptInit already + // does it for us. + EVP_EncryptInit(cipher, c, key, iv); +} +/** Change the IV of this stream cipher without changing the key. + * + * Requires that the cipher stream position is at an even multiple of 16 bytes. + */ +void +aes_cipher_set_iv_aligned(aes_cnt_cipher_t *cipher_, const uint8_t *iv) +{ + EVP_CIPHER_CTX *cipher = (EVP_CIPHER_CTX *) cipher_; +#ifdef LIBRESSL_VERSION_NUMBER + EVP_CIPHER_CTX_set_iv(cipher, iv, 16); #else - EVP_CIPHER_CTX_cleanup(cipher); + // We would have to do this if the cipher's position were not aligned: + // EVP_CIPHER_CTX_set_num(cipher, 0); + + memcpy(EVP_CIPHER_CTX_iv_noconst(cipher), iv, 16); #endif - EVP_CIPHER_CTX_free(cipher); } void aes_crypt_inplace(aes_cnt_cipher_t *cipher_, char *data, size_t len) @@ -134,276 +173,105 @@ EVP_EncryptUpdate(cipher, (unsigned char*)data, &outl, (unsigned char*)data, (int)len); } -int -evaluate_evp_for_aes(int force_val) -{ - (void) force_val; - log_info(LD_CRYPTO, "This version of OpenSSL has a known-good EVP " - "counter-mode implementation. Using it."); - return 0; -} -int -evaluate_ctr_for_aes(void) -{ - return 0; -} -#else /* !defined(USE_EVP_AES_CTR) */ - -/*======================================================================*/ -/* Interface to AES code, and counter implementation */ - -/** Implements an AES counter-mode cipher. */ -struct aes_cnt_cipher_t { -/** This next element (however it's defined) is the AES key. */ - union { - EVP_CIPHER_CTX evp; - AES_KEY aes; - } key; - -#if !defined(WORDS_BIGENDIAN) -#define USING_COUNTER_VARS - /** These four values, together, implement a 128-bit counter, with - * counter0 as the low-order word and counter3 as the high-order word. */ - uint32_t counter3; - uint32_t counter2; - uint32_t counter1; - uint32_t counter0; -#endif /* !defined(WORDS_BIGENDIAN) */ - - union { - /** The counter, in big-endian order, as bytes. */ - uint8_t buf[16]; - /** The counter, in big-endian order, as big-endian words. Note that - * on big-endian platforms, this is redundant with counter3...0, - * so we just use these values instead. */ - uint32_t buf32[4]; - } ctr_buf; - - /** The encrypted value of ctr_buf. */ - uint8_t buf[16]; - /** Our current stream position within buf. */ - unsigned int pos; - - /** True iff we're using the evp implementation of this cipher. */ - uint8_t using_evp; -}; - -/** True iff we should prefer the EVP implementation for AES, either because - * we're testing it or because we have hardware acceleration configured */ -static int should_use_EVP = 0; - -/** Check whether we should use the EVP interface for AES. If force_val - * is nonnegative, we use use EVP iff it is true. Otherwise, we use EVP - * if there is an engine enabled for aes-ecb. */ -int -evaluate_evp_for_aes(int force_val) -{ - ENGINE *e; - - if (force_val >= 0) { - should_use_EVP = force_val; - return 0; - } -#ifdef DISABLE_ENGINES - should_use_EVP = 0; -#else - e = ENGINE_get_cipher_engine(NID_aes_128_ecb); - - if (e) { - log_info(LD_CRYPTO, "AES engine \"%s\" found; using EVP_* functions.", - ENGINE_get_name(e)); - should_use_EVP = 1; - } else { - log_info(LD_CRYPTO, "No AES engine found; using AES_* functions."); - should_use_EVP = 0; - } -#endif /* defined(DISABLE_ENGINES) */ - - return 0; -} -/** Test the OpenSSL counter mode implementation to see whether it has the - * counter-mode bug from OpenSSL 1.0.0. If the implementation works, then - * we will use it for future encryption/decryption operations. +/* ======== + * Functions for "raw" (ECB) AES. * - * We can't just look at the OpenSSL version, since some distributions update - * their OpenSSL packages without changing the version number. - **/ -int -evaluate_ctr_for_aes(void) -{ - /* Result of encrypting an all-zero block with an all-zero 128-bit AES key. - * This should be the same as encrypting an all-zero block with an all-zero - * 128-bit AES key in counter mode, starting at position 0 of the stream. - */ - static const unsigned char encrypt_zero[] = - "\x66\xe9\x4b\xd4\xef\x8a\x2c\x3b\x88\x4c\xfa\x59\xca\x34\x2b\x2e"; - unsigned char zero[16]; - unsigned char output[16]; - unsigned char ivec[16]; - unsigned char ivec_tmp[16]; - unsigned int pos, i; - AES_KEY key; - memset(zero, 0, sizeof(zero)); - memset(ivec, 0, sizeof(ivec)); - AES_set_encrypt_key(zero, 128, &key); - - pos = 0; - /* Encrypting a block one byte at a time should make the error manifest - * itself for known bogus openssl versions. */ - for (i=0; i<16; ++i) - AES_ctr128_encrypt(&zero[i], &output[i], 1, &key, ivec, ivec_tmp, &pos); - - if (fast_memneq(output, encrypt_zero, 16)) { - /* Counter mode is buggy */ - /* LCOV_EXCL_START */ - log_err(LD_CRYPTO, "This OpenSSL has a buggy version of counter mode; " - "quitting tor."); - exit(1); // exit ok: openssl is broken. - /* LCOV_EXCL_STOP */ - } - return 0; -} - -#if !defined(USING_COUNTER_VARS) -#define COUNTER(c, n) ((c)->ctr_buf.buf32[3-(n)]) -#else -#define COUNTER(c, n) ((c)->counter ## n) -#endif - -static void aes_set_key(aes_cnt_cipher_t *cipher, const uint8_t *key, - int key_bits); -static void aes_set_iv(aes_cnt_cipher_t *cipher, const uint8_t *iv); + * I'm choosing the name "raw" here because ECB is not a mode; + * it's a disaster. The only way to use this safely is + * within a real construction. + */ /** - * Return a newly allocated counter-mode AES128 cipher implementation, - * using the 128-bit key key and the 128-bit IV iv. + * Create a new instance of AES using a key of length 'key_bits' + * for raw block encryption. + * + * This is even more low-level than counter-mode, and you should + * only use it with extreme caution. */ -aes_cnt_cipher_t* -aes_new_cipher(const uint8_t *key, const uint8_t *iv, int bits) +aes_raw_t * +aes_raw_new(const uint8_t *key, int key_bits, bool encrypt) { - aes_cnt_cipher_t* result = tor_malloc_zero(sizeof(aes_cnt_cipher_t)); - - aes_set_key(result, key, bits); - aes_set_iv(result, iv); + INIT_CIPHERS(); + EVP_CIPHER_CTX *cipher = EVP_CIPHER_CTX_new(); + tor_assert(cipher); + const EVP_CIPHER *c = NULL; + switch (key_bits) { + case 128: c = aes128ecb; break; + case 192: c = aes192ecb; break; + case 256: c = aes256ecb; break; + default: tor_assert_unreached(); + } - return result; + // No need to call EVP_CIPHER_CTX_Reset here; EncryptInit already + // does it for us. + int r = EVP_CipherInit(cipher, c, key, NULL, encrypt); + tor_assert(r == 1); + EVP_CIPHER_CTX_set_padding(cipher, 0); + return (aes_raw_t *)cipher; } - -/** Set the key of cipher to key, which is - * key_bits bits long (must be 128, 192, or 256). Also resets - * the counter to 0. +/** + * Replace the key on an existing aes_raw_t. + * + * This may be faster than freeing and reallocating. */ -static void -aes_set_key(aes_cnt_cipher_t *cipher, const uint8_t *key, int key_bits) +void +aes_raw_set_key(aes_raw_t **cipher_, const uint8_t *key, + int key_bits, bool encrypt) { - if (should_use_EVP) { - const EVP_CIPHER *c = 0; - switch (key_bits) { - case 128: c = EVP_aes_128_ecb(); break; - case 192: c = EVP_aes_192_ecb(); break; - case 256: c = EVP_aes_256_ecb(); break; - default: tor_assert(0); // LCOV_EXCL_LINE - } - EVP_EncryptInit(&cipher->key.evp, c, key, NULL); - cipher->using_evp = 1; - } else { - AES_set_encrypt_key(key, key_bits,&cipher->key.aes); - cipher->using_evp = 0; + const EVP_CIPHER *c = *(EVP_CIPHER**) cipher_; + switch (key_bits) { + case 128: c = aes128ecb; break; + case 192: c = aes192ecb; break; + case 256: c = aes256ecb; break; + default: tor_assert_unreached(); } - -#ifdef USING_COUNTER_VARS - cipher->counter0 = 0; - cipher->counter1 = 0; - cipher->counter2 = 0; - cipher->counter3 = 0; -#endif /* defined(USING_COUNTER_VARS) */ - - memset(cipher->ctr_buf.buf, 0, sizeof(cipher->ctr_buf.buf)); - - cipher->pos = 0; - - memset(cipher->buf, 0, sizeof(cipher->buf)); + aes_raw_t *cipherp = *cipher_; + EVP_CIPHER_CTX *cipher = (EVP_CIPHER_CTX *)cipherp; + int r = EVP_CipherInit(cipher, c, key, NULL, encrypt); + tor_assert(r == 1); + EVP_CIPHER_CTX_set_padding(cipher, 0); } -/** Release storage held by cipher +/** + * Release storage held by 'cipher'. */ void -aes_cipher_free_(aes_cnt_cipher_t *cipher) +aes_raw_free_(aes_raw_t *cipher_) { - if (!cipher) + if (!cipher_) return; - if (cipher->using_evp) { - EVP_CIPHER_CTX_cleanup(&cipher->key.evp); - } - memwipe(cipher, 0, sizeof(aes_cnt_cipher_t)); - tor_free(cipher); -} - -#if defined(USING_COUNTER_VARS) -#define UPDATE_CTR_BUF(c, n) STMT_BEGIN \ - (c)->ctr_buf.buf32[3-(n)] = htonl((c)->counter ## n); \ - STMT_END + EVP_CIPHER_CTX *cipher = (EVP_CIPHER_CTX *)cipher_; +#ifdef OPENSSL_1_1_API + EVP_CIPHER_CTX_reset(cipher); #else -#define UPDATE_CTR_BUF(c, n) -#endif /* defined(USING_COUNTER_VARS) */ - -/* Helper function to use EVP with openssl's counter-mode wrapper. */ -static void -evp_block128_fn(const uint8_t in[16], - uint8_t out[16], - const void *key) -{ - EVP_CIPHER_CTX *ctx = (void*)key; - int inl=16, outl=16; - EVP_EncryptUpdate(ctx, out, &outl, in, inl); + EVP_CIPHER_CTX_cleanup(cipher); +#endif + EVP_CIPHER_CTX_free(cipher); } - -/** Encrypt len bytes from input, storing the results in place. - * Uses the key in cipher, and advances the counter by len bytes - * as it encrypts. +#define aes_raw_free(cipher) \ + FREE_AND_NULL(aes_raw_t, aes_raw_free_, (cipher)) +/** + * Encrypt a single 16-byte block with 'cipher', + * which must have been initialized for encryption. */ void -aes_crypt_inplace(aes_cnt_cipher_t *cipher, char *data, size_t len) +aes_raw_encrypt(const aes_raw_t *cipher, uint8_t *block) { - /* Note that the "128" below refers to the length of the counter, - * not the length of the AES key. */ - if (cipher->using_evp) { - /* In openssl 1.0.0, there's an if'd out EVP_aes_128_ctr in evp.h. If - * it weren't disabled, it might be better just to use that. - */ - CRYPTO_ctr128_encrypt((const unsigned char *)data, - (unsigned char *)data, - len, - &cipher->key.evp, - cipher->ctr_buf.buf, - cipher->buf, - &cipher->pos, - evp_block128_fn); - } else { - AES_ctr128_encrypt((const unsigned char *)data, - (unsigned char *)data, - len, - &cipher->key.aes, - cipher->ctr_buf.buf, - cipher->buf, - &cipher->pos); - } + int outl = 16; + int r = EVP_EncryptUpdate((EVP_CIPHER_CTX *)cipher, block, &outl, block, 16); + tor_assert(r == 1); + tor_assert(outl == 16); } - -/** Reset the 128-bit counter of cipher to the 16-bit big-endian value - * in iv. */ -static void -aes_set_iv(aes_cnt_cipher_t *cipher, const uint8_t *iv) +/** + * Decrypt a single 16-byte block with 'cipher', + * which must have been initialized for decryption. + */ +void +aes_raw_decrypt(const aes_raw_t *cipher, uint8_t *block) { -#ifdef USING_COUNTER_VARS - cipher->counter3 = tor_ntohl(get_uint32(iv)); - cipher->counter2 = tor_ntohl(get_uint32(iv+4)); - cipher->counter1 = tor_ntohl(get_uint32(iv+8)); - cipher->counter0 = tor_ntohl(get_uint32(iv+12)); -#endif /* defined(USING_COUNTER_VARS) */ - cipher->pos = 0; - memcpy(cipher->ctr_buf.buf, iv, 16); + int outl = 16; + int r = EVP_DecryptUpdate((EVP_CIPHER_CTX *)cipher, block, &outl, block, 16); + tor_assert(r == 1); + tor_assert(outl == 16); } - -#endif /* defined(USE_EVP_AES_CTR) */ diff -Nru tor-0.4.7.16/src/lib/crypt_ops/compat_openssl.h tor-0.4.9.6/src/lib/crypt_ops/compat_openssl.h --- tor-0.4.7.16/src/lib/crypt_ops/compat_openssl.h 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/lib/crypt_ops/compat_openssl.h 2026-03-25 14:30:34.000000000 +0000 @@ -20,33 +20,13 @@ * \brief compatibility definitions for working with different openssl forks **/ -#if !defined(LIBRESSL_VERSION_NUMBER) && \ - OPENSSL_VERSION_NUMBER < OPENSSL_V_SERIES(1,0,1) -#error "We require OpenSSL >= 1.0.1" -#endif - -#if OPENSSL_VERSION_NUMBER >= OPENSSL_V_SERIES(1,1,0) && \ - ! defined(LIBRESSL_VERSION_NUMBER) -/* We define this macro if we're trying to build with the majorly refactored - * API in OpenSSL 1.1 */ -#define OPENSSL_1_1_API -#endif /* OPENSSL_VERSION_NUMBER >= OPENSSL_V_SERIES(1,1,0) && ... */ - -#ifndef OPENSSL_1_1_API -#define OpenSSL_version(v) SSLeay_version(v) -#define tor_OpenSSL_version_num() SSLeay() +/* LibreSSL claims to be OpenSSL 2.0 but lacks this OpenSSL 1.1 API. */ +#if defined(LIBRESSL_VERSION_NUMBER) #define RAND_OpenSSL() RAND_SSLeay() -#define STATE_IS_SW_SERVER_HELLO(st) \ - (((st) == SSL3_ST_SW_SRVR_HELLO_A) || \ - ((st) == SSL3_ST_SW_SRVR_HELLO_B)) #define OSSL_HANDSHAKE_STATE int -#define CONST_IF_OPENSSL_1_1_API -#else /* defined(OPENSSL_1_1_API) */ +#endif + #define tor_OpenSSL_version_num() OpenSSL_version_num() -#define STATE_IS_SW_SERVER_HELLO(st) \ - ((st) == TLS_ST_SW_SRVR_HELLO) -#define CONST_IF_OPENSSL_1_1_API const -#endif /* !defined(OPENSSL_1_1_API) */ #endif /* defined(ENABLE_OPENSSL) */ diff -Nru tor-0.4.7.16/src/lib/crypt_ops/crypto_dh.c tor-0.4.9.6/src/lib/crypt_ops/crypto_dh.c --- tor-0.4.7.16/src/lib/crypt_ops/crypto_dh.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/lib/crypt_ops/crypto_dh.c 2026-03-25 14:30:34.000000000 +0000 @@ -21,16 +21,20 @@ /** Our DH 'g' parameter */ const unsigned DH_GENERATOR = 2; -/** This is the 1024-bit safe prime that Apache uses for its DH stuff; see - * modules/ssl/ssl_engine_dh.c; Apache also uses a generator of 2 with this - * prime. +/** This is ffdhe2048 from RFC 7919. */ const char TLS_DH_PRIME[] = - "D67DE440CBBBDC1936D693D34AFD0AD50C84D239A45F520BB88174CB98" - "BCE951849F912E639C72FB13B4B4D7177E16D55AC179BA420B2A29FE324A" - "467A635E81FF5901377BEDDCFD33168A461AAD3B72DAE8860078045B07A7" - "DBCA7874087D1510EA9FCC9DDD330507DD62DB88AEAA747DE0F4D6E2BD68" - "B0E7393E0F24218EB3"; + "FFFFFFFFFFFFFFFFADF85458A2BB4A9AAFDC5620273D3CF1" + "D8B9C583CE2D3695A9E13641146433FBCC939DCE249B3EF9" + "7D2FE363630C75D8F681B202AEC4617AD3DF1ED5D5FD6561" + "2433F51F5F066ED0856365553DED1AF3B557135E7F57C935" + "984F0C70E0E68B77E2A689DAF3EFE8721DF158A136ADE735" + "30ACCA4F483A797ABC0AB182B324FB61D108A94BB2C8E3FB" + "B96ADAB760D7F4681D4F42A3DE394DF4AE56EDE76372BB19" + "0B07A7C8EE0A6D709E02FCE1CDF7E2ECC03404CD28342F61" + "9172FE9CE98583FF8E4F1232EEF28183C3FE3B1B4C6FAD73" + "3BB5FCBC2EC22005C58EF1837D1683B2C6F34A26C1B2EFFA" + "886B423861285C97FFFFFFFFFFFFFFFF"; /** * This is from rfc2409, section 6.2. It's a safe prime, and * supposedly it equals: diff -Nru tor-0.4.7.16/src/lib/crypt_ops/crypto_dh.h tor-0.4.9.6/src/lib/crypt_ops/crypto_dh.h --- tor-0.4.7.16/src/lib/crypt_ops/crypto_dh.h 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/lib/crypt_ops/crypto_dh.h 2026-03-25 14:30:34.000000000 +0000 @@ -61,4 +61,6 @@ void crypto_dh_free_all_nss(void); #endif +#define DH_TLS_KEY_BITS 2048 + #endif /* !defined(TOR_CRYPTO_DH_H) */ diff -Nru tor-0.4.7.16/src/lib/crypt_ops/crypto_dh_nss.c tor-0.4.9.6/src/lib/crypt_ops/crypto_dh_nss.c --- tor-0.4.7.16/src/lib/crypt_ops/crypto_dh_nss.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/lib/crypt_ops/crypto_dh_nss.c 2026-03-25 14:30:34.000000000 +0000 @@ -25,7 +25,7 @@ static int dh_initialized = 0; static SECKEYDHParams tls_dh_param, circuit_dh_param; -static unsigned char tls_dh_prime_data[DH1024_KEY_LEN]; +static unsigned char tls_dh_prime_data[DH2048_KEY_LEN]; static unsigned char circuit_dh_prime_data[DH1024_KEY_LEN]; static unsigned char dh_generator_data[1]; @@ -39,7 +39,7 @@ r = base16_decode((char*)tls_dh_prime_data, sizeof(tls_dh_prime_data), TLS_DH_PRIME, strlen(TLS_DH_PRIME)); - tor_assert(r == DH1024_KEY_LEN); + tor_assert(r == DH2048_KEY_LEN); r = base16_decode((char*)circuit_dh_prime_data, sizeof(circuit_dh_prime_data), OAKLEY_PRIME_2, strlen(OAKLEY_PRIME_2)); @@ -47,7 +47,7 @@ dh_generator_data[0] = DH_GENERATOR; tls_dh_param.prime.data = tls_dh_prime_data; - tls_dh_param.prime.len = DH1024_KEY_LEN; + tls_dh_param.prime.len = DH2048_KEY_LEN; tls_dh_param.base.data = dh_generator_data; tls_dh_param.base.len = 1; diff -Nru tor-0.4.7.16/src/lib/crypt_ops/crypto_dh_openssl.c tor-0.4.9.6/src/lib/crypt_ops/crypto_dh_openssl.c --- tor-0.4.7.16/src/lib/crypt_ops/crypto_dh_openssl.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/lib/crypt_ops/crypto_dh_openssl.c 2026-03-25 14:30:34.000000000 +0000 @@ -27,7 +27,8 @@ #include #ifndef ENABLE_NSS -static int tor_check_dh_key(int severity, const BIGNUM *bn); +static int tor_check_dh_key(int severity, const BIGNUM *bn, + const BIGNUM *dh_p); /** A structure to hold the first half (x, g^x) of a Diffie-Hellman handshake * while we're waiting for the second.*/ @@ -60,7 +61,7 @@ /* Copy into a temporary DH object, just so that DH_check() can be called. */ if (!(dh = DH_new())) goto out; -#ifdef OPENSSL_1_1_API + BIGNUM *dh_p, *dh_g; if (!(dh_p = BN_dup(p))) goto out; @@ -68,12 +69,6 @@ goto out; if (!DH_set0_pqg(dh, dh_p, NULL, dh_g)) goto out; -#else /* !defined(OPENSSL_1_1_API) */ - if (!(dh->p = BN_dup(p))) - goto out; - if (!(dh->g = BN_dup(g))) - goto out; -#endif /* defined(OPENSSL_1_1_API) */ /* Perform the validation. */ int codes = 0; @@ -223,19 +218,12 @@ goto err; } -#ifdef OPENSSL_1_1_API - if (!DH_set0_pqg(res_dh, dh_p, NULL, dh_g)) { goto err; } if (!DH_set_length(res_dh, DH_PRIVATE_KEY_BITS)) goto err; -#else /* !defined(OPENSSL_1_1_API) */ - res_dh->p = dh_p; - res_dh->g = dh_g; - res_dh->length = DH_PRIVATE_KEY_BITS; -#endif /* defined(OPENSSL_1_1_API) */ return res_dh; @@ -276,9 +264,6 @@ int crypto_dh_generate_public(crypto_dh_t *dh) { -#ifndef OPENSSL_1_1_API - again: -#endif if (!DH_generate_key(dh->dh)) { /* LCOV_EXCL_START * To test this we would need some way to tell openssl to break DH. */ @@ -286,32 +271,19 @@ return -1; /* LCOV_EXCL_STOP */ } -#ifdef OPENSSL_1_1_API + /* OpenSSL 1.1.x doesn't appear to let you regenerate a DH key, without * recreating the DH object. I have no idea what sort of aliasing madness * can occur here, so do the check, and just bail on failure. */ const BIGNUM *pub_key, *priv_key; DH_get0_key(dh->dh, &pub_key, &priv_key); - if (tor_check_dh_key(LOG_WARN, pub_key)<0) { + if (tor_check_dh_key(LOG_WARN, pub_key, DH_get0_p(dh->dh))<0) { log_warn(LD_CRYPTO, "Weird! Our own DH key was invalid. I guess once-in-" "the-universe chances really do happen. Treating as a failure."); return -1; } -#else /* !defined(OPENSSL_1_1_API) */ - if (tor_check_dh_key(LOG_WARN, dh->dh->pub_key)<0) { - /* LCOV_EXCL_START - * If this happens, then openssl's DH implementation is busted. */ - log_warn(LD_CRYPTO, "Weird! Our own DH key was invalid. I guess once-in-" - "the-universe chances really do happen. Trying again."); - /* Free and clear the keys, so OpenSSL will actually try again. */ - BN_clear_free(dh->dh->pub_key); - BN_clear_free(dh->dh->priv_key); - dh->dh->pub_key = dh->dh->priv_key = NULL; - goto again; - /* LCOV_EXCL_STOP */ - } -#endif /* defined(OPENSSL_1_1_API) */ + return 0; } @@ -327,22 +299,14 @@ const BIGNUM *dh_pub; -#ifdef OPENSSL_1_1_API const BIGNUM *dh_priv; DH_get0_key(dh->dh, &dh_pub, &dh_priv); -#else - dh_pub = dh->dh->pub_key; -#endif /* defined(OPENSSL_1_1_API) */ if (!dh_pub) { if (crypto_dh_generate_public(dh)<0) return -1; else { -#ifdef OPENSSL_1_1_API DH_get0_key(dh->dh, &dh_pub, &dh_priv); -#else - dh_pub = dh->dh->pub_key; -#endif } } @@ -351,7 +315,7 @@ tor_assert(bytes >= 0); if (pubkey_len < (size_t)bytes) { log_warn(LD_CRYPTO, - "Weird! pubkey_len (%d) was smaller than DH1024_KEY_LEN (%d)", + "Weird! pubkey_len (%d) was smaller than key length (%d)", (int) pubkey_len, bytes); return -1; } @@ -367,21 +331,19 @@ * See http://www.cl.cam.ac.uk/ftp/users/rja14/psandqs.ps.gz for some tips. */ static int -tor_check_dh_key(int severity, const BIGNUM *bn) +tor_check_dh_key(int severity, const BIGNUM *bn, const BIGNUM *dh_p) { BIGNUM *x; char *s; tor_assert(bn); x = BN_new(); tor_assert(x); - if (BUG(!dh_param_p)) - crypto_dh_init(); //LCOV_EXCL_LINE we already checked whether we did this. BN_set_word(x, 1); if (BN_cmp(bn,x)<=0) { log_fn(severity, LD_CRYPTO, "DH key must be at least 2."); goto err; } - BN_copy(x,dh_param_p); + BN_copy(x,dh_p); BN_sub_word(x, 1); if (BN_cmp(bn,x)>=0) { log_fn(severity, LD_CRYPTO, "DH key must be at most p-2."); @@ -425,7 +387,7 @@ if (!(pubkey_bn = BN_bin2bn((const unsigned char*)pubkey, (int)pubkey_len, NULL))) goto error; - if (tor_check_dh_key(severity, pubkey_bn)<0) { + if (tor_check_dh_key(severity, pubkey_bn, DH_get0_p(dh->dh))<0) { /* Check for invalid public keys. */ log_fn(severity, LD_CRYPTO,"Rejected invalid g^x"); goto error; diff -Nru tor-0.4.7.16/src/lib/crypt_ops/crypto_hkdf.c tor-0.4.9.6/src/lib/crypt_ops/crypto_hkdf.c --- tor-0.4.7.16/src/lib/crypt_ops/crypto_hkdf.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/lib/crypt_ops/crypto_hkdf.c 2026-03-25 14:30:34.000000000 +0000 @@ -20,11 +20,8 @@ #ifdef ENABLE_OPENSSL #include #include - -#if defined(HAVE_ERR_LOAD_KDF_STRINGS) #include -#define HAVE_OPENSSL_HKDF 1 -#endif +#define HAVE_OPENSSL_HKDF #endif /* defined(ENABLE_OPENSSL) */ #include diff -Nru tor-0.4.7.16/src/lib/crypt_ops/crypto_init.c tor-0.4.9.6/src/lib/crypt_ops/crypto_init.c --- tor-0.4.7.16/src/lib/crypt_ops/crypto_init.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/lib/crypt_ops/crypto_init.c 2026-03-25 14:30:34.000000000 +0000 @@ -26,6 +26,7 @@ #include "lib/crypt_ops/crypto_options_st.h" #include "lib/conf/conftypes.h" #include "lib/log/util_bug.h" +#include "ext/polyval/polyval.h" #include "lib/subsys/subsys.h" @@ -69,6 +70,8 @@ crypto_nss_early_init(0); #endif + polyval_detect_implementation(); + if (crypto_seed_rng() < 0) return -1; if (crypto_init_siphash_key() < 0) diff -Nru tor-0.4.7.16/src/lib/crypt_ops/crypto_nss_mgt.c tor-0.4.9.6/src/lib/crypt_ops/crypto_nss_mgt.c --- tor-0.4.7.16/src/lib/crypt_ops/crypto_nss_mgt.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/lib/crypt_ops/crypto_nss_mgt.c 2026-03-25 14:30:34.000000000 +0000 @@ -16,6 +16,7 @@ #include "lib/log/util_bug.h" #include "lib/string/printf.h" +DISABLE_GCC_WARNING("-Wredundant-decls") DISABLE_GCC_WARNING("-Wstrict-prototypes") #include #include @@ -25,6 +26,7 @@ #include #include ENABLE_GCC_WARNING("-Wstrict-prototypes") +ENABLE_GCC_WARNING("-Wredundant-decls") const char * crypto_nss_get_version_str(void) diff -Nru tor-0.4.7.16/src/lib/crypt_ops/crypto_openssl_mgt.c tor-0.4.9.6/src/lib/crypt_ops/crypto_openssl_mgt.c --- tor-0.4.7.16/src/lib/crypt_ops/crypto_openssl_mgt.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/lib/crypt_ops/crypto_openssl_mgt.c 2026-03-25 14:30:34.000000000 +0000 @@ -40,19 +40,13 @@ #include -#ifndef NEW_THREAD_API -/** A number of preallocated mutexes for use by OpenSSL. */ -static tor_mutex_t **openssl_mutexes_ = NULL; -/** How many mutexes have we allocated for use by OpenSSL? */ -static int n_openssl_mutexes_ = 0; -#endif /* !defined(NEW_THREAD_API) */ +#ifdef OPENSSL_NO_ENGINE +/* Android's OpenSSL seems to have removed all of its Engine support. */ +#define DISABLE_ENGINES +#endif /** Declare STATIC functions */ STATIC char * parse_openssl_version_str(const char *raw_version); -#ifndef NEW_THREAD_API -STATIC void openssl_locking_cb_(int mode, int n, const char *file, int line); -STATIC void tor_set_openssl_thread_id(CRYPTO_THREADID *threadid); -#endif /** Log all pending crypto errors at level severity. Use * doing to describe our current activities. @@ -101,12 +95,7 @@ const char * crypto_openssl_get_version_str(void) { -#ifdef OPENSSL_VERSION const int query = OPENSSL_VERSION; -#else - /* This old name was changed around OpenSSL 1.1.0 */ - const int query = SSLEAY_VERSION; -#endif /* defined(OPENSSL_VERSION) */ if (crypto_openssl_version_str == NULL) { const char *raw_version = OpenSSL_version(query); @@ -115,8 +104,6 @@ return crypto_openssl_version_str; } -#undef QUERY_OPENSSL_VERSION - static char *crypto_openssl_header_version_str = NULL; /* Return a human-readable version of the compile-time openssl version * number. */ @@ -137,46 +124,11 @@ #endif #endif /* !defined(COCCI) */ -#ifndef NEW_THREAD_API -/** Helper: OpenSSL uses this callback to manipulate mutexes. */ -STATIC void -openssl_locking_cb_(int mode, int n, const char *file, int line) -{ - (void)file; - (void)line; - if (!openssl_mutexes_) - /* This is not a really good fix for the - * "release-freed-lock-from-separate-thread-on-shutdown" problem, but - * it can't hurt. */ - return; - if (mode & CRYPTO_LOCK) - tor_mutex_acquire(openssl_mutexes_[n]); - else - tor_mutex_release(openssl_mutexes_[n]); -} - -STATIC void -tor_set_openssl_thread_id(CRYPTO_THREADID *threadid) -{ - CRYPTO_THREADID_set_numeric(threadid, tor_get_thread_id()); -} -#endif /* !defined(NEW_THREAD_API) */ - /** Helper: Construct mutexes, and set callbacks to help OpenSSL handle being * multithreaded. Returns 0. */ static int setup_openssl_threading(void) { -#ifndef NEW_THREAD_API - int i; - int n = CRYPTO_num_locks(); - n_openssl_mutexes_ = n; - openssl_mutexes_ = tor_calloc(n, sizeof(tor_mutex_t *)); - for (i=0; i < n; ++i) - openssl_mutexes_[i] = tor_mutex_new(); - CRYPTO_set_locking_callback(openssl_locking_cb_); - CRYPTO_THREADID_set_callback(tor_set_openssl_thread_id); -#endif /* !defined(NEW_THREAD_API) */ return 0; } @@ -186,39 +138,16 @@ { 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_; - tor_mutex_t **ms = openssl_mutexes_; - int i; - openssl_mutexes_ = NULL; - n_openssl_mutexes_ = 0; - for (i=0;i=3.5 would be ideal.", + OPENSSL_VERSION_TEXT); + } +#endif + if (useAccel > 0) { if (crypto_openssl_init_engines(accelName, accelDir) < 0) return -1; @@ -389,9 +323,6 @@ return -1; } - evaluate_evp_for_aes(-1); - evaluate_ctr_for_aes(); - return 0; } @@ -399,35 +330,13 @@ void crypto_openssl_thread_cleanup(void) { -#ifndef NEW_THREAD_API - ERR_remove_thread_state(NULL); -#endif } /** Clean up global resources held by openssl. */ void crypto_openssl_global_cleanup(void) { -#ifndef OPENSSL_1_1_API - EVP_cleanup(); -#endif -#ifndef NEW_THREAD_API - ERR_remove_thread_state(NULL); -#endif -#ifndef OPENSSL_1_1_API - ERR_free_strings(); -#endif - -#ifndef DISABLE_ENGINES -#ifndef OPENSSL_1_1_API - ENGINE_cleanup(); -#endif -#endif - CONF_modules_unload(1); -#ifndef OPENSSL_1_1_API - CRYPTO_cleanup_all_ex_data(); -#endif crypto_openssl_free_all(); } diff -Nru tor-0.4.7.16/src/lib/crypt_ops/crypto_openssl_mgt.h tor-0.4.9.6/src/lib/crypt_ops/crypto_openssl_mgt.h --- tor-0.4.7.16/src/lib/crypt_ops/crypto_openssl_mgt.h 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/lib/crypt_ops/crypto_openssl_mgt.h 2026-03-25 14:30:34.000000000 +0000 @@ -49,27 +49,6 @@ #define OPENSSL_V_SERIES(a,b,c) \ OPENSSL_VER((a),(b),(c),0,0) -#ifdef OPENSSL_NO_ENGINE -/* Android's OpenSSL seems to have removed all of its Engine support. */ -#define DISABLE_ENGINES -#endif - -#if OPENSSL_VERSION_NUMBER >= OPENSSL_VER(1,1,0,0,5) && \ - !defined(LIBRESSL_VERSION_NUMBER) -/* OpenSSL as of 1.1.0pre4 has an "new" thread API, which doesn't require - * setting up various callbacks. - * - * OpenSSL 1.1.0pre4 has a messed up `ERR_remove_thread_state()` prototype, - * while the previous one was restored in pre5, and the function made a no-op - * (along with a deprecated annotation, which produces a compiler warning). - * - * While it is possible to support all three versions of the thread API, - * a version that existed only for one snapshot pre-release is kind of - * pointless, so let's not. - */ -#define NEW_THREAD_API -#endif /* OPENSSL_VERSION_NUMBER >= OPENSSL_VER(1,1,0,0,5) && ... */ - void crypto_openssl_log_errors(int severity, const char *doing); /* global openssl state */ diff -Nru tor-0.4.7.16/src/lib/crypt_ops/crypto_rsa_openssl.c tor-0.4.9.6/src/lib/crypt_ops/crypto_rsa_openssl.c --- tor-0.4.7.16/src/lib/crypt_ops/crypto_rsa_openssl.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/lib/crypt_ops/crypto_rsa_openssl.c 2026-03-25 14:30:34.000000000 +0000 @@ -47,16 +47,12 @@ int crypto_pk_key_is_private(const crypto_pk_t *k) { -#ifdef OPENSSL_1_1_API if (!k || !k->key) return 0; const BIGNUM *p, *q; RSA_get0_factors(k->key, &p, &q); return p != NULL; /* XXX/yawning: Should we check q? */ -#else /* !defined(OPENSSL_1_1_API) */ - return k && k->key && k->key->p; -#endif /* defined(OPENSSL_1_1_API) */ } /** used by tortls.c: wrap an RSA* in a crypto_pk_t. Takes ownership of @@ -212,12 +208,8 @@ const BIGNUM *e; -#ifdef OPENSSL_1_1_API const BIGNUM *n, *d; RSA_get0_key(env->key, &n, &e, &d); -#else - e = env->key->e; -#endif /* defined(OPENSSL_1_1_API) */ return BN_is_word(e, TOR_RSA_EXPONENT); } @@ -242,16 +234,9 @@ const BIGNUM *a_n, *a_e; const BIGNUM *b_n, *b_e; -#ifdef OPENSSL_1_1_API const BIGNUM *a_d, *b_d; RSA_get0_key(a->key, &a_n, &a_e, &a_d); RSA_get0_key(b->key, &b_n, &b_e, &b_d); -#else - a_n = a->key->n; - a_e = a->key->e; - b_n = b->key->n; - b_e = b->key->e; -#endif /* defined(OPENSSL_1_1_API) */ tor_assert(a_n != NULL && a_e != NULL); tor_assert(b_n != NULL && b_e != NULL); @@ -279,7 +264,6 @@ tor_assert(env); tor_assert(env->key); -#ifdef OPENSSL_1_1_API /* It's so stupid that there's no other way to check that n is valid * before calling RSA_bits(). */ @@ -288,10 +272,6 @@ tor_assert(n != NULL); return RSA_bits(env->key); -#else /* !defined(OPENSSL_1_1_API) */ - tor_assert(env->key->n); - return BN_num_bits(env->key->n); -#endif /* defined(OPENSSL_1_1_API) */ } /** Increase the reference count of env, and return it. @@ -572,9 +552,7 @@ rsa_private_key_too_long(RSA *rsa, int max_bits) { const BIGNUM *n, *e, *p, *q, *d, *dmp1, *dmq1, *iqmp; -#ifdef OPENSSL_1_1_API -#if OPENSSL_VERSION_NUMBER >= OPENSSL_V_SERIES(1,1,1) n = RSA_get0_n(rsa); e = RSA_get0_e(rsa); p = RSA_get0_p(rsa); @@ -583,24 +561,9 @@ dmp1 = RSA_get0_dmp1(rsa); dmq1 = RSA_get0_dmq1(rsa); iqmp = RSA_get0_iqmp(rsa); -#else /* !(OPENSSL_VERSION_NUMBER >= OPENSSL_V_SERIES(1,1,1)) */ - /* The accessors above did not exist in openssl 1.1.0. */ - p = q = dmp1 = dmq1 = iqmp = NULL; - RSA_get0_key(rsa, &n, &e, &d); -#endif /* OPENSSL_VERSION_NUMBER >= OPENSSL_V_SERIES(1,1,1) */ if (RSA_bits(rsa) > max_bits) return true; -#else /* !defined(OPENSSL_1_1_API) */ - n = rsa->n; - e = rsa->e; - p = rsa->p; - q = rsa->q; - d = rsa->d; - dmp1 = rsa->dmp1; - dmq1 = rsa->dmq1; - iqmp = rsa->iqmp; -#endif /* defined(OPENSSL_1_1_API) */ if (n && BN_num_bits(n) > max_bits) return true; diff -Nru tor-0.4.7.16/src/lib/crypt_ops/include.am tor-0.4.9.6/src/lib/crypt_ops/include.am --- tor-0.4.7.16/src/lib/crypt_ops/include.am 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/lib/crypt_ops/include.am 2026-03-25 14:30:34.000000000 +0000 @@ -15,14 +15,14 @@ src/lib/crypt_ops/crypto_format.c \ src/lib/crypt_ops/crypto_hkdf.c \ src/lib/crypt_ops/crypto_init.c \ - src/lib/crypt_ops/crypto_ope.c \ + src/lib/crypt_ops/crypto_ope.c \ src/lib/crypt_ops/crypto_pwbox.c \ src/lib/crypt_ops/crypto_rand.c \ src/lib/crypt_ops/crypto_rand_fast.c \ src/lib/crypt_ops/crypto_rand_numeric.c \ src/lib/crypt_ops/crypto_rsa.c \ src/lib/crypt_ops/crypto_s2k.c \ - src/lib/crypt_ops/crypto_util.c \ + src/lib/crypt_ops/crypto_util.c \ src/lib/crypt_ops/digestset.c if USE_NSS @@ -75,5 +75,5 @@ src/lib/crypt_ops/crypto_rsa.h \ src/lib/crypt_ops/crypto_s2k.h \ src/lib/crypt_ops/crypto_sys.h \ - src/lib/crypt_ops/crypto_util.h \ + src/lib/crypt_ops/crypto_util.h \ src/lib/crypt_ops/digestset.h diff -Nru tor-0.4.7.16/src/lib/ctime/include.am tor-0.4.9.6/src/lib/ctime/include.am --- tor-0.4.7.16/src/lib/ctime/include.am 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/lib/ctime/include.am 2026-03-25 14:30:34.000000000 +0000 @@ -13,8 +13,8 @@ # ADD_C_FILE: INSERT SOURCES HERE. src_lib_libtor_ctime_a_SOURCES = \ - $(mulodi4_source) \ - src/ext/csiphash.c \ + $(mulodi4_source) \ + src/ext/csiphash.c \ src/lib/ctime/di_ops.c src_lib_libtor_ctime_testing_a_SOURCES = \ diff -Nru tor-0.4.7.16/src/lib/defs/dh_sizes.h tor-0.4.9.6/src/lib/defs/dh_sizes.h --- tor-0.4.7.16/src/lib/defs/dh_sizes.h 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/lib/defs/dh_sizes.h 2026-03-25 14:30:34.000000000 +0000 @@ -16,7 +16,10 @@ #ifndef TOR_DH_SIZES_H #define TOR_DH_SIZES_H -/** Length of our legacy DH keys. */ +/** Length of our legacy DH keys, in bytes. */ #define DH1024_KEY_LEN (1024/8) +/** Length of our current TLS DH keys, in bytes. */ +#define DH2048_KEY_LEN (2048/8) + #endif /* !defined(TOR_DH_SIZES_H) */ diff -Nru tor-0.4.7.16/src/lib/defs/include.am tor-0.4.9.6/src/lib/defs/include.am --- tor-0.4.7.16/src/lib/defs/include.am 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/lib/defs/include.am 2026-03-25 14:30:34.000000000 +0000 @@ -1,8 +1,8 @@ # ADD_C_FILE: INSERT HEADERS HERE. -noinst_HEADERS += \ - src/lib/defs/dh_sizes.h \ +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/time.h \ src/lib/defs/x25519_sizes.h diff -Nru tor-0.4.7.16/src/lib/dispatch/dispatch_cfg.c tor-0.4.9.6/src/lib/dispatch/dispatch_cfg.c --- tor-0.4.7.16/src/lib/dispatch/dispatch_cfg.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/lib/dispatch/dispatch_cfg.c 2026-03-25 14:30:34.000000000 +0000 @@ -93,7 +93,7 @@ /** * Associate a receiver with a message ID. Multiple receivers may be - * associated with a single messasge ID. + * associated with a single message ID. * * Return 0 on success, on failure. **/ diff -Nru tor-0.4.7.16/src/lib/dispatch/dispatch_cfg_st.h tor-0.4.9.6/src/lib/dispatch/dispatch_cfg_st.h --- tor-0.4.7.16/src/lib/dispatch/dispatch_cfg_st.h 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/lib/dispatch/dispatch_cfg_st.h 2026-03-25 14:30:34.000000000 +0000 @@ -24,9 +24,9 @@ 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. */ + /** A list of dispatch_typefns_t, indexed by msg_type_id_t. */ struct smartlist_t *fns_by_type; - /** A list of dispatch_typefns_t, indexed by msg_t. */ + /** A list of dispatch_rcv_t, indexed by msg_t. */ struct smartlist_t *recv_by_msg; }; diff -Nru tor-0.4.7.16/src/lib/dispatch/include.am tor-0.4.9.6/src/lib/dispatch/include.am --- tor-0.4.7.16/src/lib/dispatch/include.am 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/lib/dispatch/include.am 2026-03-25 14:30:34.000000000 +0000 @@ -20,8 +20,8 @@ # 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_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 -Nru tor-0.4.7.16/src/lib/err/backtrace.h tor-0.4.9.6/src/lib/err/backtrace.h --- tor-0.4.7.16/src/lib/err/backtrace.h 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/lib/err/backtrace.h 2026-03-25 14:30:34.000000000 +0000 @@ -29,6 +29,14 @@ #define log_backtrace(sev, dom, msg) \ log_backtrace_impl((sev), (dom), (msg), tor_log) +#define log_backtrace_once(sev, dom, msg) STMT_BEGIN \ + static int backtrace_logged__ = 0; \ + if (!backtrace_logged__) { \ + backtrace_logged__ = 1; \ + log_backtrace((sev), (dom), (msg)); \ + } \ + STMT_END + #ifdef BACKTRACE_PRIVATE #if defined(HAVE_EXECINFO_H) && defined(HAVE_BACKTRACE) && \ defined(HAVE_BACKTRACE_SYMBOLS_FD) && defined(HAVE_SIGACTION) diff -Nru tor-0.4.7.16/src/lib/evloop/compat_libevent.c tor-0.4.9.6/src/lib/evloop/compat_libevent.c --- tor-0.4.7.16/src/lib/evloop/compat_libevent.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/lib/evloop/compat_libevent.c 2026-03-25 14:30:34.000000000 +0000 @@ -137,10 +137,8 @@ (void)torcfg; { - int attempts = 0; struct event_config *cfg; - ++attempts; cfg = event_config_new(); tor_assert(cfg); diff -Nru tor-0.4.7.16/src/lib/evloop/compat_libevent.h tor-0.4.9.6/src/lib/evloop/compat_libevent.h --- tor-0.4.7.16/src/lib/evloop/compat_libevent.h 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/lib/evloop/compat_libevent.h 2026-03-25 14:30:34.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (c) 2009-2021, The Tor Project, Inc. */ +/* Copyright (c) 2009-2024, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -19,6 +19,7 @@ void suppress_libevent_log_msg(const char *msg); #define tor_event_new event_new +#define tor_event_del event_del #define tor_evtimer_new evtimer_new #define tor_evsignal_new evsignal_new #define tor_evdns_add_server_port(sock, tcp, cb, data) \ diff -Nru tor-0.4.7.16/src/lib/evloop/token_bucket.c tor-0.4.9.6/src/lib/evloop/token_bucket.c --- tor-0.4.7.16/src/lib/evloop/token_bucket.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/lib/evloop/token_bucket.c 2026-03-25 14:30:34.000000000 +0000 @@ -58,7 +58,7 @@ } /** - * Adust a preexisting token bucket to respect the new configuration + * Adjust a preexisting token bucket to respect the new configuration * cfg, by decreasing its current level if needed. */ void token_bucket_raw_adjust(token_bucket_raw_t *bucket, @@ -111,7 +111,9 @@ return becomes_empty; } -/** Convert a rate in bytes per second to a rate in bytes per step */ +/** Convert a rate in bytes per second to a rate in bytes per step. + * This is used for the 'rw' style (tick based) token buckets but not for + * the 'ctr' style buckets which count seconds. */ STATIC uint32_t rate_per_sec_to_rate_per_step(uint32_t rate) { @@ -130,18 +132,18 @@ /** * Initialize a token bucket in *bucket, set up to allow rate * bytes per second, with a maximum burst of burst bytes. The bucket - * is created such that now_ts is the current timestamp. The bucket - * starts out full. + * is created such that now_ts_stamp is the current time in coarse stamp + * units. The bucket starts out full. */ void token_bucket_rw_init(token_bucket_rw_t *bucket, uint32_t rate, uint32_t burst, - uint32_t now_ts) + uint32_t now_ts_stamp) { memset(bucket, 0, sizeof(token_bucket_rw_t)); token_bucket_rw_adjust(bucket, rate, burst); - token_bucket_rw_reset(bucket, now_ts); + token_bucket_rw_reset(bucket, now_ts_stamp); } /** @@ -161,56 +163,54 @@ } /** - * Reset bucket to be full, as of timestamp now_ts. + * Reset bucket to be full, as of timestamp now_ts_stamp. */ void token_bucket_rw_reset(token_bucket_rw_t *bucket, - uint32_t now_ts) + uint32_t now_ts_stamp) { token_bucket_raw_reset(&bucket->read_bucket, &bucket->cfg); token_bucket_raw_reset(&bucket->write_bucket, &bucket->cfg); - bucket->last_refilled_at_timestamp = now_ts; + bucket->last_refilled_at_timestamp = now_ts_stamp; } /** * Refill bucket as appropriate, given that the current timestamp - * is now_ts. + * is now_ts_stamp in coarse timestamp units. * * Return a bitmask containing TB_READ iff read bucket was empty and became * nonempty, and TB_WRITE iff the write bucket was empty and became nonempty. */ int token_bucket_rw_refill(token_bucket_rw_t *bucket, - uint32_t now_ts) + uint32_t now_ts_stamp) { 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 0; - } - const uint32_t elapsed_steps = elapsed_ticks / TICKS_PER_STEP; + (now_ts_stamp - bucket->last_refilled_at_timestamp); + int flags = 0; - if (!elapsed_steps) { - /* Note that if less than one whole step elapsed, we don't advance the - * time in last_refilled_at. That's intentional: we want to make sure - * that we add some bytes to it eventually. */ - return 0; + /* Skip over updates that include an overflow or a very large jump. + * This can happen for platform specific reasons, such as the old ~48 + * day windows timer. */ + if (elapsed_ticks <= UINT32_MAX/4) { + const uint32_t elapsed_steps = elapsed_ticks / TICKS_PER_STEP; + + if (!elapsed_steps) { + /* Note that if less than one whole step elapsed, we don't advance the + * time in last_refilled_at. That's intentional: we want to make sure + * that we add some bytes to it eventually. */ + return 0; + } + + if (token_bucket_raw_refill_steps(&bucket->read_bucket, + &bucket->cfg, elapsed_steps)) + flags |= TB_READ; + if (token_bucket_raw_refill_steps(&bucket->write_bucket, + &bucket->cfg, elapsed_steps)) + flags |= TB_WRITE; } - int flags = 0; - if (token_bucket_raw_refill_steps(&bucket->read_bucket, - &bucket->cfg, elapsed_steps)) - flags |= TB_READ; - if (token_bucket_raw_refill_steps(&bucket->write_bucket, - &bucket->cfg, elapsed_steps)) - flags |= TB_WRITE; - - bucket->last_refilled_at_timestamp = now_ts; + bucket->last_refilled_at_timestamp = now_ts_stamp; return flags; } @@ -259,15 +259,17 @@ /** 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. */ + * such that now_ts_sec is the current timestamp. The bucket starts + * out full. Note that these counters use seconds instead of approximate + * milliseconds, in order to allow a lower minimum rate than the rw counters. + */ void token_bucket_ctr_init(token_bucket_ctr_t *bucket, uint32_t rate, - uint32_t burst, uint32_t now_ts) + uint32_t burst, uint32_t now_ts_sec) { memset(bucket, 0, sizeof(token_bucket_ctr_t)); token_bucket_ctr_adjust(bucket, rate, burst); - token_bucket_ctr_reset(bucket, now_ts); + token_bucket_ctr_reset(bucket, now_ts_sec); } /** Change the configured rate and burst of the given token bucket object in @@ -280,31 +282,28 @@ token_bucket_raw_adjust(&bucket->counter, &bucket->cfg); } -/** Reset bucket to be full, as of timestamp now_ts. */ +/** Reset bucket to be full, as of timestamp now_ts_sec. */ void -token_bucket_ctr_reset(token_bucket_ctr_t *bucket, uint32_t now_ts) +token_bucket_ctr_reset(token_bucket_ctr_t *bucket, uint32_t now_ts_sec) { token_bucket_raw_reset(&bucket->counter, &bucket->cfg); - bucket->last_refilled_at_timestamp = now_ts; + bucket->last_refilled_at_timestamp = now_ts_sec; } /** Refill bucket as appropriate, given that the current timestamp is - * now_ts. */ + * now_ts_sec in seconds. */ void -token_bucket_ctr_refill(token_bucket_ctr_t *bucket, uint32_t now_ts) +token_bucket_ctr_refill(token_bucket_ctr_t *bucket, uint32_t now_ts_sec) { - 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; - } + const uint32_t elapsed_sec = + (now_ts_sec - bucket->last_refilled_at_timestamp); - token_bucket_raw_refill_steps(&bucket->counter, &bucket->cfg, - elapsed_ticks); - bucket->last_refilled_at_timestamp = now_ts; + /* Are we detecting a rollover or a similar extremely large jump? This + * shouldn't generally happen, but if it does for whatever (possibly + * platform-specific) reason, ignore it. */ + if (elapsed_sec <= UINT32_MAX/4) { + token_bucket_raw_refill_steps(&bucket->counter, &bucket->cfg, + elapsed_sec); + } + bucket->last_refilled_at_timestamp = now_ts_sec; } diff -Nru tor-0.4.7.16/src/lib/evloop/token_bucket.h tor-0.4.9.6/src/lib/evloop/token_bucket.h --- tor-0.4.7.16/src/lib/evloop/token_bucket.h 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/lib/evloop/token_bucket.h 2026-03-25 14:30:34.000000000 +0000 @@ -66,19 +66,19 @@ void token_bucket_rw_init(token_bucket_rw_t *bucket, uint32_t rate, uint32_t burst, - uint32_t now_ts); + uint32_t now_ts_stamp); void token_bucket_rw_adjust(token_bucket_rw_t *bucket, uint32_t rate, uint32_t burst); void token_bucket_rw_reset(token_bucket_rw_t *bucket, - uint32_t now_ts); + uint32_t now_ts_stamp); #define TB_READ 1 #define TB_WRITE 2 int token_bucket_rw_refill(token_bucket_rw_t *bucket, - uint32_t now_ts); + uint32_t now_ts_stamp); int token_bucket_rw_dec_read(token_bucket_rw_t *bucket, ssize_t n); @@ -114,11 +114,11 @@ } token_bucket_ctr_t; void token_bucket_ctr_init(token_bucket_ctr_t *bucket, uint32_t rate, - uint32_t burst, uint32_t now_ts); + uint32_t burst, uint32_t now_ts_sec); 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); +void token_bucket_ctr_reset(token_bucket_ctr_t *bucket, uint32_t now_ts_sec); +void token_bucket_ctr_refill(token_bucket_ctr_t *bucket, uint32_t now_ts_sec); static inline bool token_bucket_ctr_dec(token_bucket_ctr_t *bucket, ssize_t n) diff -Nru tor-0.4.7.16/src/lib/evloop/workqueue.c tor-0.4.9.6/src/lib/evloop/workqueue.c --- tor-0.4.7.16/src/lib/evloop/workqueue.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/lib/evloop/workqueue.c 2026-03-25 14:30:34.000000000 +0000 @@ -1,5 +1,5 @@ -/* copyright (c) 2013-2015, The Tor Project, Inc. */ +/* copyright (c) 2013-2024, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -20,7 +20,10 @@ * The main thread can also queue an "update" that will be handled by all the * workers. This is useful for updating state that all the workers share. * - * In Tor today, there is currently only one thread pool, used in cpuworker.c. + * In Tor today, there is currently only one thread pool, managed + * in cpuworker.c and handling a variety of types of work, from the original + * "onion skin" circuit handshakes, to consensus diff computation, to + * client-side onion service PoW generation. */ #include "orconfig.h" @@ -35,6 +38,7 @@ #include "lib/net/alertsock.h" #include "lib/net/socket.h" #include "lib/thread/threads.h" +#include "lib/time/compat_time.h" #include "ext/tor_queue.h" #include @@ -75,6 +79,8 @@ /** Number of elements in threads. */ int n_threads; + /** Number of elements to be created in threads. */ + int n_threads_max; /** Mutex to protect all the above fields. */ tor_mutex_t lock; @@ -85,6 +91,11 @@ void *(*new_thread_state_fn)(void*); void (*free_thread_state_fn)(void*); void *new_thread_state_arg; + + /** Used for signalling the worker threads to exit. */ + int exit; + /** Mutex for controlling worker threads' startup and exit. */ + tor_mutex_t control_lock; }; /** Used to put a workqueue_priority_t value into a bitfield. */ @@ -140,6 +151,12 @@ } workerthread_t; static void queue_reply(replyqueue_t *queue, workqueue_entry_t *work); +static void workerthread_free_(workerthread_t *thread); +#define workerthread_free(thread) \ + FREE_AND_NULL(workerthread_t, workerthread_free_, (thread)) +static void replyqueue_free_(replyqueue_t *queue); +#define replyqueue_free(queue) \ + FREE_AND_NULL(replyqueue_t, replyqueue_free_, (queue)) /** Allocate and return a new workqueue_entry_t, set up to run the function * fn in the worker thread, and reply_fn in the main @@ -261,13 +278,43 @@ static void worker_thread_main(void *thread_) { + static int n_worker_threads_running = 0; + static unsigned long control_lock_owner = 0; workerthread_t *thread = thread_; threadpool_t *pool = thread->in_pool; workqueue_entry_t *work; workqueue_reply_t result; + tor_mutex_acquire(&pool->control_lock); + log_debug(LD_GENERAL, "Worker thread %u/%u has started [TID: %lu].", + n_worker_threads_running + 1, pool->n_threads_max, + tor_get_thread_id()); + + if (++n_worker_threads_running == pool->n_threads_max) + tor_cond_signal_one(&pool->condition); + + tor_mutex_release(&pool->control_lock); + + /* Wait until all worker threads have started. + * pool->lock must be prelocked here. */ tor_mutex_acquire(&pool->lock); + + if (control_lock_owner == 0) { + /* pool->control_lock stays locked. This is required for the main thread + * to wait for the worker threads to exit on shutdown, so the memory + * clean up won't begin before all threads have exited. */ + tor_mutex_acquire(&pool->control_lock); + control_lock_owner = tor_get_thread_id(); + } + + log_debug(LD_GENERAL, "Worker thread has entered the work loop [TID: %lu].", + tor_get_thread_id()); + while (1) { + /* Exit thread when signaled to exit */ + if (pool->exit) + goto exit; + /* lock must be held at this point. */ while (worker_thread_has_work(thread)) { /* lock must be held at this point. */ @@ -281,11 +328,12 @@ workqueue_reply_t r = update_fn(thread->state, arg); - if (r != WQ_RPL_REPLY) { - return; - } - tor_mutex_acquire(&pool->lock); + + /* We may need to exit the thread. */ + if (r != WQ_RPL_REPLY) + goto exit; + continue; } work = worker_thread_extract_next_work(thread); @@ -300,11 +348,11 @@ /* Queue the reply for the main thread. */ queue_reply(thread->reply_queue, work); - /* We may need to exit the thread. */ - if (result != WQ_RPL_REPLY) { - return; - } tor_mutex_acquire(&pool->lock); + + /* We may need to exit the thread. */ + if (result != WQ_RPL_REPLY) + goto exit; } /* At this point the lock is held, and there is no work in this thread's * queue. */ @@ -316,6 +364,30 @@ log_warn(LD_GENERAL, "Fail tor_cond_wait."); } } + +exit: + /* At this point pool->lock must be held */ + + log_debug(LD_GENERAL, "Worker thread %u/%u has exited [TID: %lu].", + pool->n_threads_max - n_worker_threads_running + 1, + pool->n_threads_max, tor_get_thread_id()); + + if (tor_get_thread_id() == control_lock_owner) { + /* Wait for the other worker threads to exit so we + * can safely unlock pool->control_lock. */ + while (n_worker_threads_running > 1) { + tor_mutex_release(&pool->lock); + tor_sleep_msec(10); + tor_mutex_acquire(&pool->lock); + } + + tor_mutex_release(&pool->lock); + /* Let the main thread know, the last worker thread has exited. */ + tor_mutex_release(&pool->control_lock); + } else { + --n_worker_threads_running; + tor_mutex_release(&pool->lock); + } } /** Put a reply on the reply queue. The reply must not currently be on @@ -352,7 +424,7 @@ //LCOV_EXCL_START tor_assert_nonfatal_unreached(); log_err(LD_GENERAL, "Can't launch worker thread."); - tor_free(thr); + workerthread_free(thr); return NULL; //LCOV_EXCL_STOP } @@ -361,6 +433,15 @@ } /** + * Free up the resources allocated by a worker thread. + */ +static void +workerthread_free_(workerthread_t *thread) +{ + tor_free(thread); +} + +/** * Queue an item of work for a thread in a thread pool. The function * fn will be run in a worker thread, and will receive as arguments the * thread's state object, and the provided object arg. It must return @@ -498,12 +579,17 @@ if (n > MAX_THREADS) n = MAX_THREADS; + tor_mutex_acquire(&pool->control_lock); tor_mutex_acquire(&pool->lock); if (pool->n_threads < n) pool->threads = tor_reallocarray(pool->threads, sizeof(workerthread_t*), n); + int status = 0; + pool->n_threads_max = n; + log_debug(LD_GENERAL, "Starting worker threads..."); + while (pool->n_threads < n) { /* For half of our threads, we'll choose lower priorities permissively; * for the other half, we'll stick more strictly to higher priorities. @@ -518,16 +604,80 @@ //LCOV_EXCL_START tor_assert_nonfatal_unreached(); pool->free_thread_state_fn(state); - tor_mutex_release(&pool->lock); - return -1; + status = -1; + goto check_status; //LCOV_EXCL_STOP } thr->index = pool->n_threads; pool->threads[pool->n_threads++] = thr; } + + struct timeval tv = {.tv_sec = 30, .tv_usec = 0}; + + /* Wait for the last launched thread to confirm us, it has started. + * Wait max 30 seconds */ + status = tor_cond_wait(&pool->condition, &pool->control_lock, &tv); + +check_status: + switch (status) { + case 0: + log_debug(LD_GENERAL, "Starting worker threads finished."); + break; + case -1: + log_warn(LD_GENERAL, "Failed to confirm worker threads' start up."); + break; + case 1: + log_warn(LD_GENERAL, "Failed to confirm worker threads' " + "start up after timeout."); + FALLTHROUGH; + default: + status = -1; + } + + log_debug(LD_GENERAL, "Signaled the worker threads to enter the work loop."); + + /* If we had an error, let the worker threads (if any) exit directly. */ + if (status != 0) { + pool->exit = 1; + log_debug(LD_GENERAL, "Signaled the worker threads to exit..."); + } + + /* Let worker threads enter the work loop. */ tor_mutex_release(&pool->lock); + /* Let one of the worker threads take the ownership of pool->control_lock. + * This is required for compliance with POSIX. */ + tor_mutex_release(&pool->control_lock); - return 0; + return status; +} + +/** Stop all worker threads */ +static void +threadpool_stop_threads(threadpool_t *pool) +{ + tor_mutex_acquire(&pool->lock); + + if (pool->exit == 0) { + /* Signal the worker threads to exit */ + pool->exit = 1; + /* If worker threads are waiting for work, let them continue to exit */ + tor_cond_signal_all(&pool->condition); + + log_debug(LD_GENERAL, "Signaled worker threads to exit. " + "Waiting for them to exit..."); + } + + tor_mutex_release(&pool->lock); + + /* Wait until all worker threads have exited. + * pool->control_lock must be prelocked here. */ + tor_mutex_acquire(&pool->control_lock); + /* Unlock required, else main thread hangs on mutex uninit. */ + tor_mutex_release(&pool->control_lock); + + /* If this message appears in the log before all threads have confirmed + * their exit, then pool->control_lock wasn't prelocked for some reason. */ + log_debug(LD_GENERAL, "All worker threads have exited."); } /** @@ -548,6 +698,9 @@ pool = tor_malloc_zero(sizeof(threadpool_t)); tor_mutex_init_nonrecursive(&pool->lock); tor_cond_init(&pool->condition); + tor_mutex_init_nonrecursive(&pool->control_lock); + pool->exit = 0; + unsigned i; for (i = WORKQUEUE_PRIORITY_FIRST; i <= WORKQUEUE_PRIORITY_LAST; ++i) { TOR_TAILQ_INIT(&pool->work[i]); @@ -561,9 +714,7 @@ if (threadpool_start_threads(pool, n_threads) < 0) { //LCOV_EXCL_START tor_assert_nonfatal_unreached(); - tor_cond_uninit(&pool->condition); - tor_mutex_uninit(&pool->lock); - tor_free(pool); + threadpool_free(pool); return NULL; //LCOV_EXCL_STOP } @@ -571,6 +722,61 @@ return pool; } +/** + * Free up the resources allocated by worker threads, worker thread pool, ... + */ +void +threadpool_free_(threadpool_t *pool) +{ + if (!pool) + return; + + threadpool_stop_threads(pool); + + log_debug(LD_GENERAL, "Beginning to clean up..."); + + tor_cond_uninit(&pool->condition); + tor_mutex_uninit(&pool->lock); + tor_mutex_uninit(&pool->control_lock); + + if (pool->threads) { + for (int i = 0; i != pool->n_threads; ++i) + workerthread_free(pool->threads[i]); + + tor_free(pool->threads); + } + + if (pool->update_args) { + if (!pool->free_update_arg_fn) + log_warn(LD_GENERAL, "Freeing pool->update_args not possible. " + "pool->free_update_arg_fn is not set."); + else + pool->free_update_arg_fn(pool->update_args); + } + + if (pool->reply_event) { + if (tor_event_del(pool->reply_event) == -1) + log_warn(LD_GENERAL, "libevent error: deleting reply event failed."); + else + tor_event_free(pool->reply_event); + } + + if (pool->reply_queue) + replyqueue_free(pool->reply_queue); + + if (pool->new_thread_state_arg) { + if (!pool->free_thread_state_fn) + log_warn(LD_GENERAL, "Freeing pool->new_thread_state_arg not possible. " + "pool->free_thread_state_fn is not set."); + else + pool->free_thread_state_fn(pool->new_thread_state_arg); + } + + tor_free(pool); + + log_debug(LD_GENERAL, "Cleanup finished."); +} + /** Return the reply queue associated with a given thread pool. */ replyqueue_t * threadpool_get_replyqueue(threadpool_t *tp) @@ -590,7 +796,7 @@ rq = tor_malloc_zero(sizeof(replyqueue_t)); if (alert_sockets_create(&rq->alert, alertsocks_flags) < 0) { //LCOV_EXCL_START - tor_free(rq); + replyqueue_free(rq); return NULL; //LCOV_EXCL_STOP } @@ -601,6 +807,26 @@ return rq; } +/** + * Free up the resources allocated by a reply queue. + */ +static void +replyqueue_free_(replyqueue_t *queue) +{ + if (!queue) + return; + + workqueue_entry_t *work; + + while (!TOR_TAILQ_EMPTY(&queue->answers)) { + work = TOR_TAILQ_FIRST(&queue->answers); + TOR_TAILQ_REMOVE(&queue->answers, work, next_work); + workqueue_entry_free(work); + } + + tor_free(queue); +} + /** Internal: Run from the libevent mainloop when there is work to handle in * the reply queue handler. */ static void diff -Nru tor-0.4.7.16/src/lib/evloop/workqueue.h tor-0.4.9.6/src/lib/evloop/workqueue.h --- tor-0.4.7.16/src/lib/evloop/workqueue.h 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/lib/evloop/workqueue.h 2026-03-25 14:30:34.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2021, The Tor Project, Inc. */ +/* Copyright (c) 2013-2024, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -58,6 +58,9 @@ void *(*new_thread_state_fn)(void*), void (*free_thread_state_fn)(void*), void *arg); +void threadpool_free_(threadpool_t *tp); +#define threadpool_free(pool) \ + FREE_AND_NULL(threadpool_t, threadpool_free_, (pool)) replyqueue_t *threadpool_get_replyqueue(threadpool_t *tp); replyqueue_t *replyqueue_new(uint32_t alertsocks_flags); diff -Nru tor-0.4.7.16/src/lib/fdio/fdio.c tor-0.4.9.6/src/lib/fdio/fdio.c --- tor-0.4.7.16/src/lib/fdio/fdio.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/lib/fdio/fdio.c 2026-03-25 14:30:34.000000000 +0000 @@ -14,6 +14,9 @@ #ifdef HAVE_UNISTD_H #include #endif +#ifdef HAVE_FCNTL_H +#include +#endif #ifdef _WIN32 #include #endif @@ -118,3 +121,28 @@ } return 0; } + +#if defined(HAVE_PIPE2) && defined(O_CLOEXEC) +int +tor_pipe_cloexec(int pipefd[2]) +{ + return pipe2(pipefd, O_CLOEXEC); +} +#elif defined(HAVE_PIPE) && defined(FD_CLOEXEC) +int +tor_pipe_cloexec(int pipefd[2]) +{ + if (pipe(pipefd)) { + return -1; + } + if (fcntl(pipefd[0], F_SETFD, FD_CLOEXEC)) { + return -1; + } + if (fcntl(pipefd[1], F_SETFD, FD_CLOEXEC)) { + return -1; + } + return 0; +} +#else +/* Intentionally leave symbol undefined. */ +#endif diff -Nru tor-0.4.7.16/src/lib/fdio/fdio.h tor-0.4.9.6/src/lib/fdio/fdio.h --- tor-0.4.7.16/src/lib/fdio/fdio.h 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/lib/fdio/fdio.h 2026-03-25 14:30:34.000000000 +0000 @@ -22,5 +22,6 @@ int tor_fd_seekend(int fd); int tor_ftruncate(int fd); int write_all_to_fd_minimal(int fd, const char *buf, size_t count); +int tor_pipe_cloexec(int pipefd[2]); #endif /* !defined(TOR_FDIO_H) */ diff -Nru tor-0.4.7.16/src/lib/fdio/include.am tor-0.4.9.6/src/lib/fdio/include.am --- tor-0.4.7.16/src/lib/fdio/include.am 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/lib/fdio/include.am 2026-03-25 14:30:34.000000000 +0000 @@ -15,5 +15,5 @@ src_lib_libtor_fdio_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS) # ADD_C_FILE: INSERT HEADERS HERE. -noinst_HEADERS += \ +noinst_HEADERS += \ src/lib/fdio/fdio.h diff -Nru tor-0.4.7.16/src/lib/fs/conffile.c tor-0.4.9.6/src/lib/fs/conffile.c --- tor-0.4.7.16/src/lib/fs/conffile.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/lib/fs/conffile.c 2026-03-25 14:30:34.000000000 +0000 @@ -54,7 +54,7 @@ opened_lst, 1, NULL, config_process_include); } -/** Return a list of paths obtained when expading globs in pattern. +/** Return a list of paths obtained when expanding globs in pattern. * If pattern has no globs, return a list with pattern in it. * If opened_files is provided, add paths opened by glob to it. * Return NULL on failure. */ diff -Nru tor-0.4.7.16/src/lib/fs/files.c tor-0.4.9.6/src/lib/fs/files.c --- tor-0.4.7.16/src/lib/fs/files.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/lib/fs/files.c 2026-03-25 14:30:34.000000000 +0000 @@ -85,7 +85,8 @@ FILE * tor_fopen_cloexec(const char *path, const char *mode) { - FILE *result = fopen(path, mode); + const char *p = sandbox_intern_string(path); + FILE *result = fopen(p, mode); #ifdef FD_CLOEXEC if (result != NULL) { if (fcntl(fileno(result), F_SETFD, FD_CLOEXEC) == -1) { @@ -572,9 +573,10 @@ /** * Read the contents of the open file fd presuming it is a FIFO * (or similar) file descriptor for which the size of the file isn't - * known ahead of time. Return NULL on failure, and a NUL-terminated - * string on success. On success, set sz_out to the number of - * bytes read. + * known ahead of time. + * Return NULL on failure, and a NUL-terminated string on success. + * On success, set sz_out to the number of bytes read (not including + * the final NULL, which wasn't read from fd). */ char * read_file_to_str_until_eof(int fd, size_t max_bytes_to_read, size_t *sz_out) diff -Nru tor-0.4.7.16/src/lib/fs/files.h tor-0.4.9.6/src/lib/fs/files.h --- tor-0.4.7.16/src/lib/fs/files.h 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/lib/fs/files.h 2026-03-25 14:30:34.000000000 +0000 @@ -29,6 +29,10 @@ #endif #endif /* defined(_WIN32) */ +#if HAVE_FCNTL_H +#include +#endif + #ifndef O_BINARY #define O_BINARY 0 #endif diff -Nru tor-0.4.7.16/src/lib/fs/path.c tor-0.4.9.6/src/lib/fs/path.c --- tor-0.4.7.16/src/lib/fs/path.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/lib/fs/path.c 2026-03-25 14:30:34.000000000 +0000 @@ -108,7 +108,8 @@ rest = strlen(filename)>=2?(filename+2):""; } else { #ifdef HAVE_PWD_H - char *username, *slash; + char *username; + const char *slash; slash = strchr(filename, '/'); if (slash) username = tor_strndup(filename+1,slash-filename-1); diff -Nru tor-0.4.7.16/src/lib/geoip/geoip.c tor-0.4.9.6/src/lib/geoip/geoip.c --- tor-0.4.7.16/src/lib/geoip/geoip.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/lib/geoip/geoip.c 2026-03-25 14:30:34.000000000 +0000 @@ -387,7 +387,7 @@ * be less than geoip_get_n_countries(). To decode it, call * geoip_get_country_name(). */ -int +STATIC int geoip_get_country_by_ipv4(uint32_t ipaddr) { geoip_ipv4_entry_t *ent; @@ -403,7 +403,7 @@ * 0 for the 'unknown country'. The return value will always be less than * geoip_get_n_countries(). To decode it, call geoip_get_country_name(). */ -int +STATIC int geoip_get_country_by_ipv6(const struct in6_addr *addr) { geoip_ipv6_entry_t *ent; diff -Nru tor-0.4.7.16/src/lib/geoip/geoip.h tor-0.4.9.6/src/lib/geoip/geoip.h --- tor-0.4.7.16/src/lib/geoip/geoip.h 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/lib/geoip/geoip.h 2026-03-25 14:30:34.000000000 +0000 @@ -21,14 +21,14 @@ #ifdef GEOIP_PRIVATE STATIC int geoip_parse_entry(const char *line, sa_family_t family); STATIC void clear_geoip_db(void); + +STATIC int geoip_get_country_by_ipv4(uint32_t ipaddr); +STATIC int geoip_get_country_by_ipv6(const struct in6_addr *addr); #endif /* defined(GEOIP_PRIVATE) */ struct in6_addr; struct tor_addr_t; -int geoip_get_country_by_ipv4(uint32_t ipaddr); -int geoip_get_country_by_ipv6(const struct in6_addr *addr); - /** A per-country GeoIP record. */ typedef struct geoip_country_t { /** A nul-terminated two-letter country-code. */ diff -Nru tor-0.4.7.16/src/lib/geoip/include.am tor-0.4.9.6/src/lib/geoip/include.am --- tor-0.4.7.16/src/lib/geoip/include.am 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/lib/geoip/include.am 2026-03-25 14:30:34.000000000 +0000 @@ -15,5 +15,5 @@ # ADD_C_FILE: INSERT HEADERS HERE. noinst_HEADERS += \ - src/lib/geoip/geoip.h \ + src/lib/geoip/geoip.h \ src/lib/geoip/country.h diff -Nru tor-0.4.7.16/src/lib/lock/include.am tor-0.4.9.6/src/lib/lock/include.am --- tor-0.4.7.16/src/lib/lock/include.am 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/lib/lock/include.am 2026-03-25 14:30:34.000000000 +0000 @@ -22,5 +22,5 @@ src_lib_libtor_lock_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS) # ADD_C_FILE: INSERT HEADERS HERE. -noinst_HEADERS += \ +noinst_HEADERS += \ src/lib/lock/compat_mutex.h diff -Nru tor-0.4.7.16/src/lib/log/log.c tor-0.4.9.6/src/lib/log/log.c --- tor-0.4.7.16/src/lib/log/log.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/lib/log/log.c 2026-03-25 14:30:34.000000000 +0000 @@ -33,6 +33,7 @@ #define LOG_PRIVATE #include "lib/log/log.h" #include "lib/log/log_sys.h" +#include "lib/log/util_bug.h" #include "lib/version/git_revision.h" #include "lib/log/ratelim.h" #include "lib/lock/compat_mutex.h" @@ -706,6 +707,8 @@ const char *format, ...) { va_list ap; + if ((domain & LD_BUG) && (severity >= LOG_WARN)) + tor_bug_increment_count_(); if (severity > log_global_min_severity_) return; va_start(ap,format); @@ -718,6 +721,8 @@ { va_list ap; char *m; + if ((domain & LD_BUG) && (severity >= LOG_WARN)) + tor_bug_increment_count_(); if (severity > log_global_min_severity_) return; m = rate_limit_log(ratelim, approx_time()); @@ -912,6 +917,7 @@ { if (!log_mutex_initialized) { tor_mutex_init(&log_mutex); + tor_bug_init_counter(); log_mutex_initialized = 1; } #ifdef __GNUC__ diff -Nru tor-0.4.7.16/src/lib/log/log_sys.c tor-0.4.9.6/src/lib/log/log_sys.c --- tor-0.4.7.16/src/lib/log/log_sys.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/lib/log/log_sys.c 2026-03-25 14:30:34.000000000 +0000 @@ -11,11 +11,16 @@ #include "lib/log/escape.h" #include "lib/log/log.h" #include "lib/log/log_sys.h" +#include "lib/log/util_bug.h" +#include "lib/metrics/metrics_store.h" + +static metrics_store_t *the_store; static int subsys_logging_initialize(void) { init_logging(0); + the_store = metrics_store_new(); return 0; } @@ -26,6 +31,29 @@ escaped(NULL); } +static const smartlist_t * +logging_metrics_get_stores(void) +{ + static smartlist_t *stores_list = NULL; + + metrics_store_reset(the_store); + + metrics_store_entry_t *sentry = metrics_store_add( + the_store, + METRICS_TYPE_COUNTER, + METRICS_NAME(bug_reached_count), + "Total number of BUG() and similar assertion reached", + 0, NULL); + metrics_store_entry_update(sentry, tor_bug_get_count()); + + if (!stores_list) { + stores_list = smartlist_new(); + smartlist_add(stores_list, the_store); + } + + return stores_list; +} + const subsys_fns_t sys_logging = { .name = "log", SUBSYS_DECLARE_LOCATION(), @@ -35,4 +63,5 @@ .level = -90, .initialize = subsys_logging_initialize, .shutdown = subsys_logging_shutdown, + .get_metrics = logging_metrics_get_stores, }; diff -Nru tor-0.4.7.16/src/lib/log/util_bug.c tor-0.4.9.6/src/lib/log/util_bug.c --- tor-0.4.7.16/src/lib/log/util_bug.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/lib/log/util_bug.c 2026-03-25 14:30:34.000000000 +0000 @@ -18,6 +18,7 @@ #endif #include "lib/malloc/malloc.h" #include "lib/string/printf.h" +#include "lib/thread/threads.h" #include #include @@ -101,6 +102,27 @@ tor_free(buf); } +static atomic_counter_t total_bug_reached; + +void +tor_bug_init_counter(void) +{ + atomic_counter_init(&total_bug_reached); +} + +/** Helper to update BUG count in metrics. */ +void +tor_bug_increment_count_(void) +{ + atomic_counter_add(&total_bug_reached, 1); +} + +size_t +tor_bug_get_count(void) +{ + return atomic_counter_get(&total_bug_reached); +} + /** Helper for tor_assert_nonfatal: report the assertion failure. */ void tor_bug_occurred_(const char *fname, unsigned int line, @@ -110,6 +132,11 @@ char *buf = NULL; const char *once_str = once ? " (Future instances of this warning will be silenced.)": ""; + if (! once) { + // _once assertions count from the macro directly so we count them as many + // times as they are reached, and not just once. + tor_bug_increment_count_(); + } if (! expr) { if (capturing_bugs()) { add_captured_bug("This line should not have been reached."); diff -Nru tor-0.4.7.16/src/lib/log/util_bug.h tor-0.4.9.6/src/lib/log/util_bug.h --- tor-0.4.7.16/src/lib/log/util_bug.h 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/lib/log/util_bug.h 2026-03-25 14:30:34.000000000 +0000 @@ -39,6 +39,7 @@ #include "orconfig.h" #include "lib/cc/compat_compiler.h" #include "lib/log/log.h" +#include "lib/smartlist_core/smartlist_core.h" #include "lib/testsupport/testsupport.h" /* Replace assert() with a variant that sends failures to the log before @@ -191,6 +192,7 @@ STMT_END #define tor_assert_nonfatal_unreached_once() STMT_BEGIN \ static int warning_logged__ = 0; \ + tor_bug_increment_count_(); \ if (!warning_logged__) { \ warning_logged__ = 1; \ tor_bug_occurred_(SHORT_FILE__, __LINE__, __func__, NULL, 1, NULL); \ @@ -198,10 +200,12 @@ STMT_END #define tor_assert_nonfatal_once(cond) STMT_BEGIN \ static int warning_logged__ = 0; \ - if (ASSERT_PREDICT_LIKELY_(cond)) { \ - } else if (!warning_logged__) { \ - warning_logged__ = 1; \ - tor_bug_occurred_(SHORT_FILE__, __LINE__, __func__, #cond, 1, NULL);\ + if (!ASSERT_PREDICT_LIKELY_(cond)) { \ + tor_bug_increment_count_(); \ + if (!warning_logged__) { \ + warning_logged__ = 1; \ + tor_bug_occurred_(SHORT_FILE__, __LINE__, __func__, #cond, 1, NULL);\ + } \ } \ STMT_END #define BUG(cond) \ @@ -215,18 +219,22 @@ if (( { \ static int var = 0; \ int bool_result = !!(cond); \ - if (bool_result && !var) { \ - var = 1; \ - tor_bug_occurred_(SHORT_FILE__, __LINE__, __func__, \ - ("!("#cond")"), 1, NULL); \ + if (bool_result) { \ + tor_bug_increment_count_(); \ + if (!var) { \ + var = 1; \ + tor_bug_occurred_(SHORT_FILE__, __LINE__, __func__, \ + ("!("#cond")"), 1, NULL); \ + } \ } \ bool_result; } )) #else /* !defined(__GNUC__) */ #define IF_BUG_ONCE__(cond,var) \ static int var = 0; \ if ((cond) ? \ - (var ? 1 : \ + (var ? (tor_bug_increment_count_(), 1) : \ (var=1, \ + tor_bug_increment_count_(), \ tor_bug_occurred_(SHORT_FILE__, __LINE__, __func__, \ ("!("#cond")"), 1, NULL), \ 1)) \ @@ -273,12 +281,15 @@ const char *func, const char *expr, const char *fmt, ...) CHECK_PRINTF(5,6); +void tor_bug_increment_count_(void); +size_t tor_bug_get_count(void); void tor_bug_occurred_(const char *fname, unsigned int line, const char *func, const char *expr, int once, const char *fmt, ...) CHECK_PRINTF(6,7); void tor_abort_(void) ATTR_NORETURN; +void tor_bug_init_counter(void); #ifdef _WIN32 #define SHORT_FILE__ (tor_fix_source_file(__FILE__)) diff -Nru tor-0.4.7.16/src/lib/malloc/malloc.h tor-0.4.9.6/src/lib/malloc/malloc.h --- tor-0.4.7.16/src/lib/malloc/malloc.h 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/lib/malloc/malloc.h 2026-03-25 14:30:34.000000000 +0000 @@ -11,6 +11,7 @@ #ifndef TOR_UTIL_MALLOC_H #define TOR_UTIL_MALLOC_H +#include #include #include #include "lib/cc/compat_compiler.h" @@ -45,6 +46,9 @@ #ifdef __GNUC__ #define tor_free(p) STMT_BEGIN \ typeof(&(p)) tor_free__tmpvar = &(p); \ + _Static_assert(!__builtin_types_compatible_p(typeof(*tor_free__tmpvar), \ + struct event *), \ + "use tor_event_free for struct event *"); \ raw_free(*tor_free__tmpvar); \ *tor_free__tmpvar=NULL; \ STMT_END diff -Nru tor-0.4.7.16/src/lib/math/include.am tor-0.4.9.6/src/lib/math/include.am --- tor-0.4.7.16/src/lib/math/include.am 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/lib/math/include.am 2026-03-25 14:30:34.000000000 +0000 @@ -7,7 +7,7 @@ # ADD_C_FILE: INSERT SOURCES HERE. src_lib_libtor_math_a_SOURCES = \ - src/lib/math/fp.c \ + src/lib/math/fp.c \ src/lib/math/laplace.c \ src/lib/math/prob_distr.c @@ -19,6 +19,6 @@ # ADD_C_FILE: INSERT HEADERS HERE. noinst_HEADERS += \ src/lib/math/fp.h \ - src/lib/math/laplace.h \ - src/lib/math/prob_distr.h \ + src/lib/math/laplace.h \ + src/lib/math/prob_distr.h \ src/lib/math/stats.h diff -Nru tor-0.4.7.16/src/lib/math/prob_distr.c tor-0.4.9.6/src/lib/math/prob_distr.c --- tor-0.4.7.16/src/lib/math/prob_distr.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/lib/math/prob_distr.c 2026-03-25 14:30:34.000000000 +0000 @@ -54,7 +54,7 @@ #ifndef COCCI /** Declare a function that downcasts from a generic dist struct to the actual - * subtype probablity distribution it represents. */ + * subtype probability distribution it represents. */ #define DECLARE_PROB_DISTR_DOWNCAST_FN(name) \ static inline \ const struct name##_t * \ diff -Nru tor-0.4.7.16/src/lib/math/stats.h tor-0.4.9.6/src/lib/math/stats.h --- tor-0.4.7.16/src/lib/math/stats.h 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/lib/math/stats.h 2026-03-25 14:30:34.000000000 +0000 @@ -25,7 +25,7 @@ /* If the average was not previously computed, return value. * The less than is because we have stupid C warning flags that * prevent exact comparison to 0.0, so we can't do an exact - * check for unitialized double values. Yay pedantry! + * check for uninitialized double values. Yay pedantry! * Love it when it introduces surprising edge case bugs like * this will. */ if (avg < 0.0000002) diff -Nru tor-0.4.7.16/src/lib/metrics/include.am tor-0.4.9.6/src/lib/metrics/include.am --- tor-0.4.7.16/src/lib/metrics/include.am 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/lib/metrics/include.am 2026-03-25 14:30:34.000000000 +0000 @@ -8,8 +8,8 @@ # ADD_C_FILE: INSERT SOURCES HERE. src_lib_libtor_metrics_a_SOURCES = \ src/lib/metrics/metrics_store.c \ - src/lib/metrics/metrics_store_entry.c \ - src/lib/metrics/metrics_common.c \ + src/lib/metrics/metrics_store_entry.c \ + src/lib/metrics/metrics_common.c \ src/lib/metrics/prometheus.c src_lib_libtor_metrics_testing_a_SOURCES = \ @@ -18,8 +18,8 @@ src_lib_libtor_metrics_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS) # ADD_C_FILE: INSERT HEADERS HERE. -noinst_HEADERS += \ - src/lib/metrics/metrics_store.h \ +noinst_HEADERS += \ + src/lib/metrics/metrics_store.h \ src/lib/metrics/metrics_store_entry.h \ src/lib/metrics/metrics_common.h \ src/lib/metrics/prometheus.h diff -Nru tor-0.4.7.16/src/lib/metrics/metrics_common.c tor-0.4.9.6/src/lib/metrics/metrics_common.c --- tor-0.4.7.16/src/lib/metrics/metrics_common.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/lib/metrics/metrics_common.c 2026-03-25 14:30:34.000000000 +0000 @@ -24,6 +24,8 @@ return "counter"; case METRICS_TYPE_GAUGE: return "gauge"; + case METRICS_TYPE_HISTOGRAM: + return "histogram"; default: tor_assert_unreached(); } diff -Nru tor-0.4.7.16/src/lib/metrics/metrics_common.h tor-0.4.9.6/src/lib/metrics/metrics_common.h --- tor-0.4.7.16/src/lib/metrics/metrics_common.h 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/lib/metrics/metrics_common.h 2026-03-25 14:30:34.000000000 +0000 @@ -10,6 +10,7 @@ #define TOR_LIB_METRICS_METRICS_COMMON_H #include "lib/cc/torint.h" +#include "lib/container/smartlist.h" /** Helper macro that must be used to construct the right namespaced metrics * name. A name is a string so stringify the result. */ @@ -28,8 +29,18 @@ METRICS_TYPE_COUNTER, /* Can go up or down. */ METRICS_TYPE_GAUGE, + /* Cumulative counters for multiple observation buckets. */ + METRICS_TYPE_HISTOGRAM, } metrics_type_t; +typedef struct metrics_histogram_bucket_t { + /* The value of the counter of this bucket. */ + uint64_t value; + /* Technically, this should be a floating point value, but in practice, we + * can make do with integer buckets. */ + int64_t bucket; +} metrics_histogram_bucket_t; + /** Metric counter object (METRICS_TYPE_COUNTER). */ typedef struct metrics_counter_t { uint64_t value; @@ -40,6 +51,18 @@ int64_t value; } metrics_gauge_t; +/** Metric histogram object (METRICS_TYPE_HISTOGRAM). */ +typedef struct metrics_histogram_t { + /* The observation buckets. */ + metrics_histogram_bucket_t *buckets; + /* The number of observation buckets. */ + size_t bucket_count; + /* The sum of all observations */ + int64_t sum; + /* The total number of observations */ + uint64_t count; +} metrics_histogram_t; + const char *metrics_type_to_str(const metrics_type_t type); /* Helpers. */ diff -Nru tor-0.4.7.16/src/lib/metrics/metrics_store.c tor-0.4.9.6/src/lib/metrics/metrics_store.c --- tor-0.4.7.16/src/lib/metrics/metrics_store.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/lib/metrics/metrics_store.c 2026-03-25 14:30:34.000000000 +0000 @@ -107,7 +107,9 @@ * unique identifier. The help string can be omitted. */ metrics_store_entry_t * metrics_store_add(metrics_store_t *store, metrics_type_t type, - const char *name, const char *help) + const char *name, const char *help, size_t bucket_count, + const int64_t *buckets) + { smartlist_t *entries; metrics_store_entry_t *entry; @@ -120,7 +122,7 @@ entries = smartlist_new(); strmap_set(store->entries, name, entries); } - entry = metrics_store_entry_new(type, name, help); + entry = metrics_store_entry_new(type, name, help, bucket_count, buckets); smartlist_add(entries, entry); return entry; diff -Nru tor-0.4.7.16/src/lib/metrics/metrics_store.h tor-0.4.9.6/src/lib/metrics/metrics_store.h --- tor-0.4.7.16/src/lib/metrics/metrics_store.h 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/lib/metrics/metrics_store.h 2026-03-25 14:30:34.000000000 +0000 @@ -26,8 +26,10 @@ /* Modifiers. */ metrics_store_entry_t *metrics_store_add(metrics_store_t *store, - metrics_type_t type, - const char *name, const char *help); + metrics_type_t type, const char *name, + const char *help, size_t bucket_count, + const int64_t *buckets); + void metrics_store_reset(metrics_store_t *store); /* Accessors. */ diff -Nru tor-0.4.7.16/src/lib/metrics/metrics_store_entry.c tor-0.4.9.6/src/lib/metrics/metrics_store_entry.c --- tor-0.4.7.16/src/lib/metrics/metrics_store_entry.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/lib/metrics/metrics_store_entry.c 2026-03-25 14:30:34.000000000 +0000 @@ -6,6 +6,7 @@ * @brief Metrics store entry which contains the gathered data. **/ +#include "metrics_common.h" #define METRICS_STORE_ENTRY_PRIVATE #include @@ -22,10 +23,11 @@ * Public API. */ -/** Return newly allocated store entry of type COUNTER. */ +/** Return newly allocated store entry of the specified type. */ metrics_store_entry_t * metrics_store_entry_new(const metrics_type_t type, const char *name, - const char *help) + const char *help, size_t bucket_count, + const int64_t *buckets) { metrics_store_entry_t *entry = tor_malloc_zero(sizeof(*entry)); @@ -38,6 +40,18 @@ entry->help = tor_strdup(help); } + if (type == METRICS_TYPE_HISTOGRAM && bucket_count > 0) { + tor_assert(buckets); + + entry->u.histogram.bucket_count = bucket_count; + entry->u.histogram.buckets = + tor_malloc_zero(sizeof(metrics_histogram_bucket_t) * bucket_count); + + for (size_t i = 0; i < bucket_count; ++i) { + entry->u.histogram.buckets[i].bucket = buckets[i]; + } + } + return entry; } @@ -52,6 +66,11 @@ smartlist_free(entry->labels); tor_free(entry->name); tor_free(entry->help); + + if (entry->type == METRICS_TYPE_HISTOGRAM) { + tor_free(entry->u.histogram.buckets); + } + tor_free(entry); } @@ -61,6 +80,11 @@ { tor_assert(entry); + /* Histogram values are updated using metrics_store_hist_entry_update */ + if (BUG(entry->type == METRICS_TYPE_HISTOGRAM)) { + return; + } + switch (entry->type) { case METRICS_TYPE_COUNTER: /* Counter can ONLY be positive. */ @@ -73,6 +97,43 @@ /* Gauge can increment or decrement. And can be positive or negative. */ entry->u.gauge.value += value; break; + case METRICS_TYPE_HISTOGRAM: + tor_assert_unreached(); + } +} + +/** Update a store entry with value for the specified observation obs. + * + * Note: entry **must** be a histogram. */ +void +metrics_store_hist_entry_update(metrics_store_entry_t *entry, + const int64_t value, const int64_t obs) +{ + if (BUG(entry->type != METRICS_TYPE_HISTOGRAM)) { + return; + } + + /* Counter can ONLY be positive for histograms. */ + if (BUG(value < 0)) { + return; + } + + /* If we're about to overflow or underflow the sum, reset all counters back + * to 0 before recording the observation. */ + if (PREDICT_UNLIKELY( + (obs > 0 && entry->u.histogram.sum > INT64_MAX - obs) || + (obs < 0 && entry->u.histogram.sum < INT64_MIN - obs))) { + metrics_store_entry_reset(entry); + } + + entry->u.histogram.count += value; + entry->u.histogram.sum += obs; + + for (size_t i = 0; i < entry->u.histogram.bucket_count; ++i) { + metrics_histogram_bucket_t *hb = &entry->u.histogram.buckets[i]; + if (obs <= hb->bucket) { + hb->value += value; + } } } @@ -81,8 +142,22 @@ metrics_store_entry_reset(metrics_store_entry_t *entry) { tor_assert(entry); - /* Everything back to 0. */ - memset(&entry->u, 0, sizeof(entry->u)); + + switch (entry->type) { + case METRICS_TYPE_COUNTER: FALLTHROUGH; + case METRICS_TYPE_GAUGE: + /* Everything back to 0. */ + memset(&entry->u, 0, sizeof(entry->u)); + break; + case METRICS_TYPE_HISTOGRAM: + for (size_t i = 0; i < entry->u.histogram.bucket_count; ++i) { + metrics_histogram_bucket_t *hb = &entry->u.histogram.buckets[i]; + hb->value = 0; + } + entry->u.histogram.sum = 0; + entry->u.histogram.count = 0; + break; + } } /** Return store entry value. */ @@ -91,6 +166,11 @@ { tor_assert(entry); + /* Histogram values are accessed using metrics_store_hist_entry_get_value. */ + if (BUG(entry->type == METRICS_TYPE_HISTOGRAM)) { + return 0; + } + switch (entry->type) { case METRICS_TYPE_COUNTER: if (entry->u.counter.value > INT64_MAX) { @@ -99,6 +179,9 @@ return entry->u.counter.value; case METRICS_TYPE_GAUGE: return entry->u.gauge.value; + case METRICS_TYPE_HISTOGRAM: + tor_assert_unreached(); + return 0; } // LCOV_EXCL_START @@ -106,6 +189,35 @@ // LCOV_EXCL_STOP } +/** Return store entry value for the specified bucket. + * + * Note: entry **must** be a histogram. */ +uint64_t +metrics_store_hist_entry_get_value(const metrics_store_entry_t *entry, + const int64_t bucket) +{ + tor_assert(entry); + + if (BUG(entry->type != METRICS_TYPE_HISTOGRAM)) { + return 0; + } + + for (size_t i = 0; i <= entry->u.histogram.bucket_count; ++i) { + metrics_histogram_bucket_t hb = entry->u.histogram.buckets[i]; + if (bucket == hb.bucket) { + if (hb.value > INT64_MAX) { + return INT64_MAX; + } else { + return hb.value; + } + } + } + + tor_assertf_nonfatal(false, "attempted to get the value of non-existent " + "bucket %" PRId64, bucket); + return 0; +} + /** Add a label into the given entry.*/ void metrics_store_entry_add_label(metrics_store_entry_t *entry, @@ -127,3 +239,60 @@ return smartlist_contains_string(entry->labels, label); } + +/** Return the first entry that has the given label, or NULL if none + * of the entries have the label. */ +metrics_store_entry_t * +metrics_store_find_entry_with_label(const smartlist_t *entries, + const char *label) +{ + tor_assert(entries); + tor_assert(label); + + SMARTLIST_FOREACH_BEGIN(entries, metrics_store_entry_t *, entry) { + tor_assert(entry); + + if (smartlist_contains_string(entry->labels, label)) { + return entry; + } + } SMARTLIST_FOREACH_END(entry); + + return NULL; +} + +/** Return true iff the specified entry is a histogram. */ +bool +metrics_store_entry_is_histogram(const metrics_store_entry_t *entry) +{ + if (entry->type == METRICS_TYPE_HISTOGRAM) { + return true; + } + + return false; +} + +/** Return the total number of observations for the specified histogram. */ +uint64_t +metrics_store_hist_entry_get_count(const metrics_store_entry_t *entry) +{ + tor_assert(entry); + + if (BUG(entry->type != METRICS_TYPE_HISTOGRAM)) { + return 0; + } + + return entry->u.histogram.count; +} + +/** Return the sum of all observations for the specified histogram. */ +int64_t +metrics_store_hist_entry_get_sum(const metrics_store_entry_t *entry) +{ + tor_assert(entry); + + if (BUG(entry->type != METRICS_TYPE_HISTOGRAM)) { + return 0; + } + + return entry->u.histogram.sum; +} diff -Nru tor-0.4.7.16/src/lib/metrics/metrics_store_entry.h tor-0.4.9.6/src/lib/metrics/metrics_store_entry.h --- tor-0.4.7.16/src/lib/metrics/metrics_store_entry.h 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/lib/metrics/metrics_store_entry.h 2026-03-25 14:30:34.000000000 +0000 @@ -12,6 +12,7 @@ #include "lib/cc/torint.h" #include "lib/metrics/metrics_common.h" +#include "lib/container/smartlist.h" #ifdef METRICS_STORE_ENTRY_PRIVATE @@ -37,6 +38,7 @@ union { metrics_counter_t counter; metrics_gauge_t gauge; + metrics_histogram_t histogram; } u; }; @@ -47,7 +49,9 @@ /* Allocators. */ metrics_store_entry_t *metrics_store_entry_new(const metrics_type_t type, const char *name, - const char *help); + const char *help, + size_t bucket_count, + const int64_t *buckets); void metrics_store_entry_free_(metrics_store_entry_t *entry); #define metrics_store_entry_free(entry) \ @@ -55,8 +59,16 @@ /* Accessors. */ int64_t metrics_store_entry_get_value(const metrics_store_entry_t *entry); +uint64_t metrics_store_hist_entry_get_value(const metrics_store_entry_t *entry, + const int64_t bucket); bool metrics_store_entry_has_label(const metrics_store_entry_t *entry, const char *label); +metrics_store_entry_t *metrics_store_find_entry_with_label( + const smartlist_t *entries, const char *label); +bool metrics_store_entry_is_histogram(const metrics_store_entry_t *entry); +uint64_t metrics_store_hist_entry_get_count( + const metrics_store_entry_t *entry); +int64_t metrics_store_hist_entry_get_sum(const metrics_store_entry_t *entry); /* Modifiers. */ void metrics_store_entry_add_label(metrics_store_entry_t *entry, @@ -64,5 +76,7 @@ void metrics_store_entry_reset(metrics_store_entry_t *entry); void metrics_store_entry_update(metrics_store_entry_t *entry, const int64_t value); +void metrics_store_hist_entry_update(metrics_store_entry_t *entry, + const int64_t value, const int64_t obs); #endif /* !defined(TOR_LIB_METRICS_METRICS_STORE_ENTRY_H) */ diff -Nru tor-0.4.7.16/src/lib/metrics/prometheus.c tor-0.4.9.6/src/lib/metrics/prometheus.c --- tor-0.4.7.16/src/lib/metrics/prometheus.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/lib/metrics/prometheus.c 2026-03-25 14:30:34.000000000 +0000 @@ -17,6 +17,8 @@ #include "lib/metrics/prometheus.h" +#include + /** Return a static buffer containing all the labels properly formatted * for the output as a string. * @@ -33,13 +35,54 @@ } line = smartlist_join_strings(labels, ",", 0, NULL); - tor_snprintf(buf, sizeof(buf), "{%s}", line); + tor_snprintf(buf, sizeof(buf), "%s", line); end: tor_free(line); return buf; } +/** Write the string representation of the histogram entry to the specified + * buffer. + * + * Note: entry **must** be a histogram. + */ +static void +format_histogram(const metrics_store_entry_t *entry, buf_t *data) +{ + tor_assert(entry->type == METRICS_TYPE_HISTOGRAM); + + const char *labels = format_labels(entry->labels); + + for (size_t i = 0; i < entry->u.histogram.bucket_count; ++i) { + metrics_histogram_bucket_t hb = entry->u.histogram.buckets[i]; + if (strlen(labels) > 0) { + buf_add_printf(data, "%s_bucket{%s,le=\"%.2f\"} %" PRIi64 "\n", + entry->name, labels, (double)hb.bucket, hb.value); + } else { + buf_add_printf(data, "%s_bucket{le=\"%.2f\"} %" PRIi64 "\n", + entry->name, (double)hb.bucket, hb.value); + } + } + + if (strlen(labels) > 0) { + buf_add_printf(data, "%s_bucket{%s,le=\"+Inf\"} %" PRIi64 "\n", + entry->name, labels, + metrics_store_hist_entry_get_count(entry)); + buf_add_printf(data, "%s_sum{%s} %" PRIi64 "\n", entry->name, labels, + metrics_store_hist_entry_get_sum(entry)); + buf_add_printf(data, "%s_count{%s} %" PRIi64 "\n", entry->name, labels, + metrics_store_hist_entry_get_count(entry)); + } else { + buf_add_printf(data, "%s_bucket{le=\"+Inf\"} %" PRIi64 "\n", entry->name, + metrics_store_hist_entry_get_count(entry)); + buf_add_printf(data, "%s_sum %" PRIi64 "\n", entry->name, + metrics_store_hist_entry_get_sum(entry)); + buf_add_printf(data, "%s_count %" PRIi64 "\n", entry->name, + metrics_store_hist_entry_get_count(entry)); + } +} + /** Format the given entry in to the buffer data. */ void prometheus_format_store_entry(const metrics_store_entry_t *entry, buf_t *data, @@ -53,7 +96,26 @@ buf_add_printf(data, "# TYPE %s %s\n", entry->name, metrics_type_to_str(entry->type)); } - buf_add_printf(data, "%s%s %" PRIi64 "\n", entry->name, - format_labels(entry->labels), - metrics_store_entry_get_value(entry)); + + switch (entry->type) { + case METRICS_TYPE_COUNTER: FALLTHROUGH; + case METRICS_TYPE_GAUGE: + { + const char *labels = format_labels(entry->labels); + if (strlen(labels) > 0) { + buf_add_printf(data, "%s{%s} %" PRIi64 "\n", entry->name, + labels, + metrics_store_entry_get_value(entry)); + } else { + buf_add_printf(data, "%s %" PRIi64 "\n", entry->name, + metrics_store_entry_get_value(entry)); + } + break; + } + case METRICS_TYPE_HISTOGRAM: + format_histogram(entry, data); + break; + default: + tor_assert_unreached(); + } } diff -Nru tor-0.4.7.16/src/lib/net/include.am tor-0.4.9.6/src/lib/net/include.am --- tor-0.4.7.16/src/lib/net/include.am 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/lib/net/include.am 2026-03-25 14:30:34.000000000 +0000 @@ -8,7 +8,7 @@ # ADD_C_FILE: INSERT SOURCES HERE. src_lib_libtor_net_a_SOURCES = \ src/lib/net/address.c \ - src/lib/net/alertsock.c \ + src/lib/net/alertsock.c \ src/lib/net/buffers_net.c \ src/lib/net/gethostname.c \ src/lib/net/inaddr.c \ @@ -25,7 +25,7 @@ # ADD_C_FILE: INSERT HEADERS HERE. noinst_HEADERS += \ src/lib/net/address.h \ - src/lib/net/alertsock.h \ + src/lib/net/alertsock.h \ src/lib/net/buffers_net.h \ src/lib/net/gethostname.h \ src/lib/net/inaddr.h \ diff -Nru tor-0.4.7.16/src/lib/net/socket.c tor-0.4.9.6/src/lib/net/socket.c --- tor-0.4.7.16/src/lib/net/socket.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/lib/net/socket.c 2026-03-25 14:30:34.000000000 +0000 @@ -652,7 +652,13 @@ #if defined(_WIN32) #define E(code, s) { code, (s " [" #code " ]") } -struct { int code; const char *msg; } windows_socket_errors[] = { + +typedef struct windows_socket_error { + int code; + const char *msg; +} windows_socket_error_t; + +static windows_socket_error_t windows_socket_errors[] = { E(WSAEINTR, "Interrupted function call"), E(WSAEACCES, "Permission denied"), E(WSAEFAULT, "Bad address"), diff -Nru tor-0.4.7.16/src/lib/osinfo/include.am tor-0.4.9.6/src/lib/osinfo/include.am --- tor-0.4.7.16/src/lib/osinfo/include.am 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/lib/osinfo/include.am 2026-03-25 14:30:34.000000000 +0000 @@ -6,7 +6,7 @@ endif # ADD_C_FILE: INSERT SOURCES HERE. -src_lib_libtor_osinfo_a_SOURCES = \ +src_lib_libtor_osinfo_a_SOURCES = \ src/lib/osinfo/uname.c \ src/lib/osinfo/libc.c @@ -16,6 +16,6 @@ src_lib_libtor_osinfo_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS) # ADD_C_FILE: INSERT HEADERS HERE. -noinst_HEADERS += \ +noinst_HEADERS += \ src/lib/osinfo/uname.h \ src/lib/osinfo/libc.h diff -Nru tor-0.4.7.16/src/lib/osinfo/libc.c tor-0.4.9.6/src/lib/osinfo/libc.c --- tor-0.4.7.16/src/lib/osinfo/libc.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/lib/osinfo/libc.c 2026-03-25 14:30:34.000000000 +0000 @@ -26,11 +26,18 @@ #define STR_IMPL(x) #x #define STR(x) STR_IMPL(x) +#if defined(__BSD_VISIBLE) || defined(__NETBSD_SOURCE) +#include +#endif /* defined(__BSD_VISIBLE) || defined(__NETBSD_SOURCE) */ + /** Return the name of the compile time libc. Returns NULL if we * cannot identify the libc. */ const char * tor_libc_get_name(void) { +#if defined(__BSD_VISIBLE) || defined(__NETBSD_SOURCE) + return "BSD"; +#endif /* defined(__BSD_VISIBLE) || defined(__NETBSD_SOURCE) */ #ifdef __GLIBC__ return "Glibc"; #else /* !defined(__GLIBC__) */ @@ -43,6 +50,18 @@ const char * tor_libc_get_version_str(void) { +#ifdef __DragonFly_version + return STR(__DragonFly_version); +#endif +#ifdef __FreeBSD__ + return STR(__FreeBSD_version); +#endif +#ifdef __NetBSD_Version__ + return STR(__NetBSD_Version__); +#endif +#ifdef OpenBSD + return STR(OpenBSD); +#endif #ifdef CHECK_LIBC_VERSION const char *version = gnu_get_libc_version(); if (version == NULL) diff -Nru tor-0.4.7.16/src/lib/process/daemon.c tor-0.4.9.6/src/lib/process/daemon.c --- tor-0.4.7.16/src/lib/process/daemon.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/lib/process/daemon.c 2026-03-25 14:30:34.000000000 +0000 @@ -13,6 +13,7 @@ #ifndef _WIN32 +#include "lib/fdio/fdio.h" #include "lib/fs/files.h" #include "lib/log/log.h" #include "lib/thread/threads.h" @@ -63,7 +64,7 @@ return 0; start_daemon_called = 1; - if (pipe(daemon_filedes)) { + if (tor_pipe_cloexec(daemon_filedes)) { /* LCOV_EXCL_START */ log_err(LD_GENERAL,"pipe failed; exiting. Error was %s", strerror(errno)); exit(1); // exit ok: during daemonize, pipe failed. diff -Nru tor-0.4.7.16/src/lib/process/process_unix.c tor-0.4.9.6/src/lib/process/process_unix.c --- tor-0.4.7.16/src/lib/process/process_unix.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/lib/process/process_unix.c 2026-03-25 14:30:34.000000000 +0000 @@ -49,8 +49,7 @@ #ifndef _WIN32 -/** Maximum number of file descriptors, if we cannot get it via sysconf() */ -#define DEFAULT_MAX_FD 256 +#include "lib/fdio/fdio.h" /** Internal state for Unix handles. */ struct process_unix_handle_t { @@ -130,19 +129,17 @@ process_status_t process_unix_exec(process_t *process) { - static int max_fd = -1; - process_unix_t *unix_process; pid_t pid; int stdin_pipe[2]; int stdout_pipe[2]; int stderr_pipe[2]; - int retval, fd; + int retval; unix_process = process_get_unix_process(process); /* Create standard in pipe. */ - retval = pipe(stdin_pipe); + retval = tor_pipe_cloexec(stdin_pipe); if (-1 == retval) { log_warn(LD_PROCESS, @@ -154,7 +151,7 @@ } /* Create standard out pipe. */ - retval = pipe(stdout_pipe); + retval = tor_pipe_cloexec(stdout_pipe); if (-1 == retval) { log_warn(LD_PROCESS, @@ -170,7 +167,7 @@ } /* Create standard error pipe. */ - retval = pipe(stderr_pipe); + retval = tor_pipe_cloexec(stderr_pipe); if (-1 == retval) { log_warn(LD_PROCESS, @@ -189,20 +186,6 @@ return PROCESS_STATUS_ERROR; } -#ifdef _SC_OPEN_MAX - if (-1 == max_fd) { - max_fd = (int)sysconf(_SC_OPEN_MAX); - - if (max_fd == -1) { - max_fd = DEFAULT_MAX_FD; - log_warn(LD_PROCESS, - "Cannot find maximum file descriptor, assuming: %d", max_fd); - } - } -#else /* !defined(_SC_OPEN_MAX) */ - max_fd = DEFAULT_MAX_FD; -#endif /* defined(_SC_OPEN_MAX) */ - pid = fork(); if (0 == pid) { @@ -240,11 +223,9 @@ close(stdin_pipe[0]); close(stdin_pipe[1]); - /* Close all other fds, including the read end of the pipe. XXX: We should - * now be doing enough FD_CLOEXEC setting to make this needless. - */ - for (fd = STDERR_FILENO + 1; fd < max_fd; fd++) - close(fd); + /* Note that we don't close all FDs from here, which we used to do, because + * all our open are CLOEXEC. With a very large maximum number of FDs, the + * loop was taking a long time: #40990 */ /* Create the argv value for our new process. */ char **argv = process_get_argv(process); diff -Nru tor-0.4.7.16/src/lib/process/process_win32.c tor-0.4.9.6/src/lib/process/process_win32.c --- tor-0.4.7.16/src/lib/process/process_win32.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/lib/process/process_win32.c 2026-03-25 14:30:34.000000000 +0000 @@ -888,7 +888,7 @@ /* Check if we have been asked to read from a handle that have already told * us that we have reached the end of the file. */ - if (BUG(handle->reached_eof)) + if (handle->reached_eof) return 0; /* This cast should be safe since our buffer can be at maximum up to diff -Nru tor-0.4.7.16/src/lib/process/restrict.c tor-0.4.9.6/src/lib/process/restrict.c --- tor-0.4.7.16/src/lib/process/restrict.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/lib/process/restrict.c 2026-03-25 14:30:34.000000000 +0000 @@ -177,8 +177,8 @@ * return 0 and max_out is set to the current maximum value returned * by getrlimit(). * - * Otherwise, return 0 and store the maximum we found inside max_out - * and set max_sockets with that value as well.*/ + * Otherwise: return 0, store the maximum we found inside max_out, + * and call set_max_sockets() with that value as well.*/ int set_max_file_descriptors(rlim_t limit, int *max_out) { diff -Nru tor-0.4.7.16/src/lib/process/waitpid.c tor-0.4.9.6/src/lib/process/waitpid.c --- tor-0.4.7.16/src/lib/process/waitpid.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/lib/process/waitpid.c 2026-03-25 14:30:34.000000000 +0000 @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2021, The Tor Project, Inc. */ + * Copyright (c) 2007-2025, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -146,6 +146,7 @@ int status = 0; while ((child = waitpid(-1, &status, WNOHANG)) > 0) { + status = WIFEXITED(status) ? WEXITSTATUS(status) : -1; notify_waitpid_callback_by_pid(child, status); status = 0; /* should be needless */ } diff -Nru tor-0.4.7.16/src/lib/sandbox/sandbox.c tor-0.4.9.6/src/lib/sandbox/sandbox.c --- tor-0.4.7.16/src/lib/sandbox/sandbox.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/lib/sandbox/sandbox.c 2026-03-25 14:30:34.000000000 +0000 @@ -23,7 +23,7 @@ * * 28/06/2017: This value was increased from 16 MB to 20 MB after we introduced * LZMA support in Tor (0.3.1.1-alpha). We limit our LZMA coder to 16 MB, but - * liblzma have a small overhead that we need to compensate for to avoid being + * liblzma has a small overhead that we need to compensate for to avoid being * killed by the sandbox. */ #define MALLOC_MP_LIM (20*1024*1024) @@ -125,6 +125,15 @@ #define SYSCALL_NAME_DEBUGGING #endif +/** + * On newer architectures Linux provides a standardized, generic set of system + * calls (defined in Linux's include/uapi/asm-generic/unistd.h), which omits a + * number of legacy calls used by glibc on other platforms. + */ +#if defined(__aarch64__) || defined(__riscv) +#define ARCH_USES_GENERIC_SYSCALLS +#endif + /**Determines if at least one sandbox is active.*/ static int sandbox_active = 0; /** Holds the parameter list configuration for the sandbox.*/ @@ -141,10 +150,12 @@ * the high bits of the value might get masked out improperly. */ #define SCMP_CMP_MASKED(a,b,c) \ SCMP_CMP4((a), SCMP_CMP_MASKED_EQ, ~(scmp_datum_t)(b), (c)) -/* For negative constants, the rule to add depends on the glibc version. */ -#define SCMP_CMP_NEG(a,op,b) (libc_negative_constant_needs_cast() ? \ - (SCMP_CMP((a), (op), (unsigned int)(b))) : \ - (SCMP_CMP_STR((a), (op), (b)))) +/* Negative constants aren't consistently sign extended or zero extended. + * Different compilers, libc, and architectures behave differently. For cases + * where the kernel ABI uses a 32 bit integer, this macro can be used to + * mask-compare only the lower 32 bits of the value. */ +#define SCMP_CMP_LOWER32_EQ(a,b) \ + SCMP_CMP4((a), SCMP_CMP_MASKED_EQ, 0xFFFFFFFF, (unsigned int)(b)) /** Variable used for storing all syscall numbers that will be allowed with the * stage 1 general Tor sandbox. @@ -261,8 +272,9 @@ #ifdef __NR_sigreturn SCMP_SYS(sigreturn), #endif +#if defined(__NR_stat) SCMP_SYS(stat), -#if defined(__i386__) && defined(__NR_statx) +#elif defined(__i386__) && defined(__NR_statx) SCMP_SYS(statx), #endif SCMP_SYS(uname), @@ -277,6 +289,10 @@ // getaddrinfo uses this.. SCMP_SYS(stat64), #endif +#ifdef __NR_lstat64 + // glob uses this on i386 with glibc 2.36+ + SCMP_SYS(lstat64), +#endif #ifdef __NR_getrandom SCMP_SYS(getrandom), @@ -316,7 +332,7 @@ }; /* opendir is not a syscall but it will use either open or openat. We do not - * want the decision to allow open/openat to be the callers reponsability, so + * want the decision to allow open/openat to be the callers responsibility, so * we create a phony syscall number for opendir and sb_opendir will choose the * correct syscall. */ #define PHONY_OPENDIR_SYSCALL -2 @@ -333,6 +349,8 @@ seccomp_rule_add((ctx),(act),(call),3,(f1),(f2),(f3)) #define seccomp_rule_add_4(ctx,act,call,f1,f2,f3,f4) \ seccomp_rule_add((ctx),(act),(call),4,(f1),(f2),(f3),(f4)) +#define seccomp_rule_add_5(ctx,act,call,f1,f2,f3,f4,f5) \ + seccomp_rule_add((ctx),(act),(call),4,(f1),(f2),(f3),(f4),(f5)) static const char *sandbox_get_interned_string(const char *str); @@ -439,7 +457,14 @@ rc = seccomp_rule_add_2(ctx, SCMP_ACT_ALLOW, SCMP_SYS(mmap2), SCMP_CMP(2, SCMP_CMP_EQ, PROT_READ|PROT_WRITE), - SCMP_CMP(3, SCMP_CMP_EQ,MAP_PRIVATE|MAP_ANONYMOUS|MAP_STACK)); + SCMP_CMP(3, SCMP_CMP_EQ, MAP_PRIVATE|MAP_ANONYMOUS|MAP_STACK)); + if (rc) { + return rc; + } + + rc = seccomp_rule_add_2(ctx, SCMP_ACT_ALLOW, SCMP_SYS(mmap2), + SCMP_CMP(2, SCMP_CMP_EQ, PROT_NONE), + SCMP_CMP(3, SCMP_CMP_EQ, MAP_PRIVATE|MAP_ANONYMOUS|MAP_STACK)); if (rc) { return rc; } @@ -507,26 +532,33 @@ static int libc_uses_openat_for_open(void) { +#ifdef __NR_open return is_libc_at_least(2, 26); +#else + return 1; +#endif /* defined(__NR_open) */ } +/* Calls to opendir() cannot be filtered by the sandbox when built with fragile + * hardening for an architecture that uses Linux's generic syscall interface, + * so prevent a compiler warning by omitting this function along with + * sb_opendir(). */ +#if !(defined(ENABLE_FRAGILE_HARDENING) && defined(ARCH_USES_GENERIC_SYSCALLS)) /* Return true if we think we're running with a libc that uses openat for the * opendir function on linux. */ static int libc_uses_openat_for_opendir(void) { +#ifdef __NR_open // libc 2.27 and above or between 2.15 (inclusive) and 2.22 (exclusive) return is_libc_at_least(2, 27) || (is_libc_at_least(2, 15) && !is_libc_at_least(2, 22)); +#else + return 1; +#endif /* defined(__NR_open) */ } - -/* Return true if we think we're running with a libc that needs to cast - * negative arguments like AT_FDCWD for seccomp rules. */ -static int -libc_negative_constant_needs_cast(void) -{ - return is_libc_at_least(2, 27); -} +#endif /* !(defined(ENABLE_FRAGILE_HARDENING) && + defined(ARCH_USES_GENERIC_SYSCALLS)) */ /** Allow a single file to be opened. If use_openat is true, * we're using a libc that remaps all the opens into openats. */ @@ -535,7 +567,7 @@ { if (use_openat) { return seccomp_rule_add_2(ctx, SCMP_ACT_ALLOW, SCMP_SYS(openat), - SCMP_CMP_NEG(0, SCMP_CMP_EQ, AT_FDCWD), + SCMP_CMP_LOWER32_EQ(0, AT_FDCWD), SCMP_CMP_STR(1, SCMP_CMP_EQ, file)); } else { return seccomp_rule_add_1(ctx, SCMP_ACT_ALLOW, SCMP_SYS(open), @@ -556,10 +588,25 @@ int use_openat = libc_uses_openat_for_open(); #ifdef ENABLE_FRAGILE_HARDENING - /* AddressSanitizer uses the "open" syscall to access information about the - * running process via the filesystem, so that call must be allowed without + /* AddressSanitizer uses either the "open" or the "openat" syscall (depending + * on the architecture) to access information about the running process via + * the filesystem, so the appropriate call must be allowed without * restriction or the sanitizer will be unable to execute normally when the * process terminates. */ +#ifdef ARCH_USES_GENERIC_SYSCALLS + rc = seccomp_rule_add_1(ctx, SCMP_ACT_ALLOW, SCMP_SYS(openat), + SCMP_CMP_LOWER32_EQ(0, AT_FDCWD)); + if (rc != 0) { + log_err(LD_BUG,"(Sandbox) failed to add openat syscall, received " + "libseccomp error %d", rc); + return rc; + } + + /* The "open" syscall is not defined on this architecture, so any other + * requests to open files will necessarily use "openat" as well and there is + * no need to consider any additional rules. */ + return 0; +#else rc = seccomp_rule_add_0(ctx, SCMP_ACT_ALLOW, SCMP_SYS(open)); if (rc != 0) { log_err(LD_BUG,"(Sandbox) failed to add open syscall, received " @@ -571,7 +618,8 @@ * there is no need to consider any additional rules. */ if (!use_openat) return 0; -#endif +#endif /* defined(ARCH_USES_GENERIC_SYSCALLS) */ +#endif /* defined(ENABLE_FRAGILE_HARDENING) */ // for each dynamic parameter filters for (elem = filter; elem != NULL; elem = elem->next) { @@ -591,6 +639,33 @@ return 0; } +#ifdef ARCH_USES_GENERIC_SYSCALLS +static int +sb_fchmodat(scmp_filter_ctx ctx, sandbox_cfg_t *filter) +{ + int rc; + sandbox_cfg_t *elem = NULL; + + // for each dynamic parameter filters + for (elem = filter; elem != NULL; elem = elem->next) { + smp_param_t *param = elem->param; + + if (param != NULL && param->prot == 1 && param->syscall + == SCMP_SYS(fchmodat)) { + rc = seccomp_rule_add_2(ctx, SCMP_ACT_ALLOW, SCMP_SYS(fchmodat), + SCMP_CMP_LOWER32_EQ(0, AT_FDCWD), + SCMP_CMP_STR(1, SCMP_CMP_EQ, param->value)); + if (rc != 0) { + log_err(LD_BUG,"(Sandbox) failed to add fchmodat syscall, received " + "libseccomp error %d", rc); + return rc; + } + } + } + + return 0; +} +#else static int sb_chmod(scmp_filter_ctx ctx, sandbox_cfg_t *filter) { @@ -615,8 +690,35 @@ return 0; } +#endif /* defined(ARCH_USES_GENERIC_SYSCALLS) */ -#ifdef __i386__ +#if defined(ARCH_USES_GENERIC_SYSCALLS) +static int +sb_fchownat(scmp_filter_ctx ctx, sandbox_cfg_t *filter) +{ + int rc; + sandbox_cfg_t *elem = NULL; + + // for each dynamic parameter filters + for (elem = filter; elem != NULL; elem = elem->next) { + smp_param_t *param = elem->param; + + if (param != NULL && param->prot == 1 && param->syscall + == SCMP_SYS(fchownat)) { + rc = seccomp_rule_add_2(ctx, SCMP_ACT_ALLOW, SCMP_SYS(fchownat), + SCMP_CMP_LOWER32_EQ(0, AT_FDCWD), + SCMP_CMP_STR(1, SCMP_CMP_EQ, param->value)); + if (rc != 0) { + log_err(LD_BUG,"(Sandbox) failed to add fchownat syscall, received " + "libseccomp error %d", rc); + return rc; + } + } + } + + return 0; +} +#elif defined(__i386__) static int sb_chown32(scmp_filter_ctx ctx, sandbox_cfg_t *filter) { @@ -666,8 +768,9 @@ return 0; } -#endif /* defined(__i386__) */ +#endif /* defined(ARCH_USES_GENERIC_SYSCALLS) || defined(__i386__) */ +#if defined(__NR_rename) /** * Function responsible for setting up the rename syscall for * the seccomp filter sandbox. @@ -698,7 +801,86 @@ return 0; } +#elif defined(__NR_renameat) +/** + * Function responsible for setting up the renameat syscall for + * the seccomp filter sandbox. + */ +static int +sb_renameat(scmp_filter_ctx ctx, sandbox_cfg_t *filter) +{ + int rc; + sandbox_cfg_t *elem = NULL; + // for each dynamic parameter filters + for (elem = filter; elem != NULL; elem = elem->next) { + smp_param_t *param = elem->param; + + if (param != NULL && param->prot == 1 && + param->syscall == SCMP_SYS(renameat)) { + + rc = seccomp_rule_add_4(ctx, SCMP_ACT_ALLOW, SCMP_SYS(renameat), + SCMP_CMP_LOWER32_EQ(0, AT_FDCWD), + SCMP_CMP_STR(1, SCMP_CMP_EQ, param->value), + SCMP_CMP_LOWER32_EQ(2, AT_FDCWD), + SCMP_CMP_STR(3, SCMP_CMP_EQ, param->value2)); + if (rc != 0) { + log_err(LD_BUG,"(Sandbox) failed to add renameat syscall, received " + "libseccomp error %d", rc); + return rc; + } + } + } + + return 0; +} +#else +/** + * Function responsible for setting up the renameat2 syscall for + * the seccomp filter sandbox. + */ +static int +sb_renameat2(scmp_filter_ctx ctx, sandbox_cfg_t *filter) +{ + int rc; + sandbox_cfg_t *elem = NULL; + + // for each dynamic parameter filters + for (elem = filter; elem != NULL; elem = elem->next) { + smp_param_t *param = elem->param; + + if (param != NULL && param->prot == 1 && + param->syscall == SCMP_SYS(renameat2)) { + + rc = seccomp_rule_add_5(ctx, SCMP_ACT_ALLOW, SCMP_SYS(renameat2), + SCMP_CMP_LOWER32_EQ(0, AT_FDCWD), + SCMP_CMP_STR(1, SCMP_CMP_EQ, param->value), + SCMP_CMP_LOWER32_EQ(2, AT_FDCWD), + SCMP_CMP_STR(3, SCMP_CMP_EQ, param->value2), + SCMP_CMP(4, SCMP_CMP_EQ, 0)); + if (rc != 0) { + log_err(LD_BUG,"(Sandbox) failed to add renameat2 syscall, received " + "libseccomp error %d", rc); + return rc; + } + } + } + + return 0; +} +#endif /* defined(__NR_rename) || defined(__NR_renameat) */ + +/* If Tor is built with fragile hardening for an architecture that uses Linux's + * generic syscall interface a rule allowing the "openat" syscall without + * restriction will have already been added by sb_open(), so there is no need + * to consider adding additional, more restrictive rules here as they will + * simply be ignored. + * + * Also, since the "open" syscall is not defined on these architectures, glibc + * will necessarily use "openat" for its implementation of opendir() as well. + * This means neither of the following two functions will have any effect and + * both can be omitted. */ +#if !(defined(ENABLE_FRAGILE_HARDENING) && defined(ARCH_USES_GENERIC_SYSCALLS)) /** * Function responsible for setting up the openat syscall for * the seccomp filter sandbox. @@ -716,7 +898,7 @@ if (param != NULL && param->prot == 1 && param->syscall == SCMP_SYS(openat)) { rc = seccomp_rule_add_3(ctx, SCMP_ACT_ALLOW, SCMP_SYS(openat), - SCMP_CMP_NEG(0, SCMP_CMP_EQ, AT_FDCWD), + SCMP_CMP_LOWER32_EQ(0, AT_FDCWD), SCMP_CMP_STR(1, SCMP_CMP_EQ, param->value), SCMP_CMP(2, SCMP_CMP_EQ, O_RDONLY|O_NONBLOCK|O_LARGEFILE|O_DIRECTORY| O_CLOEXEC)); @@ -754,6 +936,8 @@ return 0; } +#endif /* !(defined(ENABLE_FRAGILE_HARDENING) && + defined(ARCH_USES_GENERIC_SYSCALLS)) */ #ifdef ENABLE_FRAGILE_HARDENING /** @@ -773,9 +957,17 @@ if (rc) return rc; + /* AddressSanitizer uses "PTRACE_GETREGSET" on AArch64 (ARM64) and + * System/390, "PTRACE_GETREGS" everywhere else. */ +#if defined(__aarch64__) || defined(__s390__) + rc = seccomp_rule_add_2(ctx, SCMP_ACT_ALLOW, SCMP_SYS(ptrace), + SCMP_CMP(0, SCMP_CMP_EQ, PTRACE_GETREGSET), + SCMP_CMP(1, SCMP_CMP_EQ, pid)); +#else rc = seccomp_rule_add_2(ctx, SCMP_ACT_ALLOW, SCMP_SYS(ptrace), SCMP_CMP(0, SCMP_CMP_EQ, PTRACE_GETREGS), SCMP_CMP(1, SCMP_CMP_EQ, pid)); +#endif /* defined(__aarch64__) || defined(__s390__) */ if (rc) return rc; @@ -1265,6 +1457,40 @@ return 0; } +#ifdef ARCH_USES_GENERIC_SYSCALLS +/** + * Function responsible for setting up the newfstatat syscall for + * the seccomp filter sandbox. + */ +static int +sb_newfstatat(scmp_filter_ctx ctx, sandbox_cfg_t *filter) +{ + int rc = 0; + + sandbox_cfg_t *elem = NULL; + + // for each dynamic parameter filters + for (elem = filter; elem != NULL; elem = elem->next) { + smp_param_t *param = elem->param; + + if (param != NULL && param->prot == 1 && (param->syscall == SCMP_SYS(open) + || param->syscall == PHONY_OPENDIR_SYSCALL + || param->syscall == SCMP_SYS(newfstatat))) { + rc = seccomp_rule_add_2(ctx, SCMP_ACT_ALLOW, SCMP_SYS(newfstatat), + SCMP_CMP_LOWER32_EQ(0, AT_FDCWD), + SCMP_CMP_STR(1, SCMP_CMP_EQ, param->value)); + if (rc != 0) { + log_err(LD_BUG,"(Sandbox) failed to add newfstatat syscall, received " + "libseccomp error %d", rc); + return rc; + } + } + } + + return 0; +} +#endif /* defined(ARCH_USES_GENERIC_SYSCALLS) */ + #ifdef __NR_stat64 /** * Function responsible for setting up the stat64 syscall for @@ -1323,19 +1549,33 @@ #ifdef __NR_mmap2 sb_mmap2, #endif -#ifdef __i386__ +#if defined(ARCH_USES_GENERIC_SYSCALLS) + sb_fchownat, +#elif defined(__i386__) sb_chown32, #else sb_chown, #endif +#if defined(ARCH_USES_GENERIC_SYSCALLS) + sb_fchmodat, +#else sb_chmod, +#endif sb_open, +#if !(defined(ENABLE_FRAGILE_HARDENING) && defined(ARCH_USES_GENERIC_SYSCALLS)) sb_openat, sb_opendir, +#endif #ifdef ENABLE_FRAGILE_HARDENING sb_ptrace, #endif +#if defined(__NR_rename) sb_rename, +#elif defined(__NR_renameat) + sb_renameat, +#else + sb_renameat2, +#endif #ifdef __NR_fcntl64 sb_fcntl64, #endif @@ -1345,7 +1585,9 @@ sb_flock, sb_futex, sb_mremap, -#ifdef __NR_stat64 +#if defined(ARCH_USES_GENERIC_SYSCALLS) + sb_newfstatat, +#elif defined(__NR_stat64) sb_stat64, #endif @@ -1601,13 +1843,31 @@ return new_element2(syscall, value, NULL); } -#ifdef __i386__ +#if defined(ARCH_USES_GENERIC_SYSCALLS) +#define SCMP_chown SCMP_SYS(fchownat) +#elif defined(__i386__) #define SCMP_chown SCMP_SYS(chown32) #else #define SCMP_chown SCMP_SYS(chown) #endif -#ifdef __NR_stat64 +#if defined(ARCH_USES_GENERIC_SYSCALLS) +#define SCMP_chmod SCMP_SYS(fchmodat) +#else +#define SCMP_chmod SCMP_SYS(chmod) +#endif + +#if defined(__NR_rename) +#define SCMP_rename SCMP_SYS(rename) +#elif defined(__NR_renameat) +#define SCMP_rename SCMP_SYS(renameat) +#else +#define SCMP_rename SCMP_SYS(renameat2) +#endif + +#if defined(ARCH_USES_GENERIC_SYSCALLS) +#define SCMP_stat SCMP_SYS(newfstatat) +#elif defined(__NR_stat64) #define SCMP_stat SCMP_SYS(stat64) #else #define SCMP_stat SCMP_SYS(stat) @@ -1644,7 +1904,7 @@ { sandbox_cfg_t *elem = NULL; - elem = new_element(SCMP_SYS(chmod), file); + elem = new_element(SCMP_chmod, file); elem->next = *cfg; *cfg = elem; @@ -1670,7 +1930,7 @@ { sandbox_cfg_t *elem = NULL; - elem = new_element2(SCMP_SYS(rename), file1, file2); + elem = new_element2(SCMP_rename, file1, file2); elem->next = *cfg; *cfg = elem; @@ -1766,6 +2026,25 @@ "received libseccomp error %d", rc); return rc; } +#elif defined(__NR_fstatat64) + // On i386, glibc uses fstatat64 instead of newfstatat. + // This is needed for glob() and stat() operations on 32-bit systems. + rc = seccomp_rule_add_0(ctx, SCMP_ACT_ALLOW, SCMP_SYS(fstatat64)); + if (rc != 0) { + log_err(LD_BUG,"(Sandbox) failed to add fstatat64() syscall; " + "received libseccomp error %d", rc); + return rc; + } +#endif +#if defined(__i386__) && defined(__NR_statx) + // On i386 with glibc 2.33+, statx may be used for time64 support. + // glob() in glibc 2.36+ uses statx for directory traversal. + rc = seccomp_rule_add_0(ctx, SCMP_ACT_ALLOW, SCMP_SYS(statx)); + if (rc != 0) { + log_err(LD_BUG,"(Sandbox) failed to add statx() syscall; " + "received libseccomp error %d", rc); + return rc; + } #endif } diff -Nru tor-0.4.7.16/src/lib/sandbox/sandbox.h tor-0.4.9.6/src/lib/sandbox/sandbox.h --- tor-0.4.7.16/src/lib/sandbox/sandbox.h 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/lib/sandbox/sandbox.h 2026-03-25 14:30:34.000000000 +0000 @@ -16,6 +16,9 @@ #include "lib/cc/torint.h" #ifndef SYS_SECCOMP +#ifdef HAVE_SIGNAL_H +#include +#endif /** * Used by SIGSYS signal handler to check if the signal was issued due to a diff -Nru tor-0.4.7.16/src/lib/smartlist_core/include.am tor-0.4.9.6/src/lib/smartlist_core/include.am --- tor-0.4.7.16/src/lib/smartlist_core/include.am 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/lib/smartlist_core/include.am 2026-03-25 14:30:34.000000000 +0000 @@ -7,7 +7,7 @@ # 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_core.c \ src/lib/smartlist_core/smartlist_split.c src_lib_libtor_smartlist_core_testing_a_SOURCES = \ @@ -18,6 +18,6 @@ # ADD_C_FILE: INSERT HEADERS HERE. noinst_HEADERS += \ - src/lib/smartlist_core/smartlist_core.h \ - src/lib/smartlist_core/smartlist_foreach.h \ + src/lib/smartlist_core/smartlist_core.h \ + src/lib/smartlist_core/smartlist_foreach.h \ src/lib/smartlist_core/smartlist_split.h diff -Nru tor-0.4.7.16/src/lib/string/util_string.c tor-0.4.9.6/src/lib/string/util_string.c --- tor-0.4.7.16/src/lib/string/util_string.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/lib/string/util_string.c 2026-03-25 14:30:34.000000000 +0000 @@ -31,6 +31,8 @@ { #if defined(HAVE_MEMMEM) && (!defined(__GNUC__) || __GNUC__ >= 2) raw_assert(nlen); + if (nlen > hlen) + return NULL; return memmem(_haystack, hlen, _needle, nlen); #else /* This isn't as fast as the GLIBC implementation, but it doesn't need to diff -Nru tor-0.4.7.16/src/lib/term/include.am tor-0.4.9.6/src/lib/term/include.am --- tor-0.4.7.16/src/lib/term/include.am 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/lib/term/include.am 2026-03-25 14:30:34.000000000 +0000 @@ -22,5 +22,5 @@ src_lib_libtor_term_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS) # ADD_C_FILE: INSERT HEADERS HERE. -noinst_HEADERS += \ +noinst_HEADERS += \ src/lib/term/getpass.h diff -Nru tor-0.4.7.16/src/lib/time/compat_time.c tor-0.4.9.6/src/lib/time/compat_time.c --- tor-0.4.7.16/src/lib/time/compat_time.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/lib/time/compat_time.c 2026-03-25 14:30:34.000000000 +0000 @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2021, The Tor Project, Inc. */ + * Copyright (c) 2007-2025, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -53,13 +53,15 @@ #undef HAVE_CLOCK_GETTIME #endif -#ifdef TOR_UNIT_TESTS -/** Delay for msec milliseconds. Only used in tests. */ +/** Delay for msec milliseconds. */ void tor_sleep_msec(int msec) { #ifdef _WIN32 Sleep(msec); +#elif defined(HAVE_TIME_H) + struct timespec ts = {msec / 1000, (msec % 1000) * 1000 * 1000}; + while (nanosleep(&ts, &ts) == -1 && errno == EINTR); #elif defined(HAVE_USLEEP) sleep(msec / 1000); /* Some usleep()s hate sleeping more than 1 sec */ @@ -71,7 +73,6 @@ sleep(CEIL_DIV(msec, 1000)); #endif /* defined(_WIN32) || ... */ } -#endif /* defined(TOR_UNIT_TESTS) */ #define ONE_MILLION ((int64_t) (1000 * 1000)) #define ONE_BILLION ((int64_t) (1000 * 1000 * 1000)) @@ -812,6 +813,12 @@ return monotime_absolute_nsec() / ONE_MILLION; } +uint64_t +monotime_absolute_sec(void) +{ + return monotime_absolute_nsec() / ONE_BILLION; +} + #ifdef MONOTIME_COARSE_FN_IS_DIFFERENT uint64_t monotime_coarse_absolute_nsec(void) @@ -836,6 +843,17 @@ { return monotime_coarse_absolute_nsec() / ONE_MILLION; } + +uint64_t +monotime_coarse_absolute_sec(void) +{ + /* Note: Right now I'm not too concerned about 64-bit division, but if this + * ever becomes a hotspot we need to optimize, we can modify this to grab + * tv_sec directly from CLOCK_MONOTONIC_COARSE on linux at least. Right now + * I'm choosing to make this simpler and easier to test, but this + * optimization is available easily if we need it. */ + return monotime_coarse_absolute_nsec() / ONE_BILLION; +} #else /* !defined(MONOTIME_COARSE_FN_IS_DIFFERENT) */ #define initialized_at_coarse initialized_at #endif /* defined(MONOTIME_COARSE_FN_IS_DIFFERENT) */ diff -Nru tor-0.4.7.16/src/lib/time/compat_time.h tor-0.4.9.6/src/lib/time/compat_time.h --- tor-0.4.7.16/src/lib/time/compat_time.h 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/lib/time/compat_time.h 2026-03-25 14:30:34.000000000 +0000 @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2021, The Tor Project, Inc. */ + * Copyright (c) 2007-2025, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -89,6 +89,13 @@ * A: In general, regular monotime uses something that requires a system call. * On platforms where system calls are cheap, you win! Otherwise, you lose. * + * XXX: This hasn't been true for a long time. Expect both coarse and fine + * monotime won't require a syscall, but they will have different + * costs in terms of low-level synchronization inside the vDSO and + * the hardware. The basic guidelines here still apply, but we aren't + * really worrying about system calls any more, and the integer div + * concerns are becoming nearly unimportant as well. + * * On Windows, monotonic time uses QuereyPerformanceCounter. Storing * monotime_t costs 8 bytes. * @@ -232,7 +239,12 @@ * Fractional units are truncated, not rounded. */ uint64_t monotime_absolute_msec(void); - +/** + * Return the number of seconds since the timer system was initialized. + * The returned value may be equal to zero. + * Fractional units are truncated, not rounded. + */ +uint64_t monotime_absolute_sec(void); /** * Set out to zero. */ @@ -259,11 +271,13 @@ uint64_t monotime_coarse_absolute_nsec(void); uint64_t monotime_coarse_absolute_usec(void); uint64_t monotime_coarse_absolute_msec(void); +uint64_t monotime_coarse_absolute_sec(void); #else /* !defined(MONOTIME_COARSE_FN_IS_DIFFERENT) */ #define monotime_coarse_get monotime_get #define monotime_coarse_absolute_nsec monotime_absolute_nsec #define monotime_coarse_absolute_usec monotime_absolute_usec #define monotime_coarse_absolute_msec monotime_absolute_msec +#define monotime_coarse_absolute_sec monotime_absolute_sec #endif /* defined(MONOTIME_COARSE_FN_IS_DIFFERENT) */ /** @@ -347,9 +361,9 @@ #endif /* SIZEOF_VOID_P == 8 */ } -#ifdef TOR_UNIT_TESTS void tor_sleep_msec(int msec); +#ifdef TOR_UNIT_TESTS void monotime_enable_test_mocking(void); void monotime_disable_test_mocking(void); void monotime_set_mock_time_nsec(int64_t); diff -Nru tor-0.4.7.16/src/lib/time/include.am tor-0.4.9.6/src/lib/time/include.am --- tor-0.4.7.16/src/lib/time/include.am 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/lib/time/include.am 2026-03-25 14:30:34.000000000 +0000 @@ -6,7 +6,7 @@ endif # ADD_C_FILE: INSERT SOURCES HERE. -src_lib_libtor_time_a_SOURCES = \ +src_lib_libtor_time_a_SOURCES = \ src/lib/time/compat_time.c \ src/lib/time/time_sys.c \ src/lib/time/tvdiff.c diff -Nru tor-0.4.7.16/src/lib/tls/ciphers.inc tor-0.4.9.6/src/lib/tls/ciphers.inc --- tor-0.4.7.16/src/lib/tls/ciphers.inc 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/lib/tls/ciphers.inc 2026-03-25 14:30:34.000000000 +0000 @@ -2,27 +2,8 @@ * advertise. Before including it, you should define the CIPHER and XCIPHER * macros. * - * This file was automatically generated by get_mozilla_ciphers.py; - * TLSv1.3 ciphers were added manually. + * This file was automatically generated by get_mozilla_ciphers.py. */ - -/* Here are the TLS1.3 ciphers. Note that we don't have XCIPHER instances - * here, since we don't want to ever fake them. - */ -#ifdef TLS1_3_TXT_AES_128_GCM_SHA256 - CIPHER(0x1301, TLS1_3_TXT_AES_128_GCM_SHA256) -#endif -#ifdef TLS1_3_TXT_AES_256_GCM_SHA384 - CIPHER(0x1302, TLS1_3_TXT_AES_256_GCM_SHA384) -#endif -#ifdef TLS1_3_TXT_CHACHA20_POLY1305_SHA256 - CIPHER(0x1303, TLS1_3_TXT_CHACHA20_POLY1305_SHA256) -#endif -#ifdef TLS1_3_TXT_AES_128_CCM_SHA256 - CIPHER(0x1304, TLS1_3_TXT_AES_128_CCM_SHA256) -#endif - -/* Here's the machine-generated list. */ #ifdef TLS1_TXT_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 CIPHER(0xc02b, TLS1_TXT_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256) #else @@ -73,15 +54,15 @@ #else XCIPHER(0xc014, TLS1_TXT_ECDHE_RSA_WITH_AES_256_CBC_SHA) #endif -#ifdef TLS1_TXT_DHE_RSA_WITH_AES_128_SHA - CIPHER(0x0033, TLS1_TXT_DHE_RSA_WITH_AES_128_SHA) +#ifdef TLS1_TXT_RSA_WITH_AES_128_GCM_SHA256 + CIPHER(0x009c, TLS1_TXT_RSA_WITH_AES_128_GCM_SHA256) #else - XCIPHER(0x0033, TLS1_TXT_DHE_RSA_WITH_AES_128_SHA) + XCIPHER(0x009c, TLS1_TXT_RSA_WITH_AES_128_GCM_SHA256) #endif -#ifdef TLS1_TXT_DHE_RSA_WITH_AES_256_SHA - CIPHER(0x0039, TLS1_TXT_DHE_RSA_WITH_AES_256_SHA) +#ifdef TLS1_TXT_RSA_WITH_AES_256_GCM_SHA384 + CIPHER(0x009d, TLS1_TXT_RSA_WITH_AES_256_GCM_SHA384) #else - XCIPHER(0x0039, TLS1_TXT_DHE_RSA_WITH_AES_256_SHA) + XCIPHER(0x009d, TLS1_TXT_RSA_WITH_AES_256_GCM_SHA384) #endif #ifdef TLS1_TXT_RSA_WITH_AES_128_SHA CIPHER(0x002f, TLS1_TXT_RSA_WITH_AES_128_SHA) @@ -93,8 +74,3 @@ #else XCIPHER(0x0035, TLS1_TXT_RSA_WITH_AES_256_SHA) #endif -#ifdef SSL3_TXT_RSA_DES_192_CBC3_SHA - CIPHER(0x000a, SSL3_TXT_RSA_DES_192_CBC3_SHA) -#else - XCIPHER(0x000a, SSL3_TXT_RSA_DES_192_CBC3_SHA) -#endif diff -Nru tor-0.4.7.16/src/lib/tls/ciphers_v13.inc tor-0.4.9.6/src/lib/tls/ciphers_v13.inc --- tor-0.4.7.16/src/lib/tls/ciphers_v13.inc 1970-01-01 00:00:00.000000000 +0000 +++ tor-0.4.9.6/src/lib/tls/ciphers_v13.inc 2026-03-25 14:30:34.000000000 +0000 @@ -0,0 +1,15 @@ +/* Here are the TLS1.3 ciphers. Note that we don't have XCIPHER instances + * here, since we don't want to ever fake them. + * + * This matches Firefox's list: + * https://searchfox.org/mozilla-central/source/security/nss/lib/ssl/ssl3con.c#100 + */ +#ifdef TLS1_3_RFC_AES_128_GCM_SHA256 + CIPHER(0x1301, TLS1_3_RFC_AES_128_GCM_SHA256) +#endif +#ifdef TLS1_3_RFC_CHACHA20_POLY1305_SHA256 + CIPHER(0x1303, TLS1_3_RFC_CHACHA20_POLY1305_SHA256) +#endif +#ifdef TLS1_3_RFC_AES_256_GCM_SHA384 + CIPHER(0x1302, TLS1_3_RFC_AES_256_GCM_SHA384) +#endif diff -Nru tor-0.4.7.16/src/lib/tls/include.am tor-0.4.9.6/src/lib/tls/include.am --- tor-0.4.7.16/src/lib/tls/include.am 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/lib/tls/include.am 2026-03-25 14:30:34.000000000 +0000 @@ -33,6 +33,7 @@ # ADD_C_FILE: INSERT HEADERS HERE. noinst_HEADERS += \ src/lib/tls/ciphers.inc \ + src/lib/tls/ciphers_v13.inc \ src/lib/tls/buffers_tls.h \ src/lib/tls/nss_countbytes.h \ src/lib/tls/tortls.h \ diff -Nru tor-0.4.7.16/src/lib/tls/tortls.c tor-0.4.9.6/src/lib/tls/tortls.c --- tor-0.4.7.16/src/lib/tls/tortls.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/lib/tls/tortls.c 2026-03-25 14:30:34.000000000 +0000 @@ -93,19 +93,6 @@ return rv; } -/** - * Return the authentication key that we use to authenticate ourselves as a - * client in the V3 in-protocol handshake. - */ -crypto_pk_t * -tor_tls_get_my_client_auth_key(void) -{ - tor_tls_context_t *context = tor_tls_context_get(0); - if (! context) - return NULL; - return context->auth_key; -} - /** Increase the reference count of ctx. */ void tor_tls_context_incref(tor_tls_context_t *ctx) @@ -175,9 +162,8 @@ * If server_identity is NULL, this will not generate a server * TLS context. If TOR_TLS_CTX_IS_PUBLIC_SERVER is set in flags, use * the same TLS context for incoming and outgoing connections, and - * ignore client_identity. If one of TOR_TLS_CTX_USE_ECDHE_P{224,256} - * is set in flags, use that ECDHE group if possible; otherwise use - * the default ECDHE group. */ + * ignore client_identity. + */ int tor_tls_context_init(unsigned flags, crypto_pk_t *client_identity, @@ -407,47 +393,6 @@ tor_free(tls); } -/** If the provided tls connection is authenticated and has a - * certificate chain that is currently valid and signed, then set - * *identity_key to the identity certificate's key and return - * 0. Else, return -1 and log complaints with log-level severity. - */ -int -tor_tls_verify(int severity, tor_tls_t *tls, crypto_pk_t **identity) -{ - tor_x509_cert_impl_t *cert = NULL, *id_cert = NULL; - tor_x509_cert_t *peer_x509 = NULL, *id_x509 = NULL; - tor_assert(tls); - tor_assert(identity); - int rv = -1; - - try_to_extract_certs_from_tls(severity, tls, &cert, &id_cert); - if (!cert) - goto done; - if (!id_cert) { - log_fn(severity,LD_PROTOCOL,"No distinct identity certificate found"); - goto done; - } - peer_x509 = tor_x509_cert_new(cert); - id_x509 = tor_x509_cert_new(id_cert); - cert = id_cert = NULL; /* Prevent double-free */ - - if (! tor_tls_cert_is_valid(severity, peer_x509, id_x509, time(NULL), 0)) { - goto done; - } - - *identity = tor_tls_cert_get_key(id_x509); - rv = 0; - - done: - tor_x509_cert_impl_free(cert); - tor_x509_cert_impl_free(id_cert); - tor_x509_cert_free(peer_x509); - tor_x509_cert_free(id_x509); - - return rv; -} - static void subsys_tortls_shutdown(void) { diff -Nru tor-0.4.7.16/src/lib/tls/tortls.h tor-0.4.9.6/src/lib/tls/tortls.h --- tor-0.4.7.16/src/lib/tls/tortls.h 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/lib/tls/tortls.h 2026-03-25 14:30:34.000000000 +0000 @@ -75,8 +75,6 @@ void tor_tls_free_all(void); #define TOR_TLS_CTX_IS_PUBLIC_SERVER (1u<<0) -#define TOR_TLS_CTX_USE_ECDHE_P256 (1u<<1) -#define TOR_TLS_CTX_USE_ECDHE_P224 (1u<<2) void tor_tls_init(void); void tls_log_errors(tor_tls_t *tls, int severity, int domain, @@ -91,9 +89,6 @@ tor_tls_context_t *tor_tls_context_get(int is_server); tor_tls_t *tor_tls_new(tor_socket_t sock, int is_server); void tor_tls_set_logged_address(tor_tls_t *tls, const char *address); -void tor_tls_set_renegotiate_callback(tor_tls_t *tls, - void (*cb)(tor_tls_t *, void *arg), - void *arg); int tor_tls_is_server(tor_tls_t *tls); void tor_tls_release_socket(tor_tls_t *tls); void tor_tls_free_(tor_tls_t *tls); @@ -101,13 +96,9 @@ int tor_tls_peer_has_cert(tor_tls_t *tls); MOCK_DECL(struct tor_x509_cert_t *,tor_tls_get_peer_cert,(tor_tls_t *tls)); MOCK_DECL(struct tor_x509_cert_t *,tor_tls_get_own_cert,(tor_tls_t *tls)); -int tor_tls_verify(int severity, tor_tls_t *tls, crypto_pk_t **identity); MOCK_DECL(int, tor_tls_read, (tor_tls_t *tls, char *cp, size_t len)); int tor_tls_write(tor_tls_t *tls, const char *cp, size_t n); int tor_tls_handshake(tor_tls_t *tls); -int tor_tls_finish_handshake(tor_tls_t *tls); -void tor_tls_unblock_renegotiation(tor_tls_t *tls); -void tor_tls_block_renegotiation(tor_tls_t *tls); int tor_tls_get_pending_bytes(tor_tls_t *tls); size_t tor_tls_get_forced_write_size(tor_tls_t *tls); @@ -120,16 +111,8 @@ MOCK_DECL(double, tls_get_write_overhead_ratio, (void)); -int tor_tls_used_v1_handshake(tor_tls_t *tls); -int tor_tls_get_num_server_handshakes(tor_tls_t *tls); -int tor_tls_server_got_renegotiate(tor_tls_t *tls); MOCK_DECL(int,tor_tls_cert_matches_key,(const tor_tls_t *tls, const struct tor_x509_cert_t *cert)); -MOCK_DECL(int,tor_tls_get_tlssecrets,(tor_tls_t *tls, uint8_t *secrets_out)); -#ifdef ENABLE_OPENSSL -/* OpenSSL lets us see these master secrets; NSS sensibly does not. */ -#define HAVE_WORKING_TOR_TLS_GET_TLSSECRETS -#endif MOCK_DECL(int,tor_tls_export_key_material,( tor_tls_t *tls, uint8_t *secrets_out, const uint8_t *context, @@ -151,9 +134,6 @@ int tor_tls_get_my_certs(int server, const struct tor_x509_cert_t **link_cert_out, const struct tor_x509_cert_t **id_cert_out); -crypto_pk_t *tor_tls_get_my_client_auth_key(void); - -const char *tor_tls_get_ciphersuite_name(tor_tls_t *tls); int evaluate_ecgroup_for_tls(const char *ecgroup); diff -Nru tor-0.4.7.16/src/lib/tls/tortls_internal.h tor-0.4.9.6/src/lib/tls/tortls_internal.h --- tor-0.4.7.16/src/lib/tls/tortls_internal.h 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/lib/tls/tortls_internal.h 2026-03-25 14:30:34.000000000 +0000 @@ -18,10 +18,6 @@ int tor_tls_get_error(tor_tls_t *tls, int r, int extra, const char *doing, int severity, int domain); #endif -MOCK_DECL(void, try_to_extract_certs_from_tls, - (int severity, tor_tls_t *tls, - tor_x509_cert_impl_t **cert_out, - tor_x509_cert_impl_t **id_cert_out)); tor_tls_context_t *tor_tls_context_new(crypto_pk_t *identity, unsigned int key_lifetime, unsigned flags, int is_client); @@ -44,30 +40,14 @@ #ifdef ENABLE_OPENSSL tor_tls_t *tor_tls_get_by_ssl(const struct ssl_st *ssl); -int tor_tls_client_is_using_v2_ciphers(const struct ssl_st *ssl); void tor_tls_debug_state_callback(const struct ssl_st *ssl, int type, int val); void tor_tls_server_info_callback(const struct ssl_st *ssl, int type, int val); void tor_tls_allocate_tor_tls_object_ex_data_index(void); -#if !defined(HAVE_SSL_SESSION_GET_MASTER_KEY) -size_t SSL_SESSION_get_master_key(struct ssl_session_st *s, - uint8_t *out, - size_t len); -#endif - #ifdef TORTLS_OPENSSL_PRIVATE int always_accept_verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx); -int tor_tls_classify_client_ciphers(const struct ssl_st *ssl, - STACK_OF(SSL_CIPHER) *peer_ciphers); -STATIC int tor_tls_session_secret_cb(struct ssl_st *ssl, void *secret, - int *secret_len, - STACK_OF(SSL_CIPHER) *peer_ciphers, - CONST_IF_OPENSSL_1_1_API SSL_CIPHER **cipher, - void *arg); -STATIC int find_cipher_by_id(const SSL *ssl, const SSL_METHOD *m, - uint16_t cipher); #endif /* defined(TORTLS_OPENSSL_PRIVATE) */ #endif /* defined(ENABLE_OPENSSL) */ diff -Nru tor-0.4.7.16/src/lib/tls/tortls_nss.c tor-0.4.9.6/src/lib/tls/tortls_nss.c --- tor-0.4.7.16/src/lib/tls/tortls_nss.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/lib/tls/tortls_nss.c 2026-03-25 14:30:34.000000000 +0000 @@ -46,34 +46,6 @@ static SECStatus always_accept_cert_cb(void *, PRFileDesc *, PRBool, PRBool); -MOCK_IMPL(void, -try_to_extract_certs_from_tls,(int severity, tor_tls_t *tls, - tor_x509_cert_impl_t **cert_out, - tor_x509_cert_impl_t **id_cert_out)) -{ - tor_assert(tls); - tor_assert(cert_out); - tor_assert(id_cert_out); - (void) severity; - - *cert_out = *id_cert_out = NULL; - - CERTCertificate *peer = SSL_PeerCertificate(tls->ssl); - if (!peer) - return; - *cert_out = peer; /* Now owns pointer. */ - - CERTCertList *chain = SSL_PeerCertificateChain(tls->ssl); - CERTCertListNode *c = CERT_LIST_HEAD(chain); - for (; !CERT_LIST_END(c, chain); c = CERT_LIST_NEXT(c)) { - if (CERT_CompareCerts(c->cert, peer) == PR_FALSE) { - *id_cert_out = CERT_DupCertificate(c->cert); - break; - } - } - CERT_DestroyCertList(chain); -} - static bool we_like_ssl_cipher(SSLCipherAlgorithm ca) { @@ -104,6 +76,11 @@ case ssl_kea_ecdh_psk: return false; case ssl_kea_dh_psk: return false; +#ifdef NSS_HAS_ECDH_HYBRID + case ssl_kea_ecdh_hybrid_psk: return false; + case ssl_kea_ecdh_hybrid: return true; +#endif + case ssl_kea_dh: return true; case ssl_kea_ecdh: return true; case ssl_kea_tls13_any: return true; @@ -464,18 +441,6 @@ return tls; } -void -tor_tls_set_renegotiate_callback(tor_tls_t *tls, - void (*cb)(tor_tls_t *, void *arg), - void *arg) -{ - tor_assert(tls); - (void)cb; - (void)arg; - - /* We don't support renegotiation-based TLS with NSS. */ -} - /** * Tell the TLS library that the underlying socket for tls has been * closed, and the library should not attempt to free that socket itself. @@ -619,7 +584,7 @@ if (s == SECSuccess) { tls->state = TOR_TLS_ST_OPEN; log_debug(LD_NET, "SSL handshake is supposedly complete."); - return tor_tls_finish_handshake(tls); + return TOR_TLS_DONE; } if (PORT_GetError() == PR_WOULD_BLOCK_ERROR) return TOR_TLS_WANTREAD; /* XXXX What about wantwrite? */ @@ -628,29 +593,6 @@ } int -tor_tls_finish_handshake(tor_tls_t *tls) -{ - tor_assert(tls); - // We don't need to do any of the weird handshake nonsense stuff on NSS, - // since we only support recent handshakes. - return TOR_TLS_DONE; -} - -void -tor_tls_unblock_renegotiation(tor_tls_t *tls) -{ - tor_assert(tls); - /* We don't support renegotiation with NSS. */ -} - -void -tor_tls_block_renegotiation(tor_tls_t *tls) -{ - tor_assert(tls); - /* We don't support renegotiation with NSS. */ -} - -int tor_tls_get_pending_bytes(tor_tls_t *tls) { tor_assert(tls); @@ -713,22 +655,6 @@ return 0.95; } -int -tor_tls_used_v1_handshake(tor_tls_t *tls) -{ - tor_assert(tls); - /* We don't support or allow the V1 handshake with NSS. - */ - return 0; -} - -int -tor_tls_server_got_renegotiate(tor_tls_t *tls) -{ - tor_assert(tls); - return 0; /* We don't support renegotiation with NSS */ -} - MOCK_IMPL(int, tor_tls_cert_matches_key,(const tor_tls_t *tls, const struct tor_x509_cert_t *cert)) @@ -789,17 +715,6 @@ } MOCK_IMPL(int, -tor_tls_get_tlssecrets,(tor_tls_t *tls, uint8_t *secrets_out)) -{ - tor_assert(tls); - tor_assert(secrets_out); - - /* There's no way to get this information out of NSS. */ - - return -1; -} - -MOCK_IMPL(int, tor_tls_export_key_material,(tor_tls_t *tls, uint8_t *secrets_out, const uint8_t *context, size_t context_len, @@ -829,30 +744,6 @@ return (s == SECSuccess) ? 0 : -1; } -const char * -tor_tls_get_ciphersuite_name(tor_tls_t *tls) -{ - tor_assert(tls); - - SSLChannelInfo channel_info; - SSLCipherSuiteInfo cipher_info; - - memset(&channel_info, 0, sizeof(channel_info)); - memset(&cipher_info, 0, sizeof(cipher_info)); - - SECStatus s = SSL_GetChannelInfo(tls->ssl, - &channel_info, sizeof(channel_info)); - if (s != SECSuccess) - return NULL; - - s = SSL_GetCipherSuiteInfo(channel_info.cipherSuite, - &cipher_info, sizeof(cipher_info)); - if (s != SECSuccess) - return NULL; - - return cipher_info.cipherSuiteName; -} - /** The group we should use for ecdhe when none was selected. */ #define SEC_OID_TOR_DEFAULT_ECDHE_GROUP SEC_OID_ANSIX962_EC_PRIME256V1 diff -Nru tor-0.4.7.16/src/lib/tls/tortls_openssl.c tor-0.4.9.6/src/lib/tls/tortls_openssl.c --- tor-0.4.7.16/src/lib/tls/tortls_openssl.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/lib/tls/tortls_openssl.c 2026-03-25 14:30:34.000000000 +0000 @@ -80,46 +80,9 @@ #define ADDR(tls) (((tls) && (tls)->address) ? tls->address : "peer") -#if OPENSSL_VERSION_NUMBER < OPENSSL_V(1,0,0,'f') -/* This is a version of OpenSSL before 1.0.0f. It does not have - * the CVE-2011-4576 fix, and as such it can't use RELEASE_BUFFERS and - * SSL3 safely at the same time. - */ -#define DISABLE_SSL3_HANDSHAKE -#endif /* OPENSSL_VERSION_NUMBER < OPENSSL_V(1,0,0,'f') */ - -/* We redefine these so that we can run correctly even if the vendor gives us - * a version of OpenSSL that does not match its header files. (Apple: I am - * looking at you.) - */ -#ifndef SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION -#define SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION 0x00040000L -#endif -#ifndef SSL3_FLAGS_ALLOW_UNSAFE_LEGACY_RENEGOTIATION -#define SSL3_FLAGS_ALLOW_UNSAFE_LEGACY_RENEGOTIATION 0x0010 -#endif - /** Set to true iff openssl bug 7712 has been detected. */ static int openssl_bug_7712_is_present = 0; -/** Return values for tor_tls_classify_client_ciphers. - * - * @{ - */ -/** An error occurred when examining the client ciphers */ -#define CIPHERS_ERR -1 -/** The client cipher list indicates that a v1 handshake was in use. */ -#define CIPHERS_V1 1 -/** The client cipher list indicates that the client is using the v2 or the - * v3 handshake, but that it is (probably!) lying about what ciphers it - * supports */ -#define CIPHERS_V2 2 -/** The client cipher list indicates that the client is using the v2 or the - * v3 handshake, and that it is telling the truth about what ciphers it - * supports */ -#define CIPHERS_UNRESTRICTED 3 -/** @} */ - /** The ex_data index in which we store a pointer to an SSL object's * corresponding tor_tls_t object. */ STATIC int tor_tls_object_ex_data_index = -1; @@ -208,9 +171,6 @@ case SSL_R_HTTP_REQUEST: case SSL_R_HTTPS_PROXY_REQUEST: case SSL_R_RECORD_LENGTH_MISMATCH: -#ifndef OPENSSL_1_1_API - case SSL_R_RECORD_TOO_LARGE: -#endif case SSL_R_UNKNOWN_PROTOCOL: case SSL_R_UNSUPPORTED_PROTOCOL: severity = LOG_INFO; @@ -333,46 +293,7 @@ check_no_tls_errors(); if (!tls_library_is_initialized) { -#ifdef OPENSSL_1_1_API OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS, NULL); -#else - SSL_library_init(); - SSL_load_error_strings(); -#endif /* defined(OPENSSL_1_1_API) */ - -#if (SIZEOF_VOID_P >= 8 && \ - OPENSSL_VERSION_NUMBER >= OPENSSL_V_SERIES(1,0,1)) - long version = tor_OpenSSL_version_num(); - - /* LCOV_EXCL_START : we can't test these lines on the same machine */ - if (version >= OPENSSL_V_SERIES(1,0,1)) { - /* Warn if we could *almost* be running with much faster ECDH. - If we're built for a 64-bit target, using OpenSSL 1.0.1, but we - don't have one of the built-in __uint128-based speedups, we are - just one build operation away from an accelerated handshake. - - (We could be looking at OPENSSL_NO_EC_NISTP_64_GCC_128 instead of - doing this test, but that gives compile-time options, not runtime - behavior.) - */ - EC_KEY *key = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1); - const EC_GROUP *g = key ? EC_KEY_get0_group(key) : NULL; - const EC_METHOD *m = g ? EC_GROUP_method_of(g) : NULL; - const int warn = (m == EC_GFp_simple_method() || - m == EC_GFp_mont_method() || - m == EC_GFp_nist_method()); - EC_KEY_free(key); - - if (warn) - log_notice(LD_GENERAL, "We were built to run on a 64-bit CPU, with " - "OpenSSL 1.0.1 or later, but with a version of OpenSSL " - "that apparently lacks accelerated support for the NIST " - "P-224 and P-256 groups. Building openssl with such " - "support (using the enable-ec_nistp_64_gcc_128 option " - "when configuring it) would make ECDH much faster."); - } - /* LCOV_EXCL_STOP */ -#endif /* (SIZEOF_VOID_P >= 8 && ... */ tor_tls_allocate_tor_tls_object_ex_data_index(); @@ -393,37 +314,8 @@ return 1; } -/** List of ciphers that servers should select from when the client might be - * claiming extra unsupported ciphers in order to avoid fingerprinting. */ -static const char SERVER_CIPHER_LIST[] = -#ifdef TLS1_3_TXT_AES_128_GCM_SHA256 - /* This one can never actually get selected, since if the client lists it, - * we will assume that the client is honest, and not use this list. - * Nonetheless we list it if it's available, so that the server doesn't - * conclude that it has no valid ciphers if it's running with TLS1.3. - */ - TLS1_3_TXT_AES_128_GCM_SHA256 ":" -#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; - -/** List of ciphers that servers should select from when we actually have - * our choice of what cipher to use. */ -static const char UNRESTRICTED_SERVER_CIPHER_LIST[] = - /* Here are the TLS 1.3 ciphers we like, in the order we prefer. */ -#ifdef TLS1_3_TXT_AES_256_GCM_SHA384 - TLS1_3_TXT_AES_256_GCM_SHA384 ":" -#endif -#ifdef TLS1_3_TXT_CHACHA20_POLY1305_SHA256 - TLS1_3_TXT_CHACHA20_POLY1305_SHA256 ":" -#endif -#ifdef TLS1_3_TXT_AES_128_GCM_SHA256 - TLS1_3_TXT_AES_128_GCM_SHA256 ":" -#endif -#ifdef TLS1_3_TXT_AES_128_CCM_SHA256 - TLS1_3_TXT_AES_128_CCM_SHA256 ":" -#endif - +/** List of ciphers that servers should select from when using TLS 1.2 */ +static const char UNRESTRICTED_TLS1_2_SERVER_CIPHER_LIST[] = /* This list is autogenerated with the gen_server_ciphers.py script; * don't hand-edit it. */ #ifdef TLS1_TXT_ECDHE_RSA_WITH_AES_256_GCM_SHA384 @@ -491,6 +383,12 @@ * of any cipher we say. */ "!SSLv2" ; +static char CLIENT_CIPHER_LIST_TLSv13[] = +#ifndef COCCI +#include "lib/tls/ciphers_v13.inc" +#endif + "" + ; #undef CIPHER #undef XCIPHER @@ -556,32 +454,17 @@ } } -#if 0 - /* Tell OpenSSL to only use TLS1. This may have subtly different results - * from SSLv23_method() with SSLv2 and SSLv3 disabled, so we need to do some - * investigation before we consider adjusting it. It should be compatible - * with existing Tors. */ - if (!(result->ctx = SSL_CTX_new(TLSv1_method()))) - goto error; -#endif /* 0 */ - - /* Tell OpenSSL to use TLS 1.0 or later but not SSL2 or SSL3. */ -#ifdef HAVE_TLS_METHOD + /* Tell OpenSSL to use TLS 1.2 or later. */ if (!(result->ctx = SSL_CTX_new(TLS_method()))) goto error; -#else - if (!(result->ctx = SSL_CTX_new(SSLv23_method()))) + if (!SSL_CTX_set_min_proto_version(result->ctx, TLS1_2_VERSION)) goto error; -#endif /* defined(HAVE_TLS_METHOD) */ #ifdef HAVE_SSL_CTX_SET_SECURITY_LEVEL /* Level 1 re-enables RSA1024 and DH1024 for compatibility with old tors */ SSL_CTX_set_security_level(result->ctx, 1); #endif - SSL_CTX_set_options(result->ctx, SSL_OP_NO_SSLv2); - SSL_CTX_set_options(result->ctx, SSL_OP_NO_SSLv3); - /* Prefer the server's ordering of ciphers: the client's ordering has * historically been chosen for fingerprinting resistance. */ SSL_CTX_set_options(result->ctx, SSL_OP_CIPHER_SERVER_PREFERENCE); @@ -609,13 +492,12 @@ SSL_CTX_set_options(result->ctx, SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION); #endif - /* Yes, we know what we are doing here. No, we do not treat a renegotiation - * as authenticating any earlier-received data. - */ - { - SSL_CTX_set_options(result->ctx, - SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION); - } +#ifdef SSL_OP_NO_RENEGOTIATION + SSL_CTX_set_options(result->ctx, SSL_OP_NO_RENEGOTIATION); +#endif +#ifdef SSL_OP_NO_CLIENT_RENEGOTIATION + SSL_CTX_set_options(result->ctx, SSL_OP_NO_CLIENT_RENEGOTIATION); +#endif /* Don't actually allow compression; it uses RAM and time, it makes TLS * vulnerable to CRIME-style attacks, and most of the data we transmit over @@ -623,12 +505,6 @@ #ifdef SSL_OP_NO_COMPRESSION SSL_CTX_set_options(result->ctx, SSL_OP_NO_COMPRESSION); #endif -#if OPENSSL_VERSION_NUMBER < OPENSSL_V_SERIES(1,1,0) -#ifndef OPENSSL_NO_COMP - if (result->ctx->comp_methods) - result->ctx->comp_methods = NULL; -#endif -#endif /* OPENSSL_VERSION_NUMBER < OPENSSL_V_SERIES(1,1,0) */ #ifdef SSL_MODE_RELEASE_BUFFERS SSL_CTX_set_mode(result->ctx, SSL_MODE_RELEASE_BUFFERS); @@ -639,11 +515,10 @@ result->my_link_cert->cert)) { goto error; } - if (result->my_id_cert) { - X509_STORE *s = SSL_CTX_get_cert_store(result->ctx); - tor_assert(s); - X509_STORE_add_cert(s, result->my_id_cert->cert); - } + // Here we would once add my_id_cert too via X509_STORE_add_cert. + // + // We no longer do that, since we no longer send multiple certs; + // that was part of the obsolete v1 handshake. } SSL_CTX_set_session_cache_mode(result->ctx, SSL_SESS_CACHE_OFF); if (!is_client) { @@ -664,40 +539,78 @@ SSL_CTX_set_tmp_dh(result->ctx, dh); DH_free(dh); } -/* We check for this function in two ways, since it might be either a symbol - * or a macro. */ -#if defined(SSL_CTX_set1_groups_list) || defined(HAVE_SSL_CTX_SET1_GROUPS_LIST) + { - const char *list; - if (flags & TOR_TLS_CTX_USE_ECDHE_P224) - list = "P-224:P-256"; - else if (flags & TOR_TLS_CTX_USE_ECDHE_P256) - list = "P-256:P-224"; - else - list = "P-256:P-224"; - int r = (int) SSL_CTX_set1_groups_list(result->ctx, list); - if (r < 0) - goto error; + // We'd like to say something like: + // "?X25519MLKEM768:P-256:P-224" + // to mean that we prefer X25519MLKEM768 if it is present; + // but we do insist on the presence of P-256 and P-224. + // + // Unfortunately, we support back to OpenSSL 3.0, which did not provide + // any syntax for saying "don't worry if this group isn't supported." + // Instead, we have to make this preference list of preference lists. + static const struct { + // Minimal version with which to try this syntax. + // We have to restrict, since older versions of openssl + // can misunderstand-but nonetheless accept!-syntaxes + // supported by newer versions. See #41058 for one example. + long min_version; + const char *groups; + } group_lists[] = { + // We do use the ? syntax here, since every version of OpenSSL + // that supports ML-KEM also supports the ? syntax. + // We also use the * and / syntaxes: + // '*' indicates that the client should send these keyshares. + // "/" separates tuples of groups that are "comparably secure". + // + // Note that we tell the client to send a P-256 keyshare, since until + // this commit, our servers didn't accept X25519. + // + // Also note that until the upstream LibreSSL bug from tor#41134 gets + // fixed, the order of groups common between each preference list must + // be the same. We can't prefer P-256 in one, and X25519 in another. + { + OPENSSL_V_SERIES(3,5,0), + "?*X25519MLKEM768 / ?SecP256r1MLKEM768 / *P-256:?X25519:P-224" + }, + { 0, "P-256:X25519:P-224" }, + { 0, "P-256:P-224" }, + }; + bool success = false; + long our_version = tor_OpenSSL_version_num(); + for (unsigned j = 0; j < ARRAY_LENGTH(group_lists); ++j) { + const char *list = group_lists[j].groups; + if (group_lists[j].min_version > our_version) { + log_info(LD_NET, "Not trying groups %s because of OpenSSL version.", + list); + continue; + } + int r = (int) SSL_CTX_set1_groups_list(result->ctx, list); + if (r == 1) { + static bool have_logged_already = false; + if (!have_logged_already) { + /* say it only once at startup, since the answer won't change */ + log_notice(LD_NET, "Set list of supported TLS groups to: %s", list); + have_logged_already = true; + } + success = true; + break; + } + log_info(LD_NET, "Group list %s wasn't accepted", list); + } + if (! success) { + log_warn(LD_NET, "No lists of TLS groups were supported. " + "Using library defaults"); + } + } + + if (is_client) { + SSL_CTX_set_verify(result->ctx, SSL_VERIFY_PEER, + always_accept_verify_cb); + } else { + /* Don't send a certificate request at all if we're not a client. */ + SSL_CTX_set_verify(result->ctx, SSL_VERIFY_NONE, NULL); } -#else /* !(defined(SSL_CTX_set1_groups_list) || defined(HAVE_SSL_CTX_SE...)) */ - if (! is_client) { - int nid; - EC_KEY *ec_key; - if (flags & TOR_TLS_CTX_USE_ECDHE_P224) - nid = NID_secp224r1; - else if (flags & TOR_TLS_CTX_USE_ECDHE_P256) - nid = NID_X9_62_prime256v1; - else - nid = NID_tor_default_ecdhe_group; - /* Use P-256 for ECDHE. */ - ec_key = EC_KEY_new_by_curve_name(nid); - if (ec_key != NULL) /*XXXX Handle errors? */ - SSL_CTX_set_tmp_ecdh(result->ctx, ec_key); - EC_KEY_free(ec_key); - } -#endif /* defined(SSL_CTX_set1_groups_list) || defined(HAVE_SSL_CTX_SET1...) */ - SSL_CTX_set_verify(result->ctx, SSL_VERIFY_PEER, - always_accept_verify_cb); /* let us realloc bufs that we're writing from */ SSL_CTX_set_mode(result->ctx, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER); @@ -727,336 +640,6 @@ /* LCOV_EXCL_STOP */ } -/* Return the name of the negotiated ciphersuite in use on tls */ -const char * -tor_tls_get_ciphersuite_name(tor_tls_t *tls) -{ - return SSL_get_cipher(tls->ssl); -} - -/* Here's the old V2 cipher list we sent from 0.2.1.1-alpha up to - * 0.2.3.17-beta. If a client is using this list, we can't believe the ciphers - * that it claims to support. We'll prune this list to remove the ciphers - * *we* don't recognize. */ -STATIC uint16_t v2_cipher_list[] = { - 0xc00a, /* TLS1_TXT_ECDHE_ECDSA_WITH_AES_256_CBC_SHA */ - 0xc014, /* TLS1_TXT_ECDHE_RSA_WITH_AES_256_CBC_SHA */ - 0x0039, /* TLS1_TXT_DHE_RSA_WITH_AES_256_SHA */ - 0x0038, /* TLS1_TXT_DHE_DSS_WITH_AES_256_SHA */ - 0xc00f, /* TLS1_TXT_ECDH_RSA_WITH_AES_256_CBC_SHA */ - 0xc005, /* TLS1_TXT_ECDH_ECDSA_WITH_AES_256_CBC_SHA */ - 0x0035, /* TLS1_TXT_RSA_WITH_AES_256_SHA */ - 0xc007, /* TLS1_TXT_ECDHE_ECDSA_WITH_RC4_128_SHA */ - 0xc009, /* TLS1_TXT_ECDHE_ECDSA_WITH_AES_128_CBC_SHA */ - 0xc011, /* TLS1_TXT_ECDHE_RSA_WITH_RC4_128_SHA */ - 0xc013, /* TLS1_TXT_ECDHE_RSA_WITH_AES_128_CBC_SHA */ - 0x0033, /* TLS1_TXT_DHE_RSA_WITH_AES_128_SHA */ - 0x0032, /* TLS1_TXT_DHE_DSS_WITH_AES_128_SHA */ - 0xc00c, /* TLS1_TXT_ECDH_RSA_WITH_RC4_128_SHA */ - 0xc00e, /* TLS1_TXT_ECDH_RSA_WITH_AES_128_CBC_SHA */ - 0xc002, /* TLS1_TXT_ECDH_ECDSA_WITH_RC4_128_SHA */ - 0xc004, /* TLS1_TXT_ECDH_ECDSA_WITH_AES_128_CBC_SHA */ - 0x0004, /* SSL3_TXT_RSA_RC4_128_MD5 */ - 0x0005, /* SSL3_TXT_RSA_RC4_128_SHA */ - 0x002f, /* TLS1_TXT_RSA_WITH_AES_128_SHA */ - 0xc008, /* TLS1_TXT_ECDHE_ECDSA_WITH_DES_192_CBC3_SHA */ - 0xc012, /* TLS1_TXT_ECDHE_RSA_WITH_DES_192_CBC3_SHA */ - 0x0016, /* SSL3_TXT_EDH_RSA_DES_192_CBC3_SHA */ - 0x0013, /* SSL3_TXT_EDH_DSS_DES_192_CBC3_SHA */ - 0xc00d, /* TLS1_TXT_ECDH_RSA_WITH_DES_192_CBC3_SHA */ - 0xc003, /* TLS1_TXT_ECDH_ECDSA_WITH_DES_192_CBC3_SHA */ - 0xfeff, /* SSL3_TXT_RSA_FIPS_WITH_3DES_EDE_CBC_SHA */ - 0x000a, /* SSL3_TXT_RSA_DES_192_CBC3_SHA */ - 0 -}; -/** Have we removed the unrecognized ciphers from v2_cipher_list yet? */ -static int v2_cipher_list_pruned = 0; - -/** Return 0 if m does not support the cipher with ID cipher; - * return 1 if it does support it, or if we have no way to tell. */ -int -find_cipher_by_id(const SSL *ssl, const SSL_METHOD *m, uint16_t cipher) -{ - const SSL_CIPHER *c; -#ifdef HAVE_SSL_CIPHER_FIND - (void) m; - { - unsigned char cipherid[3]; - tor_assert(ssl); - set_uint16(cipherid, tor_htons(cipher)); - cipherid[2] = 0; /* If ssl23_get_cipher_by_char finds no cipher starting - * with a two-byte 'cipherid', it may look for a v2 - * cipher with the appropriate 3 bytes. */ - c = SSL_CIPHER_find((SSL*)ssl, cipherid); - if (c) - tor_assert((SSL_CIPHER_get_id(c) & 0xffff) == cipher); - return c != NULL; - } -#else /* !defined(HAVE_SSL_CIPHER_FIND) */ - -# if defined(HAVE_STRUCT_SSL_METHOD_ST_GET_CIPHER_BY_CHAR) - if (m && m->get_cipher_by_char) { - unsigned char cipherid[3]; - set_uint16(cipherid, tor_htons(cipher)); - cipherid[2] = 0; /* If ssl23_get_cipher_by_char finds no cipher starting - * with a two-byte 'cipherid', it may look for a v2 - * cipher with the appropriate 3 bytes. */ - c = m->get_cipher_by_char(cipherid); - if (c) - tor_assert((c->id & 0xffff) == cipher); - return c != NULL; - } -#endif /* defined(HAVE_STRUCT_SSL_METHOD_ST_GET_CIPHER_BY_CHAR) */ -# ifndef OPENSSL_1_1_API - if (m && m->get_cipher && m->num_ciphers) { - /* It would seem that some of the "let's-clean-up-openssl" forks have - * removed the get_cipher_by_char function. Okay, so now you get a - * quadratic search. - */ - int i; - for (i = 0; i < m->num_ciphers(); ++i) { - c = m->get_cipher(i); - if (c && (c->id & 0xffff) == cipher) { - return 1; - } - } - return 0; - } -#endif /* !defined(OPENSSL_1_1_API) */ - (void) ssl; - (void) m; - (void) cipher; - return 1; /* No way to search */ -#endif /* defined(HAVE_SSL_CIPHER_FIND) */ -} - -/** Remove from v2_cipher_list every cipher that we don't support, so that - * comparing v2_cipher_list to a client's cipher list will give a sensible - * result. */ -static void -prune_v2_cipher_list(const SSL *ssl) -{ - uint16_t *inp, *outp; -#ifdef HAVE_TLS_METHOD - const SSL_METHOD *m = TLS_method(); -#else - const SSL_METHOD *m = SSLv23_method(); -#endif - - inp = outp = v2_cipher_list; - while (*inp) { - if (find_cipher_by_id(ssl, m, *inp)) { - *outp++ = *inp++; - } else { - inp++; - } - } - *outp = 0; - - v2_cipher_list_pruned = 1; -} - -/** Examine the client cipher list in ssl, and determine what kind of - * client it is. Return one of CIPHERS_ERR, CIPHERS_V1, CIPHERS_V2, - * CIPHERS_UNRESTRICTED. - **/ -int -tor_tls_classify_client_ciphers(const SSL *ssl, - STACK_OF(SSL_CIPHER) *peer_ciphers) -{ - int i, res; - tor_tls_t *tor_tls; - if (PREDICT_UNLIKELY(!v2_cipher_list_pruned)) - prune_v2_cipher_list(ssl); - - tor_tls = tor_tls_get_by_ssl(ssl); - if (tor_tls && tor_tls->client_cipher_list_type) - return tor_tls->client_cipher_list_type; - - /* If we reached this point, we just got a client hello. See if there is - * a cipher list. */ - if (!peer_ciphers) { - log_info(LD_NET, "No ciphers on session"); - res = CIPHERS_ERR; - goto done; - } - /* Now we need to see if there are any ciphers whose presence means we're - * dealing with an updated Tor. */ - for (i = 0; i < sk_SSL_CIPHER_num(peer_ciphers); ++i) { - const SSL_CIPHER *cipher = sk_SSL_CIPHER_value(peer_ciphers, i); - const char *ciphername = SSL_CIPHER_get_name(cipher); - if (strcmp(ciphername, TLS1_TXT_DHE_RSA_WITH_AES_128_SHA) && - strcmp(ciphername, TLS1_TXT_DHE_RSA_WITH_AES_256_SHA) && - strcmp(ciphername, SSL3_TXT_EDH_RSA_DES_192_CBC3_SHA) && - strcmp(ciphername, "(NONE)")) { - log_debug(LD_NET, "Got a non-version-1 cipher called '%s'", ciphername); - // return 1; - goto v2_or_higher; - } - } - res = CIPHERS_V1; - goto done; - v2_or_higher: - { - const uint16_t *v2_cipher = v2_cipher_list; - for (i = 0; i < sk_SSL_CIPHER_num(peer_ciphers); ++i) { - const SSL_CIPHER *cipher = sk_SSL_CIPHER_value(peer_ciphers, i); - uint16_t id = SSL_CIPHER_get_id(cipher) & 0xffff; - if (id == 0x00ff) /* extended renegotiation indicator. */ - continue; - if (!id || id != *v2_cipher) { - res = CIPHERS_UNRESTRICTED; - goto dump_ciphers; - } - ++v2_cipher; - } - if (*v2_cipher != 0) { - res = CIPHERS_UNRESTRICTED; - goto dump_ciphers; - } - res = CIPHERS_V2; - } - - dump_ciphers: - { - smartlist_t *elts = smartlist_new(); - char *s; - for (i = 0; i < sk_SSL_CIPHER_num(peer_ciphers); ++i) { - const SSL_CIPHER *cipher = sk_SSL_CIPHER_value(peer_ciphers, i); - const char *ciphername = SSL_CIPHER_get_name(cipher); - smartlist_add(elts, (char*)ciphername); - } - s = smartlist_join_strings(elts, ":", 0, NULL); - log_debug(LD_NET, "Got a %s V2/V3 cipher list from %s. It is: '%s'", - (res == CIPHERS_V2) ? "fictitious" : "real", ADDR(tor_tls), s); - tor_free(s); - smartlist_free(elts); - } - done: - if (tor_tls && peer_ciphers) - return tor_tls->client_cipher_list_type = res; - - return res; -} - -/** Return true iff the cipher list suggested by the client for ssl is - * a list that indicates that the client knows how to do the v2 TLS connection - * handshake. */ -int -tor_tls_client_is_using_v2_ciphers(const SSL *ssl) -{ - STACK_OF(SSL_CIPHER) *ciphers; -#ifdef HAVE_SSL_GET_CLIENT_CIPHERS - ciphers = SSL_get_client_ciphers(ssl); -#else - SSL_SESSION *session; - if (!(session = SSL_get_session((SSL *)ssl))) { - log_info(LD_NET, "No session on TLS?"); - return CIPHERS_ERR; - } - ciphers = session->ciphers; -#endif /* defined(HAVE_SSL_GET_CLIENT_CIPHERS) */ - - return tor_tls_classify_client_ciphers(ssl, ciphers) >= CIPHERS_V2; -} - -/** Invoked when we're accepting a connection on ssl, and the connection - * changes state. We use this: - *

    • To alter the state of the handshake partway through, so we - * do not send or request extra certificates in v2 handshakes.
    • - *
    • To detect renegotiation
    - */ -void -tor_tls_server_info_callback(const SSL *ssl, int type, int val) -{ - tor_tls_t *tls; - (void) val; - - IF_BUG_ONCE(ssl == NULL) { - return; // LCOV_EXCL_LINE - } - - tor_tls_debug_state_callback(ssl, type, val); - - if (type != SSL_CB_ACCEPT_LOOP) - return; - - OSSL_HANDSHAKE_STATE ssl_state = SSL_get_state(ssl); - if (! STATE_IS_SW_SERVER_HELLO(ssl_state)) - return; - tls = tor_tls_get_by_ssl(ssl); - if (tls) { - /* Check whether we're watching for renegotiates. If so, this is one! */ - if (tls->negotiated_callback) - tls->got_renegotiate = 1; - } else { - log_warn(LD_BUG, "Couldn't look up the tls for an SSL*. How odd!"); - return; - } - - /* Now check the cipher list. */ - if (tor_tls_client_is_using_v2_ciphers(ssl)) { - if (tls->wasV2Handshake) - return; /* We already turned this stuff off for the first handshake; - * This is a renegotiation. */ - - /* Yes, we're casting away the const from ssl. This is very naughty of us. - * Let's hope openssl doesn't notice! */ - - /* Set SSL_MODE_NO_AUTO_CHAIN to keep from sending back any extra certs. */ - SSL_set_mode((SSL*) ssl, SSL_MODE_NO_AUTO_CHAIN); - /* Don't send a hello request. */ - SSL_set_verify((SSL*) ssl, SSL_VERIFY_NONE, NULL); - - if (tls) { - tls->wasV2Handshake = 1; - } else { - /* LCOV_EXCL_START this line is not reachable */ - log_warn(LD_BUG, "Couldn't look up the tls for an SSL*. How odd!"); - /* LCOV_EXCL_STOP */ - } - } -} - -/** Callback to get invoked on a server after we've read the list of ciphers - * the client supports, but before we pick our own ciphersuite. - * - * We can't abuse an info_cb for this, since by the time one of the - * client_hello info_cbs is called, we've already picked which ciphersuite to - * use. - * - * Technically, this function is an abuse of this callback, since the point of - * a session_secret_cb is to try to set up and/or verify a shared-secret for - * authentication on the fly. But as long as we return 0, we won't actually be - * setting up a shared secret, and all will be fine. - */ -int -tor_tls_session_secret_cb(SSL *ssl, void *secret, int *secret_len, - STACK_OF(SSL_CIPHER) *peer_ciphers, - CONST_IF_OPENSSL_1_1_API SSL_CIPHER **cipher, - void *arg) -{ - (void) secret; - (void) secret_len; - (void) peer_ciphers; - (void) cipher; - (void) arg; - - if (tor_tls_classify_client_ciphers(ssl, peer_ciphers) == - CIPHERS_UNRESTRICTED) { - SSL_set_cipher_list(ssl, UNRESTRICTED_SERVER_CIPHER_LIST); - } - - SSL_set_session_secret_cb(ssl, NULL, NULL); - - return 0; -} -static void -tor_tls_setup_session_secret_cb(tor_tls_t *tls) -{ - SSL_set_session_secret_cb(tls->ssl, tor_tls_session_secret_cb, NULL); -} - /** Create a new TLS object from a file descriptor, and a flag to * determine whether it is functioning as a server. */ @@ -1092,8 +675,26 @@ } #endif /* defined(SSL_CTRL_SET_MAX_PROTO_VERSION) */ - if (!SSL_set_cipher_list(result->ssl, - isServer ? SERVER_CIPHER_LIST : CLIENT_CIPHER_LIST)) { + /* Contrary to SSL_set_cipher_list(), TLSv1.3 SSL_set_ciphersuites() does NOT + * accept the final ':' so we have to strip it out. */ + size_t TLSv13len = strlen(CLIENT_CIPHER_LIST_TLSv13); + if (TLSv13len && CLIENT_CIPHER_LIST_TLSv13[TLSv13len - 1] == ':') { + CLIENT_CIPHER_LIST_TLSv13[TLSv13len - 1] = '\0'; + } + + const bool tls12_ciphers_ok = SSL_set_cipher_list( + result->ssl, + isServer ? UNRESTRICTED_TLS1_2_SERVER_CIPHER_LIST : CLIENT_CIPHER_LIST); + + bool tls13_ciphers_ok = true; +#ifdef HAVE_SSL_SET_CIPHERSUITES + if (!isServer) { + tls13_ciphers_ok = + SSL_set_ciphersuites(result->ssl, CLIENT_CIPHER_LIST_TLSv13); + } +#endif + + if (!tls12_ciphers_ok || !tls13_ciphers_ok) { tls_log_errors(NULL, LOG_WARN, LD_NET, "setting ciphers"); #ifdef SSL_set_tlsext_host_name SSL_set_tlsext_host_name(result->ssl, NULL); @@ -1102,6 +703,7 @@ tor_free(result); goto err; } + result->socket = sock; bio = BIO_new_socket(sock, BIO_CLOSE); if (! bio) { @@ -1133,14 +735,8 @@ log_warn(LD_NET, "Newly created BIO has read count %lu, write count %lu", result->last_read_count, result->last_write_count); } - if (isServer) { - SSL_set_info_callback(result->ssl, tor_tls_server_info_callback); - } else { - SSL_set_info_callback(result->ssl, tor_tls_debug_state_callback); - } - if (isServer) - tor_tls_setup_session_secret_cb(result); + SSL_set_info_callback(result->ssl, tor_tls_debug_state_callback); goto done; err: @@ -1151,51 +747,6 @@ return result; } -/** Set cb to be called with argument arg whenever tls - * next gets a client-side renegotiate in the middle of a read. Do not - * invoke this function until after initial handshaking is done! - */ -void -tor_tls_set_renegotiate_callback(tor_tls_t *tls, - void (*cb)(tor_tls_t *, void *arg), - void *arg) -{ - tls->negotiated_callback = cb; - tls->callback_arg = arg; - tls->got_renegotiate = 0; - if (cb) { - SSL_set_info_callback(tls->ssl, tor_tls_server_info_callback); - } else { - SSL_set_info_callback(tls->ssl, tor_tls_debug_state_callback); - } -} - -/** If this version of openssl requires it, turn on renegotiation on - * tls. - */ -void -tor_tls_unblock_renegotiation(tor_tls_t *tls) -{ - /* Yes, we know what we are doing here. No, we do not treat a renegotiation - * as authenticating any earlier-received data. */ - SSL_set_options(tls->ssl, - SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION); -} - -/** If this version of openssl supports it, turn off renegotiation on - * tls. (Our protocol never requires this for security, but it's nice - * to use belt-and-suspenders here.) - */ -void -tor_tls_block_renegotiation(tor_tls_t *tls) -{ -#ifdef SUPPORT_UNSAFE_RENEGOTIATION_FLAG - tls->ssl->s3->flags &= ~SSL3_FLAGS_ALLOW_UNSAFE_LEGACY_RENEGOTIATION; -#else - (void) tls; -#endif -} - /** * Tell the TLS library that the underlying socket for tls has been * closed, and the library should not attempt to free that socket itself. @@ -1245,13 +796,6 @@ tor_assert(lenssl, cp, (int)len); if (r > 0) { - if (tls->got_renegotiate) { - /* Renegotiation happened! */ - log_info(LD_NET, "Got a TLS renegotiation from %s", ADDR(tls)); - if (tls->negotiated_callback) - tls->negotiated_callback(tls, tls->callback_arg); - tls->got_renegotiate = 0; - } return r; } err = tor_tls_get_error(tls, r, CATCH_ZERO, "reading", LOG_DEBUG, LD_NET); @@ -1339,9 +883,7 @@ if (oldstate != newstate) log_debug(LD_HANDSHAKE, "After call, %p was in state %s", tls, SSL_state_string_long(tls->ssl)); - /* We need to call this here and not earlier, since OpenSSL has a penchant - * for clearing its flags when you say accept or connect. */ - tor_tls_unblock_renegotiation(tls); + r = tor_tls_get_error(tls,r,0, "handshaking", LOG_INFO, LD_HANDSHAKE); if (ERR_peek_error() != 0) { tls_log_errors(tls, tls->isServer ? LOG_INFO : LOG_WARN, LD_HANDSHAKE, @@ -1350,52 +892,7 @@ } if (r == TOR_TLS_DONE) { tls->state = TOR_TLS_ST_OPEN; - return tor_tls_finish_handshake(tls); - } - return r; -} - -/** Perform the final part of the initial TLS handshake on tls. This - * should be called for the first handshake only: it determines whether the v1 - * or the v2 handshake was used, and adjusts things for the renegotiation - * handshake as appropriate. - * - * tor_tls_handshake() calls this on its own; you only need to call this if - * bufferevent is doing the handshake for you. - */ -int -tor_tls_finish_handshake(tor_tls_t *tls) -{ - int r = TOR_TLS_DONE; - check_no_tls_errors(); - if (tls->isServer) { - SSL_set_info_callback(tls->ssl, NULL); - SSL_set_verify(tls->ssl, SSL_VERIFY_PEER, always_accept_verify_cb); - SSL_clear_mode(tls->ssl, SSL_MODE_NO_AUTO_CHAIN); - if (tor_tls_client_is_using_v2_ciphers(tls->ssl)) { - /* This check is redundant, but back when we did it in the callback, - * we might have not been able to look up the tor_tls_t if the code - * was buggy. Fixing that. */ - if (!tls->wasV2Handshake) { - log_warn(LD_BUG, "For some reason, wasV2Handshake didn't" - " get set. Fixing that."); - } - tls->wasV2Handshake = 1; - log_debug(LD_HANDSHAKE, "Completed V2 TLS handshake with client; waiting" - " for renegotiation."); - } else { - tls->wasV2Handshake = 0; - } - } else { - /* Client-side */ - tls->wasV2Handshake = 1; - /* XXXX this can move, probably? -NM */ - if (SSL_set_cipher_list(tls->ssl, SERVER_CIPHER_LIST) == 0) { - tls_log_errors(NULL, LOG_WARN, LD_HANDSHAKE, "re-setting ciphers"); - r = TOR_TLS_ERROR_MISC; - } } - tls_log_errors(NULL, LOG_WARN, LD_NET, "finishing the handshake"); return r; } @@ -1444,44 +941,6 @@ return tor_x509_cert_new(duplicate); } -/** Helper function: try to extract a link certificate and an identity - * certificate from tls, and store them in *cert_out and - * *id_cert_out respectively. Log all messages at level - * severity. - * - * Note that a reference is added both of the returned certificates. */ -MOCK_IMPL(void, -try_to_extract_certs_from_tls,(int severity, tor_tls_t *tls, - X509 **cert_out, X509 **id_cert_out)) -{ - X509 *cert = NULL, *id_cert = NULL; - STACK_OF(X509) *chain = NULL; - int num_in_chain, i; - *cert_out = *id_cert_out = NULL; - if (!(cert = SSL_get_peer_certificate(tls->ssl))) - return; - *cert_out = cert; - if (!(chain = SSL_get_peer_cert_chain(tls->ssl))) - return; - num_in_chain = sk_X509_num(chain); - /* 1 means we're receiving (server-side), and it's just the id_cert. - * 2 means we're connecting (client-side), and it's both the link - * cert and the id_cert. - */ - if (num_in_chain < 1) { - log_fn(severity,LD_PROTOCOL, - "Unexpected number of certificates in chain (%d)", - num_in_chain); - return; - } - for (i=0; itls. */ int @@ -1516,18 +975,9 @@ * save the original BIO for tls->ssl in the tor_tls_t structure, but * that would be tempting fate. */ wbio = SSL_get_wbio(tls->ssl); -#if OPENSSL_VERSION_NUMBER >= OPENSSL_VER(1,1,0,0,5) - /* BIO structure is opaque as of OpenSSL 1.1.0-pre5-dev. Again, not - * supposed to use this form of the version macro, but the OpenSSL developers - * introduced major API changes in the pre-release stage. - */ if (BIO_method_type(wbio) == BIO_TYPE_BUFFER && (tmpbio = BIO_next(wbio)) != NULL) wbio = tmpbio; -#else /* !(OPENSSL_VERSION_NUMBER >= OPENSSL_VER(1,1,0,0,5)) */ - if (wbio->method == BIO_f_buffer() && (tmpbio = BIO_next(wbio)) != NULL) - wbio = tmpbio; -#endif /* OPENSSL_VERSION_NUMBER >= OPENSSL_VER(1,1,0,0,5) */ w = (unsigned long) BIO_number_written(wbio); /* We are ok with letting these unsigned ints go "negative" here: @@ -1571,153 +1021,6 @@ tls_log_errors(NULL, LOG_WARN, LD_NET, NULL); } -/** Return true iff the initial TLS connection at tls did not use a v2 - * TLS handshake. Output is undefined if the handshake isn't finished. */ -int -tor_tls_used_v1_handshake(tor_tls_t *tls) -{ - return ! tls->wasV2Handshake; -} - -/** Return true iff the server TLS connection tls got the renegotiation - * request it was waiting for. */ -int -tor_tls_server_got_renegotiate(tor_tls_t *tls) -{ - return tls->got_renegotiate; -} - -#ifndef HAVE_SSL_GET_CLIENT_RANDOM -static size_t -SSL_get_client_random(SSL *s, uint8_t *out, size_t len) -{ - if (len == 0) - return SSL3_RANDOM_SIZE; - tor_assert(len == SSL3_RANDOM_SIZE); - tor_assert(s->s3); - memcpy(out, s->s3->client_random, len); - return len; -} -#endif /* !defined(HAVE_SSL_GET_CLIENT_RANDOM) */ - -#ifndef HAVE_SSL_GET_SERVER_RANDOM -static size_t -SSL_get_server_random(SSL *s, uint8_t *out, size_t len) -{ - if (len == 0) - return SSL3_RANDOM_SIZE; - tor_assert(len == SSL3_RANDOM_SIZE); - tor_assert(s->s3); - memcpy(out, s->s3->server_random, len); - return len; -} -#endif /* !defined(HAVE_SSL_GET_SERVER_RANDOM) */ - -#ifndef HAVE_SSL_SESSION_GET_MASTER_KEY -size_t -SSL_SESSION_get_master_key(SSL_SESSION *s, uint8_t *out, size_t len) -{ - tor_assert(s); - if (len == 0) - return s->master_key_length; - tor_assert(len == (size_t)s->master_key_length); - tor_assert(out); - memcpy(out, s->master_key, len); - return len; -} -#endif /* !defined(HAVE_SSL_SESSION_GET_MASTER_KEY) */ - -/** Set the DIGEST256_LEN buffer at secrets_out to the value used in - * the v3 handshake to prove that the client knows the TLS secrets for the - * connection tls. Return 0 on success, -1 on failure. - */ -MOCK_IMPL(int, -tor_tls_get_tlssecrets,(tor_tls_t *tls, uint8_t *secrets_out)) -{ -#define TLSSECRET_MAGIC "Tor V3 handshake TLS cross-certification" - uint8_t buf[128]; - size_t len; - tor_assert(tls); - - SSL *const ssl = tls->ssl; - SSL_SESSION *const session = SSL_get_session(ssl); - - tor_assert(ssl); - tor_assert(session); - - const size_t server_random_len = SSL_get_server_random(ssl, NULL, 0); - const size_t client_random_len = SSL_get_client_random(ssl, NULL, 0); - const size_t master_key_len = SSL_SESSION_get_master_key(session, NULL, 0); - - if (BUG(! server_random_len)) { - log_warn(LD_NET, "Missing server randomness after handshake " - "using %s (cipher: %s, server: %s) from %s", - SSL_get_version(ssl), - SSL_get_cipher_name(ssl), - tls->isServer ? "true" : "false", - ADDR(tls)); - return -1; - } - - if (BUG(! client_random_len)) { - log_warn(LD_NET, "Missing client randomness after handshake " - "using %s (cipher: %s, server: %s) from %s", - SSL_get_version(ssl), - SSL_get_cipher_name(ssl), - tls->isServer ? "true" : "false", - ADDR(tls)); - return -1; - } - - if (BUG(! master_key_len)) { - log_warn(LD_NET, "Missing master key after handshake " - "using %s (cipher: %s, server: %s) from %s", - SSL_get_version(ssl), - SSL_get_cipher_name(ssl), - tls->isServer ? "true" : "false", - ADDR(tls)); - return -1; - } - - len = client_random_len + server_random_len + strlen(TLSSECRET_MAGIC) + 1; - tor_assert(len <= sizeof(buf)); - - { - size_t r = SSL_get_client_random(ssl, buf, client_random_len); - tor_assert(r == client_random_len); - } - - { - size_t r = SSL_get_server_random(ssl, - buf+client_random_len, - server_random_len); - tor_assert(r == server_random_len); - } - - uint8_t *master_key = tor_malloc_zero(master_key_len); - { - size_t r = SSL_SESSION_get_master_key(session, master_key, master_key_len); - tor_assert(r == master_key_len); - } - - uint8_t *nextbuf = buf + client_random_len + server_random_len; - memcpy(nextbuf, TLSSECRET_MAGIC, strlen(TLSSECRET_MAGIC) + 1); - - /* - The value is an HMAC, using the TLS master key as the HMAC key, of - client_random | server_random | TLSSECRET_MAGIC - */ - crypto_hmac_sha256((char*)secrets_out, - (char*)master_key, - master_key_len, - (char*)buf, len); - memwipe(buf, 0, sizeof(buf)); - memwipe(master_key, 0, master_key_len); - tor_free(master_key); - - return 0; -} - /** Using the RFC5705 key material exporting construction, and the * provided context (context_len bytes long) and * label (a NUL-terminated string), compute a 32-byte secret in @@ -1760,8 +1063,7 @@ * issue 7712. */ openssl_bug_7712_is_present = 1; log_warn(LD_GENERAL, "Detected OpenSSL bug 7712: disabling TLS 1.3 on " - "future connections. A fix is expected to appear in OpenSSL " - "1.1.1b."); + "future connections."); } } if (openssl_bug_7712_is_present) @@ -1786,7 +1088,6 @@ size_t *rbuf_capacity, size_t *rbuf_bytes, size_t *wbuf_capacity, size_t *wbuf_bytes) { -#if OPENSSL_VERSION_NUMBER >= OPENSSL_V_SERIES(1,1,0) (void)tls; (void)rbuf_capacity; (void)rbuf_bytes; @@ -1794,19 +1095,6 @@ (void)wbuf_bytes; return -1; -#else /* !(OPENSSL_VERSION_NUMBER >= OPENSSL_V_SERIES(1,1,0)) */ - if (tls->ssl->s3->rbuf.buf) - *rbuf_capacity = tls->ssl->s3->rbuf.len; - else - *rbuf_capacity = 0; - if (tls->ssl->s3->wbuf.buf) - *wbuf_capacity = tls->ssl->s3->wbuf.len; - else - *wbuf_capacity = 0; - *rbuf_bytes = tls->ssl->s3->rbuf.left; - *wbuf_bytes = tls->ssl->s3->wbuf.left; - return 0; -#endif /* OPENSSL_VERSION_NUMBER >= OPENSSL_V_SERIES(1,1,0) */ } /** Check whether the ECC group requested is supported by the current OpenSSL diff -Nru tor-0.4.7.16/src/lib/tls/tortls_st.h tor-0.4.9.6/src/lib/tls/tortls_st.h --- tor-0.4.7.16/src/lib/tls/tortls_st.h 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/lib/tls/tortls_st.h 2026-03-25 14:30:34.000000000 +0000 @@ -49,17 +49,7 @@ * depending on which operations * have completed successfully. */ unsigned int isServer:1; /**< True iff this is a server-side connection */ - unsigned int wasV2Handshake:1; /**< True iff the original handshake for - * this connection used the updated version - * of the connection protocol (client sends - * different cipher list, server sends only - * one certificate). */ - /** True iff we should call negotiated_callback when we're done reading. */ - unsigned int got_renegotiate:1; #ifdef ENABLE_OPENSSL - /** Return value from tor_tls_classify_client_ciphers, or 0 if we haven't - * called that function yet. */ - int8_t client_cipher_list_type; size_t wantwrite_n; /**< 0 normally, >0 if we returned wantwrite last * time. */ /** Last values retrieved from BIO_number_read()/write(); see diff -Nru tor-0.4.7.16/src/lib/tls/x509_openssl.c tor-0.4.9.6/src/lib/tls/x509_openssl.c --- tor-0.4.7.16/src/lib/tls/x509_openssl.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/lib/tls/x509_openssl.c 2026-03-25 14:30:34.000000000 +0000 @@ -46,7 +46,6 @@ #include #include -#ifdef OPENSSL_1_1_API #define X509_get_notBefore_const(cert) \ X509_get0_notBefore(cert) #define X509_get_notAfter_const(cert) \ @@ -59,12 +58,6 @@ #define X509_get_notAfter(cert) \ X509_getm_notAfter(cert) #endif -#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 /* defined(OPENSSL_1_1_API) */ /** Return a newly allocated X509 name with commonName cname. */ static X509_NAME * @@ -329,11 +322,7 @@ cert_key = X509_get_pubkey(cert->cert); if (check_rsa_1024 && cert_key) { RSA *rsa = EVP_PKEY_get1_RSA(cert_key); -#ifdef OPENSSL_1_1_API if (rsa && RSA_bits(rsa) == 1024) { -#else - if (rsa && BN_num_bits(rsa->n) == 1024) { -#endif key_ok = 1; } else { log_fn(severity, LD_CRYPTO, "Invalid certificate: Key is not RSA1024."); diff -Nru tor-0.4.7.16/src/test/bench.c tor-0.4.9.6/src/test/bench.c --- tor-0.4.7.16/src/test/bench.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/test/bench.c 2026-03-25 14:30:34.000000000 +0000 @@ -11,7 +11,6 @@ #include "orconfig.h" #include "core/or/or.h" -#include "core/crypto/onion_tap.h" #include "core/crypto/relay_crypto.h" #include "lib/intmath/weakrng.h" @@ -24,6 +23,9 @@ #include #endif /* defined(ENABLE_OPENSSL) */ +#include + +#include "ext/polyval/polyval.h" #include "core/or/circuitlist.h" #include "app/config/config.h" #include "app/main/subsysmgr.h" @@ -34,6 +36,7 @@ #include "lib/crypt_ops/crypto_rand.h" #include "feature/dircommon/consdiff.h" #include "lib/compress/compress.h" +#include "core/crypto/relay_crypto_cgo.h" #include "core/or/cell_st.h" #include "core/or/or_circuit_st.h" @@ -44,6 +47,27 @@ #include "feature/dirparse/microdesc_parse.h" #include "feature/nodelist/microdesc.h" +#if defined(__amd64__) || defined(__amd64) || defined(__x86_64__) \ + || defined(_M_X64) || defined(_M_IX86) || defined(__i486) \ + || defined(__i386__) +#define INTEL +#endif + +#ifdef INTEL +#include "x86intrin.h" + +static inline uint64_t +cycles(void) +{ + return __rdtsc(); +} +#define cpb(start, end, bytes) \ + (((double)(end - start)) / (bytes)) +#else +#define cycles() 0 +#define cpb(start,end,bytes) ((void)(start+end+bytes), (double)NAN) +#endif + #if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_PROCESS_CPUTIME_ID) static uint64_t nanostart; static inline uint64_t @@ -127,75 +151,6 @@ } static void -bench_onion_TAP(void) -{ - const int iters = 1<<9; - int i; - crypto_pk_t *key, *key2; - uint64_t start, end; - char os[TAP_ONIONSKIN_CHALLENGE_LEN]; - char or[TAP_ONIONSKIN_REPLY_LEN]; - crypto_dh_t *dh_out = NULL; - - key = crypto_pk_new(); - key2 = crypto_pk_new(); - if (crypto_pk_generate_key_with_bits(key, 1024) < 0) - goto done; - if (crypto_pk_generate_key_with_bits(key2, 1024) < 0) - goto done; - - reset_perftime(); - start = perftime(); - for (i = 0; i < iters; ++i) { - onion_skin_TAP_create(key, &dh_out, os); - crypto_dh_free(dh_out); - } - end = perftime(); - printf("Client-side, part 1: %f usec.\n", NANOCOUNT(start, end, iters)/1e3); - - onion_skin_TAP_create(key, &dh_out, os); - start = perftime(); - for (i = 0; i < iters; ++i) { - char key_out[CPATH_KEY_MATERIAL_LEN]; - onion_skin_TAP_server_handshake(os, key, NULL, or, - key_out, sizeof(key_out)); - } - end = perftime(); - printf("Server-side, key guessed right: %f usec\n", - NANOCOUNT(start, end, iters)/1e3); - - start = perftime(); - for (i = 0; i < iters; ++i) { - char key_out[CPATH_KEY_MATERIAL_LEN]; - onion_skin_TAP_server_handshake(os, key2, key, or, - key_out, sizeof(key_out)); - } - end = perftime(); - printf("Server-side, key guessed wrong: %f usec.\n", - NANOCOUNT(start, end, iters)/1e3); - - start = perftime(); - for (i = 0; i < iters; ++i) { - crypto_dh_t *dh; - char key_out[CPATH_KEY_MATERIAL_LEN]; - int s; - dh = crypto_dh_dup(dh_out); - s = onion_skin_TAP_client_handshake(dh, or, key_out, sizeof(key_out), - NULL); - crypto_dh_free(dh); - tor_assert(s == 0); - } - end = perftime(); - printf("Client-side, part 2: %f usec.\n", - NANOCOUNT(start, end, iters)/1e3); - - done: - crypto_dh_free(dh_out); - crypto_pk_free(key); - crypto_pk_free(key2); -} - -static void bench_onion_ntor_impl(void) { const int iters = 1<<10; @@ -380,6 +335,7 @@ uint32_t t=0; for (i = 0; i < N; ++i) { t += tor_weak_random(&weak); + (void) t; } end = perftime(); printf("weak_rand(4): %f nsec.\n", NANOCOUNT(start,end,N)); @@ -567,9 +523,9 @@ } static void -bench_cell_ops(void) +bench_cell_ops_tor1(void) { - const int iters = 1<<16; + const int iters = 1<<20; int i; /* benchmarks for cell ops at relay. */ @@ -577,6 +533,10 @@ cell_t *cell = tor_malloc(sizeof(cell_t)); int outbound; uint64_t start, end; + uint64_t cstart, cend; + + // TODO CGO: use constant after this is merged or rebased. + const unsigned payload_len = 498; crypto_rand((char*)cell->payload, sizeof(cell->payload)); @@ -585,31 +545,46 @@ or_circ->base_.purpose = CIRCUIT_PURPOSE_OR; /* Initialize crypto */ - char key1[CIPHER_KEY_LEN], key2[CIPHER_KEY_LEN]; - crypto_rand(key1, sizeof(key1)); - crypto_rand(key2, sizeof(key2)); - or_circ->crypto.f_crypto = crypto_cipher_new(key1); - or_circ->crypto.b_crypto = crypto_cipher_new(key2); - or_circ->crypto.f_digest = crypto_digest_new(); - or_circ->crypto.b_digest = crypto_digest_new(); + char keys[CPATH_KEY_MATERIAL_LEN]; + crypto_rand(keys, sizeof(keys)); + size_t keylen = sizeof(keys); + relay_crypto_init(RELAY_CRYPTO_ALG_TOR1, + &or_circ->crypto, keys, keylen); reset_perftime(); for (outbound = 0; outbound <= 1; ++outbound) { cell_direction_t d = outbound ? CELL_DIRECTION_OUT : CELL_DIRECTION_IN; start = perftime(); + cstart = cycles(); for (i = 0; i < iters; ++i) { char recognized = 0; crypt_path_t *layer_hint = NULL; relay_decrypt_cell(TO_CIRCUIT(or_circ), cell, d, &layer_hint, &recognized); } + cend = cycles(); end = perftime(); - printf("%sbound cells: %.2f ns per cell. (%.2f ns per byte of payload)\n", + printf("%sbound cells: %.2f ns per cell. " + "(%.2f ns per byte of payload, %.2f cpb)\n", outbound?"Out":" In", NANOCOUNT(start,end,iters), - NANOCOUNT(start,end,iters*CELL_PAYLOAD_SIZE)); + NANOCOUNT(start,end,iters * payload_len), + cpb(cstart, cend, iters * payload_len)); + } + + start = perftime(); + cstart = cycles(); + for (i = 0; i < iters; ++i) { + relay_encrypt_cell_inbound(cell, or_circ); } + cend = cycles(); + end = perftime(); + printf("originate inbound : %.2f ns per cell. " + "(%.2f ns per payload byte, %.2f cpb)\n", + NANOCOUNT(start, end, iters), + NANOCOUNT(start, end, iters * payload_len), + cpb(cstart, cend, iters*payload_len)); relay_crypto_clear(&or_circ->crypto); tor_free(or_circ); @@ -617,6 +592,126 @@ } static void +bench_polyval(void) +{ + polyval_t pv; + polyvalx_t pvx; + uint8_t key[16]; + uint8_t input[512]; + uint64_t start, end, cstart, cend; + crypto_rand((char*) key, sizeof(key)); + crypto_rand((char*) input, sizeof(input)); + + const int iters = 1<<20; + + polyval_init(&pv, key); + start = perftime(); + cstart = cycles(); + for (int i = 0; i < iters; ++i) { + polyval_add_block(&pv, input); + } + cend = cycles(); + end = perftime(); + printf("polyval (add 16): %.2f ns; %.2f cpb\n", + NANOCOUNT(start, end, iters), + cpb(cstart, cend, iters * 16)); + + start = perftime(); + cstart = cycles(); + for (int i = 0; i < iters; ++i) { + polyval_add_zpad(&pv, input, 512); + } + cend = cycles(); + end = perftime(); + printf("polyval (add 512): %.2f ns; %.2f cpb\n", + NANOCOUNT(start, end, iters), + cpb(cstart, cend, iters * 512)); + + polyvalx_init(&pvx, key); + start = perftime(); + cstart = cycles(); + for (int i = 0; i < iters; ++i) { + polyvalx_add_zpad(&pvx, input, 512); + } + cend = cycles(); + end = perftime(); + printf("polyval (add 512, pre-expanded key): %.2f ns; %.2f cpb\n", + NANOCOUNT(start, end, iters), + cpb(cstart, cend, iters * 512)); +} + +static void +bench_cell_ops_cgo(void) +{ + const int iters = 1<<20; + + /* benchmarks for cell ops at relay. */ + cell_t *cell = tor_malloc(sizeof(cell_t)); + + uint64_t start, end; + uint64_t cstart, cend; + + const uint8_t *tag = NULL; + size_t keylen = cgo_key_material_len(128); + uint8_t *keys = tor_malloc(keylen); + crypto_rand((char*) keys, keylen); + + // We're using the version of this constant that _does_ include + // stream IDs, for an apples-to-apples comparison with tor1. + // + // TODO CGO: use constant after this is merged or rebased. + const unsigned payload_len = 488; + + memset(cell, 0, sizeof(*cell)); + +#define SHOW(operation) \ + printf("%s: %.2f per cell (%.2f cpb)\n", \ + (operation), \ + NANOCOUNT(start,end,iters), \ + cpb(cstart, cend, (double)iters * payload_len)) + + // Initialize crypto + cgo_crypt_t *r_f = cgo_crypt_new(CGO_MODE_RELAY_FORWARD, 128, keys, keylen); + cgo_crypt_t *r_b = cgo_crypt_new(CGO_MODE_RELAY_BACKWARD, 128, keys, keylen); + + reset_perftime(); + + start = perftime(); + cstart = cycles(); + for (int i=0; i < iters; ++i) { + cgo_crypt_relay_forward(r_f, cell, &tag); + } + cend = cycles(); + end = perftime(); + SHOW("CGO outbound at relay"); + + start = perftime(); + cstart = cycles(); + for (int i=0; i < iters; ++i) { + cgo_crypt_relay_backward(r_b, cell); + } + cend = cycles(); + end = perftime(); + SHOW("CGO inbound at relay"); + + start = perftime(); + cstart = cycles(); + for (int i=0; i < iters; ++i) { + cgo_crypt_relay_originate(r_b, cell, &tag); + } + cend = cycles(); + end = perftime(); + SHOW("CGO originate at relay"); + + tor_free(cell); + tor_free(keys); + cgo_crypt_free(r_f); + cgo_crypt_free(r_b); + +#undef SHOW +} + +static void bench_dh(void) { const int iters = 1<<10; @@ -752,14 +847,15 @@ ENT(dmap), ENT(siphash), ENT(digest), + ENT(polyval), ENT(aes), - ENT(onion_TAP), ENT(onion_ntor), ENT(ed25519), ENT(rand), ENT(cell_aes), - ENT(cell_ops), + ENT(cell_ops_tor1), + ENT(cell_ops_cgo), ENT(dh), #ifdef ENABLE_OPENSSL diff -Nru tor-0.4.7.16/src/test/cgo_vectors.inc tor-0.4.9.6/src/test/cgo_vectors.inc --- tor-0.4.7.16/src/test/cgo_vectors.inc 1970-01-01 00:00:00.000000000 +0000 +++ tor-0.4.9.6/src/test/cgo_vectors.inc 2026-03-25 14:30:34.000000000 +0000 @@ -0,0 +1,651 @@ +/* CGO test vectors. Chosen from those generated by + * the python reference implementation. + */ + +/* Accept python booleans here. */ +#define True true +#define False false + +static const struct et_testvec { + bool encrypt; + const char *keys; + const char *tweaks; + const char *block; + const char *expect; +} ET_TESTVECS[] = { +// Zeroes, encrypt +{ + // Encrypt + True, + // (KB,KU) + "0000000000000000000000000000000000000000000000000000000000000000", + // T + "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + // M + "00000000000000000000000000000000", + // OUTPUT + "66e94bd4ef8a2c3b884cfa59ca342b2e", +}, +// Zeroes, decrypt +{ + // Encrypt + False, + // (KB,KU) + "0000000000000000000000000000000000000000000000000000000000000000", + // T + "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + // M + "00000000000000000000000000000000", + // OUTPUT + "140f0f1011b5223d79587717ffd9ec3a", +}, +// Pseudorandom 1, Encrypt +{ + // Encrypt + True, + // (KB,KU) + "39dd87e0b958cec5d2ba04a17fad9f134770f20f14038bdcd751056a7f16041f", + // T + "fbf69df9bfc3bec7e4a5dd0c9785dd18727dab2b11baf2898b3b775baed777d209812a71e8d5a1f624a4c2c3ccd91064f494f5deb2b7ab362cda53df3e0291cc439052a05cdbc8fe259f7190792b637eeaf0c5ebdf7d02ec6b89beecf131a916f5c6989267e28defaa5937b35f0a1ce1ef91838c408b2d199170f29e76ae21b8b62a733e4de9d281e6935d20d991e3e1801907f6477f9fd40bd4e72de681336e603bb7ec17d512728864b7cebc9bc6bbc0629082830fa3702cb2eff0fb289b7431d4e1b0b6109599c91c4c78540792331e592fe8c0c190ea18275386ec3d85f68996b6891e484ad4b0601008ead6ed60145f8d01b81d1cf31556744b1676f6c5caea56c5cd424350e0bc3c478efc2e11d868ddf73185627c778ba8b7d684f3d0b9dfe7e1b63985bb43e37a2e5938cae8b1741cb58aea2b383de9bf0531e344a5651f7f145aad1656e695e30ee6483b5e18e43b0aa6e308f2e1c8cfdd85a118476c9ca91c8ca993563b2df014289738c4b6ce772e2ac36a26547b97ba26673e28e634f88a91007e220f1beaa97ae00972954fc705de30642014fa5c4c07792a0f0b4a8ef3c6f0584b1029171a28cd5898e760c91f71c5f9610747ae21f30f1b1bfa7e4df9aedfa8b006f29e89e5b182ac9957067f86767ed5620abcb2c50a41c423e48a676864a2d151c5bf2442f3b90bfd7c047f92cd112367d0579c9f02", + // M + "40f417ba5a4c78a23e6540b52b68e1e6", + // OUTPUT + "84bfff8347889f1a9f2cf930c82677be", +}, +// Pseudorandom 1, Decrypt +{ + // Encrypt + False, + // (KB,KU) + "39dd87e0b958cec5d2ba04a17fad9f134770f20f14038bdcd751056a7f16041f", + // T + "fbf69df9bfc3bec7e4a5dd0c9785dd18727dab2b11baf2898b3b775baed777d209812a71e8d5a1f624a4c2c3ccd91064f494f5deb2b7ab362cda53df3e0291cc439052a05cdbc8fe259f7190792b637eeaf0c5ebdf7d02ec6b89beecf131a916f5c6989267e28defaa5937b35f0a1ce1ef91838c408b2d199170f29e76ae21b8b62a733e4de9d281e6935d20d991e3e1801907f6477f9fd40bd4e72de681336e603bb7ec17d512728864b7cebc9bc6bbc0629082830fa3702cb2eff0fb289b7431d4e1b0b6109599c91c4c78540792331e592fe8c0c190ea18275386ec3d85f68996b6891e484ad4b0601008ead6ed60145f8d01b81d1cf31556744b1676f6c5caea56c5cd424350e0bc3c478efc2e11d868ddf73185627c778ba8b7d684f3d0b9dfe7e1b63985bb43e37a2e5938cae8b1741cb58aea2b383de9bf0531e344a5651f7f145aad1656e695e30ee6483b5e18e43b0aa6e308f2e1c8cfdd85a118476c9ca91c8ca993563b2df014289738c4b6ce772e2ac36a26547b97ba26673e28e634f88a91007e220f1beaa97ae00972954fc705de30642014fa5c4c07792a0f0b4a8ef3c6f0584b1029171a28cd5898e760c91f71c5f9610747ae21f30f1b1bfa7e4df9aedfa8b006f29e89e5b182ac9957067f86767ed5620abcb2c50a41c423e48a676864a2d151c5bf2442f3b90bfd7c047f92cd112367d0579c9f02", + // M + "40f417ba5a4c78a23e6540b52b68e1e6", + // OUTPUT + "e2c0bfdef28b5504cf0ec708a6866a17", +}}; + +static const struct prf_testvec { + const char *keys; + int t; + const char *input; + const char *expect; +} PRF_TESTVECS[] = { +// All zeros, t=0 +{ + // K,B + "0000000000000000000000000000000000000000000000000000000000000000", + // T + 0, + // t + "00000000000000000000000000000000", + // OUTPUT + "66e94bd4ef8a2c3b884cfa59ca342b2e58e2fccefa7e3061367f1d57a4e7455a0388dace60b6a392f328c2b971b2fe78f795aaab494b5923f7fd89ff948bc1e0200211214e7394da2089b6acd093abe0c94da219118e297d7b7ebcbcc9c388f28ade7d85a8ee35616f7124a9d527029195b84d1b96c690ff2f2de30bf2ec89e00253786e126504f0dab90c48a30321de3345e6b0461e7c9e6c6b7afedde83f40deb3fa6794f8fd8f55a88dcbda9d68f2137cc9c83420077e7cf28ab2696b0df05d11452b58ac50aa2eb3a195b61b87e5c65a6dd5d7f7a84065d5a17ff46273086002496db63fa4b91bee387fa3030c95a73f8d0437e0915fbce5d7a62d8dab0a58b2431bc0bede02550f40238969ec780410befccde6944b69dd007debe39a9dbc5e24f519a4bdf478b1d9ec0b67125f28b06efaa55d79412ad628d45089c3c304f94db3a21df6cdaf6d2e2e3b355441eff64ad90527e752a4b2ebb4d0a1070ce2e2982e272fdb7cf4b584b095a0f957fdb828689437e37dc48b2ad379c6f3c6e957ee77afb88c65949ba12eec45c22865e4907ae42aee813898acdf91e2e4c21d828e0a76de2bb6bb6f869e5eef1f618dedd27562812b9a14e8996a5c352df3817e60d6ec20119a52c80a61ec195622627240212decca515feab63e2734587948a836a7de205cfec0c288351c", +}, +// All zeros, t=1 +{ + // K,B + "0000000000000000000000000000000000000000000000000000000000000000", + // T + 1, + // t + "00000000000000000000000000000000", + // OUTPUT + "7941dd0a63d994703e63d94a446804213ab4fb1d2b7ba376590a2c241d1f508dc6a7f418a14503deb89b17aadb2806f73fc06e5d14e675f5ec880023d4f7329612dce4a0e5bc792b5b5a55f9c2f30e07", +}, +// All ones, t=0 +{ + // K,B + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + // T + 0, + // t + "ffffffffffffffffffffffffffffffff", + // OUTPUT + "3ae902931ae8d3ba07a2efdbf0411525c966356463673443646d3ed3e5ba68a61ccd8ae0d8f8d84adca5c0023f02efd10cc7bc7c9fbfd169bf47a792bbba07d6c9338101d0c28e476e99520413a37c3c9045909a8d37c6cba7f9e33254ff0b2ea11ccd6d0a6eed028bb3acccb38fe0a50ea2ca51dc35dc12541f5ce00611336ef966d9a9027a6342c09590d056880e79bfd1a271aff821114649e33a6b4d83be0883b3ad4b315ac6b77017c748a8bb71a981678ff9c6ca086507efb6e8850043767bea06d66ee5e9b2870107474150044488a2d00bd1d5154e0f1aeac5af0b73049004f8717baa13c1ae0088f2dfdf8e08a612aa11a8bb64ab2a4d292967504a6cb451a56275b756c2d7f65aab728617154693a7b31d048802b0ce635754977fb851bb21dddcd9564795e31523fcc35ccfc066b9542508b4daa65b4c9083b12a5cd08f7c45906523d5d7131f279959900473a756e48ababa93fb42663401d84bef93c6cfd6e02fc17797a7004671d21d3bc35cb2e9a344da0a16c300f3c977b6c892e0c2a9517862bec47a51fd49c5a4d46620ea5df9a055e89c2d54abffb00704c1219175433bc1683d93c75ffd7feccc605092b197c5aa5aa995ba0c0e33870b0f513a5eefd9d64fc6e89862709ca9876df86c189181e70e4eed2d876a12480b64afaffe54ba4ac8f23043d8", +}, +// All ones, t=1 +{ + // K,B + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + // T + 1, + // t + "ffffffffffffffffffffffffffffffff", + // OUTPUT + "be938fc23009440bfb5d7bba1d28428ec0897793bb878b8e1eb3ec1257b88024d551d770b56c9312de3dd4ac64e194c91185a89f2ba01f90b03b3acb93f634df4b263f03af0acda2f9721d0f4c0783c7", +}, +// Pseudorandom 1, t=0 +{ + // K,B + "908bf9a158c67f9cd5cb5cee476a4b30b9ec92756d94b1f9f40073c185c39780", + // T + 0, + // t + "d5d73799a0f37a1c7ff3ceb187ebd059", + // OUTPUT + "0573c27e297dad58e84942c498d3c376c1f8423dea1df70338259814f2b939ffe074b22fae1385e2d453aca882cb6257ec4fc86915f05be11ae36df4d8678ff29f68c45797c2a4158c4c30c703faeda452858ae37b7735f47b2924cd6f6040e7f6b19958f6d5a12aae72b589d6f85e5a3267881b2916da948fe1626d68ee60a13c90599b40f8a14fd8d1354bc5beb23f38043d7e547b879f618302426dd7785bc2caf44b31a2e1ec5d4dcb4047415d0bbc6900dfdfa01e61c4aa3624f6d7f03cc1641610bd0d6f155cae7465a3d1e0ae8db7d5a00afd27824fd35b65a91728981566c7a046f1773210b76a449b76b5684eb3532a06225d89b70aae1d20c27d03c528b00051a3eb74f3b217b3d474076b8c4bab837476c6191bc7ae8266328d5a65f6a2c55c30999984e2747b7dc45af9e43533b750d9196cd2d64947b6dcf839821002441a428bbbeee45de052502aa76385b47aedbdbeed500c359fdd1ba042a5c9956a1b2e3e456472665f7a674d898a9c5ee58e6288304a323986f0d09b731ae401ac5f8ebeaf808cecce9945439ec76cccb5aafb875faf1274bc29beb29413e01ef72cb37eebc06428c24221f8af3c5ea742fc41506d501d8e45bed5d982ab16669da486c985a3e140eb55c754aaf3d7923d76519f8bac02e0e0c0961411d8c010d1c58498caeae8c69c62", +}, +// Pseudorandom 1, t=1 +{ + // K,B + "908bf9a158c67f9cd5cb5cee476a4b30b9ec92756d94b1f9f40073c185c39780", + // T + 1, + // t + "d5d73799a0f37a1c7ff3ceb187ebd059", + // OUTPUT + "75c5c6787bd0edf325cf772b8c09478df5094f093eddda9d4b7c2ab4ebcdd84c87192038ade81b8560ef7f5a3eb89a4957cf9bd138c575b6951f9940d44d443f47616dfdaf73be7a4664aa46bc279c20", +}, +// Pseudorandom 2, t=0 +{ + // K,B + "fcd9361d1dca1c7b9a24f754464eeda5727152bc98a818b2e720a0afa9103e10", + // T + 0, + // t + "d22ea954482f5bc511c6fcae80233d57", + // OUTPUT + "e5be8144283c5b638a7bbcae231cfb9d6727ee8f04bcf0f3c7ff94930facee8030712bc8b0d151a5ea27c4f614cd46fe1ef9eee2f64c8d8ddfce7ab1ed01cdd610e7b341b75408a6a8310ed62389348b76a59277a0eee05bdd5f5227d43fc113294b3af71d505a0c88d920387f44ef33029797d0c282991683adca83449e68aff578df836ee6b89cfc5fb0e8ce0d8d5146a09d57ec816e0fbbbdf80b298dfe6509aefcc892a6dd4bbbbfc6d9507e4013305986bb9d0cc050de172faa2039623cb93177a0b7c5966933ad2ee6fa930dbfe24148b63561551364fdcc3a1e1a5381d62a9508c6bd86a43ed602e5fcc0cee2c8d2a67c7de50428fa72ef75fd4aafe4bbc17cb03ffeb69066e5c6ee65c1df67fc9c33515d45cfc504c2d2db213b36df5a6b7864ccf11061464048329f2a79b6935b4219aab811fa07896497ba8dc47c1f2e9207e4be7a4f3651bba673d4911787df8423cc60601785ac5072516954efa6e30f27c04136f6bdff2d23b0489b2d7c9aea7f5320d48c337eeb2dd4f06eedab55316ba8f45b6f9a584ae8241183a261b467be3b500febbb609a38895d92f0aa8ca31197e81c85aefcea4d7a5f0d4f7825de0260f9563db272720c723a38f935113d1f2a89b02303eced1312316f29001f224a730031ac6e002916a2077fff2de0cb740622692fde1ffe1811", +}, +// Pseudorandom 2, t=1 +{ + // K,B + "fcd9361d1dca1c7b9a24f754464eeda5727152bc98a818b2e720a0afa9103e10", + // T + 1, + // t + "d22ea954482f5bc511c6fcae80233d57", + // OUTPUT + "242f479249fefc782eb74cb5304e54cf9f1230ba8908c1a322650edd916ecf76527d3a84db32d8ca0931b0420c8bcf388042cb152ee080af416a37cf2e0406de5ebb9c27061650e72552ecadca5af451", +}, +// Pseudorandom 3, t=0 +{ + // K,B + "b445f9a92d267dbd3b2dd9ad0cf90538b4013b72df0a23ef997f7baf9440733a", + // T + 0, + // t + "1d16d4b08c19887a050603dc8f17bb6d", + // OUTPUT + "d609818f6c26b96efadb6e5d84ed63c4d426e133cc72acc222a161feb8810f99d0d8dbace6181b8f41e601cf7bd33a3a23e84bf8898505e222a42fb889fe759e48fda34e6d39c357e6445864e55633bc264d4f4d33d0afd20a51ad1b3d6d18288d6930ac9775e6928cdce46642b5b81bdbbdb469f1d6f1a889a2c76c0258ca6a95c5f590c54f1503ec46f1b3ad6e93233f9f4ca9a57bc14aa505f4678d9fee8fa7b8f047252569b83c79e3a4abea6d4a481e159e91dced13f58be46f41ef52f1ebb17cd68875f2dee11ab6409fe5f0d5a189fdc86b4b214f2ccd47d419e66ba3889bac4b7da810b3ba647082662c74c2e2972962d8af31fc05a22e0df7f5e87a6bdfb2b414bf55e46581ca982bca237a0af99030d079b6e81404b6bad3011bdf114e2d042e019342a41b06d1ece656ff994b80796747ca413f783c903f0980873c95b1b3d6d3c99410d75993a9b28ae23d26847da256e09f7c727f1b05eb1fa4aea6d0b4b69307363c2ec7d75e136c14f3ca44d2d2bf001095ee5505bcb56c06842233411e5bc38da56d97c1ce6b1807db9b832fc10625d55fb259a5cd75c0a1d27a8b8a8c9b2a98bdfe7903a927026f2d2616b481e13e3bf7eb1039ec892a2fa054fd8dd6aac76b0efbece35b374310583d1c5f594604c3a49b35af7c3065f9f5f3bbe5cac3e8522a0654463c", +}, +// Pseudorandom 3, t=1 +{ + // K,B + "b445f9a92d267dbd3b2dd9ad0cf90538b4013b72df0a23ef997f7baf9440733a", + // T + 1, + // t + "1d16d4b08c19887a050603dc8f17bb6d", + // OUTPUT + "85da4380c7376cdd451aef93c15303626a9a54b1b21ddf5fa88beb1ade9331438764e8ad4f640dae16e3708806bab62d948e2ac6210b198184d0bface602a49f606d13e72574d7cda3e8458736d180b6", +}, +}; + +static const struct uiv_testvec { + bool encrypt; + const char *keys; + const char *tweaks; + const char *x_l; + const char *x_r; + struct { + const char *y_l; + const char *y_r; + } y; +} UIV_TESTVECS[] = { +// All zeros, encrypt +{ + // Encrypt + True, + // {J,S} + "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + // H + "0000000000000000000000000000000000", + // X_L + "00000000000000000000000000000000", + // X_R + "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + // Output={Y_L, Y_R} + {"66e94bd4ef8a2c3b884cfa59ca342b2e", "66e94bd4ef8a2c3b884cfa59ca342b2e58e2fccefa7e3061367f1d57a4e7455a0388dace60b6a392f328c2b971b2fe78f795aaab494b5923f7fd89ff948bc1e0200211214e7394da2089b6acd093abe0c94da219118e297d7b7ebcbcc9c388f28ade7d85a8ee35616f7124a9d527029195b84d1b96c690ff2f2de30bf2ec89e00253786e126504f0dab90c48a30321de3345e6b0461e7c9e6c6b7afedde83f40deb3fa6794f8fd8f55a88dcbda9d68f2137cc9c83420077e7cf28ab2696b0df05d11452b58ac50aa2eb3a195b61b87e5c65a6dd5d7f7a84065d5a17ff46273086002496db63fa4b91bee387fa3030c95a73f8d0437e0915fbce5d7a62d8dab0a58b2431bc0bede02550f40238969ec780410befccde6944b69dd007debe39a9dbc5e24f519a4bdf478b1d9ec0b67125f28b06efaa55d79412ad628d45089c3c304f94db3a21df6cdaf6d2e2e3b355441eff64ad90527e752a4b2ebb4d0a1070ce2e2982e272fdb7cf4b584b095a0f957fdb828689437e37dc48b2ad379c6f3c6e957ee77afb88c65949ba12eec45c22865e4907ae42aee813898acdf91e2e4c21d828e0a76de2bb6bb6f869e5eef1f618dedd27562812b9a14e8996a5c352df3817e60d6ec20119a52c80a61ec195622627240212decca515feab63e2734587948a836a7de205cfec0c288351c"}, +}, +// All zeros, decrypt +{ + // Encrypt + False, + // {J,S} + "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + // H + "0000000000000000000000000000000000", + // X_L + "00000000000000000000000000000000", + // X_R + "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + // Output={Y_L, Y_R} + {"140f0f1011b5223d79587717ffd9ec3a", "66e94bd4ef8a2c3b884cfa59ca342b2e58e2fccefa7e3061367f1d57a4e7455a0388dace60b6a392f328c2b971b2fe78f795aaab494b5923f7fd89ff948bc1e0200211214e7394da2089b6acd093abe0c94da219118e297d7b7ebcbcc9c388f28ade7d85a8ee35616f7124a9d527029195b84d1b96c690ff2f2de30bf2ec89e00253786e126504f0dab90c48a30321de3345e6b0461e7c9e6c6b7afedde83f40deb3fa6794f8fd8f55a88dcbda9d68f2137cc9c83420077e7cf28ab2696b0df05d11452b58ac50aa2eb3a195b61b87e5c65a6dd5d7f7a84065d5a17ff46273086002496db63fa4b91bee387fa3030c95a73f8d0437e0915fbce5d7a62d8dab0a58b2431bc0bede02550f40238969ec780410befccde6944b69dd007debe39a9dbc5e24f519a4bdf478b1d9ec0b67125f28b06efaa55d79412ad628d45089c3c304f94db3a21df6cdaf6d2e2e3b355441eff64ad90527e752a4b2ebb4d0a1070ce2e2982e272fdb7cf4b584b095a0f957fdb828689437e37dc48b2ad379c6f3c6e957ee77afb88c65949ba12eec45c22865e4907ae42aee813898acdf91e2e4c21d828e0a76de2bb6bb6f869e5eef1f618dedd27562812b9a14e8996a5c352df3817e60d6ec20119a52c80a61ec195622627240212decca515feab63e2734587948a836a7de205cfec0c288351c"}, +}, +// All ones, encrypt +{ + // Encrypt + True, + // {J,S} + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + // H + "ffffffffffffffffffffffffffffffffff", + // X_L + "ffffffffffffffffffffffffffffffff", + // X_R + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + // Output={Y_L, Y_R} + {"7209baed4b605b158b7eb25de2200e83", "5546c0d2d8da37d92908803d88ff5a646e24a9f9c8c0e9f239726ccc5107d45ed813697aab0b27969930489e47c87475d71b92fc875e268d2ed92fa735b8258c657ff883512adf916a7a8819596e878415da7dc689fc658b862235133b4366e5bea11ece0990a544cb324e27313d67567797213ddb9102e75caca82a15035e44a306c906f8c17e2c88975808b35ad13443849d9ebec10f2c888738ff5b7cb3043b2bbd6098b167746addcc55238fb32d9ef404f3d0f7db0bc5f30aca0cf9ce5f87c989268d18b1069b33bbd5b7818a99603ec0d82871e75cffd1d84e2be1e0f8e8b3678b1ccd7a5a676d83fe0e68f09027ad912d58d2257932750b383e2f2fa3c889ee9d71919cc05d982230c6ff8b7e5e3ed302ed82bed429794c261aa009d231bb6c8675e513313432017cea50843a0309153f7f9d556330f19c38bc5ae6d33d63abaa7ebabd3335c1bf59a2121378288da679259bb1b8a8b027938f3e902c655c781e7f5d9514e53502e7ebc31e344344c3ae2a6397a9a8b846dab8a84174e91664804c7804bab09d6d40aeeb491d6f6184830ac7b5807418a05a7ab9938c3fdc18066b5d503f8c98e83be033b6fba905324267618cc6989b486e0decf7cc897d17be093286a4d4fb5016c3e3323ccc416a30473081473bd471e430194ec4e2ac0af3bca0577b78f4c70e4d"}, +}, +// All ones, decrypt +{ + // Encrypt + False, + // {J,S} + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + // H + "ffffffffffffffffffffffffffffffffff", + // X_L + "ffffffffffffffffffffffffffffffff", + // X_R + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + // Output={Y_L, Y_R} + {"a9166add184e00b007217cb4e4f52ee5", "c516fd6ce5172c45f85d10240fbeeada3699ca9b9c98cbbc9b92c12c1a459759e332751f270727b5235a3ffdc0fd102ef338438360402e9640b8586d4445f82936cc7efe2f3d71b89166adfbec5c83c36fba6f6572c8393458061ccdab00f4d15ee33292f59112fd744c53334c701f5af15d35ae23ca23edabe0a31ff9eecc9106992656fd859cbd3f6a6f2fa977f186402e5d8e5007deeeb9b61cc594b27c41f77c4c52b4cea539488fe838b757448e567e9870063935f79af81049177affbc898415f929911a164d78fef8b8beaffbbb775d2ff42e2aeab1f0e5153a50f48cfb6ffb078e8455ec3e51ff770d202071f759ed55ee57449b54d5b2d6d698afb5934bae5a9d8a48a93d2809a5548d79e8eab96c584ce2fb77fd4f319ca8ab688047ae44de222326a9b86a1ceadc033ca3303f9946abdaf74b2559a4b36f7c4ed5a32f7083ba6f9adc2a28ece0d866a66ffb8c58a91b7545456c04bd99cbfe27b4106c3930291fd03e886858ffb98e2de2c43ca34d165cbb25f5e93cff0c368849376d1f3d56ae879d413b85ae02b63a5b2b99df15a2065faa1763d2ab54004ff8fb3ede6e8abcc43e97c26c38a0028013339faf6d4e683a55a5566a45f3f1cc78f4f0aec5a1102629b03917679d8f635678920793e76e7e18f1b112d27895edb7f49b505001ab45b5370dcfbc27"}, +}, +// Pseudorandom 1, Encrypt +{ + // Encrypt + True, + // {J,S} + "22169d562646db8ce3322daf9fa8e84bed57dac18beabdb619b40f5a02786e439e6132a5b7e7445ef962e2c7f30a0b2ec994ee1935e1787d6f89cbc15b9254d5", + // H + "81b1a82c63d8dd9f682f734e82e259a14b", + // X_L + "db4adc246c6a54fe55e11901f08f0eee", + // X_R + "dccb8aa0570982d5b08fa6b4fbb3bc7bcd7e1cb374f114fcdd0ed53255c523c1e8ecabfbaab00105af9933eff304a40877e3006be82417e44462fc6955777baf2f2f9c99966ddee30b7c65050dcc8f5d7bc22f9192e1c4a83ca0a2338deca9da4fed14058812ace259e9851f50c83d97515b647ff56749a3c615e1860a404e9b05619a48aa3e5f09779e72c77dfdd1ab5d796860178938efffb4e43bda443c2fba0d5be14baa375d881ee5e14d760a12c4d9807c8c54b714a75324c4074296ba8c86beceb4dc2337946f0af67c759d999d56aceebefd80438dc625b0b50f749440e8cd5bcee1afa05ff8cff1bfd3e0e68930b74b3baa7e6cb723896afc3098326716e0554319c9f8f3683a8fd359ae48a3591dac67adeea6e24600037cb1a42c38b23a9e7c31e6d0b13b84e88341458050856c476f6875dfe17806e0cd72baeebd0e1108fb13088a887153a1d13bac414ed120c26bda5bc08202fc1489746305dcda5dfc3e6a869b52d63654f3bc35841a2345df8691caf1de06d5ebd214af729e239efd62d05060eab13fb973ffb41f461224e2eee1f739529d37e8db40c065e52de7b8f19fbf695470341062c7f212d8cf5310cc17f487e04e8ed03fe50f3758eda9e41bf37af62f94709b16e01b4305d1a5ccad2bcacc7e35d4a1d1a40c26dbf3153739175ca65ab59cc1c9", + // Output={Y_L, Y_R} + {"9ff8aec547f02caae7555ad7b0cb1372", "d2ceaad0ef52ac304d9550f0c365fa7728dca633f4f62228b241e47754dfa01c709e66f54a018e667573dbf5063c10a6167592250a8f6af17c68d5e190c5e8bdb40082b54e428ada58b3a805cdd56d87cc56591f8ac5f310eb37ce4d8a6ea6a80c3d7316f872aeb8a1a40ef7d1f0bbd1711d38c500eccc0acb88c1a3491ceee45bf82ba3fdf939dcbedb4f140fae21339f671df748d18e8bc8d72eb8e7cf18feafcd6f363345e2b05bc2d4d6f3affb8589d002aadb711d5ad2fa81398137b9e88f5a8663787e746bb878c0973d9b80145f8dd18bce30ea10e13ad07aeb469f62c4507ff8aaba09ed988a794232b5fc4e64466103366ed474fb99406fc80dd5ae5cb90001b1485476978dada0df83456feb3674ec7070b177871203410c5f7adbefbf5069c64bce59ef381514cb2a8d0804d855cca0a9c84d4c60c44e7242ffc479aabf357016166e9b184311c0e04dd9d1c512ae508b8f8c6bfdba68d46e338250f23668aaf11f45f57bfbc8e32d14ccab853af085a17405058ecd993cb21b41f8456c54a3900a50c270fc2b0931394ba257fd49bf79ae54d9c39a8504067b9cee1e42b688dcc606bee57006bc561b991dd10c56c129d1db8997e0d163fd06fca83249f146e348a4f35d0cb47d0ea6b3c6c587487f3816e13c2494d6d1e866fa182855cd668462a30b4e7019d2"}, +}, +// Pseudorandom 1, Decrypt +{ + // Encrypt + False, + // {J,S} + "22169d562646db8ce3322daf9fa8e84bed57dac18beabdb619b40f5a02786e439e6132a5b7e7445ef962e2c7f30a0b2ec994ee1935e1787d6f89cbc15b9254d5", + // H + "81b1a82c63d8dd9f682f734e82e259a14b", + // X_L + "db4adc246c6a54fe55e11901f08f0eee", + // X_R + "dccb8aa0570982d5b08fa6b4fbb3bc7bcd7e1cb374f114fcdd0ed53255c523c1e8ecabfbaab00105af9933eff304a40877e3006be82417e44462fc6955777baf2f2f9c99966ddee30b7c65050dcc8f5d7bc22f9192e1c4a83ca0a2338deca9da4fed14058812ace259e9851f50c83d97515b647ff56749a3c615e1860a404e9b05619a48aa3e5f09779e72c77dfdd1ab5d796860178938efffb4e43bda443c2fba0d5be14baa375d881ee5e14d760a12c4d9807c8c54b714a75324c4074296ba8c86beceb4dc2337946f0af67c759d999d56aceebefd80438dc625b0b50f749440e8cd5bcee1afa05ff8cff1bfd3e0e68930b74b3baa7e6cb723896afc3098326716e0554319c9f8f3683a8fd359ae48a3591dac67adeea6e24600037cb1a42c38b23a9e7c31e6d0b13b84e88341458050856c476f6875dfe17806e0cd72baeebd0e1108fb13088a887153a1d13bac414ed120c26bda5bc08202fc1489746305dcda5dfc3e6a869b52d63654f3bc35841a2345df8691caf1de06d5ebd214af729e239efd62d05060eab13fb973ffb41f461224e2eee1f739529d37e8db40c065e52de7b8f19fbf695470341062c7f212d8cf5310cc17f487e04e8ed03fe50f3758eda9e41bf37af62f94709b16e01b4305d1a5ccad2bcacc7e35d4a1d1a40c26dbf3153739175ca65ab59cc1c9", + // Output={Y_L, Y_R} + {"1c1593f30a020d44b7b2cf9b75204808", "c8135c678f97432394c2fa38ee6f590104a99028da2624a44d9a503adf1fe0d236ed5253d2e1cfca479c1b41609ef7cab58d7bb4d8e50e21108f837791f2e3066d3c40672f8e0f1a304d25ba20401a8aac6b15c1582788fe8996277b5cb554cd82e0920f212293b8bc4357349465f75e2f688a084d4c4741e2b384523d51cf94062cb7e6c1481eb48f1eb37e00937e0a2b2e12c88ac1b8ca2eef537b74b9f22e016b1a72818eddd1bde1e3643f4aa8fbf1e69543475131c17e8562c6c7d9a4375936fcc1c6ffeb131195e2168cd26368c3ab40f436563b4a5b6db2a7fa61e521321dad4d1aaaca8d0b38d68de26f402233d3bc25c78cd9019d2985f0f02c51cd07423726bd7ef3d19a8bb7b5a94d54ed86c460e7b02388fcedaa99902bc43c8339a171e89dc8123a9cd05287f2c0a39fdf24dd56dcf4326c163d38c9282d1f2f9a0faf50beb6e5caeb300a6192f6c1aaa5ba515bb677bb399edfcb05eab48870e79018d60ccdf3f1b5b6eb1e1a9e24a8a11da26c0919e6ec7db6a1260d6299e7a2830d48d3bf33b40f4c5cc0c4acae037a4bf5731fff732f44752bd002c8493f1d48ea6c5f0cbbd596d679c7130d687211e74a96473275f2c8df1634ad36aab16eb0221777e98f62057d669b51bee20ab45db78b619aa619a40245d9ddd074a35c54b77f7ccc0410c00719e423"}, +}, +// Pseudorandom 2, Encrypt +{ + // Encrypt + True, + // {J,S} + "e61126a280c66e99171b1ec940a75ba6d4c3301062760a9ff9f9b332433b8408af4a49ad5326b95da7f501bb8b34bce8ce6e8c33f57263a4779a161d3736b7e4", + // H + "837d18ad2b0162977d3461349b00bcfdd7", + // X_L + "4b9fa9b1d31ada9a15d29cd0bd920a53", + // X_R + "c819e68a3dbdb6e730e4c9ed6dc11187f7ef0f021f63f0da32b55c8e2c78d4bc55d0e487329542e0b63a8f57313a146443cb5b8ba9eaf77d7e80884333b0e33b806da9cb32e231b5a23aa9ffa6f598df337126b26d6f9ef0d6c6a1bb59d83d253ea0ddc7272d633eb785dd7649fb7618a3b2c721cfba7d3e3d4a95fafcb90c2c60a52258ff3da3e1ab1205747e049e4730d734eaa5744a18fa8b8c4aed37d28857a5877839a40659e9754795859dad3163d6358234072ae62f64e58c861fd2225c60a708bb9b199e2070315e6d8eda8365b7cdaf5d067280086fda2a304ccbf3177fb0d34bbc3b02b4aaf42e535fbf2a15b782a8f3004eecda69aade92eb7bc92b6d552172bd26db28dcdf36547fa2794bf598db51ba0578f176e0cd3db04bf8333819a17f9c0d6faa9128930a3d8e93170d1bdf4e17a26f794631c870d9fd0edc73c3ce51753cbf59f3c942b689ccd08d8c0e0b19840b5113b760893b7d3b3a7c8f2c8794cab2f35a49d1d3f8c93bc353f376904d1961d3958cdc7a1841fe305c5c48b98f3b829ab1540876c3bd9d73e979107ab6f8146fe8acf33bde92b0a0ec2088dca60ae8374bda9d36977e5653762e8744d2b66d5bcc26dde754ec5eb3f665fbdd1ce2d0a7a48c499c0a5b846a7cb3c478484703c31ebb0c20c66bc1c1722529be0bb850d9bff7437ca7", + // Output={Y_L, Y_R} + {"6db7f5e28e54c81ce9a22df58eef5f65", "bc742015a226d2f1f855c06e9c12ce9866a311622befc8ff5f796c1813308fecb8c91b7fdc00de93198498afeec55422f678fd1822131877c947236c4c978b0f0fc3d0ddeee5770bac3c635895d9b922399a0062e4c80b9ea753f89608ed6920fc2f8a9e09ba87b40c6ef2a9354524e7f0ac1d967ef520a348e37fccc35f584ed5270b7e4694cd263a25f8869e07693df3f9a5fbc6aa4f8697456fa830e07f6ab89d3ae18790b6208c09ec2cf530239bb7d514691a01b4a772233693dc398bc6b4a08e412dce4d3b3556c0aa8ad2d0ee474ef56c1dd232b677c2d38be103921b8373e9e1c8ef2e98ededce0439351e74ca751db03e8213cd6adb6ee5a7b3103675776b82e59120d21e4b4e03e01aa420c254530ed74c24dcc514ddb241450642dedd0c5b1a0f7c2a7af243b96f1d1312ff8448a0c3a2b9cdaa90c45d11fdd82e6b17bc83f246313d7d67dd380165ceac938f5cd7896ffb8c22669526345f42892e1cb2b5af64f39139e6f3d5ed8e03efa61d653bbfcdf387c9ccf9de686b9603a681143ccd21a12004c810acc7e9c17bbdeba632bc9e5f0c6d3cbf72c8e7b958fb66d38bdb77c1e170de541b0750d942e9f8bcf123bd4a369af220135816b6d9b09778a8bc5e0378ec82678c1344a978fd1b271376ac31ba3981a1639a3808a8cd35424daa91d59f6e34967434"}, +}, +// Pseudorandom 2, Decrypt +{ + // Encrypt + False, + // {J,S} + "e61126a280c66e99171b1ec940a75ba6d4c3301062760a9ff9f9b332433b8408af4a49ad5326b95da7f501bb8b34bce8ce6e8c33f57263a4779a161d3736b7e4", + // H + "837d18ad2b0162977d3461349b00bcfdd7", + // X_L + "4b9fa9b1d31ada9a15d29cd0bd920a53", + // X_R + "c819e68a3dbdb6e730e4c9ed6dc11187f7ef0f021f63f0da32b55c8e2c78d4bc55d0e487329542e0b63a8f57313a146443cb5b8ba9eaf77d7e80884333b0e33b806da9cb32e231b5a23aa9ffa6f598df337126b26d6f9ef0d6c6a1bb59d83d253ea0ddc7272d633eb785dd7649fb7618a3b2c721cfba7d3e3d4a95fafcb90c2c60a52258ff3da3e1ab1205747e049e4730d734eaa5744a18fa8b8c4aed37d28857a5877839a40659e9754795859dad3163d6358234072ae62f64e58c861fd2225c60a708bb9b199e2070315e6d8eda8365b7cdaf5d067280086fda2a304ccbf3177fb0d34bbc3b02b4aaf42e535fbf2a15b782a8f3004eecda69aade92eb7bc92b6d552172bd26db28dcdf36547fa2794bf598db51ba0578f176e0cd3db04bf8333819a17f9c0d6faa9128930a3d8e93170d1bdf4e17a26f794631c870d9fd0edc73c3ce51753cbf59f3c942b689ccd08d8c0e0b19840b5113b760893b7d3b3a7c8f2c8794cab2f35a49d1d3f8c93bc353f376904d1961d3958cdc7a1841fe305c5c48b98f3b829ab1540876c3bd9d73e979107ab6f8146fe8acf33bde92b0a0ec2088dca60ae8374bda9d36977e5653762e8744d2b66d5bcc26dde754ec5eb3f665fbdd1ce2d0a7a48c499c0a5b846a7cb3c478484703c31ebb0c20c66bc1c1722529be0bb850d9bff7437ca7", + // Output={Y_L, Y_R} + {"e6d9d943df0c57ffcf625bd142f023cc", "16fcd880981c22d459e61a502213668f6f040c57f9db8cf39fc07bce35a9df2e2cd083359e833944bb1da2d107caa11d171abfe5878787ca89c5460753a8df4c3af7d9e1091a68e1976eba0ba81005f60f1fb2f26b6163896070efb1c39e31d24bfcd23e897062645b5d5766ab81eef662ca789d4e5bf7aa76414d01acd67e9ec372e63f5a676fb4645cbff0c47b3ec0c667b781ac42a0fedb75eaf39fce4da7f37a660db56ca92836609ca32faa4987f232e89177cee0b45ab8d34ca1c9a9f29fcd057cc6e491387f75e01ffc40ddef01c0bb557803cb514afb19718a9b918ed266f5c3283d93b6fdd1232758f059a0f6f78b7d5e8cb0d61a7e974936b6bf007a0121db05051a3f3279c3b295de61af596f8ce8820480f666f963ad4c9af0490272f88eb01bdad77ca43c8d5cc3abf7b1d1b6b15890b43008d68ddbc9f2426985d6ef946cae5099b1b81eb500959d8e5571b438f796aafadfa85ae29e6373878f0eac3f91e75cd37c609064e57fc588bdba25f5f2cd095e14d01fe72ddb30f784fe97ccb7619ebe809a5acb24f73a69f9a3b348b99ff554fa316b4b16cb7cdcd79602ac17003057e7bff980521e43a57a43df4c13ed71740767ab277e1da09b371843aa1160b599b5cc0b1cb4c31d348718b64b9a6d66cd691185465ae5dcea649391b342bea21d430df41080"}, +}, +}; + +static const struct uiv_update_testvec { + const char *keys; + const char *nonce; + struct { + const char *new_keys; + const char *new_nonce; + } output; +} UIV_UPDATE_TESTVECS[] = { +// All zeros +{ + // {J,S} + "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + // N + "00000000000000000000000000000000", + // Output={{J',S'}, N'} + {"7941dd0a63d994703e63d94a446804213ab4fb1d2b7ba376590a2c241d1f508dc6a7f418a14503deb89b17aadb2806f73fc06e5d14e675f5ec880023d4f73296", "12dce4a0e5bc792b5b5a55f9c2f30e07"}, +}, +// All ones +{ + // {J,S} + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + // N + "ffffffffffffffffffffffffffffffff", + // Output={{J',S'}, N'} + {"be938fc23009440bfb5d7bba1d28428ec0897793bb878b8e1eb3ec1257b88024d551d770b56c9312de3dd4ac64e194c91185a89f2ba01f90b03b3acb93f634df", "4b263f03af0acda2f9721d0f4c0783c7"}, +}, +// Pseudorandom 1 +{ + // {J,S} + "bf9b13b7097f5eee96b15423348ebf7aa13da31a2955a72ff17c7f75f9fd92f3280bb2d8992bc2a5f70f8e4e10f0404f16f3a0bbb91975bae7e11180adcba6da", + // N + "1ecb6e1ee6f0531c233676fd1c3ca701", + // Output={{J',S'}, N'} + {"4c03bdb301aaa20b907ac88ecd3174bb1b476a00a81ad67cb4eceba22354ce8f241ab2da59d565781634e9252358006b5b78166ea59028e1ff40a71687dd2f11", "30151c332e40594324ef033a469d4f50"}, +}, +// Pseudorandom 2 +{ + // {J,S} + "e773e6211d22f03e0220bd6e69803b2d0bfbd6321a9e0184e49660bc1989318a868d5ccd3f769537c4990df2998cddc14cd853d8614c6e7e3548af9c824b457d", + // N + "d8097e67afff2d56a6279229cfb37f29", + // Output={{J',S'}, N'} + {"c9f14480f4d46a1e40ba3daaab9004ec0e7afab84f3c60da9f7f01ab46aab7a81e2138eed6f141047bc4169013450134586120852ca9a952417b402834fbedf4", "c79fdf8d9ae28e55eaed6e556e12b994"}, +}, +// Pseudorandom 3 +{ + // {J,S} + "a150329bf382e5c3b11619ac72ac3b2cdf55b19e94fd2f92bfca40ef540274ba571c53695d5d8f0d4d4935d2b599ee095754d3bbdd9929d60997eb4f745e0a48", + // N + "071652e3ea1b1d299ac07ab3df431090", + // Output={{J',S'}, N'} + {"7c7a284801c7aa0f727f8e24b87a2dca1b7550577924490291a7343924dfd1b9e2b86e4f7db39b77715888f7d3b9aa4ea44bd72a8b1eb79df0d46f25c130fc87", "3c8ecadfbe9ee9587332a6568c7f2476"}, +}, +}; + +typedef struct cgo_tv_state_t { + const char *keys; + const char *nonce; + const char *tprime; +} cgo_tv_state_t; + +static const struct cgo_relay_testvec { + bool inbound; + cgo_tv_state_t state_in; + const char *cmd; + const char *tag; + const char *msg; + struct { + cgo_tv_state_t state; + struct { + const char *t_out; + const char *msg_out; + } result; + } output; +} CGO_RELAY_TESTVECS[] = { +// All zeros, inbound +{ + // Inbound + True, + // R = {K, N, T'} + {"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000"}, + // AD + "00", + // T + "00000000000000000000000000000000", + // C + "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + // Output={R', {T_out, C_out}} + {{"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "66e94bd4ef8a2c3b884cfa59ca342b2e"}, {"66e94bd4ef8a2c3b884cfa59ca342b2e", "66e94bd4ef8a2c3b884cfa59ca342b2e58e2fccefa7e3061367f1d57a4e7455a0388dace60b6a392f328c2b971b2fe78f795aaab494b5923f7fd89ff948bc1e0200211214e7394da2089b6acd093abe0c94da219118e297d7b7ebcbcc9c388f28ade7d85a8ee35616f7124a9d527029195b84d1b96c690ff2f2de30bf2ec89e00253786e126504f0dab90c48a30321de3345e6b0461e7c9e6c6b7afedde83f40deb3fa6794f8fd8f55a88dcbda9d68f2137cc9c83420077e7cf28ab2696b0df05d11452b58ac50aa2eb3a195b61b87e5c65a6dd5d7f7a84065d5a17ff46273086002496db63fa4b91bee387fa3030c95a73f8d0437e0915fbce5d7a62d8dab0a58b2431bc0bede02550f40238969ec780410befccde6944b69dd007debe39a9dbc5e24f519a4bdf478b1d9ec0b67125f28b06efaa55d79412ad628d45089c3c304f94db3a21df6cdaf6d2e2e3b355441eff64ad90527e752a4b2ebb4d0a1070ce2e2982e272fdb7cf4b584b095a0f957fdb828689437e37dc48b2ad379c6f3c6e957ee77afb88c65949ba12eec45c22865e4907ae42aee813898acdf91e2e4c21d828e0a76de2bb6bb6f869e5eef1f618dedd27562812b9a14e8996a5c352df3817e60d6ec20119a52c80a61ec195622627240212decca515feab63e2734587948a836a7de205cfec0c288351c"}}, +}, +// All zeros, outbound +{ + // Inbound + False, + // R = {K, N, T'} + {"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000"}, + // AD + "00", + // T + "00000000000000000000000000000000", + // C + "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + // Output={R', {T_out, C_out}} + {{"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "66e94bd4ef8a2c3b884cfa59ca342b2e"}, {"66e94bd4ef8a2c3b884cfa59ca342b2e", "66e94bd4ef8a2c3b884cfa59ca342b2e58e2fccefa7e3061367f1d57a4e7455a0388dace60b6a392f328c2b971b2fe78f795aaab494b5923f7fd89ff948bc1e0200211214e7394da2089b6acd093abe0c94da219118e297d7b7ebcbcc9c388f28ade7d85a8ee35616f7124a9d527029195b84d1b96c690ff2f2de30bf2ec89e00253786e126504f0dab90c48a30321de3345e6b0461e7c9e6c6b7afedde83f40deb3fa6794f8fd8f55a88dcbda9d68f2137cc9c83420077e7cf28ab2696b0df05d11452b58ac50aa2eb3a195b61b87e5c65a6dd5d7f7a84065d5a17ff46273086002496db63fa4b91bee387fa3030c95a73f8d0437e0915fbce5d7a62d8dab0a58b2431bc0bede02550f40238969ec780410befccde6944b69dd007debe39a9dbc5e24f519a4bdf478b1d9ec0b67125f28b06efaa55d79412ad628d45089c3c304f94db3a21df6cdaf6d2e2e3b355441eff64ad90527e752a4b2ebb4d0a1070ce2e2982e272fdb7cf4b584b095a0f957fdb828689437e37dc48b2ad379c6f3c6e957ee77afb88c65949ba12eec45c22865e4907ae42aee813898acdf91e2e4c21d828e0a76de2bb6bb6f869e5eef1f618dedd27562812b9a14e8996a5c352df3817e60d6ec20119a52c80a61ec195622627240212decca515feab63e2734587948a836a7de205cfec0c288351c"}}, +}, +// All ones, inbound +{ + // Inbound + True, + // R = {K, N, T'} + {"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "ffffffffffffffffffffffffffffffff", "ffffffffffffffffffffffffffffffff"}, + // AD + "ff", + // T + "ffffffffffffffffffffffffffffffff", + // C + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + // Output={R', {T_out, C_out}} + {{"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "ffffffffffffffffffffffffffffffff", "7209baed4b605b158b7eb25de2200e83"}, {"7209baed4b605b158b7eb25de2200e83", "5546c0d2d8da37d92908803d88ff5a646e24a9f9c8c0e9f239726ccc5107d45ed813697aab0b27969930489e47c87475d71b92fc875e268d2ed92fa735b8258c657ff883512adf916a7a8819596e878415da7dc689fc658b862235133b4366e5bea11ece0990a544cb324e27313d67567797213ddb9102e75caca82a15035e44a306c906f8c17e2c88975808b35ad13443849d9ebec10f2c888738ff5b7cb3043b2bbd6098b167746addcc55238fb32d9ef404f3d0f7db0bc5f30aca0cf9ce5f87c989268d18b1069b33bbd5b7818a99603ec0d82871e75cffd1d84e2be1e0f8e8b3678b1ccd7a5a676d83fe0e68f09027ad912d58d2257932750b383e2f2fa3c889ee9d71919cc05d982230c6ff8b7e5e3ed302ed82bed429794c261aa009d231bb6c8675e513313432017cea50843a0309153f7f9d556330f19c38bc5ae6d33d63abaa7ebabd3335c1bf59a2121378288da679259bb1b8a8b027938f3e902c655c781e7f5d9514e53502e7ebc31e344344c3ae2a6397a9a8b846dab8a84174e91664804c7804bab09d6d40aeeb491d6f6184830ac7b5807418a05a7ab9938c3fdc18066b5d503f8c98e83be033b6fba905324267618cc6989b486e0decf7cc897d17be093286a4d4fb5016c3e3323ccc416a30473081473bd471e430194ec4e2ac0af3bca0577b78f4c70e4d"}}, +}, +// All ones, outbound +{ + // Inbound + False, + // R = {K, N, T'} + {"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "ffffffffffffffffffffffffffffffff", "ffffffffffffffffffffffffffffffff"}, + // AD + "ff", + // T + "ffffffffffffffffffffffffffffffff", + // C + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + // Output={R', {T_out, C_out}} + {{"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "ffffffffffffffffffffffffffffffff", "7209baed4b605b158b7eb25de2200e83"}, {"7209baed4b605b158b7eb25de2200e83", "5546c0d2d8da37d92908803d88ff5a646e24a9f9c8c0e9f239726ccc5107d45ed813697aab0b27969930489e47c87475d71b92fc875e268d2ed92fa735b8258c657ff883512adf916a7a8819596e878415da7dc689fc658b862235133b4366e5bea11ece0990a544cb324e27313d67567797213ddb9102e75caca82a15035e44a306c906f8c17e2c88975808b35ad13443849d9ebec10f2c888738ff5b7cb3043b2bbd6098b167746addcc55238fb32d9ef404f3d0f7db0bc5f30aca0cf9ce5f87c989268d18b1069b33bbd5b7818a99603ec0d82871e75cffd1d84e2be1e0f8e8b3678b1ccd7a5a676d83fe0e68f09027ad912d58d2257932750b383e2f2fa3c889ee9d71919cc05d982230c6ff8b7e5e3ed302ed82bed429794c261aa009d231bb6c8675e513313432017cea50843a0309153f7f9d556330f19c38bc5ae6d33d63abaa7ebabd3335c1bf59a2121378288da679259bb1b8a8b027938f3e902c655c781e7f5d9514e53502e7ebc31e344344c3ae2a6397a9a8b846dab8a84174e91664804c7804bab09d6d40aeeb491d6f6184830ac7b5807418a05a7ab9938c3fdc18066b5d503f8c98e83be033b6fba905324267618cc6989b486e0decf7cc897d17be093286a4d4fb5016c3e3323ccc416a30473081473bd471e430194ec4e2ac0af3bca0577b78f4c70e4d"}}, +}, +// Pseudorandom 1, inbound +{ + // Inbound + True, + // R = {K, N, T'} + {"3ab14ee71f417dc6cba5aaaba8eff9c3cd5f408020b4e8586ff734dad4aff593f4d863afbc519eba44d6e8643ae3fabf7ba8cd0803094d82b18acb03c1207927", "e616de4990c8efc5e58131f635f35776", "310495f73b4d20f4d8069bb1d2ed5638"}, + // AD + "88", + // T + "5de86524ea1542e8f1b8ea118c12d1fd", + // C + "43f965f6b01b939d972a2b9bd3b2cefe4315da3f97b51af875dc7717b97d9ac37c9e18e4a00fdcc65dde90ebd6c2909fa3e1d83cb07863596408f94334522c1e04688855c44dbee3bad7ab2872c1b87493766c6e0639bcdbbb2717be2d848c37ef034607f6b05facec43f5c1ef99a78631ab8387385cf0b272b0759513807451c63b4ba7f8908e5822b43bea59013c4bba59ab70dd9951ad1d015ccc9b4067aa02cc40d530e2e2bc473906f03a69f5f92183d2094af98edd23199940572edf095a42ec9be535982d6bdf8e525cf2a26011082d0ad019bd3580be817b1049db2e3ca35ee1212b15faa2c35bd4b342c930cc44e77336d84fcbd36454aa3a3cd7961047b58fd26383d1fbe0beb250f8389c1e949728d3d8218b36f4989e3499ced2e660b7ed6a5edb51a36f2fe9f32238f1a318141fcb3bed2c8a34efb5f98b8bccf2548fb542826e6abf3db576ccb064c905c246ecb4ecd5d638e7d3705b549df99de126227485f8dcb499dabc6f3e5d9735a70f1073f708293b2855dd64c981bdfceb8c75bd7d692f7a2d26f453c302d4593af2bb17a785d52bc87914f62056326dbedb8b5d45333dc7fca8d5eea986b1c19ff122b60c74f9220a3eaddf0f40ee105fee1c336c93afef1804a81bb57f918dbd7ef220428dd26c6d83c95e6adcec8f997b8ed810dcdc0bb3867f37", + // Output={R', {T_out, C_out}} + {{"3ab14ee71f417dc6cba5aaaba8eff9c3cd5f408020b4e8586ff734dad4aff593f4d863afbc519eba44d6e8643ae3fabf7ba8cd0803094d82b18acb03c1207927", "e616de4990c8efc5e58131f635f35776", "84fe1db6790ae6e32e418a70bb70d695"}, {"84fe1db6790ae6e32e418a70bb70d695", "be638eacedc6fbbdf8d9f75f414b3b43ff4fdef3c261a24ffec5eae75a3a1016432bdfc6df956b1e19eb011dc891238d86938ee98d7e0beac3df360818e45aff037e42e345153f5814937d53f92492b03f526c3e85464912742bbb26df3258e7fe0e3fdd7c8b855122543a6d277f896bec6875e6d320d5f329b90d1e57ea2aa9691542c13c9601f7dae18313737387a85eff1ba244be546cd1511782555b8ab90306bd85170e3a489c13f892f4430ae39c49ab1514d05b510709da34651dbe600f68642541ee9ab2163a0e442b6017014c80e05b622d53fa40cbd5eaafbfec34289c5b48c2908a2e7749e1c3f0cceab57bea1f3c925756e477d0c32c1d6262f259a5b20b8234aba22c36604fa6c9f0b953724089b549b7442adae8a91a7a7c3070aad0099d3cb94c17b2f767a8933bbae1de8322d73d9688f6f211b9b3922e758b2407179083490d3bd2d3f366e012f86aa268c2d24ea843953b3cc4a83f33c795f5df035da1c7ef4b160d013d201adcc469def9b4c6334cb9f091f789ba1a23cb2a667564eea9ea3a24c5f1fea54c8f7842ba6266c5405b6cf5f611ee4d0253b09500ce0e704ae2b9aad6271b59ac3e34a446c03c1cf261757c6798d6cc9fe6be8793666d8d046cb5aee99a0598184b3c614444a7b0ed812fe46c1e7ae9a0aee9f49908e705896edf53a3a90f"}}, +}, +// Pseudorandom 1, outbound +{ + // Inbound + False, + // R = {K, N, T'} + {"3ab14ee71f417dc6cba5aaaba8eff9c3cd5f408020b4e8586ff734dad4aff593f4d863afbc519eba44d6e8643ae3fabf7ba8cd0803094d82b18acb03c1207927", "e616de4990c8efc5e58131f635f35776", "310495f73b4d20f4d8069bb1d2ed5638"}, + // AD + "88", + // T + "5de86524ea1542e8f1b8ea118c12d1fd", + // C + "43f965f6b01b939d972a2b9bd3b2cefe4315da3f97b51af875dc7717b97d9ac37c9e18e4a00fdcc65dde90ebd6c2909fa3e1d83cb07863596408f94334522c1e04688855c44dbee3bad7ab2872c1b87493766c6e0639bcdbbb2717be2d848c37ef034607f6b05facec43f5c1ef99a78631ab8387385cf0b272b0759513807451c63b4ba7f8908e5822b43bea59013c4bba59ab70dd9951ad1d015ccc9b4067aa02cc40d530e2e2bc473906f03a69f5f92183d2094af98edd23199940572edf095a42ec9be535982d6bdf8e525cf2a26011082d0ad019bd3580be817b1049db2e3ca35ee1212b15faa2c35bd4b342c930cc44e77336d84fcbd36454aa3a3cd7961047b58fd26383d1fbe0beb250f8389c1e949728d3d8218b36f4989e3499ced2e660b7ed6a5edb51a36f2fe9f32238f1a318141fcb3bed2c8a34efb5f98b8bccf2548fb542826e6abf3db576ccb064c905c246ecb4ecd5d638e7d3705b549df99de126227485f8dcb499dabc6f3e5d9735a70f1073f708293b2855dd64c981bdfceb8c75bd7d692f7a2d26f453c302d4593af2bb17a785d52bc87914f62056326dbedb8b5d45333dc7fca8d5eea986b1c19ff122b60c74f9220a3eaddf0f40ee105fee1c336c93afef1804a81bb57f918dbd7ef220428dd26c6d83c95e6adcec8f997b8ed810dcdc0bb3867f37", + // Output={R', {T_out, C_out}} + {{"3ab14ee71f417dc6cba5aaaba8eff9c3cd5f408020b4e8586ff734dad4aff593f4d863afbc519eba44d6e8643ae3fabf7ba8cd0803094d82b18acb03c1207927", "e616de4990c8efc5e58131f635f35776", "84fe1db6790ae6e32e418a70bb70d695"}, {"84fe1db6790ae6e32e418a70bb70d695", "be638eacedc6fbbdf8d9f75f414b3b43ff4fdef3c261a24ffec5eae75a3a1016432bdfc6df956b1e19eb011dc891238d86938ee98d7e0beac3df360818e45aff037e42e345153f5814937d53f92492b03f526c3e85464912742bbb26df3258e7fe0e3fdd7c8b855122543a6d277f896bec6875e6d320d5f329b90d1e57ea2aa9691542c13c9601f7dae18313737387a85eff1ba244be546cd1511782555b8ab90306bd85170e3a489c13f892f4430ae39c49ab1514d05b510709da34651dbe600f68642541ee9ab2163a0e442b6017014c80e05b622d53fa40cbd5eaafbfec34289c5b48c2908a2e7749e1c3f0cceab57bea1f3c925756e477d0c32c1d6262f259a5b20b8234aba22c36604fa6c9f0b953724089b549b7442adae8a91a7a7c3070aad0099d3cb94c17b2f767a8933bbae1de8322d73d9688f6f211b9b3922e758b2407179083490d3bd2d3f366e012f86aa268c2d24ea843953b3cc4a83f33c795f5df035da1c7ef4b160d013d201adcc469def9b4c6334cb9f091f789ba1a23cb2a667564eea9ea3a24c5f1fea54c8f7842ba6266c5405b6cf5f611ee4d0253b09500ce0e704ae2b9aad6271b59ac3e34a446c03c1cf261757c6798d6cc9fe6be8793666d8d046cb5aee99a0598184b3c614444a7b0ed812fe46c1e7ae9a0aee9f49908e705896edf53a3a90f"}}, +}, +// Pseudorandom 2, inbound +{ + // Inbound + True, + // R = {K, N, T'} + {"302b0f1333b68c8c2c367b1aa02701e07f715b2fc28f34e124893657a98d5442339c9dc55adec43305e5c03e0b9ac69d35f31e92c6bf9aa066607895b453b89e", "02899ad22f2f01d8768323613476c78c", "db34fd587ddf145c5aa1ac58bef5756d"}, + // AD + "ab", + // T + "867464943ada7a8decef75a961214f9a", + // C + "0f0cfeed7dcd312b7b769cc859b20a8e18da16451925a0153ae6a57226fec6b2048dea4584e47e078ecbce0f2ca6413a2bb4e30fd6628a036d1749556adb012d110e23c979dc26c2aee3f24bf2ccf27cfd6d294073a20e9c4c5401c09bc4b2e38b6002b2b320b408b99798db1222034813fd70723a141de5a11679a56b704b1cd8751e919565ea129ce1f9fc2883c7d4cac0d8fd4da61d57501788105ef0d622fca6bfbf72b11a3a03d388c99e4aea582db920872be152bf89dc672383263936d93c0c9915db9b103cbcff5e90f4d9dbae0c4ea8e8464332b9ffaa478735faee477e28355be86f572e2ccca91e60e1874edd1d592b0f4f625276dd5a270a830147365c3fa20168088477c08c56352015ee962d1ce6d24456c96b649921ecffbafa21ff713e2d0da18f2e72e49830ada7878b7fba8eb3700c1db10cbd62ddd6bf1350374a10df5578e6b0774b510d15f11bbe95fd3ed87a8bd68c5110621e12d708f266ee8e48979e2d0fb222c008faea9d9f4ae14951301f9359ed133c5328e6fdd817e83ad84341500752b052bea6432841c801ffd68856c597dc0ce006c89222f1173194044de3d0f75b670923c4de63c683de97990af9430f83ba7510220f56a46e8a47b6ee46a4fcc132d33e059dc3783e3dfe2ecd673588feeb4af5945e18693238520aada42ab371ff4e", + // Output={R', {T_out, C_out}} + {{"302b0f1333b68c8c2c367b1aa02701e07f715b2fc28f34e124893657a98d5442339c9dc55adec43305e5c03e0b9ac69d35f31e92c6bf9aa066607895b453b89e", "02899ad22f2f01d8768323613476c78c", "61637a70ae9a95105b1e78ff6892e60e"}, {"61637a70ae9a95105b1e78ff6892e60e", "b9b2516c278a8b4bba221b185e990d4814e94b8ea6ef5e7585945ec250c1d427d2c322e3c3f3f406a43408296e0820debb518543be2ed9a18d61b0ac46e1de159101fb6431711f43eb3e35a0ab1451c30e4d895f888cfada66cffe67de67254e8bd4b3e0834f07033206c3449ae8f8ced104c14a0df0ac8fc2757ae63e1cdc99da87f5bc9fc66d2bb5216e641c04f234da501fa721263229948e51ce73c355e302219f6a8f24daeb6c771ff7aeb7f16fc431551618d32c3ea78543bc71d95593a1675b5a1fa936db5945dff819abb197da2dfa460a7619033c9de74679f02fa73badd4ce89a43b25517a12eedd5b3464ca44f4c68e8f14e671f366a541f340b376a5890202f72e15cc22ba1d2573190e3cc65ba042e874d05ed11a16bd5f93a8defb047a223d647b54b0531fc76beb3c7a23766d7cf84479aaa3c25a8b7cc40a31603283aaf98daedc2990c2c4b6006d0a9e80be6bc1a34e65b12a7414acc4046f5f653b0ea2b44e1c93ce1ae8763aa88c366349db4b2305b57030290e989f65d035fdf0375bd889552a79f6647a5810ed2020c1821e78b150501f3e41e4b836ea079fc7b89e215efd9dfb02bcbeb857b0940cb70f64840b40cddf0fc3e3ff3e561b709d8eccbd62b6cb28ebe49003cd1569eb569e87bc24c5d245079da7ae610146aef4225b6f3c6e0ce3aacc"}}, +}, +}; + +static const struct cgo_relay_originate_testvec { + cgo_tv_state_t state_in; + const char *cmd; + const char *msg; + struct { + cgo_tv_state_t state; + struct { + const char *t_out; + const char *msg_out; + } result; + } output; +} CGO_RELAY_ORIGINATE_TESTVECS[] = { +// All zeroes, originating +{ + // R = {K, N, T'} + {"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000"}, + // AD + "00", + // M + "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + // Output={R', {T_out, C_out}} + {{"7941dd0a63d994703e63d94a446804213ab4fb1d2b7ba376590a2c241d1f508dc6a7f418a14503deb89b17aadb2806f73fc06e5d14e675f5ec880023d4f73296", "12dce4a0e5bc792b5b5a55f9c2f30e07", "66e94bd4ef8a2c3b884cfa59ca342b2e"}, {"66e94bd4ef8a2c3b884cfa59ca342b2e", "66e94bd4ef8a2c3b884cfa59ca342b2e58e2fccefa7e3061367f1d57a4e7455a0388dace60b6a392f328c2b971b2fe78f795aaab494b5923f7fd89ff948bc1e0200211214e7394da2089b6acd093abe0c94da219118e297d7b7ebcbcc9c388f28ade7d85a8ee35616f7124a9d527029195b84d1b96c690ff2f2de30bf2ec89e00253786e126504f0dab90c48a30321de3345e6b0461e7c9e6c6b7afedde83f40deb3fa6794f8fd8f55a88dcbda9d68f2137cc9c83420077e7cf28ab2696b0df05d11452b58ac50aa2eb3a195b61b87e5c65a6dd5d7f7a84065d5a17ff46273086002496db63fa4b91bee387fa3030c95a73f8d0437e0915fbce5d7a62d8dab0a58b2431bc0bede02550f40238969ec780410befccde6944b69dd007debe39a9dbc5e24f519a4bdf478b1d9ec0b67125f28b06efaa55d79412ad628d45089c3c304f94db3a21df6cdaf6d2e2e3b355441eff64ad90527e752a4b2ebb4d0a1070ce2e2982e272fdb7cf4b584b095a0f957fdb828689437e37dc48b2ad379c6f3c6e957ee77afb88c65949ba12eec45c22865e4907ae42aee813898acdf91e2e4c21d828e0a76de2bb6bb6f869e5eef1f618dedd27562812b9a14e8996a5c352df3817e60d6ec20119a52c80a61ec195622627240212decca515feab63e2734587948a836a7de205cfec0c288351c"}}, +}, +// Pseudorandom 1, originating +{ + // R = {K, N, T'} + {"3ab14ee71f417dc6cba5aaaba8eff9c3cd5f408020b4e8586ff734dad4aff593f4d863afbc519eba44d6e8643ae3fabf7ba8cd0803094d82b18acb03c1207927", "e616de4990c8efc5e58131f635f35776", "310495f73b4d20f4d8069bb1d2ed5638"}, + // AD + "88", + // M + "43f965f6b01b939d972a2b9bd3b2cefe4315da3f97b51af875dc7717b97d9ac37c9e18e4a00fdcc65dde90ebd6c2909fa3e1d83cb07863596408f94334522c1e04688855c44dbee3bad7ab2872c1b87493766c6e0639bcdbbb2717be2d848c37ef034607f6b05facec43f5c1ef99a78631ab8387385cf0b272b0759513807451c63b4ba7f8908e5822b43bea59013c4bba59ab70dd9951ad1d015ccc9b4067aa02cc40d530e2e2bc473906f03a69f5f92183d2094af98edd23199940572edf095a42ec9be535982d6bdf8e525cf2a26011082d0ad019bd3580be817b1049db2e3ca35ee1212b15faa2c35bd4b342c930cc44e77336d84fcbd36454aa3a3cd7961047b58fd26383d1fbe0beb250f8389c1e949728d3d8218b36f4989e3499ced2e660b7ed6a5edb51a36f2fe9f32238f1a318141fcb3bed2c8a34efb5f98b8bccf2548fb542826e6abf3db576ccb064c905c246ecb4ecd5d638e7d3705b549df99de126227485f8dcb499dabc6f3e5d9735a70f1073f708293b2855dd64c981bdfceb8c75bd7d692f7a2d26f453c302d4593af2bb17a785d52bc87914f62056326dbedb8b5d45333dc7fca8d5eea986b1c19ff122b60c74f9220a3eaddf0f40ee105fee1c336c93afef1804a81bb57f918dbd7ef220428dd26c6d83c95e6adcec8f997b8ed810dcdc0bb3867f37", + // Output={R', {T_out, C_out}} + {{"c24b000843784bc008c70b977e62ed82085ed0cda9f841da2c89d1832e763b9e283c36875fa41caae5913293d8014451c10fedddf362849bcaaa1833a3b8fcd8", "497798331f2c32ca4de4b1b55b82c306", "b8b3b69f6e175a5649013ca99c838291"}, {"b8b3b69f6e175a5649013ca99c838291", "94773462bcfb3728ec6f2f4e3b7020234abd8a6fa778a49788509b6452556e951f49a20a552035b38143907c59788c6865dac89ec22af08cc98ed1fcf55debccd3bb18c91340205524b36e1ec0ca0c082f79c575e7e0c77ade4b6084f6b6a12592f9a24c715bc92ee2531641cb11c6e9a462242354d655c392fccc1c84af5217cefb9806eb9990cf36034188600b2a123d860d0c661362f511e7d4eafc46a38c030fbe884a681fedef9c04375793435784579a3640ce2d75d9553936e877c3c24b33e0ffa88d59fed2fbbaf91e446c8d37a6b1400f7dfcd6ba8fa425c36e111a71c661f81ac8824524038a8dab5ac5a17014f4e7af5638e27e14869b51a9a2ff43fc9b3d7205e9f2e9f20c80d52778c26589179631345b0cedcb76d4862e3f88dcd27074da5d8b36ce7f2fbb972dafe327fd0e68620f5b284b1a7f1e64e33df2abd0f4aabe30b0e168f52ea39f1c5755276bc5c25cfa3960c2646ac13cbf2d9d1748e9c8db3664a98b4ef4e6f4a401cde973a62f0d4a6409447dfd2500b916015e50d79eeaa6508295d7959cb45af82b2b1b081b84911f9feeb994ddc5c472b342eef82d611809051658215158b99f5e3002e97f343e3b29eaad6489557573780b13956e4665dd0b859631d9937d4f90e0f810b36babfe8a1371b6eb985fd600d8353962cca9ce5b9d2ebf0da8"}}, +}, +// Pseudorandom 2, originating +{ + // R = {K, N, T'} + {"302b0f1333b68c8c2c367b1aa02701e07f715b2fc28f34e124893657a98d5442339c9dc55adec43305e5c03e0b9ac69d35f31e92c6bf9aa066607895b453b89e", "02899ad22f2f01d8768323613476c78c", "db34fd587ddf145c5aa1ac58bef5756d"}, + // AD + "ab", + // M + "0f0cfeed7dcd312b7b769cc859b20a8e18da16451925a0153ae6a57226fec6b2048dea4584e47e078ecbce0f2ca6413a2bb4e30fd6628a036d1749556adb012d110e23c979dc26c2aee3f24bf2ccf27cfd6d294073a20e9c4c5401c09bc4b2e38b6002b2b320b408b99798db1222034813fd70723a141de5a11679a56b704b1cd8751e919565ea129ce1f9fc2883c7d4cac0d8fd4da61d57501788105ef0d622fca6bfbf72b11a3a03d388c99e4aea582db920872be152bf89dc672383263936d93c0c9915db9b103cbcff5e90f4d9dbae0c4ea8e8464332b9ffaa478735faee477e28355be86f572e2ccca91e60e1874edd1d592b0f4f625276dd5a270a830147365c3fa20168088477c08c56352015ee962d1ce6d24456c96b649921ecffbafa21ff713e2d0da18f2e72e49830ada7878b7fba8eb3700c1db10cbd62ddd6bf1350374a10df5578e6b0774b510d15f11bbe95fd3ed87a8bd68c5110621e12d708f266ee8e48979e2d0fb222c008faea9d9f4ae14951301f9359ed133c5328e6fdd817e83ad84341500752b052bea6432841c801ffd68856c597dc0ce006c89222f1173194044de3d0f75b670923c4de63c683de97990af9430f83ba7510220f56a46e8a47b6ee46a4fcc132d33e059dc3783e3dfe2ecd673588feeb4af5945e18693238520aada42ab371ff4e", + // Output={R', {T_out, C_out}} + {{"60b9d644a620c3f36181f6f3ecbb0be41d400b78822dd3247247d286a5b80baec2dfc3694f119beab9b40fd538844d159e7bf256fb2ce53fe33e4c8763180b0a", "094b5cdc3a49cc51aab3e1f331f03df6", "99daac5f8bdba8f4807e719c768cb3ce"}, {"99daac5f8bdba8f4807e719c768cb3ce", "30db410a04452437045b7f51210bd01eab5d034c146c766ef73a9500b1c7f75d5ea7b1fe47f8eb927bcac6fb756e80cdd48b381a431c858432047410cd526bd91283a53ab94371bff4c4370e8dc8671349316759bdd01bbe432423a66a8497a7091c8056af277112a04c65946dbf82d076e66647456e991ff44c689e57d475956a3c1dd5f1a870e711ed57dc287b96f6437e2e4194e341a2dc5913631eab53f899f09ee41361b4d74c508f42ae972c93d21797342242b7e4e39d24888dfd215458a8e134fb9da152a0b1e5304685919f5dc3da8a0dc04906763075432ce92afe1283b1d344c36832bb54cf47a28c13263fd34558ef1c7827b4d8c1aea20f23316b04d1750bf42b6317a421618c3af00f5469d28aa52e8aef1e76d80754a52982285c1d558c61268d40f2e931c0b3848f70da72b07867df56de689a19f2db0a379207ca462a0bc97a3ea7d111a144454432e4d0eb3ee1fc5f905923effa1b196ce29f9c07d32fabcdfcce4c2d582a7b80b65fff05ffd2b5e7d91fca0817e9458c68d6919ad442ca1d20d77c7c0b6e924af2665d9eeaeeac28692f978eecd4e1d5878ce300f8035d0a7ff6050a172c1d328bb392e4d55198a976d45f7d9670eeb67ed4b79c95b219fc9cf3c7613c128e2224d2799d9459b4941a248589d7bc1cd644ac96aa49e0d630288b73a028"}}, +}, +// Pseudorandom 3, originating +{ + // R = {K, N, T'} + {"f69da975bf0055353e52a8b3fa834b1bcedf1445e4b2f1dca13f59a306e8040ce64d5922b2b9de5735a96e2fa2e9524e99ce5b8888fd000f570f148191bdb54f", "8e4219f5b72d0bbf1f47005632816b36", "c5301aaf38e66f698293618354d06e0a"}, + // AD + "90", + // M + "727ee8dff3a22ad873545c040d22a67a6caac97c308a0f4109da1a1d67695d9fd7570a27593fefcdc0ce568ff6f8998a03791e12720a86d95110540073e104a86ba14ac9e58705ff20ebfced49a91d832a635924193dbf14ff995da7d4cbb4752d364908c1096606cee429adad73513bfd848fb6132fad9531178b419d4c6670224e858ff0a413b083b58cb6a8297bc7474e48050ac926c3a568df88feb135e9011d26eb2327c0797fd821a9bca3052e116f26844a2a5d23542ea666f2225700dd134cc166e2cd36f88be6a4b367be083e7d7be99a9205489de7ece3308846fcad66dd249ada0c559999fc3dd9e36036831e3e2aa51d0190b227f3bb54b365ea668009298612308361537b66e143fdb5b3da43a6a141910b7daef3dd4c5a819749c1d5d005c3c39bf7d2d749754614e794c51a965694904d30fa5be6fba2360ccf46c4ed2b4829f6434bb8951e82580a4da3d7075d734c4c12560693b9bacb1ce7ee953d7ce9dec24d7a129e8e582a3e2e1168e7b966c2e435b21f9b7ba83e27023b287e7fc420c5934af909e1a3fcb8415347c5ebd30aebaf6fe11cbea60d8dbe78cd54736dcb6a0cab929175417510d0ab2c4688b91c8d75d5a9b51ff15fddeb1a08402dc7748eb5b9d219f4ecb4116be1765a03fd06fc01d8e366b945cf6557257ef0ec2b74619d4e081c89", + // Output={R', {T_out, C_out}} + {{"c658a50d452e0ac66a543a15dfb30f791509266d47e259d56374787e3e2ccc49a06c6d2d65553223ace6097a3fb7cee5f4af4602a4c73c8128391e2454b7caa1", "2436c77f19dee78ff65f39967659e7d5", "276d823e18b1a06c0fe224431630b7b2"}, {"276d823e18b1a06c0fe224431630b7b2", "545b61a9a2d88a6f0e389c864fcdec76f5d04b836a1d1a48b26895f4c8829af6de70ac08578f2e1cd054f4a9ab5efbdbd872b712ca451270f472a621a95827a382829d794395ae507ccc1df35a677d069207296faa9c2a1d3a454ada30deac8e3a2fd4cfa69c298f9ae0f6a6d15b2a3404c84233c29fc8e85cdf009dfab83ff18f0a7f9ed8a4d7ef10e6fae321c5c526f01dc5f045ec9504e270cb634b072b03d1a0ef8b013913684b935d2883bdfd49ce8dbde8e603663b7ebe869072d61462aea8f7da0d7bc4be054032995c5f5862493f3e45580d9415a3f68eb083092a4c1066f06725da1751b025efb015683cc1935cfafafe7aef90d9c18f2a5f2cce060716838303ca8b7de3164fc09a9d15ccbedd7c24bd47f9585b3b333012ce3a1718cd8ad493b90695734350ac345c42c911d5038b9f288d2d5da8e1bafe1f22967eef3f705a49310f7ebb0837303ede480564cbd5174d354c15668846ed5e9b40002f831d118aeb1d78fd41a9e80064da3bc0f84fe0898e0e2d81cf20a14baebb1f1d784682fce429625f6a8999177f9e1adf515638280279f5dbbb8eff1fb09ba3782cb6bb49ae28b38883808c69c70a45cf2efb5932c67c77756a9eae3cc63cab0f3554cc55e6fe6f1d1fe6a7fd27c248fa0f491a5c459c0e51bc06d9574cb22c1c4d5aa64b4b66875233bbdd"}}, +}, +}; + +static const struct cgo_client_originate_testvec { + cgo_tv_state_t state_in[3]; + int target_hop; + const char *cmd; + const char *msg; + struct { + cgo_tv_state_t state[3]; + struct { + const char *t_out; + const char *msg_out; + } result; + } output; +} CGO_CLIENT_ORIGINATE_TESTVECS[] = { +// All zeros, hop 3/3 +{ + // S{} + {{"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000"}, {"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000"}, {"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000"}}, + // d + 3, + // AD + "00", + // M + "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + // Output={S'{}, T, C} + {{{"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "af65bb470269ecd7af01f68f1a2b7b78"}, {"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "140f0f1011b5223d79587717ffd9ec3a"}, {"7941dd0a63d994703e63d94a446804213ab4fb1d2b7ba376590a2c241d1f508dc6a7f418a14503deb89b17aadb2806f73fc06e5d14e675f5ec880023d4f73296", "12dce4a0e5bc792b5b5a55f9c2f30e07", "00000000000000000000000000000000"}}, {"1471e71e6fb1f04233a8ec5daa6209e0", "66e94bd4ef8a2c3b884cfa59ca342b2e58e2fccefa7e3061367f1d57a4e7455a0388dace60b6a392f328c2b971b2fe78f795aaab494b5923f7fd89ff948bc1e0200211214e7394da2089b6acd093abe0c94da219118e297d7b7ebcbcc9c388f28ade7d85a8ee35616f7124a9d527029195b84d1b96c690ff2f2de30bf2ec89e00253786e126504f0dab90c48a30321de3345e6b0461e7c9e6c6b7afedde83f40deb3fa6794f8fd8f55a88dcbda9d68f2137cc9c83420077e7cf28ab2696b0df05d11452b58ac50aa2eb3a195b61b87e5c65a6dd5d7f7a84065d5a17ff46273086002496db63fa4b91bee387fa3030c95a73f8d0437e0915fbce5d7a62d8dab0a58b2431bc0bede02550f40238969ec780410befccde6944b69dd007debe39a9dbc5e24f519a4bdf478b1d9ec0b67125f28b06efaa55d79412ad628d45089c3c304f94db3a21df6cdaf6d2e2e3b355441eff64ad90527e752a4b2ebb4d0a1070ce2e2982e272fdb7cf4b584b095a0f957fdb828689437e37dc48b2ad379c6f3c6e957ee77afb88c65949ba12eec45c22865e4907ae42aee813898acdf91e2e4c21d828e0a76de2bb6bb6f869e5eef1f618dedd27562812b9a14e8996a5c352df3817e60d6ec20119a52c80a61ec195622627240212decca515feab63e2734587948a836a7de205cfec0c288351c"}}, +}, +// All ones, hop 3/3 +{ + // S{} + {{"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "ffffffffffffffffffffffffffffffff", "ffffffffffffffffffffffffffffffff"}, {"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "ffffffffffffffffffffffffffffffff", "ffffffffffffffffffffffffffffffff"}, {"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "ffffffffffffffffffffffffffffffff", "ffffffffffffffffffffffffffffffff"}}, + // d + 3, + // AD + "ff", + // M + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + // Output={S'{}, T, C} + {{{"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "ffffffffffffffffffffffffffffffff", "3cf25f81c98d0be16ddbbffeefbdc308"}, {"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "ffffffffffffffffffffffffffffffff", "a9166add184e00b007217cb4e4f52ee5"}, {"be938fc23009440bfb5d7bba1d28428ec0897793bb878b8e1eb3ec1257b88024d551d770b56c9312de3dd4ac64e194c91185a89f2ba01f90b03b3acb93f634df", "4b263f03af0acda2f9721d0f4c0783c7", "ffffffffffffffffffffffffffffffff"}}, {"c8c388584500c58ced7ee209c08b920a", "c0685473f8558a9f9f2f22cfb31f211c6b25b7ebdabf2507b4269636caa01e1f6d4f4f5690c48d6940361059b37516b52b9d9ad93388f964666e7492a6adb91645a02cf39eed4ebd0354d8f484106c04ebb0e53d858c75a44e3145471bf93d09d48af913fdcefa6a0dd3fb730e604035d494f0a5706c3b63424253b7287392a44e9b2f66f765dd7cda20c76a2444a4dfa84170d810eb13e720867170c243ff4d9662b1df15b826c664f1a52e4f57be57b49105895e8ae3b87fd969034f67ae9784d946935dac622cb4cf786ad937174ceab2c766be361f8efc0479aa0b45c5e90da1dcee6802b5acf53dfee7a12e27d55e832b5f77360cd7190522d9057a556b8e1de773a0c29cc20c44dd963395cce1c19633fe1e386a3cc87082d5e645914d96ce3d8dcb9653dedacd8bfc2fe5d7a3e9e205a9c0961dd83d5b5515842fa3291877146081d5d776c4675de92b3f92edd80d7792b9a9f203c6650a33e54822d45a92c7136cf4fdbe6fe698ed6d3596cce17853aa988142a5925e1cd4382fb4d43307c26d57676c1ae5aaec6100de8414f8fc763e87a052f3d7519d539499d90f427c951d91348d9f0c7d77dd454bd8cd80b9b13a1870f95ea19e8dbdfd78ca4cfd520e5bcfcbd751252775165790b250b0d87989a60ccbd4243f8409a28d1d0536d9d9ad51ee474d24a92870b7"}}, +}, +// Pesudorandom 1, hop 1/3 +{ + // S{} + {{"80819c55d001b73b8d51a5c9ce4fc8e2a197bd4891f0f38df791e92fc687c99214992b6749f5b96d6477f7a2821029f714de39b47396fff84b79406ceb667213", "475cec821a2bb29682c9de4ed89fa2bc", "63c839b54659920bbf42c8a76eedc3a9"}, {"79d6e9f34cd2a01b89130bc43002e94a4c3494dfc8db9d11e08d7b8ae7782b38fde2c00e9819d5c619a5c8a92afbabdb727108b5dd4ba9d572b47567685c9e7c", "d6dc99f4ce27ffe7ad3b40c73be86ad8", "eae6b850f1f43e00be741946b5038517"}, {"cc01d778ccfabfad7a442a266aac199e277b38618ba19816d1d668c139367c8ae4c9fc4e6b5a7a214175506d4dffa1c159bc499afc638e6a54a546380b65bcd8", "e459433194d5ce2daf958ef6cb22a391", "34df2febf45efcb197fabf5eef51bf5e"}}, + // d + 1, + // AD + "00", + // M + "32b9e80d44f7fd35dc254f1b07cd10ca91e1c9ba7835a9581e99245677c1ecec22de4e30ef1799ab658305c8266d4f1c71e4ad51cd9d5798de85ece04f6ee9636ad4a14a132278df2c34a449b7d53cf71fb4e55affbc7cbc6699b97356a81d4f70591177aa509df7d8ada37bd7c6082059081e8058087bd5e357544b2b2067c62a3cb123592b44bef8ccb5f259e859ac8d6c9cf599605b370a067dced095f96dd03b3577d20b78afeb8c25cbe3b2e52f2105e952603af981a739216fc6fa29f1a417ea501199a74bab8821e828a1e66e8e0de40138aca846902f7e2c5545cb2263a8b148e65fd793abbd831d97771d5ecbc07bcde5b5cfa02489783302174b36f7570c546fcb05b1d1031089b806d9b54d2b0ebf0fa0ce8b486e26c36825b55a1bcdd001b4a6ab3686ae3b5fef3500837a1eb58e44602c87ce6d384d3dab73fc18e662f03a4112c6fd70ee2063a5dd37bc159f2584b8bcc63106ff6f219cb3e45d57e3b78c88fb0acbba7b58f2f3c54d1877160199583876e1a321bfaa813e0ce1e1803fff094e437ca879ab2d85248050f720bfac980a8455f1bd83ad8648af0052a3ff1203a75b033254edcbfc144c53ec72b603b404aac06021d51524953e9d267c912cc82d61b70d47775d80451ae59071ce7596f3dfe60ff0f636ec06689993ed52f8efd7d04415350421", + // Output={S'{}, T, C} + {{{"d0f4674c280810a523aa25f98bbcff032b4f78f536ab763365384c3f55117e26da677483b85954db5e0840ee66ed269c7089e404f881dea4ecfa1619ca809444", "2b6b31a8b26936bf1823ea99b866d000", "475cec821a2bb29682c9de4ed89fa2bc"}, {"79d6e9f34cd2a01b89130bc43002e94a4c3494dfc8db9d11e08d7b8ae7782b38fde2c00e9819d5c619a5c8a92afbabdb727108b5dd4ba9d572b47567685c9e7c", "d6dc99f4ce27ffe7ad3b40c73be86ad8", "eae6b850f1f43e00be741946b5038517"}, {"cc01d778ccfabfad7a442a266aac199e277b38618ba19816d1d668c139367c8ae4c9fc4e6b5a7a214175506d4dffa1c159bc499afc638e6a54a546380b65bcd8", "e459433194d5ce2daf958ef6cb22a391", "34df2febf45efcb197fabf5eef51bf5e"}}, {"7d05e89f33820206b821fdd7a7465525", "f97feaae58ac1c0e4a69df97b1da3641d0c8795a1ab5e957d94629b9b181129b58bdc5df73588c0068bc67ef14a50d8cb8dd1dce8c1c5ff6b7a0616bbde921f442dd876b3622f88918ba01234920759d4ec3f1079f4d5029b9903fd2b9c60540b89b59134c36b64b58509791cb6b3074f84fed410f27cd4d868a9cb59df2ebe9e3358ed557c4ed2d91e7f3080468734df02536d5e30c27d4021d5ce00eb38b08cde074587fb321510139c4d865da92a4b0ba3833d8b110e3c81e3226099677f91f570add37f6867e9faae6331bc0ca19e475ac75d8dd688b1d77cfa5c28f3e0838bb3f8457bbe7bfb567826cf42913108c268d710253c74dc09def9885c61a3e0ca65231121d746a720d0f6454d09613e9620c0ffe922be22aae5c7e5ac17b083cff28c48c1c205834880689df9dfc5085775695ac3931dce1b05a669c96664fcdb86794d3883de5f9396c351ef26880f8f5d1f64bde7c73fdf177363343a37497de8e9aa4e139c196c9069e4b9a4cfc71e89a8deb80a2a1810e9584002f3d054e64c7e3afd7f215cdac0ea35ae8e6e88c290006ef80c1a193be34f89ac8ac8f03971c2d8f35fa0ceddf9a34d9482bc9cb9787faf942606131abcce19b6ab1aba23bd45c31d15e1189987114f507661916aae148f80b03a3d769a277ca9ce8c2e9d46f4b58319a72627eba3024"}}, +}, +// Pesudorandom 1, hop 3/3 +{ + // S{} + {{"80819c55d001b73b8d51a5c9ce4fc8e2a197bd4891f0f38df791e92fc687c99214992b6749f5b96d6477f7a2821029f714de39b47396fff84b79406ceb667213", "475cec821a2bb29682c9de4ed89fa2bc", "63c839b54659920bbf42c8a76eedc3a9"}, {"79d6e9f34cd2a01b89130bc43002e94a4c3494dfc8db9d11e08d7b8ae7782b38fde2c00e9819d5c619a5c8a92afbabdb727108b5dd4ba9d572b47567685c9e7c", "d6dc99f4ce27ffe7ad3b40c73be86ad8", "eae6b850f1f43e00be741946b5038517"}, {"cc01d778ccfabfad7a442a266aac199e277b38618ba19816d1d668c139367c8ae4c9fc4e6b5a7a214175506d4dffa1c159bc499afc638e6a54a546380b65bcd8", "e459433194d5ce2daf958ef6cb22a391", "34df2febf45efcb197fabf5eef51bf5e"}}, + // d + 3, + // AD + "00", + // M + "32b9e80d44f7fd35dc254f1b07cd10ca91e1c9ba7835a9581e99245677c1ecec22de4e30ef1799ab658305c8266d4f1c71e4ad51cd9d5798de85ece04f6ee9636ad4a14a132278df2c34a449b7d53cf71fb4e55affbc7cbc6699b97356a81d4f70591177aa509df7d8ada37bd7c6082059081e8058087bd5e357544b2b2067c62a3cb123592b44bef8ccb5f259e859ac8d6c9cf599605b370a067dced095f96dd03b3577d20b78afeb8c25cbe3b2e52f2105e952603af981a739216fc6fa29f1a417ea501199a74bab8821e828a1e66e8e0de40138aca846902f7e2c5545cb2263a8b148e65fd793abbd831d97771d5ecbc07bcde5b5cfa02489783302174b36f7570c546fcb05b1d1031089b806d9b54d2b0ebf0fa0ce8b486e26c36825b55a1bcdd001b4a6ab3686ae3b5fef3500837a1eb58e44602c87ce6d384d3dab73fc18e662f03a4112c6fd70ee2063a5dd37bc159f2584b8bcc63106ff6f219cb3e45d57e3b78c88fb0acbba7b58f2f3c54d1877160199583876e1a321bfaa813e0ce1e1803fff094e437ca879ab2d85248050f720bfac980a8455f1bd83ad8648af0052a3ff1203a75b033254edcbfc144c53ec72b603b404aac06021d51524953e9d267c912cc82d61b70d47775d80451ae59071ce7596f3dfe60ff0f636ec06689993ed52f8efd7d04415350421", + // Output={S'{}, T, C} + {{{"80819c55d001b73b8d51a5c9ce4fc8e2a197bd4891f0f38df791e92fc687c99214992b6749f5b96d6477f7a2821029f714de39b47396fff84b79406ceb667213", "475cec821a2bb29682c9de4ed89fa2bc", "959551c3e8dc83f3cf2e0bf11a1acae3"}, {"79d6e9f34cd2a01b89130bc43002e94a4c3494dfc8db9d11e08d7b8ae7782b38fde2c00e9819d5c619a5c8a92afbabdb727108b5dd4ba9d572b47567685c9e7c", "d6dc99f4ce27ffe7ad3b40c73be86ad8", "9e9c84b867f7dbeb705bfcce09431813"}, {"12f2e45f012ffc1430fee1fb322879ba934f887fe2e7e7ce98071c61bc1086dbb2877845f5fb3869d3a4d23cdbcb44c85aeb9e43771755c9be3bbdb42ecac024", "88ba0caf597d953a26064c5872bdea5b", "e459433194d5ce2daf958ef6cb22a391"}}, {"3222f41f846157bdc258ac55d8f7bd6e", "fb76e827b3a0b6b8d031ea07b273c8f47763cd2c7af610dd0109ff42838bc39d5128492788a36426fc5ab17bab4906c7c4a390ceabe14ccc96ac2ec36dac92ed2a579097d1cb2258aef9cf35e950113adbb305b7ac73e1c1ea9b4e10ff39adc6b129cad8020fdcb349fd383595c61bb551d026b84ed74674bcfbbe027b4814713487a53e5aac4120da59d27b0abce7f438294860c211f19160b53deb9ab5abf49996a1d474518196a1020b460282f9dc3802db33c19e3b50d74fc5f8083403227d9801a158977f36cb2eae1525488660b59e5f45f346f24def7044f1b8e714268ff423d8c9b895e936669b4df15a99ba6382b02349f792b2383a4bd632efb6b6a5b7cbb82eaae1b0261f5386844813f23e08eeb68d63162681d51bf0d38beff2c34afc2e57772887f5c0e341ff2b7c003b24d32bb3873c7f6d5b946c36b18eb0ddfe907c201cd42b7373eb52d0c4bd8eed5179a2081504847f7f99fe529139cdde799105e8c05cf8376eaddf4af1f779835910659ff93ad3f55b25defbcc10567d23247a0f2e688363f91f90184cda34d8e4ad80d4f9f47d9d1af9c10474f7e66bef3ad0a49fbdc8020899289bea741a004df514b8ec5bf2443e3de433cd25916b2889fe6a624e65c4b1306d9feb14fbad48e2c212cb4aa8db92c31b87c20da5b493410fdafaab09fdfb57c9aa"}}, +}, +// Pesudorandom 2, hop 2/3 +{ + // S{} + {{"f2a93dfda00e7654585b911e90acdc3a825f88b497f329637bb612464d928e4182f1b360db55231f255e7265b1614d8ee895cde4e5f4768f749c051b25ac261e", "6a017e1dfd3fcee547b526b048204901", "7dae89533c98d159590a3bc5da3d5fb6"}, {"ff9b9925190d45c46e5ac9eae38da326739b3180432cf0c36cd9346699bd022c4dcb3aa2811f8ab0a2a72cfdc9e13b817d0a20cc1b03f51b8133c6d36d2c4ffa", "2e666844518d40d4a1efee952db70f36", "eeb1f87fd5c7a6b016b6df886c3f2f92"}, {"25f3b6dc37742bf020ad710e67f87ee274f5fe5d0c75c9a22da939847d1f4878de7d35867c306f3176d92d2d5900d33dec007edf02644f01046b9deff015c30f", "df6876f95d2387d8f419d018a826ffed", "c16980670fba6dcd755c567c721e0dcd"}}, + // d + 2, + // AD + "da", + // M + "346681ef9e47fff29ddaf41628ae3021888028316787f1887b6c099c921a8915b4d7937a9565d928764fae620b57d117ccd75cf8b633f2d1f1404b65f2479c8d8d590a15da2b40b14987d8968b7d210965f158627a72ba31ccecd5727f2dabf17dacc69027ccf4c53da96a75e6d28a15ffecaec1965a62402a1cc5e9cc26be181689132f54956f99192ac9bbb929c5aec7048a6653ad40cbc4fb029ea97bc15c8b05395e822af36a8b949817ee0f022c8f971eefc5b31bb46e095d4aea07fa97854e1ca4a208bebb65a605089f60a21ef5685b67d312edff8b2cc81830eab9d27ab0a7be29b7c88abb995492564772d518a912c6b40f58ab41c0497995d9b593f0387a3e597728d08f5267fba8370a062817cdf506119e0c5cc69900709195a2288322de578af491698360ad1f6b34b341e10eb21e22f6c5a6e12e26250aeb528aaa533d592b268fb22b3e77ada84d478ee9d0f2742cbb54be14503c21e39efcc73774b24bf28747203c5ff456457139fec8a46c8243b4b9738c27972e6d8f0ef9fa18944aaeed4deb437522f04795ecd7bee79f0a6d7c6c6acd90dac9a935d5f252134cd4ca1e2e0c4386fdae67950f1234cda5472e61a32bf9f037c068fe81a955d1e56a92ad1a8f16e6a31bfc0f8b3cef96410a72b92a75b09a0071ff0c0e99dd322ab7d8e4a2a2c2122af6", + // Output={S'{}, T, C} + {{{"f2a93dfda00e7654585b911e90acdc3a825f88b497f329637bb612464d928e4182f1b360db55231f255e7265b1614d8ee895cde4e5f4768f749c051b25ac261e", "6a017e1dfd3fcee547b526b048204901", "2d8aa5329c2fab108e90f64a904c4def"}, {"64b7371338ad74c249ba606c677f38b5c08ba69a7ae33c1be26ef81ea604a24a968678f48075273c6b35311642a72466fd2a6b059217f66752b0c9e15de40a5f", "5f6d3291d9d5bf3c3bece127fbf3886b", "2e666844518d40d4a1efee952db70f36"}, {"25f3b6dc37742bf020ad710e67f87ee274f5fe5d0c75c9a22da939847d1f4878de7d35867c306f3176d92d2d5900d33dec007edf02644f01046b9deff015c30f", "df6876f95d2387d8f419d018a826ffed", "c16980670fba6dcd755c567c721e0dcd"}}, {"9527488f5d1c2671e0e8139423149285", "c036126d33eea9f7cf865a9ab8e8eaace3a59f1064fa7506d45862ceb119ed854e1ab2f4294c77beb60564e2095f1f219dac41a024361e0fce045947a5e104a6db4b35175b09fca762121d46be7b4b20c674e4a13a53585586c8318549b86c02db4a554e1a43674237136f91e91e75c7ef74e6d4bceeb682e27ffbd2f47ddf667ad89fea7c48e6fbe69b8a3e54eb31585612719394480416296689d427a59b0f3adf4d92fa239c983a2c010cffe9366c01a1c945757ba07aec7c3df58b95f567e8de04d5719c2c7c62cd44668d43777b87db9126b2fccb62b241ec9d9701e8a34125a4dc2653a3de1f77415cafa76bc2713bed61c44001fb23170d716d008f12b236c0380253f2779fe52e6b2c011ffe312617b149c0b2b47055dc832ead1b297ead29028a4a0dbed96809c2aede9b276458a8a6c142a6a7876de3cfba1d4d0dea00095a66b9e925a3593b956a7e734b074941fc60d656e27a7d24f196cfe928400a180a1b7eb591c7b4e394b2c13040a98612e078094586bb197a585505335f4b5f1f721df1ee76ef27a8f6927fc40077be55a45b093d4fa1057a4a88937174885732f91d04a87424539302c7f9590e4d0b62abfdbd0f162fa3c7d750b8f212a2612127fd2443416736578deeccc76284c164a282f94786812031a19f35629e253a86c730f08676fbd0b0b41d"}}, +}, +// Pesudorandom 2, hop 3/3 +{ + // S{} + {{"f2a93dfda00e7654585b911e90acdc3a825f88b497f329637bb612464d928e4182f1b360db55231f255e7265b1614d8ee895cde4e5f4768f749c051b25ac261e", "6a017e1dfd3fcee547b526b048204901", "7dae89533c98d159590a3bc5da3d5fb6"}, {"ff9b9925190d45c46e5ac9eae38da326739b3180432cf0c36cd9346699bd022c4dcb3aa2811f8ab0a2a72cfdc9e13b817d0a20cc1b03f51b8133c6d36d2c4ffa", "2e666844518d40d4a1efee952db70f36", "eeb1f87fd5c7a6b016b6df886c3f2f92"}, {"25f3b6dc37742bf020ad710e67f87ee274f5fe5d0c75c9a22da939847d1f4878de7d35867c306f3176d92d2d5900d33dec007edf02644f01046b9deff015c30f", "df6876f95d2387d8f419d018a826ffed", "c16980670fba6dcd755c567c721e0dcd"}}, + // d + 3, + // AD + "da", + // M + "346681ef9e47fff29ddaf41628ae3021888028316787f1887b6c099c921a8915b4d7937a9565d928764fae620b57d117ccd75cf8b633f2d1f1404b65f2479c8d8d590a15da2b40b14987d8968b7d210965f158627a72ba31ccecd5727f2dabf17dacc69027ccf4c53da96a75e6d28a15ffecaec1965a62402a1cc5e9cc26be181689132f54956f99192ac9bbb929c5aec7048a6653ad40cbc4fb029ea97bc15c8b05395e822af36a8b949817ee0f022c8f971eefc5b31bb46e095d4aea07fa97854e1ca4a208bebb65a605089f60a21ef5685b67d312edff8b2cc81830eab9d27ab0a7be29b7c88abb995492564772d518a912c6b40f58ab41c0497995d9b593f0387a3e597728d08f5267fba8370a062817cdf506119e0c5cc69900709195a2288322de578af491698360ad1f6b34b341e10eb21e22f6c5a6e12e26250aeb528aaa533d592b268fb22b3e77ada84d478ee9d0f2742cbb54be14503c21e39efcc73774b24bf28747203c5ff456457139fec8a46c8243b4b9738c27972e6d8f0ef9fa18944aaeed4deb437522f04795ecd7bee79f0a6d7c6c6acd90dac9a935d5f252134cd4ca1e2e0c4386fdae67950f1234cda5472e61a32bf9f037c068fe81a955d1e56a92ad1a8f16e6a31bfc0f8b3cef96410a72b92a75b09a0071ff0c0e99dd322ab7d8e4a2a2c2122af6", + // Output={S'{}, T, C} + {{{"f2a93dfda00e7654585b911e90acdc3a825f88b497f329637bb612464d928e4182f1b360db55231f255e7265b1614d8ee895cde4e5f4768f749c051b25ac261e", "6a017e1dfd3fcee547b526b048204901", "d0c6f32d192ad998d5fa04b32a872f8e"}, {"ff9b9925190d45c46e5ac9eae38da326739b3180432cf0c36cd9346699bd022c4dcb3aa2811f8ab0a2a72cfdc9e13b817d0a20cc1b03f51b8133c6d36d2c4ffa", "2e666844518d40d4a1efee952db70f36", "c0ae73b766ba40692b47a08c07265205"}, {"7e710ab0fcc90e1919c4996abac395e440e26eadf2df429defc893bfa97eedc55afa0504c9cee635bb933013d5d1fd54ddd30d5dc8fedcc5b55368837e00c085", "43d445810df84f486bdbe4d69637633f", "df6876f95d2387d8f419d018a826ffed"}}, {"0e49b626343b62d9155ffca96b076d70", "d64d402225cfc1e55c277c5827d8fea52c683693568928ad817bdb161852f9bbb6b316c78c4ef24d3b2620bd584e128e709a399a6c320ab5943816d786a0b7d81f0023b522ebac91e4fc79d9f6b3f5dcc22f17f486ef93518e2f885327ebac19daaaa3998dfdcb5880d76a196a8bba54a0b9169427d1f83abf95fcc8f63dfeb03d50d083e11c38a55d2efbe2c607648a5caa3698393faaaf339ca1d4c48cab8184ec20d8dc4ad03793ff1806b802e932c33f00fa0253bc7da8fa560b19cac163bbf26e4507642fcc39b5df28b3941fccbd30e3e00b64f471a51d7555c3d1b6655b0a6d9d33b9cd0494163591675c50ebb5a867e849a9c6ee43a177d7fe9f6aa992c817b26316054b49894f973ae166fb20f2bfc50704f610e2cc61be08e1305fa58f15b716aaacb50c98e0dba34a300a1aa4296f7826f0ad740f36eef6d18205b1118227c285acef158b4093dd541eed76a3492240be48e89fa54cad77b020631413a8b562e655289f94191bc462b71ddf0b41a034ca1c291aa4feb0148207e2ea0d5409e801dcec151b0a5a220ac43b8be70c8c92d6eb4f9c6f44bf0fd3487c5d007ba8ddd8bbbca51fb3c679ffc0a493392039f32e7272f173e71d4a2a5f001f999dd9523c79ca3e32c99260b20f1e960a830bd7ed81d891c316c8851b3470c64b7fb15d7ebdb8d09399e74f"}}, +}, +}; diff -Nru tor-0.4.7.16/src/test/compression_bomb.h tor-0.4.9.6/src/test/compression_bomb.h --- tor-0.4.7.16/src/test/compression_bomb.h 1970-01-01 00:00:00.000000000 +0000 +++ tor-0.4.9.6/src/test/compression_bomb.h 2026-03-25 14:30:34.000000000 +0000 @@ -0,0 +1,864 @@ +/* Copyright (c) 2007-2026, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef TOR_TEST_COMPRESSION_BOMB_H +#define TOR_TEST_COMPRESSION_BOMB_H + +const char compression_bomb_gzip[] = { + 0x1f, 0x8b, 0x08, 0x00, 0x75, 0x27, 0xdd, 0x68, 0x02, 0x03, 0xec, 0xc1, + 0x01, 0x01, 0x00, 0x00, 0x00, 0x80, 0x90, 0xfe, 0xaf, 0xee, 0x08, 0x0a, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x80, 0xd9, 0x83, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x20, + 0xff, 0xd7, 0x46, 0x50, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x69, 0x0f, 0x0e, 0x09, 0x00, + 0x00, 0x00, 0x00, 0x04, 0xfd, 0x7f, 0xed, 0x0c, 0x0b, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9f, + 0x00, 0xcc, 0x2a, 0xca, 0x9e, 0x00, 0x00, 0xa0, 0x00 +}; + +const size_t compression_bomb_gzip_len = 10221; + +#endif /* !defined(TOR_TEST_COMPRESSION_BOMB_H) */ diff -Nru tor-0.4.7.16/src/test/fakecircs.c tor-0.4.9.6/src/test/fakecircs.c --- tor-0.4.7.16/src/test/fakecircs.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/test/fakecircs.c 2026-03-25 14:30:34.000000000 +0000 @@ -17,9 +17,12 @@ #include "core/or/circuitbuild.h" #include "core/or/circuitlist.h" #include "core/or/circuitpadding.h" +#include "core/or/congestion_control_common.h" +#include "core/or/conflux_pool.h" +#include "core/or/conflux.h" #include "core/or/crypt_path.h" #include "core/or/relay.h" -#include "core/or/relay_crypto_st.h" +#include "core/crypto/relay_crypto_st.h" #include "test/fakecircs.h" @@ -41,8 +44,8 @@ cell_queue_init(&(circ->n_chan_cells)); circ->n_hop = NULL; - circ->streams_blocked_on_n_chan = 0; - circ->streams_blocked_on_p_chan = 0; + circ->circuit_blocked_on_n_chan = 0; + circ->circuit_blocked_on_p_chan = 0; circ->n_delete_pending = 0; circ->p_delete_pending = 0; circ->received_destroy = 0; @@ -56,8 +59,9 @@ cell_queue_init(&(orcirc->p_chan_cells)); memset(&tmp_cpath, 0, sizeof(tmp_cpath)); - if (cpath_init_circuit_crypto(&tmp_cpath, whatevs_key, - sizeof(whatevs_key), 0, 0)<0) { + if (cpath_init_circuit_crypto(RELAY_CRYPTO_ALG_TOR1, + &tmp_cpath, whatevs_key, + sizeof(whatevs_key))<0) { log_warn(LD_BUG,"Circuit initialization failed"); return NULL; } @@ -87,5 +91,8 @@ circuitmux_detach_circuit(circ->n_chan->cmux, circ); } + conflux_circuit_about_to_free(circ); + congestion_control_free(circ->ccontrol); + tor_free_(circ); } diff -Nru tor-0.4.7.16/src/test/hs_test_helpers.c tor-0.4.9.6/src/test/hs_test_helpers.c --- tor-0.4.7.16/src/test/hs_test_helpers.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/test/hs_test_helpers.c 2026-03-25 14:30:34.000000000 +0000 @@ -354,6 +354,18 @@ } } + /* Proof of Work DoS mitigation options */ + tt_int_op(!!desc1->encrypted_data.pow_params, OP_EQ, + !!desc2->encrypted_data.pow_params); + if (desc1->encrypted_data.pow_params && desc2->encrypted_data.pow_params) { + hs_pow_desc_params_t *params1 = desc1->encrypted_data.pow_params; + hs_pow_desc_params_t *params2 = desc2->encrypted_data.pow_params; + tt_int_op(params1->type, OP_EQ, params2->type); + tt_mem_op(params1->seed, OP_EQ, params2->seed, HS_POW_SEED_LEN); + tt_int_op(params1->suggested_effort, OP_EQ, params2->suggested_effort); + tt_int_op(params1->expiration_time, OP_EQ, params2->expiration_time); + } + /* Introduction points. */ { tt_assert(desc1->encrypted_data.intro_points); diff -Nru tor-0.4.7.16/src/test/include.am tor-0.4.9.6/src/test/include.am --- tor-0.4.7.16/src/test/include.am 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/test/include.am 2026-03-25 14:30:34.000000000 +0000 @@ -22,14 +22,14 @@ src/test/test_switch_id.sh \ src/test/test_cmdline.sh \ src/test/test_parseconf.sh \ - src/test/unittest_part1.sh \ - src/test/unittest_part2.sh \ - src/test/unittest_part3.sh \ - src/test/unittest_part4.sh \ - src/test/unittest_part5.sh \ - src/test/unittest_part6.sh \ - src/test/unittest_part7.sh \ - src/test/unittest_part8.sh + src/test/unittest_part1.sh \ + src/test/unittest_part2.sh \ + src/test/unittest_part3.sh \ + src/test/unittest_part4.sh \ + src/test/unittest_part5.sh \ + src/test/unittest_part6.sh \ + src/test/unittest_part7.sh \ + src/test/unittest_part8.sh if USEPYTHON TESTSCRIPTS += \ @@ -51,7 +51,7 @@ if USE_PERL TESTSCRIPTS += \ - scripts/maint/checkSpaceTest.sh + scripts/maint/checkSpaceTest.sh endif TESTS += src/test/test-slow src/test/test-memwipe \ @@ -103,8 +103,8 @@ src_test_AM_CPPFLAGS = -DSHARE_DATADIR="\"$(datadir)\"" \ -DLOCALSTATEDIR="\"$(localstatedir)\"" \ - -DBINDIR="\"$(bindir)\"" \ - -DTOR_UNIT_TESTS \ + -DBINDIR="\"$(bindir)\"" \ + -DTOR_UNIT_TESTS \ $(AM_CPPFLAGS) # -L flags need to go in LDFLAGS. -l flags need to go in LDADD. @@ -147,8 +147,11 @@ src/test/test_circuitstats.c \ src/test/test_compat_libevent.c \ src/test/test_config.c \ + src/test/test_conflux_cell.c \ + src/test/test_conflux_pool.c \ src/test/test_confmgr.c \ src/test/test_confparse.c \ + src/test/test_congestion_control.c \ src/test/test_connection.c \ src/test/test_conscache.c \ src/test/test_consdiff.c \ @@ -159,6 +162,7 @@ src/test/test_crypto.c \ src/test/test_crypto_ope.c \ src/test/test_crypto_rng.c \ + src/test/test_crypto_cgo.c \ src/test/test_data.c \ src/test/test_dir.c \ src/test/test_dirauth_ports.c \ @@ -186,6 +190,7 @@ src/test/test_hs_descriptor.c \ src/test/test_hs_dos.c \ src/test/test_hs_metrics.c \ + src/test/test_hs_pow.c \ src/test/test_keypin.c \ src/test/test_link_handshake.c \ src/test/test_logging.c \ @@ -264,6 +269,7 @@ src/test/test_slow.c \ src/test/test_crypto_slow.c \ src/test/test_process_slow.c \ + src/test/test_hs_pow_slow.c \ src/test/test_prob_distr.c \ src/test/ptr_helpers.c \ src/test/test_ptr_slow.c \ @@ -331,7 +337,7 @@ src_test_bench_LDFLAGS = @TOR_LDFLAGS_zlib@ $(TOR_LDFLAGS_CRYPTLIB) \ @TOR_LDFLAGS_libevent@ src_test_bench_LDADD = \ - libtor.a \ + libtor.a \ @TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ @TOR_LIBEVENT_LIBS@ \ $(TOR_LIBS_CRYPTLIB) @TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_SHLWAPI@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@ \ @CURVE25519_LIBS@ \ @@ -360,6 +366,7 @@ # ADD_C_FILE: INSERT HEADERS HERE. noinst_HEADERS+= \ + src/test/compression_bomb.h \ src/test/fakechans.h \ src/test/fakecircs.h \ src/test/hs_test_helpers.h \ @@ -377,6 +384,7 @@ src/test/example_extrainfo.inc \ src/test/failing_routerdescs.inc \ src/test/ed25519_vectors.inc \ + src/test/cgo_vectors.inc \ src/test/test_descriptors.inc \ src/test/test_hs_descriptor.inc \ src/test/vote_descriptors.inc @@ -399,11 +407,10 @@ libtor.a \ @TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ \ $(TOR_LIBS_CRYPTLIB) @TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_SHLWAPI@ @TOR_LIB_GDI@ \ - @CURVE25519_LIBS@ @TOR_TRACE_LIBS@ + @CURVE25519_LIBS@ @TOR_TRACE_LIBS@ src_test_test_hs_ntor_cl_AM_CPPFLAGS = \ $(AM_CPPFLAGS) - if UNITTESTS_ENABLED noinst_PROGRAMS += src/test/test-bt-cl src_test_test_bt_cl_SOURCES = src/test/test_bt_cl.c @@ -411,7 +418,7 @@ $(TOR_UTIL_TESTING_LIBS) \ @TOR_LIB_MATH@ \ @TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_SHLWAPI@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@ \ - @TOR_TRACE_LIBS@ + @TOR_TRACE_LIBS@ src_test_test_bt_cl_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS) src_test_test_bt_cl_CPPFLAGS= $(src_test_AM_CPPFLAGS) $(TEST_CPPFLAGS) endif @@ -433,7 +440,8 @@ src/test/test_keygen.sh \ src/test/test_key_expiration.sh \ src/test/test_zero_length_keys.sh \ - src/test/test_ntor.sh src/test/test_hs_ntor.sh src/test/test_bt.sh \ + src/test/test_ntor.sh src/test/test_hs_ntor.sh \ + src/test/test_bt.sh \ src/test/test-network.sh \ src/test/test_switch_id.sh \ src/test/test_workqueue_cancel.sh \ @@ -444,11 +452,11 @@ src/test/test_workqueue_socketpair.sh \ src/test/test_cmdline.sh \ src/test/test_parseconf.sh \ - src/test/unittest_part1.sh \ - src/test/unittest_part2.sh \ - src/test/unittest_part3.sh \ - src/test/unittest_part4.sh \ - src/test/unittest_part5.sh \ - src/test/unittest_part6.sh \ - src/test/unittest_part7.sh \ - src/test/unittest_part8.sh + src/test/unittest_part1.sh \ + src/test/unittest_part2.sh \ + src/test/unittest_part3.sh \ + src/test/unittest_part4.sh \ + src/test/unittest_part5.sh \ + src/test/unittest_part6.sh \ + src/test/unittest_part7.sh \ + src/test/unittest_part8.sh diff -Nru tor-0.4.7.16/src/test/test.c tor-0.4.9.6/src/test/test.c --- tor-0.4.7.16/src/test/test.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/test/test.c 2026-03-25 14:30:34.000000000 +0000 @@ -50,7 +50,6 @@ #include "core/or/onion.h" #include "core/crypto/onion_ntor.h" #include "core/crypto/onion_fast.h" -#include "core/crypto/onion_tap.h" #include "core/or/policies.h" #include "lib/sandbox/sandbox.h" #include "app/config/statefile.h" @@ -61,150 +60,6 @@ #include "core/or/or_circuit_st.h" #include "feature/relay/onion_queue.h" -/** Run unit tests for the onion handshake code. */ -static void -test_onion_handshake(void *arg) -{ - /* client-side */ - crypto_dh_t *c_dh = NULL; - char c_buf[TAP_ONIONSKIN_CHALLENGE_LEN]; - char c_keys[40]; - /* server-side */ - char s_buf[TAP_ONIONSKIN_REPLY_LEN]; - char s_keys[40]; - int i; - /* shared */ - crypto_pk_t *pk = NULL, *pk2 = NULL; - - (void)arg; - pk = pk_generate(0); - pk2 = pk_generate(1); - - /* client handshake 1. */ - memset(c_buf, 0, TAP_ONIONSKIN_CHALLENGE_LEN); - tt_assert(! onion_skin_TAP_create(pk, &c_dh, c_buf)); - - for (i = 1; i <= 3; ++i) { - crypto_pk_t *k1, *k2; - if (i==1) { - /* server handshake: only one key known. */ - k1 = pk; k2 = NULL; - } else if (i==2) { - /* server handshake: try the right key first. */ - k1 = pk; k2 = pk2; - } else { - /* server handshake: try the right key second. */ - k1 = pk2; k2 = pk; - } - - memset(s_buf, 0, TAP_ONIONSKIN_REPLY_LEN); - memset(s_keys, 0, 40); - tt_assert(! onion_skin_TAP_server_handshake(c_buf, k1, k2, - s_buf, s_keys, 40)); - - /* client handshake 2 */ - memset(c_keys, 0, 40); - tt_assert(! onion_skin_TAP_client_handshake(c_dh, s_buf, c_keys, - 40, NULL)); - - tt_mem_op(c_keys,OP_EQ, s_keys, 40); - memset(s_buf, 0, 40); - tt_mem_op(c_keys,OP_NE, s_buf, 40); - } - done: - crypto_dh_free(c_dh); - crypto_pk_free(pk); - crypto_pk_free(pk2); -} - -static void -test_bad_onion_handshake(void *arg) -{ - char junk_buf[TAP_ONIONSKIN_CHALLENGE_LEN]; - char junk_buf2[TAP_ONIONSKIN_CHALLENGE_LEN]; - /* client-side */ - crypto_dh_t *c_dh = NULL; - char c_buf[TAP_ONIONSKIN_CHALLENGE_LEN]; - char c_keys[40]; - /* server-side */ - char s_buf[TAP_ONIONSKIN_REPLY_LEN]; - char s_keys[40]; - /* shared */ - crypto_pk_t *pk = NULL, *pk2 = NULL; - - (void)arg; - - pk = pk_generate(0); - pk2 = pk_generate(1); - - /* Server: Case 1: the encrypted data is degenerate. */ - memset(junk_buf, 0, sizeof(junk_buf)); - crypto_pk_obsolete_public_hybrid_encrypt(pk, - junk_buf2, TAP_ONIONSKIN_CHALLENGE_LEN, - junk_buf, DH1024_KEY_LEN, - PK_PKCS1_OAEP_PADDING, 1); - tt_int_op(-1, OP_EQ, - onion_skin_TAP_server_handshake(junk_buf2, pk, NULL, - s_buf, s_keys, 40)); - - /* Server: Case 2: the encrypted data is not long enough. */ - memset(junk_buf, 0, sizeof(junk_buf)); - memset(junk_buf2, 0, sizeof(junk_buf2)); - crypto_pk_public_encrypt(pk, junk_buf2, sizeof(junk_buf2), - junk_buf, 48, PK_PKCS1_OAEP_PADDING); - tt_int_op(-1, OP_EQ, - onion_skin_TAP_server_handshake(junk_buf2, pk, NULL, - s_buf, s_keys, 40)); - - /* client handshake 1: do it straight. */ - memset(c_buf, 0, TAP_ONIONSKIN_CHALLENGE_LEN); - tt_assert(! onion_skin_TAP_create(pk, &c_dh, c_buf)); - - /* Server: Case 3: we just don't have the right key. */ - tt_int_op(-1, OP_EQ, - onion_skin_TAP_server_handshake(c_buf, pk2, NULL, - s_buf, s_keys, 40)); - - /* Server: Case 4: The RSA-encrypted portion is corrupt. */ - c_buf[64] ^= 33; - tt_int_op(-1, OP_EQ, - onion_skin_TAP_server_handshake(c_buf, pk, NULL, - s_buf, s_keys, 40)); - c_buf[64] ^= 33; - - /* (Let the server proceed) */ - tt_int_op(0, OP_EQ, - onion_skin_TAP_server_handshake(c_buf, pk, NULL, - s_buf, s_keys, 40)); - - /* Client: Case 1: The server sent back junk. */ - const char *msg = NULL; - s_buf[64] ^= 33; - tt_int_op(-1, OP_EQ, - onion_skin_TAP_client_handshake(c_dh, s_buf, c_keys, 40, &msg)); - s_buf[64] ^= 33; - tt_str_op(msg, OP_EQ, "Digest DOES NOT MATCH on onion handshake. " - "Bug or attack."); - - /* Let the client finish; make sure it can. */ - msg = NULL; - tt_int_op(0, OP_EQ, - onion_skin_TAP_client_handshake(c_dh, s_buf, c_keys, 40, &msg)); - tt_mem_op(s_keys,OP_EQ, c_keys, 40); - tt_ptr_op(msg, OP_EQ, NULL); - - /* Client: Case 2: The server sent back a degenerate DH. */ - memset(s_buf, 0, sizeof(s_buf)); - tt_int_op(-1, OP_EQ, - onion_skin_TAP_client_handshake(c_dh, s_buf, c_keys, 40, &msg)); - tt_str_op(msg, OP_EQ, "DH computation failed."); - - done: - crypto_dh_free(c_dh); - crypto_pk_free(pk); - crypto_pk_free(pk2); -} - static void test_ntor_handshake(void *arg) { @@ -221,7 +76,8 @@ /* shared */ const curve25519_public_key_t *server_pubkey; - uint8_t node_id[20] = "abcdefghijklmnopqrst"; + + NONSTRING uint8_t node_id[20] = "abcdefghijklmnopqrst"; (void) arg; @@ -306,37 +162,35 @@ static void test_onion_queues(void *arg) { - uint8_t buf1[TAP_ONIONSKIN_CHALLENGE_LEN] = {0}; + uint8_t buf1[NTOR_ONIONSKIN_LEN] = {0}; uint8_t buf2[NTOR_ONIONSKIN_LEN] = {0}; or_circuit_t *circ1 = or_circuit_new(0, NULL); or_circuit_t *circ2 = or_circuit_new(0, NULL); - create_cell_t *onionskin = NULL, *create2_ptr; + create_cell_t *onionskin = NULL, *create1_ptr; create_cell_t *create1 = tor_malloc_zero(sizeof(create_cell_t)); create_cell_t *create2 = tor_malloc_zero(sizeof(create_cell_t)); (void)arg; - create2_ptr = create2; /* remember, but do not free */ + create1_ptr = create1; /* remember, but do not free */ - create_cell_init(create1, CELL_CREATE, ONION_HANDSHAKE_TYPE_TAP, - TAP_ONIONSKIN_CHALLENGE_LEN, buf1); + create_cell_init(create1, CELL_CREATE, ONION_HANDSHAKE_TYPE_NTOR, + NTOR_ONIONSKIN_LEN, buf1); create_cell_init(create2, CELL_CREATE, ONION_HANDSHAKE_TYPE_NTOR, NTOR_ONIONSKIN_LEN, buf2); - tt_int_op(0,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_TAP)); + tt_int_op(0,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR)); tt_int_op(0,OP_EQ, onion_pending_add(circ1, create1)); create1 = NULL; - tt_int_op(1,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_TAP)); + tt_int_op(1,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR)); - tt_int_op(0,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR)); tt_int_op(0,OP_EQ, onion_pending_add(circ2, create2)); create2 = NULL; - tt_int_op(1,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR)); + tt_int_op(2,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR)); - tt_ptr_op(circ2,OP_EQ, onion_next_task(&onionskin)); - tt_int_op(1,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_TAP)); - tt_int_op(0,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR)); - tt_ptr_op(onionskin, OP_EQ, create2_ptr); + tt_ptr_op(circ1,OP_EQ, onion_next_task(&onionskin)); + tt_int_op(1,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR)); + tt_ptr_op(onionskin, OP_EQ, create1_ptr); clear_pending_onions(); tt_int_op(0,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_TAP)); @@ -365,24 +219,19 @@ static void test_onion_queue_order(void *arg) { - uint8_t buf_tap[TAP_ONIONSKIN_CHALLENGE_LEN] = {0}; uint8_t buf_ntor[NTOR_ONIONSKIN_LEN] = {0}; uint8_t buf_ntor3[CELL_PAYLOAD_SIZE] = {0}; - or_circuit_t *circ_tap = or_circuit_new(0, NULL); or_circuit_t *circ_ntor = or_circuit_new(0, NULL); or_circuit_t *circ_ntor3 = or_circuit_new(0, NULL); create_cell_t *onionskin = NULL; - create_cell_t *create_tap1 = tor_malloc_zero(sizeof(create_cell_t)); create_cell_t *create_ntor1 = tor_malloc_zero(sizeof(create_cell_t)); create_cell_t *create_ntor2 = tor_malloc_zero(sizeof(create_cell_t)); create_cell_t *create_v3ntor1 = tor_malloc_zero(sizeof(create_cell_t)); create_cell_t *create_v3ntor2 = tor_malloc_zero(sizeof(create_cell_t)); (void)arg; - create_cell_init(create_tap1, CELL_CREATE, ONION_HANDSHAKE_TYPE_TAP, - TAP_ONIONSKIN_CHALLENGE_LEN, buf_tap); create_cell_init(create_ntor1, CELL_CREATE, ONION_HANDSHAKE_TYPE_NTOR, NTOR_ONIONSKIN_LEN, buf_ntor); create_cell_init(create_ntor2, CELL_CREATE, ONION_HANDSHAKE_TYPE_NTOR, @@ -393,78 +242,63 @@ NTOR_ONIONSKIN_LEN, buf_ntor3); /* sanity check queue init */ - tt_int_op(0,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_TAP)); - tt_int_op(0,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR)); - tt_int_op(0,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR_V3)); - - /* Add tap first so we can ensure it comes out last */ - tt_int_op(0,OP_EQ, onion_pending_add(circ_tap, create_tap1)); - tt_int_op(1,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_TAP)); tt_int_op(0,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR)); tt_int_op(0,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR_V3)); /* Now add interleaving ntor2 and ntor3, to ensure they share * the same queue and come out in this order */ tt_int_op(0,OP_EQ, onion_pending_add(circ_ntor, create_ntor1)); - tt_int_op(1,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_TAP)); + tt_int_op(0,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_TAP)); tt_int_op(1,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR)); tt_int_op(1,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR_V3)); tt_int_op(0,OP_EQ, onion_pending_add(circ_ntor3, create_v3ntor1)); - tt_int_op(1,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_TAP)); + tt_int_op(0,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_TAP)); tt_int_op(2,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR)); tt_int_op(2,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR_V3)); tt_int_op(0,OP_EQ, onion_pending_add(circ_ntor, create_ntor2)); - tt_int_op(1,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_TAP)); + tt_int_op(0,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_TAP)); tt_int_op(3,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR)); tt_int_op(3,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR_V3)); tt_int_op(0,OP_EQ, onion_pending_add(circ_ntor3, create_v3ntor2)); - tt_int_op(1,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_TAP)); + tt_int_op(0,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_TAP)); tt_int_op(4,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR)); tt_int_op(4,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR_V3)); /* Now remove 5 tasks, ensuring order and queue sizes */ tt_ptr_op(circ_ntor, OP_EQ, onion_next_task(&onionskin)); - tt_int_op(1,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_TAP)); + tt_int_op(0,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_TAP)); tt_int_op(3,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR)); tt_int_op(3,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR_V3)); tt_ptr_op(onionskin, OP_EQ, create_ntor1); tt_ptr_op(circ_ntor3, OP_EQ, onion_next_task(&onionskin)); - tt_int_op(1,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_TAP)); + tt_int_op(0,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_TAP)); tt_int_op(2,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR)); tt_int_op(2,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR_V3)); tt_ptr_op(onionskin, OP_EQ, create_v3ntor1); tt_ptr_op(circ_ntor, OP_EQ, onion_next_task(&onionskin)); - tt_int_op(1,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_TAP)); + tt_int_op(0,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_TAP)); tt_int_op(1,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR)); tt_int_op(1,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR_V3)); tt_ptr_op(onionskin, OP_EQ, create_ntor2); tt_ptr_op(circ_ntor3, OP_EQ, onion_next_task(&onionskin)); - tt_int_op(1,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_TAP)); - tt_int_op(0,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR)); - tt_int_op(0,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR_V3)); - tt_ptr_op(onionskin, OP_EQ, create_v3ntor2); - - tt_ptr_op(circ_tap, OP_EQ, onion_next_task(&onionskin)); tt_int_op(0,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_TAP)); tt_int_op(0,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR)); tt_int_op(0,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR_V3)); - tt_ptr_op(onionskin, OP_EQ, create_tap1); + tt_ptr_op(onionskin, OP_EQ, create_v3ntor2); clear_pending_onions(); tt_int_op(0,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_TAP)); tt_int_op(0,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR)); done: - circuit_free_(TO_CIRCUIT(circ_tap)); circuit_free_(TO_CIRCUIT(circ_ntor)); circuit_free_(TO_CIRCUIT(circ_ntor3)); - tor_free(create_tap1); tor_free(create_ntor1); tor_free(create_ntor2); tor_free(create_v3ntor1); @@ -740,8 +574,6 @@ { #name, test_ ## name , TT_FORK, NULL, NULL } static struct testcase_t test_array[] = { - ENT(onion_handshake), - { "bad_onion_handshake", test_bad_onion_handshake, 0, NULL, NULL }, ENT(onion_queues), ENT(onion_queue_order), { "ntor_handshake", test_ntor_handshake, 0, NULL, NULL }, @@ -778,6 +610,9 @@ { "config/", config_tests }, { "config/mgr/", confmgr_tests }, { "config/parse/", confparse_tests }, + { "conflux/cell/", conflux_cell_tests }, + { "conflux/pool/", conflux_pool_tests }, + { "congestion_control/", congestion_control_tests }, { "connection/", connection_tests }, { "conscache/", conscache_tests }, { "consdiff/", consdiff_tests }, @@ -794,6 +629,7 @@ #endif { "crypto/pem/", pem_tests }, { "crypto/rng/", crypto_rng_tests }, + { "crypto/cgo/", crypto_cgo_tests }, { "dir/", dir_tests }, { "dir/auth/ports/", dirauth_port_tests }, { "dir/auth/process_descs/", process_descs_tests }, @@ -822,6 +658,7 @@ { "hs_metrics/", hs_metrics_tests }, { "hs_ntor/", hs_ntor_tests }, { "hs_ob/", hs_ob_tests }, + { "hs_pow/", hs_pow_tests }, { "hs_service/", hs_service_tests }, { "keypin/", keypin_tests }, { "link-handshake/", link_handshake_tests }, diff -Nru tor-0.4.7.16/src/test/test.h tor-0.4.9.6/src/test/test.h --- tor-0.4.7.16/src/test/test.h 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/test/test.h 2026-03-25 14:30:34.000000000 +0000 @@ -107,8 +107,11 @@ extern struct testcase_t circuituse_tests[]; extern struct testcase_t compat_libevent_tests[]; extern struct testcase_t config_tests[]; +extern struct testcase_t conflux_cell_tests[]; +extern struct testcase_t conflux_pool_tests[]; extern struct testcase_t confmgr_tests[]; extern struct testcase_t confparse_tests[]; +extern struct testcase_t congestion_control_tests[]; extern struct testcase_t connection_tests[]; extern struct testcase_t conscache_tests[]; extern struct testcase_t consdiff_tests[]; @@ -119,6 +122,7 @@ extern struct testcase_t crypto_ope_tests[]; extern struct testcase_t crypto_openssl_tests[]; extern struct testcase_t crypto_rng_tests[]; +extern struct testcase_t crypto_cgo_tests[]; extern struct testcase_t crypto_tests[]; extern struct testcase_t dirauth_port_tests[]; extern struct testcase_t dir_handle_get_tests[]; @@ -145,6 +149,7 @@ extern struct testcase_t hs_metrics_tests[]; extern struct testcase_t hs_ntor_tests[]; extern struct testcase_t hs_ob_tests[]; +extern struct testcase_t hs_pow_tests[]; extern struct testcase_t hs_service_tests[]; extern struct testcase_t keypin_tests[]; extern struct testcase_t link_handshake_tests[]; @@ -205,6 +210,7 @@ extern struct testcase_t x509_tests[]; extern struct testcase_t slow_crypto_tests[]; +extern struct testcase_t slow_hs_pow_tests[]; extern struct testcase_t slow_process_tests[]; extern struct testcase_t slow_ptr_tests[]; diff -Nru tor-0.4.7.16/src/test/test_bridges.c tor-0.4.9.6/src/test/test_bridges.c --- tor-0.4.7.16/src/test/test_bridges.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/test/test_bridges.c 2026-03-25 14:30:34.000000000 +0000 @@ -253,7 +253,7 @@ { char digest[DIGEST_LEN]; bridge_info_t *bridge; - const char fingerprint[HEX_DIGEST_LEN] = + NONSTRING const char fingerprint[HEX_DIGEST_LEN] = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; tor_addr_t *addr = tor_malloc(sizeof(tor_addr_t)); char ret_addr[16]; @@ -321,7 +321,7 @@ { char digest[DIGEST_LEN]; bridge_info_t *bridge; - const char fingerprint[HEX_DIGEST_LEN] = + NONSTRING const char fingerprint[HEX_DIGEST_LEN] = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; tor_addr_t *addr = tor_malloc(sizeof(tor_addr_t)); uint16_t port = 11111; @@ -353,7 +353,7 @@ { char digest[DIGEST_LEN]; bridge_info_t *bridge; - const char fingerprint[HEX_DIGEST_LEN] = + NONSTRING const char fingerprint[HEX_DIGEST_LEN] = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; tor_addr_t *addr = tor_malloc(sizeof(tor_addr_t)); uint16_t port = 4444; @@ -419,7 +419,7 @@ { char digest1[DIGEST_LEN]; bridge_info_t *bridge; - const char fingerprint[HEX_DIGEST_LEN] = + NONSTRING const char fingerprint[HEX_DIGEST_LEN] = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; helper_add_bridges_to_bridgelist(arg); @@ -616,10 +616,10 @@ node_t node_with_digest; memset(&node_with_digest, 0, sizeof(node_with_digest)); - const char fingerprint[HEX_DIGEST_LEN] = + NONSTRING const char fingerprint[HEX_DIGEST_LEN] = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; - const char fingerprint2[HEX_DIGEST_LEN] = + NONSTRING const char fingerprint2[HEX_DIGEST_LEN] = "ffffffffffffffffffffffffffffffffffffffff"; base16_decode(node_with_digest.identity, DIGEST_LEN, diff -Nru tor-0.4.7.16/src/test/test_bwmgt.c tor-0.4.9.6/src/test/test_bwmgt.c --- tor-0.4.7.16/src/test/test_bwmgt.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/test/test_bwmgt.c 2026-03-25 14:30:34.000000000 +0000 @@ -243,10 +243,30 @@ tt_int_op(b.read_bucket.bucket, OP_GT, 8*KB-400); tt_int_op(b.read_bucket.bucket, OP_LT, 8*KB+400); - // A ridiculous amount of time passes. - tt_int_op(0, OP_EQ, token_bucket_rw_refill(&b, INT32_MAX)); + /* A large amount of time passes, but less than the threshold at which + * we start detecting an assumed rollover event. This might be about 20 + * days on a system with stamp units equal to 1ms. */ + uint32_t ts_stamp = START_TS + UINT32_MAX / 5; + tt_int_op(0, OP_EQ, token_bucket_rw_refill(&b, ts_stamp)); tt_int_op(b.read_bucket.bucket, OP_EQ, b.cfg.burst); + /* Fully empty the bucket and make sure it's filling once again */ + token_bucket_rw_dec_read(&b, b.cfg.burst); + tt_int_op(b.read_bucket.bucket, OP_EQ, 0); + tt_int_op(1, OP_EQ, token_bucket_rw_refill(&b, ts_stamp += BW_SEC)); + tt_int_op(b.read_bucket.bucket, OP_GT, 16*KB - 300); + tt_int_op(b.read_bucket.bucket, OP_LT, 16*KB + 300); + + /* An even larger amount of time passes, which we take to be a 32-bit + * rollover event. The individual update is ignored, but the timestamp + * is still updated and the very next update should be accounted properly. */ + tt_int_op(0, OP_EQ, token_bucket_rw_refill(&b, ts_stamp += UINT32_MAX/2)); + tt_int_op(b.read_bucket.bucket, OP_GT, 16*KB - 600); + tt_int_op(b.read_bucket.bucket, OP_LT, 16*KB + 600); + tt_int_op(0, OP_EQ, token_bucket_rw_refill(&b, ts_stamp += BW_SEC)); + tt_int_op(b.read_bucket.bucket, OP_GT, 32*KB - 600); + tt_int_op(b.read_bucket.bucket, OP_LT, 32*KB + 600); + done: ; } diff -Nru tor-0.4.7.16/src/test/test_cell_formats.c tor-0.4.9.6/src/test/test_cell_formats.c --- tor-0.4.7.16/src/test/test_cell_formats.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/test/test_cell_formats.c 2026-03-25 14:30:34.000000000 +0000 @@ -14,13 +14,14 @@ #include "app/config/config.h" #include "lib/crypt_ops/crypto_rand.h" #include "core/or/onion.h" -#include "core/crypto/onion_tap.h" #include "core/crypto/onion_fast.h" #include "core/crypto/onion_ntor.h" #include "core/or/relay.h" +#include "core/or/relay_msg.h" #include "core/or/cell_st.h" #include "core/or/cell_queue_st.h" +#include "core/or/relay_msg_st.h" #include "core/or/var_cell_st.h" #include "test/test.h" @@ -32,12 +33,12 @@ test_cfmt_relay_header(void *arg) { relay_header_t rh; - const uint8_t hdr_1[RELAY_HEADER_SIZE] = + NONSTRING const uint8_t hdr_1[RELAY_HEADER_SIZE_V0] = "\x03" "\x00\x00" "\x21\x22" "ABCD" "\x01\x03"; - uint8_t hdr_out[RELAY_HEADER_SIZE]; + uint8_t hdr_out[RELAY_HEADER_SIZE_V0]; (void)arg; - tt_int_op(sizeof(hdr_1), OP_EQ, RELAY_HEADER_SIZE); + tt_int_op(sizeof(hdr_1), OP_EQ, RELAY_HEADER_SIZE_V0); relay_header_unpack(&rh, hdr_1); tt_int_op(rh.command, OP_EQ, 3); tt_int_op(rh.recognized, OP_EQ, 0); @@ -46,42 +47,35 @@ tt_int_op(rh.length, OP_EQ, 0x103); relay_header_pack(hdr_out, &rh); - tt_mem_op(hdr_out, OP_EQ, hdr_1, RELAY_HEADER_SIZE); + tt_mem_op(hdr_out, OP_EQ, hdr_1, RELAY_HEADER_SIZE_V0); done: ; } static void -make_relay_cell(cell_t *out, uint8_t command, - const void *body, size_t bodylen) +make_relay_msg(relay_msg_t *out, uint8_t command, + const void *body, size_t bodylen) { - relay_header_t rh; - - memset(&rh, 0, sizeof(rh)); - rh.stream_id = 5; - rh.command = command; - rh.length = bodylen; - - out->command = CELL_RELAY; - out->circ_id = 10; - relay_header_pack(out->payload, &rh); - - memcpy(out->payload + RELAY_HEADER_SIZE, body, bodylen); + memset(out, 0, sizeof(*out)); + out->command = command; + out->body = (uint8_t *)body; + out->length = bodylen; + out->stream_id = 5; } static void test_cfmt_begin_cells(void *arg) { - cell_t cell; + relay_msg_t msg; begin_cell_t bcell; uint8_t end_reason; (void)arg; /* Try begindir. */ memset(&bcell, 0x7f, sizeof(bcell)); - make_relay_cell(&cell, RELAY_COMMAND_BEGIN_DIR, "", 0); - tt_int_op(0, OP_EQ, begin_cell_parse(&cell, &bcell, &end_reason)); + make_relay_msg(&msg, RELAY_COMMAND_BEGIN_DIR, "", 0); + tt_int_op(0, OP_EQ, begin_cell_parse(&msg, &bcell, &end_reason)); tt_ptr_op(NULL, OP_EQ, bcell.address); tt_int_op(0, OP_EQ, bcell.flags); tt_int_op(0, OP_EQ, bcell.port); @@ -90,8 +84,8 @@ /* A Begindir with extra stuff. */ memset(&bcell, 0x7f, sizeof(bcell)); - make_relay_cell(&cell, RELAY_COMMAND_BEGIN_DIR, "12345", 5); - tt_int_op(0, OP_EQ, begin_cell_parse(&cell, &bcell, &end_reason)); + make_relay_msg(&msg, RELAY_COMMAND_BEGIN_DIR, "12345", 5); + tt_int_op(0, OP_EQ, begin_cell_parse(&msg, &bcell, &end_reason)); tt_ptr_op(NULL, OP_EQ, bcell.address); tt_int_op(0, OP_EQ, bcell.flags); tt_int_op(0, OP_EQ, bcell.port); @@ -100,8 +94,8 @@ /* A short but valid begin cell */ memset(&bcell, 0x7f, sizeof(bcell)); - make_relay_cell(&cell, RELAY_COMMAND_BEGIN, "a.b:9", 6); - tt_int_op(0, OP_EQ, begin_cell_parse(&cell, &bcell, &end_reason)); + make_relay_msg(&msg, RELAY_COMMAND_BEGIN, "a.b:9", 6); + tt_int_op(0, OP_EQ, begin_cell_parse(&msg, &bcell, &end_reason)); tt_str_op("a.b", OP_EQ, bcell.address); tt_int_op(0, OP_EQ, bcell.flags); tt_int_op(9, OP_EQ, bcell.port); @@ -112,21 +106,21 @@ /* A significantly loner begin cell */ memset(&bcell, 0x7f, sizeof(bcell)); { - const char c[] = "here-is-a-nice-long.hostname.com:65535"; - make_relay_cell(&cell, RELAY_COMMAND_BEGIN, c, strlen(c)+1); - } - tt_int_op(0, OP_EQ, begin_cell_parse(&cell, &bcell, &end_reason)); + const char c[] = "here-is-a-nice-long.hostname.com:65535"; + make_relay_msg(&msg, RELAY_COMMAND_BEGIN, c, strlen(c)+1); + tt_int_op(0, OP_EQ, begin_cell_parse(&msg, &bcell, &end_reason)); tt_str_op("here-is-a-nice-long.hostname.com", OP_EQ, bcell.address); tt_int_op(0, OP_EQ, bcell.flags); tt_int_op(65535, OP_EQ, bcell.port); tt_int_op(5, OP_EQ, bcell.stream_id); tt_int_op(0, OP_EQ, bcell.is_begindir); tor_free(bcell.address); + } /* An IPv4 begin cell. */ memset(&bcell, 0x7f, sizeof(bcell)); - make_relay_cell(&cell, RELAY_COMMAND_BEGIN, "18.9.22.169:80", 15); - tt_int_op(0, OP_EQ, begin_cell_parse(&cell, &bcell, &end_reason)); + make_relay_msg(&msg, RELAY_COMMAND_BEGIN, "18.9.22.169:80", 15); + tt_int_op(0, OP_EQ, begin_cell_parse(&msg, &bcell, &end_reason)); tt_str_op("18.9.22.169", OP_EQ, bcell.address); tt_int_op(0, OP_EQ, bcell.flags); tt_int_op(80, OP_EQ, bcell.port); @@ -136,9 +130,9 @@ /* An IPv6 begin cell. Let's make sure we handle colons*/ memset(&bcell, 0x7f, sizeof(bcell)); - make_relay_cell(&cell, RELAY_COMMAND_BEGIN, + make_relay_msg(&msg, RELAY_COMMAND_BEGIN, "[2620::6b0:b:1a1a:0:26e5:480e]:80", 34); - tt_int_op(0, OP_EQ, begin_cell_parse(&cell, &bcell, &end_reason)); + tt_int_op(0, OP_EQ, begin_cell_parse(&msg, &bcell, &end_reason)); tt_str_op("[2620::6b0:b:1a1a:0:26e5:480e]", OP_EQ, bcell.address); tt_int_op(0, OP_EQ, bcell.flags); tt_int_op(80, OP_EQ, bcell.port); @@ -150,88 +144,85 @@ memset(&bcell, 0x7f, sizeof(bcell)); { const char c[] = "another.example.com:80\x00\x01\x02"; - make_relay_cell(&cell, RELAY_COMMAND_BEGIN, c, sizeof(c)-1); + make_relay_msg(&msg, RELAY_COMMAND_BEGIN, c, sizeof(c)-1); + tt_int_op(0, OP_EQ, begin_cell_parse(&msg, &bcell, &end_reason)); + tt_str_op("another.example.com", OP_EQ, bcell.address); + tt_int_op(0, OP_EQ, bcell.flags); + tt_int_op(80, OP_EQ, bcell.port); + tt_int_op(5, OP_EQ, bcell.stream_id); + tt_int_op(0, OP_EQ, bcell.is_begindir); + tor_free(bcell.address); } - tt_int_op(0, OP_EQ, begin_cell_parse(&cell, &bcell, &end_reason)); - tt_str_op("another.example.com", OP_EQ, bcell.address); - tt_int_op(0, OP_EQ, bcell.flags); - tt_int_op(80, OP_EQ, bcell.port); - tt_int_op(5, OP_EQ, bcell.stream_id); - tt_int_op(0, OP_EQ, bcell.is_begindir); - tor_free(bcell.address); /* a begin cell with flags. */ memset(&bcell, 0x7f, sizeof(bcell)); { const char c[] = "another.example.com:443\x00\x01\x02\x03\x04"; - make_relay_cell(&cell, RELAY_COMMAND_BEGIN, c, sizeof(c)-1); + make_relay_msg(&msg, RELAY_COMMAND_BEGIN, c, sizeof(c)-1); + tt_int_op(0, OP_EQ, begin_cell_parse(&msg, &bcell, &end_reason)); + tt_str_op("another.example.com", OP_EQ, bcell.address); + tt_int_op(0x1020304, OP_EQ, bcell.flags); + tt_int_op(443, OP_EQ, bcell.port); + tt_int_op(5, OP_EQ, bcell.stream_id); + tt_int_op(0, OP_EQ, bcell.is_begindir); + tor_free(bcell.address); } - tt_int_op(0, OP_EQ, begin_cell_parse(&cell, &bcell, &end_reason)); - tt_str_op("another.example.com", OP_EQ, bcell.address); - tt_int_op(0x1020304, OP_EQ, bcell.flags); - tt_int_op(443, OP_EQ, bcell.port); - tt_int_op(5, OP_EQ, bcell.stream_id); - tt_int_op(0, OP_EQ, bcell.is_begindir); - tor_free(bcell.address); /* a begin cell with flags and even more cruft after that. */ memset(&bcell, 0x7f, sizeof(bcell)); { const char c[] = "a-further.example.com:22\x00\xee\xaa\x00\xffHi mom"; - make_relay_cell(&cell, RELAY_COMMAND_BEGIN, c, sizeof(c)-1); + make_relay_msg(&msg, RELAY_COMMAND_BEGIN, c, sizeof(c)-1); + tt_int_op(0, OP_EQ, begin_cell_parse(&msg, &bcell, &end_reason)); + tt_str_op("a-further.example.com", OP_EQ, bcell.address); + tt_int_op(0xeeaa00ff, OP_EQ, bcell.flags); + tt_int_op(22, OP_EQ, bcell.port); + tt_int_op(5, OP_EQ, bcell.stream_id); + tt_int_op(0, OP_EQ, bcell.is_begindir); + tor_free(bcell.address); } - tt_int_op(0, OP_EQ, begin_cell_parse(&cell, &bcell, &end_reason)); - tt_str_op("a-further.example.com", OP_EQ, bcell.address); - tt_int_op(0xeeaa00ff, OP_EQ, bcell.flags); - tt_int_op(22, OP_EQ, bcell.port); - tt_int_op(5, OP_EQ, bcell.stream_id); - tt_int_op(0, OP_EQ, bcell.is_begindir); - tor_free(bcell.address); +#if 0 + // Note: This is now checked at when we decode the relay message. /* bad begin cell: impossible length. */ memset(&bcell, 0x7f, sizeof(bcell)); - make_relay_cell(&cell, RELAY_COMMAND_BEGIN, "a.b:80", 7); - cell.payload[9] = 0x01; /* Set length to 510 */ - cell.payload[10] = 0xfe; - { - relay_header_t rh; - relay_header_unpack(&rh, cell.payload); - tt_int_op(rh.length, OP_EQ, 510); - } - tt_int_op(-2, OP_EQ, begin_cell_parse(&cell, &bcell, &end_reason)); + make_relay_msg(&msg, RELAY_COMMAND_BEGIN, "a.b:80", 7); + msg.length = 510; + tt_int_op(-2, OP_EQ, begin_cell_parse(&msg, &bcell, &end_reason)); +#endif /* Bad begin cell: no body. */ memset(&bcell, 0x7f, sizeof(bcell)); - make_relay_cell(&cell, RELAY_COMMAND_BEGIN, "", 0); - tt_int_op(-1, OP_EQ, begin_cell_parse(&cell, &bcell, &end_reason)); + make_relay_msg(&msg, RELAY_COMMAND_BEGIN, "", 0); + tt_int_op(-1, OP_EQ, begin_cell_parse(&msg, &bcell, &end_reason)); /* bad begin cell: no body. */ memset(&bcell, 0x7f, sizeof(bcell)); - make_relay_cell(&cell, RELAY_COMMAND_BEGIN, "", 0); - tt_int_op(-1, OP_EQ, begin_cell_parse(&cell, &bcell, &end_reason)); + make_relay_msg(&msg, RELAY_COMMAND_BEGIN, "", 0); + tt_int_op(-1, OP_EQ, begin_cell_parse(&msg, &bcell, &end_reason)); /* bad begin cell: no colon */ memset(&bcell, 0x7f, sizeof(bcell)); - make_relay_cell(&cell, RELAY_COMMAND_BEGIN, "a.b", 4); - tt_int_op(-1, OP_EQ, begin_cell_parse(&cell, &bcell, &end_reason)); + make_relay_msg(&msg, RELAY_COMMAND_BEGIN, "a.b", 4); + tt_int_op(-1, OP_EQ, begin_cell_parse(&msg, &bcell, &end_reason)); /* bad begin cell: no ports */ memset(&bcell, 0x7f, sizeof(bcell)); - make_relay_cell(&cell, RELAY_COMMAND_BEGIN, "a.b:", 5); - tt_int_op(-1, OP_EQ, begin_cell_parse(&cell, &bcell, &end_reason)); + make_relay_msg(&msg, RELAY_COMMAND_BEGIN, "a.b:", 5); + tt_int_op(-1, OP_EQ, begin_cell_parse(&msg, &bcell, &end_reason)); /* bad begin cell: bad port */ memset(&bcell, 0x7f, sizeof(bcell)); - make_relay_cell(&cell, RELAY_COMMAND_BEGIN, "a.b:xyz", 8); - tt_int_op(-1, OP_EQ, begin_cell_parse(&cell, &bcell, &end_reason)); + make_relay_msg(&msg, RELAY_COMMAND_BEGIN, "a.b:xyz", 8); + tt_int_op(-1, OP_EQ, begin_cell_parse(&msg, &bcell, &end_reason)); memset(&bcell, 0x7f, sizeof(bcell)); - make_relay_cell(&cell, RELAY_COMMAND_BEGIN, "a.b:100000", 11); - tt_int_op(-1, OP_EQ, begin_cell_parse(&cell, &bcell, &end_reason)); + make_relay_msg(&msg, RELAY_COMMAND_BEGIN, "a.b:100000", 11); + tt_int_op(-1, OP_EQ, begin_cell_parse(&msg, &bcell, &end_reason)); /* bad begin cell: no nul */ memset(&bcell, 0x7f, sizeof(bcell)); - make_relay_cell(&cell, RELAY_COMMAND_BEGIN, "a.b:80", 6); - tt_int_op(-1, OP_EQ, begin_cell_parse(&cell, &bcell, &end_reason)); + make_relay_msg(&msg, RELAY_COMMAND_BEGIN, "a.b:80", 6); + tt_int_op(-1, OP_EQ, begin_cell_parse(&msg, &bcell, &end_reason)); done: tor_free(bcell.address); @@ -240,144 +231,129 @@ static void test_cfmt_connected_cells(void *arg) { - relay_header_t rh; - cell_t cell; tor_addr_t addr; int ttl, r; char *mem_op_hex_tmp = NULL; + relay_msg_t msg; + uint8_t buf[512]; (void)arg; /* Let's try an oldschool one with nothing in it. */ - make_relay_cell(&cell, RELAY_COMMAND_CONNECTED, "", 0); - relay_header_unpack(&rh, cell.payload); - r = connected_cell_parse(&rh, &cell, &addr, &ttl); + make_relay_msg(&msg, RELAY_COMMAND_CONNECTED, "", 0); + r = connected_cell_parse(&msg, &addr, &ttl); tt_int_op(r, OP_EQ, 0); tt_int_op(tor_addr_family(&addr), OP_EQ, AF_UNSPEC); tt_int_op(ttl, OP_EQ, -1); /* A slightly less oldschool one: only an IPv4 address */ - make_relay_cell(&cell, RELAY_COMMAND_CONNECTED, "\x20\x30\x40\x50", 4); - relay_header_unpack(&rh, cell.payload); - r = connected_cell_parse(&rh, &cell, &addr, &ttl); + make_relay_msg(&msg, RELAY_COMMAND_CONNECTED, "\x20\x30\x40\x50", 4); + r = connected_cell_parse(&msg, &addr, &ttl); tt_int_op(r, OP_EQ, 0); tt_int_op(tor_addr_family(&addr), OP_EQ, AF_INET); tt_str_op(fmt_addr(&addr), OP_EQ, "32.48.64.80"); tt_int_op(ttl, OP_EQ, -1); /* Bogus but understandable: truncated TTL */ - make_relay_cell(&cell, RELAY_COMMAND_CONNECTED, "\x11\x12\x13\x14\x15", 5); - relay_header_unpack(&rh, cell.payload); - r = connected_cell_parse(&rh, &cell, &addr, &ttl); + make_relay_msg(&msg, RELAY_COMMAND_CONNECTED, "\x11\x12\x13\x14\x15", 5); + r = connected_cell_parse(&msg, &addr, &ttl); tt_int_op(r, OP_EQ, 0); tt_int_op(tor_addr_family(&addr), OP_EQ, AF_INET); tt_str_op(fmt_addr(&addr), OP_EQ, "17.18.19.20"); tt_int_op(ttl, OP_EQ, -1); /* Regular IPv4 one: address and TTL */ - make_relay_cell(&cell, RELAY_COMMAND_CONNECTED, + make_relay_msg(&msg, RELAY_COMMAND_CONNECTED, "\x02\x03\x04\x05\x00\x00\x0e\x10", 8); - relay_header_unpack(&rh, cell.payload); - r = connected_cell_parse(&rh, &cell, &addr, &ttl); + r = connected_cell_parse(&msg, &addr, &ttl); tt_int_op(r, OP_EQ, 0); tt_int_op(tor_addr_family(&addr), OP_EQ, AF_INET); tt_str_op(fmt_addr(&addr), OP_EQ, "2.3.4.5"); tt_int_op(ttl, OP_EQ, 3600); /* IPv4 with too-big TTL */ - make_relay_cell(&cell, RELAY_COMMAND_CONNECTED, + make_relay_msg(&msg, RELAY_COMMAND_CONNECTED, "\x02\x03\x04\x05\xf0\x00\x00\x00", 8); - relay_header_unpack(&rh, cell.payload); - r = connected_cell_parse(&rh, &cell, &addr, &ttl); + r = connected_cell_parse(&msg, &addr, &ttl); tt_int_op(r, OP_EQ, 0); tt_int_op(tor_addr_family(&addr), OP_EQ, AF_INET); tt_str_op(fmt_addr(&addr), OP_EQ, "2.3.4.5"); tt_int_op(ttl, OP_EQ, -1); /* IPv6 (ttl is mandatory) */ - make_relay_cell(&cell, RELAY_COMMAND_CONNECTED, + make_relay_msg(&msg, RELAY_COMMAND_CONNECTED, "\x00\x00\x00\x00\x06" "\x26\x07\xf8\xb0\x40\x0c\x0c\x02" "\x00\x00\x00\x00\x00\x00\x00\x68" "\x00\x00\x02\x58", 25); - relay_header_unpack(&rh, cell.payload); - r = connected_cell_parse(&rh, &cell, &addr, &ttl); + r = connected_cell_parse(&msg, &addr, &ttl); tt_int_op(r, OP_EQ, 0); tt_int_op(tor_addr_family(&addr), OP_EQ, AF_INET6); tt_str_op(fmt_addr(&addr), OP_EQ, "2607:f8b0:400c:c02::68"); tt_int_op(ttl, OP_EQ, 600); /* IPv6 (ttl too big) */ - make_relay_cell(&cell, RELAY_COMMAND_CONNECTED, + make_relay_msg(&msg, RELAY_COMMAND_CONNECTED, "\x00\x00\x00\x00\x06" "\x26\x07\xf8\xb0\x40\x0c\x0c\x02" "\x00\x00\x00\x00\x00\x00\x00\x68" "\x90\x00\x02\x58", 25); - relay_header_unpack(&rh, cell.payload); - r = connected_cell_parse(&rh, &cell, &addr, &ttl); + r = connected_cell_parse(&msg, &addr, &ttl); tt_int_op(r, OP_EQ, 0); tt_int_op(tor_addr_family(&addr), OP_EQ, AF_INET6); tt_str_op(fmt_addr(&addr), OP_EQ, "2607:f8b0:400c:c02::68"); tt_int_op(ttl, OP_EQ, -1); /* Bogus size: 3. */ - make_relay_cell(&cell, RELAY_COMMAND_CONNECTED, + make_relay_msg(&msg, RELAY_COMMAND_CONNECTED, "\x00\x01\x02", 3); - relay_header_unpack(&rh, cell.payload); - r = connected_cell_parse(&rh, &cell, &addr, &ttl); + r = connected_cell_parse(&msg, &addr, &ttl); tt_int_op(r, OP_EQ, -1); /* Bogus family: 7. */ - make_relay_cell(&cell, RELAY_COMMAND_CONNECTED, + make_relay_msg(&msg, RELAY_COMMAND_CONNECTED, "\x00\x00\x00\x00\x07" "\x26\x07\xf8\xb0\x40\x0c\x0c\x02" "\x00\x00\x00\x00\x00\x00\x00\x68" "\x90\x00\x02\x58", 25); - relay_header_unpack(&rh, cell.payload); - r = connected_cell_parse(&rh, &cell, &addr, &ttl); + r = connected_cell_parse(&msg, &addr, &ttl); tt_int_op(r, OP_EQ, -1); /* Truncated IPv6. */ - make_relay_cell(&cell, RELAY_COMMAND_CONNECTED, + make_relay_msg(&msg, RELAY_COMMAND_CONNECTED, "\x00\x00\x00\x00\x06" "\x26\x07\xf8\xb0\x40\x0c\x0c\x02" "\x00\x00\x00\x00\x00\x00\x00\x68" "\x00\x00\x02", 24); - relay_header_unpack(&rh, cell.payload); - r = connected_cell_parse(&rh, &cell, &addr, &ttl); + r = connected_cell_parse(&msg, &addr, &ttl); tt_int_op(r, OP_EQ, -1); /* Now make sure we can generate connected cells correctly. */ /* Try an IPv4 address */ - memset(&rh, 0, sizeof(rh)); - memset(&cell, 0, sizeof(cell)); tor_addr_parse(&addr, "30.40.50.60"); - rh.length = connected_cell_format_payload(cell.payload+RELAY_HEADER_SIZE, - &addr, 1024); - tt_int_op(rh.length, OP_EQ, 8); - test_memeq_hex(cell.payload+RELAY_HEADER_SIZE, "1e28323c" "00000400"); + msg.body = buf; + msg.length = connected_cell_format_payload(buf, &addr, 1024); + tt_int_op(msg.length, OP_EQ, 8); + test_memeq_hex(msg.body, "1e28323c" "00000400"); /* Try parsing it. */ tor_addr_make_unspec(&addr); - r = connected_cell_parse(&rh, &cell, &addr, &ttl); + r = connected_cell_parse(&msg, &addr, &ttl); tt_int_op(r, OP_EQ, 0); tt_int_op(tor_addr_family(&addr), OP_EQ, AF_INET); tt_str_op(fmt_addr(&addr), OP_EQ, "30.40.50.60"); tt_int_op(ttl, OP_EQ, 1024); /* Try an IPv6 address */ - memset(&rh, 0, sizeof(rh)); - memset(&cell, 0, sizeof(cell)); tor_addr_parse(&addr, "2620::6b0:b:1a1a:0:26e5:480e"); - rh.length = connected_cell_format_payload(cell.payload+RELAY_HEADER_SIZE, - &addr, 3600); - tt_int_op(rh.length, OP_EQ, 25); - test_memeq_hex(cell.payload + RELAY_HEADER_SIZE, + msg.length = connected_cell_format_payload(buf, &addr, 3600); + tt_int_op(msg.length, OP_EQ, 25); + test_memeq_hex(msg.body, "00000000" "06" "2620000006b0000b1a1a000026e5480e" "00000e10"); /* Try parsing it. */ tor_addr_make_unspec(&addr); - r = connected_cell_parse(&rh, &cell, &addr, &ttl); + r = connected_cell_parse(&msg, &addr, &ttl); tt_int_op(r, OP_EQ, 0); tt_int_op(tor_addr_family(&addr), OP_EQ, AF_INET6); tt_str_op(fmt_addr(&addr), OP_EQ, "2620:0:6b0:b:1a1a:0:26e5:480e"); @@ -399,21 +375,6 @@ /* === Let's try parsing some good cells! */ - /* A valid create cell. */ - memset(&cell, 0, sizeof(cell)); - memset(b, 0, sizeof(b)); - crypto_rand((char*)b, TAP_ONIONSKIN_CHALLENGE_LEN); - cell.command = CELL_CREATE; - memcpy(cell.payload, b, TAP_ONIONSKIN_CHALLENGE_LEN); - tt_int_op(0, OP_EQ, create_cell_parse(&cc, &cell)); - tt_int_op(CELL_CREATE, OP_EQ, cc.cell_type); - tt_int_op(ONION_HANDSHAKE_TYPE_TAP, OP_EQ, cc.handshake_type); - tt_int_op(TAP_ONIONSKIN_CHALLENGE_LEN, OP_EQ, cc.handshake_len); - tt_mem_op(cc.onionskin,OP_EQ, b, TAP_ONIONSKIN_CHALLENGE_LEN + 10); - tt_int_op(0, OP_EQ, create_cell_format(&cell2, &cc)); - tt_int_op(cell.command, OP_EQ, cell2.command); - tt_mem_op(cell.payload,OP_EQ, cell2.payload, CELL_PAYLOAD_SIZE); - /* A valid create_fast cell. */ memset(&cell, 0, sizeof(cell)); memset(b, 0, sizeof(b)); @@ -429,22 +390,6 @@ tt_int_op(cell.command, OP_EQ, cell2.command); tt_mem_op(cell.payload,OP_EQ, cell2.payload, CELL_PAYLOAD_SIZE); - /* A valid create2 cell with a TAP payload */ - memset(&cell, 0, sizeof(cell)); - memset(b, 0, sizeof(b)); - crypto_rand((char*)b, TAP_ONIONSKIN_CHALLENGE_LEN); - cell.command = CELL_CREATE2; - memcpy(cell.payload, "\x00\x00\x00\xBA", 4); /* TAP, 186 bytes long */ - memcpy(cell.payload+4, b, TAP_ONIONSKIN_CHALLENGE_LEN); - tt_int_op(0, OP_EQ, create_cell_parse(&cc, &cell)); - tt_int_op(CELL_CREATE2, OP_EQ, cc.cell_type); - tt_int_op(ONION_HANDSHAKE_TYPE_TAP, OP_EQ, cc.handshake_type); - tt_int_op(TAP_ONIONSKIN_CHALLENGE_LEN, OP_EQ, cc.handshake_len); - tt_mem_op(cc.onionskin,OP_EQ, b, TAP_ONIONSKIN_CHALLENGE_LEN + 10); - tt_int_op(0, OP_EQ, create_cell_format(&cell2, &cc)); - tt_int_op(cell.command, OP_EQ, cell2.command); - tt_mem_op(cell.payload,OP_EQ, cell2.payload, CELL_PAYLOAD_SIZE); - /* A valid create2 cell with an ntor payload */ memset(&cell, 0, sizeof(cell)); memset(b, 0, sizeof(b)); @@ -461,22 +406,6 @@ tt_int_op(cell.command, OP_EQ, cell2.command); tt_mem_op(cell.payload,OP_EQ, cell2.payload, CELL_PAYLOAD_SIZE); - /* A valid create cell with an ntor payload, in legacy format. */ - memset(&cell, 0, sizeof(cell)); - memset(b, 0, sizeof(b)); - crypto_rand((char*)b, NTOR_ONIONSKIN_LEN); - cell.command = CELL_CREATE; - memcpy(cell.payload, "ntorNTORntorNTOR", 16); - memcpy(cell.payload+16, b, NTOR_ONIONSKIN_LEN); - tt_int_op(0, OP_EQ, create_cell_parse(&cc, &cell)); - tt_int_op(CELL_CREATE, OP_EQ, cc.cell_type); - tt_int_op(ONION_HANDSHAKE_TYPE_NTOR, OP_EQ, cc.handshake_type); - tt_int_op(NTOR_ONIONSKIN_LEN, OP_EQ, cc.handshake_len); - tt_mem_op(cc.onionskin,OP_EQ, b, NTOR_ONIONSKIN_LEN + 10); - tt_int_op(0, OP_EQ, create_cell_format(&cell2, &cc)); - tt_int_op(cell.command, OP_EQ, cell2.command); - tt_mem_op(cell.payload,OP_EQ, cell2.payload, CELL_PAYLOAD_SIZE); - /* == Okay, now let's try to parse some impossible stuff. */ /* It has to be some kind of a create cell! */ @@ -517,20 +446,6 @@ (void)arg; - /* A good CREATED cell */ - memset(&cell, 0, sizeof(cell)); - memset(b, 0, sizeof(b)); - crypto_rand((char*)b, TAP_ONIONSKIN_REPLY_LEN); - cell.command = CELL_CREATED; - memcpy(cell.payload, b, TAP_ONIONSKIN_REPLY_LEN); - tt_int_op(0, OP_EQ, created_cell_parse(&cc, &cell)); - tt_int_op(CELL_CREATED, OP_EQ, cc.cell_type); - tt_int_op(TAP_ONIONSKIN_REPLY_LEN, OP_EQ, cc.handshake_len); - tt_mem_op(cc.reply,OP_EQ, b, TAP_ONIONSKIN_REPLY_LEN + 10); - tt_int_op(0, OP_EQ, created_cell_format(&cell2, &cc)); - tt_int_op(cell.command, OP_EQ, cell2.command); - tt_mem_op(cell.payload,OP_EQ, cell2.payload, CELL_PAYLOAD_SIZE); - /* A good CREATED_FAST cell */ memset(&cell, 0, sizeof(cell)); memset(b, 0, sizeof(b)); @@ -580,11 +495,11 @@ memset(b, 0, sizeof(b)); crypto_rand((char*)b, 496); cell.command = CELL_CREATED2; - memcpy(cell.payload, "\x01\xF1", 2); + memcpy(cell.payload, "\x02\xFF", 2); tt_int_op(-1, OP_EQ, created_cell_parse(&cc, &cell)); /* Unformattable CREATED2 cell: too long! */ - cc.handshake_len = 497; + cc.handshake_len = 508; tt_int_op(-1, OP_EQ, created_cell_format(&cell2, &cc)); done: @@ -606,54 +521,6 @@ (void) arg; - /* Let's start with a simple EXTEND cell. */ - memset(p, 0, sizeof(p)); - memset(b, 0, sizeof(b)); - crypto_rand((char*)b, TAP_ONIONSKIN_CHALLENGE_LEN); - memcpy(p, "\x12\xf4\x00\x01\x01\x02", 6); /* 18 244 0 1 : 258 */ - memcpy(p+6,b,TAP_ONIONSKIN_CHALLENGE_LEN); - memcpy(p+6+TAP_ONIONSKIN_CHALLENGE_LEN, "electroencephalogram", 20); - tt_int_op(0, OP_EQ, extend_cell_parse(&ec, RELAY_COMMAND_EXTEND, - p, 26+TAP_ONIONSKIN_CHALLENGE_LEN)); - tt_int_op(RELAY_COMMAND_EXTEND, OP_EQ, ec.cell_type); - tt_str_op("18.244.0.1", OP_EQ, fmt_addr(&ec.orport_ipv4.addr)); - tt_int_op(258, OP_EQ, ec.orport_ipv4.port); - tt_int_op(AF_UNSPEC, OP_EQ, tor_addr_family(&ec.orport_ipv6.addr)); - tt_mem_op(ec.node_id,OP_EQ, "electroencephalogram", 20); - tt_int_op(cc->cell_type, OP_EQ, CELL_CREATE); - tt_int_op(cc->handshake_type, OP_EQ, ONION_HANDSHAKE_TYPE_TAP); - tt_int_op(cc->handshake_len, OP_EQ, TAP_ONIONSKIN_CHALLENGE_LEN); - tt_mem_op(cc->onionskin,OP_EQ, b, TAP_ONIONSKIN_CHALLENGE_LEN+20); - tt_int_op(0, OP_EQ, extend_cell_format(&p2_cmd, &p2_len, p2, &ec)); - tt_int_op(p2_cmd, OP_EQ, RELAY_COMMAND_EXTEND); - tt_int_op(p2_len, OP_EQ, 26+TAP_ONIONSKIN_CHALLENGE_LEN); - tt_mem_op(p2,OP_EQ, p, RELAY_PAYLOAD_SIZE); - - /* Let's do an ntor stuffed in a legacy EXTEND cell */ - memset(p, 0, sizeof(p)); - memset(b, 0, sizeof(b)); - crypto_rand((char*)b, NTOR_ONIONSKIN_LEN); - memcpy(p, "\x12\xf4\x00\x01\x01\x02", 6); /* 18 244 0 1 : 258 */ - memcpy(p+6,"ntorNTORntorNTOR", 16); - memcpy(p+22, b, NTOR_ONIONSKIN_LEN); - memcpy(p+6+TAP_ONIONSKIN_CHALLENGE_LEN, "electroencephalogram", 20); - tt_int_op(0, OP_EQ, extend_cell_parse(&ec, RELAY_COMMAND_EXTEND, - p, 26+TAP_ONIONSKIN_CHALLENGE_LEN)); - tt_int_op(RELAY_COMMAND_EXTEND, OP_EQ, ec.cell_type); - tt_str_op("18.244.0.1", OP_EQ, fmt_addr(&ec.orport_ipv4.addr)); - tt_int_op(258, OP_EQ, ec.orport_ipv4.port); - tt_int_op(AF_UNSPEC, OP_EQ, tor_addr_family(&ec.orport_ipv6.addr)); - tt_mem_op(ec.node_id,OP_EQ, "electroencephalogram", 20); - tt_int_op(cc->cell_type, OP_EQ, CELL_CREATE2); - tt_int_op(cc->handshake_type, OP_EQ, ONION_HANDSHAKE_TYPE_NTOR); - tt_int_op(cc->handshake_len, OP_EQ, NTOR_ONIONSKIN_LEN); - tt_mem_op(cc->onionskin,OP_EQ, b, NTOR_ONIONSKIN_LEN+20); - tt_int_op(0, OP_EQ, extend_cell_format(&p2_cmd, &p2_len, p2, &ec)); - tt_int_op(p2_cmd, OP_EQ, RELAY_COMMAND_EXTEND); - tt_int_op(p2_len, OP_EQ, 26+TAP_ONIONSKIN_CHALLENGE_LEN); - tt_mem_op(p2,OP_EQ, p, RELAY_PAYLOAD_SIZE); - tt_int_op(0, OP_EQ, create_cell_format_relayed(&cell, cc)); - /* Now let's do a minimal ntor EXTEND2 cell. */ memset(&ec, 0xff, sizeof(ec)); memset(p, 0, sizeof(p)); @@ -896,23 +763,6 @@ (void) arg; - /* Try a regular EXTENDED cell. */ - memset(&ec, 0xff, sizeof(ec)); - memset(p, 0, sizeof(p)); - memset(b, 0, sizeof(b)); - crypto_rand((char*)b, TAP_ONIONSKIN_REPLY_LEN); - memcpy(p,b,TAP_ONIONSKIN_REPLY_LEN); - tt_int_op(0, OP_EQ, extended_cell_parse(&ec, RELAY_COMMAND_EXTENDED, p, - TAP_ONIONSKIN_REPLY_LEN)); - tt_int_op(RELAY_COMMAND_EXTENDED, OP_EQ, ec.cell_type); - tt_int_op(cc->cell_type, OP_EQ, CELL_CREATED); - tt_int_op(cc->handshake_len, OP_EQ, TAP_ONIONSKIN_REPLY_LEN); - tt_mem_op(cc->reply,OP_EQ, b, TAP_ONIONSKIN_REPLY_LEN); - tt_int_op(0, OP_EQ, extended_cell_format(&p2_cmd, &p2_len, p2, &ec)); - tt_int_op(RELAY_COMMAND_EXTENDED, OP_EQ, p2_cmd); - tt_int_op(TAP_ONIONSKIN_REPLY_LEN, OP_EQ, p2_len); - tt_mem_op(p2,OP_EQ, p, sizeof(p2)); - /* Try an EXTENDED2 cell */ memset(&ec, 0xff, sizeof(ec)); memset(p, 0, sizeof(p)); @@ -950,15 +800,15 @@ test_cfmt_resolved_cells(void *arg) { smartlist_t *addrs = smartlist_new(); - relay_header_t rh; - cell_t cell; int r, errcode; address_ttl_t *a; + relay_msg_t msg; + uint8_t buf[500]; (void)arg; #define CLEAR_CELL() do { \ - memset(&cell, 0, sizeof(cell)); \ - memset(&rh, 0, sizeof(rh)); \ + memset(&msg, 0, sizeof(msg)); \ + memset(&buf, 0, sizeof(buf)); \ } while (0) #define CLEAR_ADDRS() do { \ SMARTLIST_FOREACH(addrs, address_ttl_t *, aa_, \ @@ -967,9 +817,10 @@ } while (0) #define SET_CELL(s) do { \ CLEAR_CELL(); \ - memcpy(cell.payload + RELAY_HEADER_SIZE, (s), sizeof((s))-1); \ - rh.length = sizeof((s))-1; \ - rh.command = RELAY_COMMAND_RESOLVED; \ + memcpy(buf, (s), sizeof((s))-1); \ + msg.length = sizeof((s))-1; \ + msg.body = buf; \ + msg.command = RELAY_COMMAND_RESOLVED; \ errcode = -1; \ } while (0) @@ -982,7 +833,7 @@ /* Let's try an empty cell */ SET_CELL(""); - r = resolved_cell_parse(&cell, &rh, addrs, &errcode); + r = resolved_cell_parse(&msg, addrs, &errcode); tt_int_op(errcode, OP_EQ, 0); tt_int_op(r, OP_EQ, 0); tt_int_op(smartlist_len(addrs), OP_EQ, 0); @@ -990,8 +841,8 @@ /* Cell with one ipv4 addr */ SET_CELL("\x04\x04" "\x7f\x00\x02\x0a" "\x00\00\x01\x00"); - tt_int_op(rh.length, OP_EQ, 10); - r = resolved_cell_parse(&cell, &rh, addrs, &errcode); + tt_int_op(msg.length, OP_EQ, 10); + r = resolved_cell_parse(&msg, addrs, &errcode); tt_int_op(errcode, OP_EQ, 0); tt_int_op(r, OP_EQ, 0); tt_int_op(smartlist_len(addrs), OP_EQ, 1); @@ -1006,8 +857,8 @@ "\x20\x02\x90\x90\x00\x00\x00\x00" "\x00\x00\x00\x00\xf0\xf0\xab\xcd" "\x02\00\x00\x01"); - tt_int_op(rh.length, OP_EQ, 22); - r = resolved_cell_parse(&cell, &rh, addrs, &errcode); + tt_int_op(msg.length, OP_EQ, 22); + r = resolved_cell_parse(&msg, addrs, &errcode); tt_int_op(errcode, OP_EQ, 0); tt_int_op(r, OP_EQ, 0); tt_int_op(smartlist_len(addrs), OP_EQ, 1); @@ -1021,8 +872,8 @@ SET_CELL("\x00\x11" "motherbrain.zebes" "\x00\00\x00\x00"); - tt_int_op(rh.length, OP_EQ, 23); - r = resolved_cell_parse(&cell, &rh, addrs, &errcode); + tt_int_op(msg.length, OP_EQ, 23); + r = resolved_cell_parse(&msg, addrs, &errcode); tt_int_op(errcode, OP_EQ, 0); tt_int_op(r, OP_EQ, 0); tt_int_op(smartlist_len(addrs), OP_EQ, 1); @@ -1042,8 +893,8 @@ SET_CELL("\x00\xff" LONG_NAME "\x00\01\x00\x00"); - tt_int_op(rh.length, OP_EQ, 261); - r = resolved_cell_parse(&cell, &rh, addrs, &errcode); + tt_int_op(msg.length, OP_EQ, 261); + r = resolved_cell_parse(&msg, addrs, &errcode); tt_int_op(errcode, OP_EQ, 0); tt_int_op(r, OP_EQ, 0); tt_int_op(smartlist_len(addrs), OP_EQ, 1); @@ -1057,8 +908,8 @@ SET_CELL("\xf0\x2b" "I'm sorry, Dave. I'm afraid I can't do that" "\x00\x11\x22\x33"); - tt_int_op(rh.length, OP_EQ, 49); - r = resolved_cell_parse(&cell, &rh, addrs, &errcode); + tt_int_op(msg.length, OP_EQ, 49); + r = resolved_cell_parse(&msg, addrs, &errcode); tt_int_op(errcode, OP_EQ, RESOLVED_TYPE_ERROR_TRANSIENT); tt_int_op(r, OP_EQ, 0); tt_int_op(smartlist_len(addrs), OP_EQ, 0); @@ -1067,8 +918,8 @@ SET_CELL("\xf1\x40" "This hostname is too important for me to allow you to resolve it" "\x00\x00\x00\x00"); - tt_int_op(rh.length, OP_EQ, 70); - r = resolved_cell_parse(&cell, &rh, addrs, &errcode); + tt_int_op(msg.length, OP_EQ, 70); + r = resolved_cell_parse(&msg, addrs, &errcode); tt_int_op(errcode, OP_EQ, RESOLVED_TYPE_ERROR); tt_int_op(r, OP_EQ, 0); tt_int_op(smartlist_len(addrs), OP_EQ, 0); @@ -1078,8 +929,8 @@ SET_CELL("\xee\x16" "fault in the AE35 unit" "\x09\x09\x01\x01"); - tt_int_op(rh.length, OP_EQ, 28); - r = resolved_cell_parse(&cell, &rh, addrs, &errcode); + tt_int_op(msg.length, OP_EQ, 28); + r = resolved_cell_parse(&msg, addrs, &errcode); tt_int_op(errcode, OP_EQ, 0); tt_int_op(r, OP_EQ, 0); tt_int_op(smartlist_len(addrs), OP_EQ, 0); @@ -1106,7 +957,7 @@ "motherbrain.zebes" "\x00\00\x00\x00" ); - r = resolved_cell_parse(&cell, &rh, addrs, &errcode); + r = resolved_cell_parse(&msg, addrs, &errcode); tt_int_op(errcode, OP_EQ, 0); /* no error reported; we got answers */ tt_int_op(r, OP_EQ, 0); tt_int_op(smartlist_len(addrs), OP_EQ, 3); @@ -1138,7 +989,7 @@ "\x20\x02\x90\x01\x00\x00\x00\x00" "\x00\x00\x00\x00\x00\xfa\xca\xde" "\x00\00\x00\x03"); - r = resolved_cell_parse(&cell, &rh, addrs, &errcode); + r = resolved_cell_parse(&msg, addrs, &errcode); tt_int_op(errcode, OP_EQ, 0); tt_int_op(r, OP_EQ, 0); tt_int_op(smartlist_len(addrs), OP_EQ, 5); @@ -1178,8 +1029,8 @@ "\x00\xe7" LONG_NAME2 "\x00\01\x00\x00"); - tt_int_op(rh.length, OP_EQ, RELAY_PAYLOAD_SIZE); - r = resolved_cell_parse(&cell, &rh, addrs, &errcode); + tt_int_op(msg.length, OP_EQ, RELAY_PAYLOAD_SIZE); + r = resolved_cell_parse(&msg, addrs, &errcode); tt_int_op(errcode, OP_EQ, 0); tt_int_op(r, OP_EQ, 0); tt_int_op(smartlist_len(addrs), OP_EQ, 2); @@ -1193,68 +1044,71 @@ /* Invalid length on an IPv4 */ SET_CELL("\x04\x03zzz1234"); - r = resolved_cell_parse(&cell, &rh, addrs, &errcode); + r = resolved_cell_parse(&msg, addrs, &errcode); tt_int_op(errcode, OP_EQ, 0); tt_int_op(r, OP_EQ, -1); tt_int_op(smartlist_len(addrs), OP_EQ, 0); SET_CELL("\x04\x04" "\x7f\x00\x02\x0a" "\x00\00\x01\x00" "\x04\x05zzzzz1234"); - r = resolved_cell_parse(&cell, &rh, addrs, &errcode); + r = resolved_cell_parse(&msg, addrs, &errcode); tt_int_op(errcode, OP_EQ, 0); tt_int_op(r, OP_EQ, -1); tt_int_op(smartlist_len(addrs), OP_EQ, 0); /* Invalid length on an IPv6 */ SET_CELL("\x06\x03zzz1234"); - r = resolved_cell_parse(&cell, &rh, addrs, &errcode); + r = resolved_cell_parse(&msg, addrs, &errcode); tt_int_op(errcode, OP_EQ, 0); tt_int_op(r, OP_EQ, -1); tt_int_op(smartlist_len(addrs), OP_EQ, 0); SET_CELL("\x04\x04" "\x7f\x00\x02\x0a" "\x00\00\x01\x00" "\x06\x17wwwwwwwwwwwwwwwww1234"); - r = resolved_cell_parse(&cell, &rh, addrs, &errcode); + r = resolved_cell_parse(&msg, addrs, &errcode); tt_int_op(errcode, OP_EQ, 0); tt_int_op(r, OP_EQ, -1); tt_int_op(smartlist_len(addrs), OP_EQ, 0); SET_CELL("\x04\x04" "\x7f\x00\x02\x0a" "\x00\00\x01\x00" "\x06\x10xxxx"); - r = resolved_cell_parse(&cell, &rh, addrs, &errcode); + r = resolved_cell_parse(&msg, addrs, &errcode); tt_int_op(errcode, OP_EQ, 0); tt_int_op(r, OP_EQ, -1); tt_int_op(smartlist_len(addrs), OP_EQ, 0); /* Empty hostname */ SET_CELL("\x00\x00xxxx"); - r = resolved_cell_parse(&cell, &rh, addrs, &errcode); + r = resolved_cell_parse(&msg, addrs, &errcode); tt_int_op(errcode, OP_EQ, 0); tt_int_op(r, OP_EQ, -1); tt_int_op(smartlist_len(addrs), OP_EQ, 0); +#if 0 + //No longer possible with relay message encoding. /* rh.length out of range */ CLEAR_CELL(); rh.length = 499; - r = resolved_cell_parse(&cell, &rh, addrs, &errcode); + r = resolved_cell_parse(&msg, addrs, &errcode); tt_int_op(errcode, OP_EQ, 0); tt_int_op(r, OP_EQ, -1); tt_int_op(smartlist_len(addrs), OP_EQ, 0); +#endif /* Item length extends beyond rh.length */ CLEAR_CELL(); SET_CELL("\x00\xff" LONG_NAME "\x00\01\x00\x00"); - rh.length -= 1; - r = resolved_cell_parse(&cell, &rh, addrs, &errcode); + msg.length -= 1; + r = resolved_cell_parse(&msg, addrs, &errcode); tt_int_op(r, OP_EQ, -1); tt_int_op(smartlist_len(addrs), OP_EQ, 0); - rh.length -= 5; - r = resolved_cell_parse(&cell, &rh, addrs, &errcode); + msg.length -= 5; + r = resolved_cell_parse(&msg, addrs, &errcode); tt_int_op(r, OP_EQ, -1); tt_int_op(smartlist_len(addrs), OP_EQ, 0); SET_CELL("\x04\x04" "\x7f\x00\x02\x0a" "\x00\00\x01\x00"); - rh.length -= 1; - r = resolved_cell_parse(&cell, &rh, addrs, &errcode); + msg.length -= 1; + r = resolved_cell_parse(&msg, addrs, &errcode); tt_int_op(r, OP_EQ, -1); tt_int_op(smartlist_len(addrs), OP_EQ, 0); @@ -1262,19 +1116,19 @@ "\x20\x02\x90\x01\x00\x00\x00\x00" "\x00\x00\x00\x00\x00\xfa\xca\xde" "\x00\00\x00\x03"); - rh.length -= 1; - r = resolved_cell_parse(&cell, &rh, addrs, &errcode); + msg.length -= 1; + r = resolved_cell_parse(&msg, addrs, &errcode); tt_int_op(r, OP_EQ, -1); tt_int_op(smartlist_len(addrs), OP_EQ, 0); /* Truncated item after first character */ SET_CELL("\x04"); - r = resolved_cell_parse(&cell, &rh, addrs, &errcode); + r = resolved_cell_parse(&msg, addrs, &errcode); tt_int_op(r, OP_EQ, -1); tt_int_op(smartlist_len(addrs), OP_EQ, 0); SET_CELL("\xee"); - r = resolved_cell_parse(&cell, &rh, addrs, &errcode); + r = resolved_cell_parse(&msg, addrs, &errcode); tt_int_op(r, OP_EQ, -1); tt_int_op(smartlist_len(addrs), OP_EQ, 0); @@ -1327,6 +1181,419 @@ tor_free(chan); } +static void +test_cfmt_relay_msg_encoding_simple(void *arg) +{ + (void)arg; + relay_msg_t *msg1 = NULL; + cell_t cell; + char *mem_op_hex_tmp = NULL; + int r; + uint8_t body[100]; + + /* Simple message: Data, fits easily in cell. */ + msg1 = tor_malloc_zero(sizeof(relay_msg_t)); + msg1->command = RELAY_COMMAND_DATA; + msg1->stream_id = 0x250; + msg1->length = 11; + msg1->body = body; + strlcpy((char*)body, "hello world", sizeof(body)); + + r = relay_msg_encode_cell(RELAY_CELL_FORMAT_V0, msg1, &cell); + tt_int_op(r, OP_EQ, 0); + tt_int_op(cell.command, OP_EQ, CELL_RELAY); + tt_int_op(cell.circ_id, OP_EQ, 0); + // command, recognized, streamid, digest, len, payload, zero-padding. + test_memeq_hex(cell.payload, + "02" "0000" "0250" "00000000" "000B" + "68656c6c6f20776f726c64" "00000000"); + // random padding + size_t used = RELAY_HEADER_SIZE_V0 + 11 + 4; + tt_assert(!fast_mem_is_zero((char*)cell.payload + used, + CELL_PAYLOAD_SIZE - used)); + + r = relay_msg_encode_cell(RELAY_CELL_FORMAT_V1, msg1, &cell); + tt_int_op(r, OP_EQ, 0); + tt_int_op(cell.command, OP_EQ, CELL_RELAY); + tt_int_op(cell.circ_id, OP_EQ, 0); + // tag, command, len, optional streamid, payload, zero-padding + test_memeq_hex(cell.payload, + "00000000000000000000000000000000" + "02" "000B" "0250" + "68656c6c6f20776f726c64" "00000000"); + // random padding. + used = RELAY_HEADER_SIZE_V1_WITH_STREAM_ID + 11 + 4; + tt_assert(!fast_mem_is_zero((char*)cell.payload + used, + CELL_PAYLOAD_SIZE - used)); + + /* Message without stream ID: SENDME, fits easily in cell. */ + relay_msg_clear(msg1); + msg1->command = RELAY_COMMAND_SENDME; + msg1->stream_id = 0; + msg1->length = 20; + msg1->body = body; + strlcpy((char *)body, "hello i am a tag....", sizeof(body)); + + r = relay_msg_encode_cell(RELAY_CELL_FORMAT_V0, msg1, &cell); + tt_int_op(r, OP_EQ, 0); + tt_int_op(cell.command, OP_EQ, CELL_RELAY); + tt_int_op(cell.circ_id, OP_EQ, 0); + // command, recognized, streamid, digest, len, payload, zero-padding. + test_memeq_hex(cell.payload, + "05" "0000" "0000" "00000000" "0014" + "68656c6c6f206920616d2061207461672e2e2e2e" "00000000"); + // random padding + used = RELAY_HEADER_SIZE_V0 + 20 + 4; + tt_assert(!fast_mem_is_zero((char*)cell.payload + used, + CELL_PAYLOAD_SIZE - used)); + + r = relay_msg_encode_cell(RELAY_CELL_FORMAT_V1, msg1, &cell); + tt_int_op(r, OP_EQ, 0); + tt_int_op(cell.command, OP_EQ, CELL_RELAY); + tt_int_op(cell.circ_id, OP_EQ, 0); + // tag, command, len, optional streamid, payload, zero-padding + test_memeq_hex(cell.payload, + "00000000000000000000000000000000" + "05" "0014" + "68656c6c6f206920616d2061207461672e2e2e2e" "00000000"); + // random padding. + used = RELAY_HEADER_SIZE_V1_NO_STREAM_ID + 20 + 4; + tt_assert(!fast_mem_is_zero((char*)cell.payload + used, + CELL_PAYLOAD_SIZE - used)); + + done: + relay_msg_free(msg1); + tor_free(mem_op_hex_tmp); +} + +/** Helper for test_cfmt_relay_cell_padding. + * Requires that that the body of 'msg' ends with 'pre_padding_byte', + * and that when encoded, the zero-padding (if any) will appear at + * offset 'zeros_begin_at' in the message. + */ +static void +msg_encoder_padding_test(const relay_msg_t *msg, + relay_cell_fmt_t fmt, + uint8_t pre_padding_byte, + size_t zeros_begin_at) +{ + cell_t cell; + int n = 16, i; + /* We set this to 0 as soon as we find that the first byte of + * random padding has been set. */ + bool padded_first = false; + /* We set this to true as soon as we find that the last byte of + * random padding has been set */ + bool padded_last = false; + + tt_int_op(zeros_begin_at, OP_LE, CELL_PAYLOAD_SIZE); + + size_t expect_n_zeros = MIN(4, CELL_PAYLOAD_SIZE - zeros_begin_at); + ssize_t first_random_at = -1; + if (CELL_PAYLOAD_SIZE - zeros_begin_at > 4) { + first_random_at = CELL_PAYLOAD_SIZE - zeros_begin_at + 4; + } + + for (i = 0; i < n; ++i) { + memset(&cell, 0, sizeof(cell)); + tt_int_op(0, OP_EQ, + relay_msg_encode_cell(fmt, msg, &cell)); + + const uint8_t *body = cell.payload; + tt_int_op(body[zeros_begin_at - 1], OP_EQ, pre_padding_byte); + + if (expect_n_zeros) { + tt_assert(fast_mem_is_zero((char*)body + zeros_begin_at, + expect_n_zeros)); + } + if (first_random_at >= 0) { + if (body[first_random_at]) + padded_first = true; + if (body[CELL_PAYLOAD_SIZE-1]) + padded_last = true; + } + } + + if (first_random_at >= 0) { + tt_assert(padded_first); + tt_assert(padded_last); + } + + done: + ; +} + +static void +test_cfmt_relay_cell_padding(void *arg) +{ + (void)arg; + relay_msg_t *msg1 = NULL; + uint8_t buf[500]; // Longer than it needs to be. + memset(buf, 0xff, sizeof(buf)); + + /* Simple message; we'll adjust the length and encode it. */ + msg1 = tor_malloc_zero(sizeof(relay_msg_t)); + msg1->command = RELAY_COMMAND_DATA; + msg1->stream_id = 0x250; + msg1->body = buf; + + // Empty message + msg1->length = 0; + msg_encoder_padding_test(msg1, RELAY_CELL_FORMAT_V0, 0x00, + RELAY_HEADER_SIZE_V0); + msg_encoder_padding_test(msg1, RELAY_CELL_FORMAT_V1, 0x50, + RELAY_HEADER_SIZE_V1_WITH_STREAM_ID); + + // Short message + msg1->length = 10; + msg_encoder_padding_test(msg1, RELAY_CELL_FORMAT_V0, 0xff, + RELAY_HEADER_SIZE_V0 + 10); + msg_encoder_padding_test(msg1, RELAY_CELL_FORMAT_V1, 0xff, + RELAY_HEADER_SIZE_V1_WITH_STREAM_ID + 10); + + // Message where zeros extend exactly up to the end of the cell. + msg1->length = CELL_PAYLOAD_SIZE - RELAY_HEADER_SIZE_V0 - 4; + msg_encoder_padding_test(msg1, RELAY_CELL_FORMAT_V0, 0xff, + RELAY_HEADER_SIZE_V0 + msg1->length); + msg1->length = CELL_PAYLOAD_SIZE - RELAY_HEADER_SIZE_V1_WITH_STREAM_ID - 4; + msg_encoder_padding_test(msg1, RELAY_CELL_FORMAT_V1, 0xff, + RELAY_HEADER_SIZE_V1_WITH_STREAM_ID + msg1->length); + + // Message where zeros would intersect with the end of the cell. + msg1->length = CELL_PAYLOAD_SIZE - RELAY_HEADER_SIZE_V0 - 3; + msg_encoder_padding_test(msg1, RELAY_CELL_FORMAT_V0, 0xff, + RELAY_HEADER_SIZE_V0 + msg1->length); + msg1->length = CELL_PAYLOAD_SIZE - RELAY_HEADER_SIZE_V1_WITH_STREAM_ID - 3; + msg_encoder_padding_test(msg1, RELAY_CELL_FORMAT_V1, 0xff, + RELAY_HEADER_SIZE_V1_WITH_STREAM_ID + msg1->length); + + // Message with no room for zeros + msg1->length = CELL_PAYLOAD_SIZE - RELAY_HEADER_SIZE_V0; + msg_encoder_padding_test(msg1, RELAY_CELL_FORMAT_V0, 0xff, + RELAY_HEADER_SIZE_V0 + msg1->length); + msg1->length = CELL_PAYLOAD_SIZE - RELAY_HEADER_SIZE_V1_WITH_STREAM_ID; + msg_encoder_padding_test(msg1, RELAY_CELL_FORMAT_V1, 0xff, + RELAY_HEADER_SIZE_V1_WITH_STREAM_ID + msg1->length); + + /////////////// + // V1 cases with no stream ID. + msg1->stream_id = 0; + msg1->command = RELAY_COMMAND_EXTENDED; + + msg1->length = 0; + msg_encoder_padding_test(msg1, RELAY_CELL_FORMAT_V1, 0x00, + RELAY_HEADER_SIZE_V1_NO_STREAM_ID); + msg1->length = 10; + msg_encoder_padding_test(msg1, RELAY_CELL_FORMAT_V1, 0xff, + RELAY_HEADER_SIZE_V1_NO_STREAM_ID + 10); + msg1->length = CELL_PAYLOAD_SIZE - RELAY_HEADER_SIZE_V1_NO_STREAM_ID - 4; + msg_encoder_padding_test(msg1, RELAY_CELL_FORMAT_V1, 0xff, + RELAY_HEADER_SIZE_V1_NO_STREAM_ID + msg1->length); + msg1->length = CELL_PAYLOAD_SIZE - RELAY_HEADER_SIZE_V1_NO_STREAM_ID - 3; + msg_encoder_padding_test(msg1, RELAY_CELL_FORMAT_V1, 0xff, + RELAY_HEADER_SIZE_V1_NO_STREAM_ID + msg1->length); + msg1->length = CELL_PAYLOAD_SIZE - RELAY_HEADER_SIZE_V1_NO_STREAM_ID; + msg_encoder_padding_test(msg1, RELAY_CELL_FORMAT_V1, 0xff, + RELAY_HEADER_SIZE_V1_NO_STREAM_ID + msg1->length); + + relay_msg_free(msg1); +} + +static void +test_cfmt_relay_msg_encoding_error(void *arg) +{ + (void)arg; +#ifdef ALL_BUGS_ARE_FATAL + // This test triggers many nonfatal assertions. + tt_skip(); + done: + ; +#else + relay_msg_t *msg1 = NULL; + int r; + cell_t cell; + uint8_t buf[500]; // Longer than it needs to be. + memset(buf, 0xff, sizeof(buf)); + + msg1 = tor_malloc_zero(sizeof(relay_msg_t)); + msg1->command = RELAY_COMMAND_DATA; + msg1->stream_id = 0x250; + msg1->body = buf; + + tor_capture_bugs_(5); + // Too long for v0. + msg1->length = CELL_PAYLOAD_SIZE - RELAY_HEADER_SIZE_V0 + 1; + r = relay_msg_encode_cell(RELAY_CELL_FORMAT_V0, msg1, &cell); + tt_int_op(r, OP_EQ, -1); + + // Too long for v1, with stream ID. + msg1->length = CELL_PAYLOAD_SIZE - RELAY_HEADER_SIZE_V1_WITH_STREAM_ID + 1; + r = relay_msg_encode_cell(RELAY_CELL_FORMAT_V1, msg1, &cell); + tt_int_op(r, OP_EQ, -1); + + // Too long for v1 with no stream ID. + msg1->command = RELAY_COMMAND_EXTENDED; + msg1->stream_id = 0; + msg1->length = CELL_PAYLOAD_SIZE - RELAY_HEADER_SIZE_V1_NO_STREAM_ID + 1; + r = relay_msg_encode_cell(RELAY_CELL_FORMAT_V1, msg1, &cell); + tt_int_op(r, OP_EQ, -1); + + // Invalid (present) stream ID for V1. + msg1->stream_id = 10; + msg1->length = 20; + r = relay_msg_encode_cell(RELAY_CELL_FORMAT_V1, msg1, &cell); + tt_int_op(r, OP_EQ, -1); + + // Invalid (absent) stream ID for V1. + msg1->stream_id = 0; + msg1->command = RELAY_COMMAND_DATA; + r = relay_msg_encode_cell(RELAY_CELL_FORMAT_V1, msg1, &cell); + tt_int_op(r, OP_EQ, -1); + + done: + tor_end_capture_bugs_(); + relay_msg_free(msg1); +#endif +} + +static void +test_cfmt_relay_msg_decoding_simple(void *arg) +{ + (void) arg; + cell_t cell; + relay_msg_t *msg1 = NULL; + const char *s; + + memset(&cell, 0, sizeof(cell)); + cell.command = CELL_RELAY; + + // V0 decoding, short message. + s = "02" "0000" "0250" "00000000" "000B" + "68656c6c6f20776f726c64" "00000000"; + base16_decode((char*)cell.payload, sizeof(cell.payload), s, strlen(s)); + msg1 = relay_msg_decode_cell(RELAY_CELL_FORMAT_V0, &cell); + tt_assert(msg1); + + tt_int_op(msg1->command, OP_EQ, RELAY_COMMAND_DATA); + tt_int_op(msg1->stream_id, OP_EQ, 0x250); + tt_int_op(msg1->length, OP_EQ, 11); + tt_mem_op(msg1->body, OP_EQ, "hello world", 11); + relay_msg_free(msg1); + + // V0 decoding, message up to length of cell. + memset(cell.payload, 0, sizeof(cell.payload)); + s = "02" "0000" "0250" "00000000" "01F2"; + base16_decode((char*)cell.payload, sizeof(cell.payload), s, strlen(s)); + msg1 = relay_msg_decode_cell(RELAY_CELL_FORMAT_V0, &cell); + tt_assert(msg1); + + tt_int_op(msg1->command, OP_EQ, RELAY_COMMAND_DATA); + tt_int_op(msg1->stream_id, OP_EQ, 0x250); + tt_int_op(msg1->length, OP_EQ, 498); + tt_assert(fast_mem_is_zero((char*)msg1->body, 498)); + relay_msg_free(msg1); + + // V1 decoding, short message, no stream ID. + s = "00000000000000000000000000000000" + "05" "0014" + "68656c6c6f206920616d2061207461672e2e2e2e" "00000000"; + base16_decode((char*)cell.payload, sizeof(cell.payload), s, strlen(s)); + + msg1 = relay_msg_decode_cell(RELAY_CELL_FORMAT_V1, &cell); + tt_assert(msg1); + tt_int_op(msg1->command, OP_EQ, RELAY_COMMAND_SENDME); + tt_int_op(msg1->stream_id, OP_EQ, 0); + tt_int_op(msg1->length, OP_EQ, 20); + tt_mem_op(msg1->body, OP_EQ, "hello i am a tag....", 20); + relay_msg_free(msg1); + + // V1 decoding, up to length of cell, no stream ID. + memset(cell.payload, 0, sizeof(cell.payload)); + s = "00000000000000000000000000000000" + "05" "01EA"; + base16_decode((char*)cell.payload, sizeof(cell.payload), s, strlen(s)); + + msg1 = relay_msg_decode_cell(RELAY_CELL_FORMAT_V1, &cell); + tt_assert(msg1); + tt_int_op(msg1->command, OP_EQ, RELAY_COMMAND_SENDME); + tt_int_op(msg1->stream_id, OP_EQ, 0); + tt_int_op(msg1->length, OP_EQ, 490); + tt_assert(fast_mem_is_zero((char*)msg1->body, 490)); + relay_msg_free(msg1); + + // V1 decoding, short message, with stream ID. + s = "00000000000000000000000000000000" + "02" "000B" "0250" + "68656c6c6f20776f726c64" "00000000"; + base16_decode((char*)cell.payload, sizeof(cell.payload), s, strlen(s)); + + msg1 = relay_msg_decode_cell(RELAY_CELL_FORMAT_V1, &cell); + tt_assert(msg1); + tt_int_op(msg1->command, OP_EQ, RELAY_COMMAND_DATA); + tt_int_op(msg1->stream_id, OP_EQ, 0x250); + tt_int_op(msg1->length, OP_EQ, 11); + tt_mem_op(msg1->body, OP_EQ, "hello world", 11); + relay_msg_free(msg1); + + // V1 decoding, up to length of cell, with stream ID. + memset(cell.payload, 0, sizeof(cell.payload)); + s = "00000000000000000000000000000000" + "02" "01E8" "0250"; + base16_decode((char*)cell.payload, sizeof(cell.payload), s, strlen(s)); + + msg1 = relay_msg_decode_cell(RELAY_CELL_FORMAT_V1, &cell); + tt_assert(msg1); + tt_int_op(msg1->command, OP_EQ, RELAY_COMMAND_DATA); + tt_int_op(msg1->stream_id, OP_EQ, 0x250); + tt_int_op(msg1->length, OP_EQ, 488); + tt_assert(fast_mem_is_zero((char*)msg1->body, 488)); + relay_msg_free(msg1); + + done: + relay_msg_free(msg1); +} + +static void +test_cfmt_relay_msg_decoding_error(void *arg) +{ + (void) arg; + relay_msg_t *msg1 = NULL; + cell_t cell; + const char *s; + memset(&cell, 0, sizeof(cell)); + + // V0, too long. + cell.command = CELL_RELAY; + s = "02" "0000" "0250" "00000000" "01F3"; + base16_decode((char*)cell.payload, sizeof(cell.payload), s, strlen(s)); + msg1 = relay_msg_decode_cell(RELAY_CELL_FORMAT_V0, &cell); + tt_ptr_op(msg1, OP_EQ, NULL); + + // V1, command unrecognized. + s = "00000000000000000000000000000000" + "F0" "000C" "0250"; + base16_decode((char*)cell.payload, sizeof(cell.payload), s, strlen(s)); + msg1 = relay_msg_decode_cell(RELAY_CELL_FORMAT_V1, &cell); + tt_ptr_op(msg1, OP_EQ, NULL); + + // V1, too long (with stream ID) + s = "00000000000000000000000000000000" + "02" "01E9" "0250"; + base16_decode((char*)cell.payload, sizeof(cell.payload), s, strlen(s)); + msg1 = relay_msg_decode_cell(RELAY_CELL_FORMAT_V1, &cell); + tt_ptr_op(msg1, OP_EQ, NULL); + + // V1, too long (without stream ID) + s = "00000000000000000000000000000000" + "05" "01EB"; + base16_decode((char*)cell.payload, sizeof(cell.payload), s, strlen(s)); + msg1 = relay_msg_decode_cell(RELAY_CELL_FORMAT_V1, &cell); + tt_ptr_op(msg1, OP_EQ, NULL); + + done: + relay_msg_free(msg1); +} + #define TEST(name, flags) \ { #name, test_cfmt_ ## name, flags, 0, NULL } @@ -1340,5 +1607,10 @@ TEST(extended_cells, 0), TEST(resolved_cells, 0), TEST(is_destroy, 0), + TEST(relay_msg_encoding_simple, 0), + TEST(relay_cell_padding, 0), + TEST(relay_msg_encoding_error, 0), + TEST(relay_msg_decoding_simple, 0), + TEST(relay_msg_decoding_error, 0), END_OF_TESTCASES }; diff -Nru tor-0.4.7.16/src/test/test_channel.c tor-0.4.9.6/src/test/test_channel.c --- tor-0.4.7.16/src/test/test_channel.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/test/test_channel.c 2026-03-25 14:30:34.000000000 +0000 @@ -1264,8 +1264,9 @@ /* Try a flat call with channel nor connections. */ channel_check_for_duplicates(); expect_log_msg_containing( - "Found 0 connections to 0 relays. Found 0 current canonical " - "connections, in 0 of which we were a non-canonical peer. " + "Found 0 connections to authorities, 0 connections to 0 relays. " + "Found 0 current canonical connections, " + "in 0 of which we were a non-canonical peer. " "0 relays had more than 1 connection, 0 had more than 2, and " "0 had more than 4 connections."); @@ -1285,8 +1286,9 @@ /* No relay has been associated with this channel. */ channel_check_for_duplicates(); expect_log_msg_containing( - "Found 0 connections to 0 relays. Found 0 current canonical " - "connections, in 0 of which we were a non-canonical peer. " + "Found 0 connections to authorities, 0 connections to 0 relays. " + "Found 0 current canonical connections, " + "in 0 of which we were a non-canonical peer. " "0 relays had more than 1 connection, 0 had more than 2, and " "0 had more than 4 connections."); @@ -1299,24 +1301,27 @@ chan->state = CHANNEL_STATE_CLOSING; channel_check_for_duplicates(); expect_log_msg_containing( - "Found 0 connections to 0 relays. Found 0 current canonical " - "connections, in 0 of which we were a non-canonical peer. " + "Found 0 connections to authorities, 0 connections to 0 relays. " + "Found 0 current canonical connections, " + "in 0 of which we were a non-canonical peer. " "0 relays had more than 1 connection, 0 had more than 2, and " "0 had more than 4 connections."); chan->state = CHANNEL_STATE_OPEN; channel_check_for_duplicates(); expect_log_msg_containing( - "Found 1 connections to 1 relays. Found 0 current canonical " - "connections, in 0 of which we were a non-canonical peer. " + "Found 0 connections to authorities, 1 connections to 1 relays. " + "Found 0 current canonical connections, " + "in 0 of which we were a non-canonical peer. " "0 relays had more than 1 connection, 0 had more than 2, and " "0 had more than 4 connections."); test_chan_should_be_canonical = 1; channel_check_for_duplicates(); expect_log_msg_containing( - "Found 1 connections to 1 relays. Found 1 current canonical " - "connections, in 1 of which we were a non-canonical peer. " + "Found 0 connections to authorities, 1 connections to 1 relays. " + "Found 1 current canonical connections, " + "in 1 of which we were a non-canonical peer. " "0 relays had more than 1 connection, 0 had more than 2, and " "0 had more than 4 connections."); teardown_capture_of_logs(); diff -Nru tor-0.4.7.16/src/test/test_channelpadding.c tor-0.4.9.6/src/test/test_channelpadding.c --- tor-0.4.7.16/src/test/test_channelpadding.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/test/test_channelpadding.c 2026-03-25 14:30:34.000000000 +0000 @@ -862,7 +862,7 @@ * 2. Channel that has not "sent a packet" before the timeout: * 2a. Not within 1.1s of the timeout. * + We should decide to pad later - * 2b. Within 1.1s of the timemout. + * 2b. Within 1.1s of the timeout. * + We should schedule padding * + We should get feedback that we wrote a cell * 2c. Within 0.1s of the timeout. diff -Nru tor-0.4.7.16/src/test/test_circuitbuild.c tor-0.4.9.6/src/test/test_circuitbuild.c --- tor-0.4.7.16/src/test/test_circuitbuild.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/test/test_circuitbuild.c 2026-03-25 14:30:34.000000000 +0000 @@ -21,6 +21,7 @@ #include "core/or/circuitlist.h" #include "core/or/circuituse.h" #include "core/or/onion.h" +#include "core/or/relay_msg.h" #include "core/or/cell_st.h" #include "core/or/cpath_build_state_st.h" @@ -1278,7 +1279,7 @@ test_circuit_extend(void *arg) { (void)arg; - cell_t *cell = tor_malloc_zero(sizeof(cell_t)); + relay_msg_t *msg = tor_malloc_zero(sizeof(relay_msg_t)); channel_t *p_chan = tor_malloc_zero(sizeof(channel_t)); or_circuit_t *or_circ = tor_malloc_zero(sizeof(or_circuit_t)); circuit_t *circ = TO_CIRCUIT(or_circ); @@ -1293,10 +1294,14 @@ setup_full_capture_of_logs(LOG_INFO); + msg->command = RELAY_COMMAND_EXTEND2; + NONSTRING uint8_t body[3] = "xyz"; + msg->body = body; + #ifndef ALL_BUGS_ARE_FATAL /* Circuit must be non-NULL */ tor_capture_bugs_(1); - tt_int_op(circuit_extend(cell, NULL), OP_EQ, -1); + tt_int_op(circuit_extend(msg, NULL), OP_EQ, -1); tt_int_op(smartlist_len(tor_get_captured_bug_log_()), OP_EQ, 1); tt_str_op(smartlist_get(tor_get_captured_bug_log_(), 0), OP_EQ, "!(ASSERT_PREDICT_UNLIKELY_(!circ))"); @@ -1308,7 +1313,7 @@ tt_int_op(circuit_extend(NULL, circ), OP_EQ, -1); tt_int_op(smartlist_len(tor_get_captured_bug_log_()), OP_EQ, 1); tt_str_op(smartlist_get(tor_get_captured_bug_log_(), 0), OP_EQ, - "!(ASSERT_PREDICT_UNLIKELY_(!cell))"); + "!(ASSERT_PREDICT_UNLIKELY_(!rmsg))"); tor_end_capture_bugs_(); mock_clean_saved_logs(); @@ -1324,13 +1329,13 @@ /* Clients can't extend */ server = 0; - tt_int_op(circuit_extend(cell, circ), OP_EQ, -1); + tt_int_op(circuit_extend(msg, circ), OP_EQ, -1); expect_log_msg("Got an extend cell, but running as a client. Closing.\n"); mock_clean_saved_logs(); /* But servers can. Unpack the cell, but fail parsing. */ server = 1; - tt_int_op(circuit_extend(cell, circ), OP_EQ, -1); + tt_int_op(circuit_extend(msg, circ), OP_EQ, -1); expect_log_msg("Can't parse extend cell. Closing circuit.\n"); mock_clean_saved_logs(); @@ -1343,7 +1348,7 @@ mock_extend_cell_parse_result = 0; mock_extend_cell_parse_calls = 0; - tt_int_op(circuit_extend(cell, circ), OP_EQ, -1); + tt_int_op(circuit_extend(msg, circ), OP_EQ, -1); tt_int_op(mock_extend_cell_parse_calls, OP_EQ, 1); expect_log_msg( "Client asked me to extend without specifying an id_digest.\n"); @@ -1354,7 +1359,7 @@ memset(&mock_extend_cell_parse_cell_out.node_id, 0xAA, sizeof(mock_extend_cell_parse_cell_out.node_id)); - tt_int_op(circuit_extend(cell, circ), OP_EQ, -1); + tt_int_op(circuit_extend(msg, circ), OP_EQ, -1); tt_int_op(mock_extend_cell_parse_calls, OP_EQ, 1); expect_log_msg("Client asked me to extend to a zero destination port " "or unspecified address '[scrubbed]'.\n"); @@ -1368,7 +1373,7 @@ #ifndef ALL_BUGS_ARE_FATAL tor_capture_bugs_(1); - tt_int_op(circuit_extend(cell, circ), OP_EQ, -1); + tt_int_op(circuit_extend(msg, circ), OP_EQ, -1); tt_int_op(mock_extend_cell_parse_calls, OP_EQ, 1); tt_int_op(smartlist_len(tor_get_captured_bug_log_()), OP_EQ, 1); tt_str_op(smartlist_get(tor_get_captured_bug_log_(), 0), OP_EQ, @@ -1389,7 +1394,7 @@ /* Test circuit not established, but don't launch another one */ mock_channel_get_for_extend_launch_out = 0; mock_channel_get_for_extend_nchan = NULL; - tt_int_op(circuit_extend(cell, circ), OP_EQ, 0); + tt_int_op(circuit_extend(msg, circ), OP_EQ, 0); tt_int_op(mock_extend_cell_parse_calls, OP_EQ, 1); tt_int_op(mock_channel_get_for_extend_calls, OP_EQ, 1); @@ -1409,7 +1414,7 @@ mock_channel_get_for_extend_launch_out = 1; mock_channel_get_for_extend_nchan = NULL; mock_channel_connect_nchan = fake_n_chan; - tt_int_op(circuit_extend(cell, circ), OP_EQ, 0); + tt_int_op(circuit_extend(msg, circ), OP_EQ, 0); tt_int_op(mock_extend_cell_parse_calls, OP_EQ, 1); tt_int_op(mock_channel_get_for_extend_calls, OP_EQ, 1); tt_int_op(mock_channel_connect_calls, OP_EQ, 1); @@ -1433,7 +1438,7 @@ mock_channel_get_for_extend_nchan = fake_n_chan; mock_channel_connect_nchan = NULL; mock_circuit_deliver_create_cell_result = 0; - tt_int_op(circuit_extend(cell, circ), OP_EQ, 0); + tt_int_op(circuit_extend(msg, circ), OP_EQ, 0); tt_int_op(mock_extend_cell_parse_calls, OP_EQ, 1); tt_int_op(mock_channel_get_for_extend_calls, OP_EQ, 1); tt_int_op(mock_channel_connect_calls, OP_EQ, 0); @@ -1456,7 +1461,7 @@ mock_channel_get_for_extend_nchan = fake_n_chan; mock_channel_connect_nchan = NULL; mock_circuit_deliver_create_cell_result = -1; - tt_int_op(circuit_extend(cell, circ), OP_EQ, -1); + tt_int_op(circuit_extend(msg, circ), OP_EQ, -1); tt_int_op(mock_extend_cell_parse_calls, OP_EQ, 1); tt_int_op(mock_channel_get_for_extend_calls, OP_EQ, 1); tt_int_op(mock_channel_connect_calls, OP_EQ, 0); @@ -1502,7 +1507,7 @@ mock_circuit_deliver_create_cell_calls = 0; mock_circuit_deliver_create_cell_result = 0; - tor_free(cell); + relay_msg_free(msg); /* circ and or_circ are the same object */ tor_free(circ->n_hop); tor_free(circ->n_chan_create_cell); @@ -1527,6 +1532,7 @@ /* Circuit must be non-NULL */ tor_capture_bugs_(1); tt_int_op(onionskin_answer(NULL, created_cell, + RELAY_CRYPTO_ALG_TOR1, keys, CPATH_KEY_MATERIAL_LEN, rend_circ_nonce), OP_EQ, -1); tt_int_op(smartlist_len(tor_get_captured_bug_log_()), OP_EQ, 1); @@ -1538,6 +1544,7 @@ /* Created cell must be non-NULL */ tor_capture_bugs_(1); tt_int_op(onionskin_answer(or_circ, NULL, + RELAY_CRYPTO_ALG_TOR1, keys, CPATH_KEY_MATERIAL_LEN, rend_circ_nonce), OP_EQ, -1); tt_int_op(smartlist_len(tor_get_captured_bug_log_()), OP_EQ, 1); @@ -1549,6 +1556,7 @@ /* Keys must be non-NULL */ tor_capture_bugs_(1); tt_int_op(onionskin_answer(or_circ, created_cell, + RELAY_CRYPTO_ALG_TOR1, NULL, CPATH_KEY_MATERIAL_LEN, rend_circ_nonce), OP_EQ, -1); tt_int_op(smartlist_len(tor_get_captured_bug_log_()), OP_EQ, 1); @@ -1560,6 +1568,7 @@ /* The rend circuit nonce must be non-NULL */ tor_capture_bugs_(1); tt_int_op(onionskin_answer(or_circ, created_cell, + RELAY_CRYPTO_ALG_TOR1, keys, CPATH_KEY_MATERIAL_LEN, NULL), OP_EQ, -1); tt_int_op(smartlist_len(tor_get_captured_bug_log_()), OP_EQ, 1); @@ -1574,6 +1583,7 @@ /* Fail when formatting the created cell */ tt_int_op(onionskin_answer(or_circ, created_cell, + RELAY_CRYPTO_ALG_TOR1, keys, CPATH_KEY_MATERIAL_LEN, rend_circ_nonce), OP_EQ, -1); expect_log_msg("couldn't format created cell (type=0, len=0).\n"); diff -Nru tor-0.4.7.16/src/test/test_circuitlist.c tor-0.4.9.6/src/test/test_circuitlist.c --- tor-0.4.7.16/src/test/test_circuitlist.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/test/test_circuitlist.c 2026-03-25 14:30:34.000000000 +0000 @@ -187,9 +187,9 @@ { or_circuit_t *c1, *c2, *c3, *c4; origin_circuit_t *c5; - const uint8_t tok1[REND_TOKEN_LEN] = "The cat can't tell y"; - const uint8_t tok2[REND_TOKEN_LEN] = "ou its name, and it "; - const uint8_t tok3[REND_TOKEN_LEN] = "doesn't really care."; + NONSTRING const uint8_t tok1[REND_TOKEN_LEN] = "The cat can't tell y"; + NONSTRING const uint8_t tok2[REND_TOKEN_LEN] = "ou its name, and it "; + NONSTRING const uint8_t tok3[REND_TOKEN_LEN] = "doesn't really care."; /* -- Adapted from a quote by Fredrik Lundh. */ (void)arg; @@ -420,7 +420,7 @@ ed25519_public_key_t intro_pk2 = { {2} }; /* Junk, not important. */ { - const uint8_t tok1[REND_TOKEN_LEN] = "bet i got some of th"; + NONSTRING const uint8_t tok1[REND_TOKEN_LEN] = "bet i got some of th"; circ1 = or_circuit_new(0, NULL); tt_assert(circ1); @@ -442,7 +442,7 @@ } { - const uint8_t tok2[REND_TOKEN_LEN] = "you dont know anythi"; + NONSTRING const uint8_t tok2[REND_TOKEN_LEN] = "you dont know anythi"; circ2 = origin_circuit_new(); tt_assert(circ2); diff -Nru tor-0.4.7.16/src/test/test_circuitpadding.c tor-0.4.9.6/src/test/test_circuitpadding.c --- tor-0.4.7.16/src/test/test_circuitpadding.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/test/test_circuitpadding.c 2026-03-25 14:30:34.000000000 +0000 @@ -24,6 +24,7 @@ #include "core/or/circuitpadding.h" #include "core/or/circuitpadding_machines.h" #include "core/or/extendinfo.h" +#include "core/or/relay_msg.h" #include "core/mainloop/netstatus.h" #include "core/crypto/relay_crypto.h" #include "core/or/protover.h" @@ -172,11 +173,16 @@ const char *filename, int lineno) { (void)cell; (void)on_stream; (void)filename; (void)lineno; + relay_msg_t *msg = NULL; + + msg = relay_msg_decode_cell(RELAY_CELL_FORMAT_V0, cell); + if (! msg) + goto done; if (circ == client_side) { if (cell->payload[0] == RELAY_COMMAND_PADDING_NEGOTIATE) { // Deliver to relay - circpad_handle_padding_negotiate(relay_side, cell); + circpad_handle_padding_negotiate(relay_side, msg); } else { int is_target_hop = circpad_padding_is_from_expected_hop(circ, @@ -190,7 +196,7 @@ // Receive padding cell at middle circpad_deliver_recognized_relay_cell_events(relay_side, - cell->payload[0], NULL); + msg->command, NULL); } n_client_cells++; } else if (circ == relay_side) { @@ -199,11 +205,11 @@ if (cell->payload[0] == RELAY_COMMAND_PADDING_NEGOTIATED) { // XXX: blah need right layer_hint.. if (deliver_negotiated) - circpad_handle_padding_negotiated(client_side, cell, + circpad_handle_padding_negotiated(client_side, msg, TO_ORIGIN_CIRCUIT(client_side) ->cpath->next); } else if (cell->payload[0] == RELAY_COMMAND_PADDING_NEGOTIATE) { - circpad_handle_padding_negotiate(client_side, cell); + circpad_handle_padding_negotiate(client_side, msg); } else { // No need to pretend a padding cell was sent: This event is // now emitted internally when the circuitpadding code sends them. @@ -211,7 +217,7 @@ // Receive padding cell at client circpad_deliver_recognized_relay_cell_events(client_side, - cell->payload[0], + msg->command, TO_ORIGIN_CIRCUIT(client_side)->cpath->next); } @@ -219,6 +225,7 @@ } done: + relay_msg_free(msg); timers_advance_and_run(1); return 0; } @@ -1251,7 +1258,7 @@ */ (void)arg; uint32_t read_bw = 0, overhead_bw = 0; - cell_t cell; + relay_msg_t msg; signed_error_t ret; origin_circuit_t *orig_client; int64_t actual_mocked_monotime_start; @@ -1331,17 +1338,21 @@ orig_client->n_overhead_read_circ_bw); /* 2. Test padding negotiated not handled from hops 1,3 */ - ret = circpad_handle_padding_negotiated(client_side, &cell, + memset(&msg, 0, sizeof(msg)); + ret = circpad_handle_padding_negotiated(client_side, &msg, TO_ORIGIN_CIRCUIT(client_side)->cpath); tt_int_op(ret, OP_EQ, -1); - ret = circpad_handle_padding_negotiated(client_side, &cell, + ret = circpad_handle_padding_negotiated(client_side, &msg, TO_ORIGIN_CIRCUIT(client_side)->cpath->next->next); tt_int_op(ret, OP_EQ, -1); /* 3. Garbled negotiated cell */ - memset(&cell, 255, sizeof(cell)); - ret = circpad_handle_padding_negotiated(client_side, &cell, + memset(&msg, 0, sizeof(msg)); + uint8_t buf[99]; + memset(buf, 0xff, 99); + msg.body = buf; + ret = circpad_handle_padding_negotiated(client_side, &msg, TO_ORIGIN_CIRCUIT(client_side)->cpath->next); tt_int_op(ret, OP_EQ, -1); @@ -1350,7 +1361,7 @@ overhead_bw = orig_client->n_overhead_read_circ_bw; relay_send_command_from_edge(0, relay_side, RELAY_COMMAND_PADDING_NEGOTIATE, - (void*)cell.payload, + "xyz", (size_t)3, NULL); tt_int_op(read_bw, OP_EQ, orig_client->n_delivered_read_circ_bw); @@ -1371,12 +1382,12 @@ tt_int_op(n_client_cells, OP_EQ, 2); /* 6. Sending negotiated command to relay does nothing */ - ret = circpad_handle_padding_negotiated(relay_side, &cell, NULL); + ret = circpad_handle_padding_negotiated(relay_side, &msg, NULL); tt_int_op(ret, OP_EQ, -1); /* 7. Test garbled negotiated cell (bad command 255) */ - memset(&cell, 0, sizeof(cell)); - ret = circpad_handle_padding_negotiate(relay_side, &cell); + relay_msg_clear(&msg); + ret = circpad_handle_padding_negotiate(relay_side, &msg); tt_int_op(ret, OP_EQ, -1); tt_int_op(n_client_cells, OP_EQ, 2); @@ -1434,6 +1445,7 @@ UNMOCK(circuitmux_attach_circuit); nodes_free(); testing_disable_reproducible_rng(); + relay_msg_clear(&msg); } void @@ -1576,7 +1588,7 @@ { char whatevs_key[CPATH_KEY_MATERIAL_LEN]; char digest[DIGEST_LEN]; - tor_addr_t addr; + tor_addr_t addr = TOR_ADDR_NULL; // Pretend a non-padding cell was sent circpad_cell_event_nonpadding_sent(client); @@ -1608,10 +1620,11 @@ hop->extend_info = extend_info_new( padding ? "padding" : "non-padding", - digest, NULL, NULL, NULL, + digest, NULL, NULL, &addr, padding, NULL, false); - cpath_init_circuit_crypto(hop, whatevs_key, sizeof(whatevs_key), 0, 0); + cpath_init_circuit_crypto(RELAY_CRYPTO_ALG_TOR1, hop, + whatevs_key, sizeof(whatevs_key)); hop->package_window = circuit_initial_package_window(); hop->deliver_window = CIRCWINDOW_START; @@ -3100,17 +3113,18 @@ test_circuitpadding_ignore_non_padding_cells(void *arg) { int retval; - relay_header_t rh; (void) arg; client_side = (circuit_t *)origin_circuit_new(); client_side->purpose = CIRCUIT_PURPOSE_C_CIRCUIT_PADDING; - rh.command = RELAY_COMMAND_BEGIN; + relay_msg_t msg; + memset(&msg, 0, sizeof(msg)); + msg.command = RELAY_COMMAND_BEGIN; setup_full_capture_of_logs(LOG_INFO); - retval = handle_relay_cell_command(NULL, client_side, NULL, NULL, &rh, 0); + retval = handle_relay_msg(&msg, client_side, NULL, NULL, 0); tt_int_op(retval, OP_EQ, 0); expect_log_msg_containing("Ignored cell"); diff -Nru tor-0.4.7.16/src/test/test_config.c tor-0.4.9.6/src/test/test_config.c --- tor-0.4.7.16/src/test/test_config.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/test/test_config.c 2026-03-25 14:30:34.000000000 +0000 @@ -2003,10 +2003,10 @@ tt_int_op(get_n_authorities(BRIDGE_DIRINFO), OP_EQ, 1); tt_int_op(smartlist_len(router_get_fallback_dir_servers()), OP_EQ, 1); - /* Assume we have eight V3 authorities */ + /* Assume we have nine V3 authorities */ add_default_trusted_dir_authorities(V3_DIRINFO); - tt_int_op(get_n_authorities(V3_DIRINFO), OP_EQ, 8); - tt_int_op(smartlist_len(router_get_fallback_dir_servers()), OP_EQ, 9); + tt_int_op(get_n_authorities(V3_DIRINFO), OP_EQ, 9); + tt_int_op(smartlist_len(router_get_fallback_dir_servers()), OP_EQ, 10); done: clear_dir_servers(); @@ -6321,14 +6321,14 @@ tt_int_op(check_bridge_distribution_setting("any"), OP_EQ, 0); tt_int_op(check_bridge_distribution_setting("https"), OP_EQ, 0); tt_int_op(check_bridge_distribution_setting("email"), OP_EQ, 0); - tt_int_op(check_bridge_distribution_setting("moat"), OP_EQ, 0); + tt_int_op(check_bridge_distribution_setting("settings"), OP_EQ, 0); // Check all the possible values we support right now with weird casing. tt_int_op(check_bridge_distribution_setting("NoNe"), OP_EQ, 0); tt_int_op(check_bridge_distribution_setting("anY"), OP_EQ, 0); tt_int_op(check_bridge_distribution_setting("hTTps"), OP_EQ, 0); tt_int_op(check_bridge_distribution_setting("emAIl"), OP_EQ, 0); - tt_int_op(check_bridge_distribution_setting("moAt"), OP_EQ, 0); + tt_int_op(check_bridge_distribution_setting("setTIngS"), OP_EQ, 0); // Invalid values. tt_int_op(check_bridge_distribution_setting("x\rx"), OP_EQ, -1); @@ -6435,7 +6435,7 @@ tt_int_op(smartlist_len(opened_files), OP_EQ, 4); tt_int_op(smartlist_contains_string(opened_files, torrcd), OP_EQ, 1); tt_int_op(smartlist_contains_string(opened_files, subfolder), OP_EQ, 1); - // files inside subfolders are not opended, only the subfolder is opened + // files inside subfolders are not opened, only the subfolder is opened tt_int_op(smartlist_contains_string(opened_files, empty), OP_EQ, 1); tt_int_op(smartlist_contains_string(opened_files, file), OP_EQ, 1); // dot files are not opened as we ignore them when we get their name from diff -Nru tor-0.4.7.16/src/test/test_conflux_cell.c tor-0.4.9.6/src/test/test_conflux_cell.c --- tor-0.4.7.16/src/test/test_conflux_cell.c 1970-01-01 00:00:00.000000000 +0000 +++ tor-0.4.9.6/src/test/test_conflux_cell.c 2026-03-25 14:30:34.000000000 +0000 @@ -0,0 +1,65 @@ +/* Copyright (c) 2023, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file test_conflux_cell. + * \brief Test conflux cells. + */ + +#include "test/test.h" +#include "test/test_helpers.h" +#include "test/log_test_helpers.h" + +#include "core/or/conflux_cell.h" +#include "core/or/conflux_st.h" +#include "trunnel/conflux.h" +#include "core/or/relay_msg.h" +#include "core/or/relay_msg_st.h" + +#include "lib/crypt_ops/crypto_rand.h" + +static void +test_link(void *arg) +{ + conflux_cell_link_t link; + conflux_cell_link_t *decoded_link = NULL; + relay_msg_t msg; + uint8_t buf0[RELAY_PAYLOAD_SIZE_MAX]; + uint8_t buf1[RELAY_PAYLOAD_SIZE_MAX]; + + (void) arg; + + memset(&link, 0, sizeof(link)); + + link.desired_ux = CONFLUX_UX_HIGH_THROUGHPUT; + link.last_seqno_recv = 0; + link.last_seqno_sent = 0; + link.version = 0x01; + + crypto_rand((char *) link.nonce, sizeof(link.nonce)); + + ssize_t cell_len = build_link_cell(&link, buf0); + tt_int_op(cell_len, OP_GT, 0); + msg.length = cell_len; + msg.body = buf0; + + decoded_link = conflux_cell_parse_link(&msg); + tt_assert(decoded_link); + + ssize_t enc_cell_len = build_link_cell(decoded_link, buf1); + tt_int_op(cell_len, OP_EQ, enc_cell_len); + + /* Validate the original link object with the decoded one. */ + tt_mem_op(&link, OP_EQ, decoded_link, sizeof(link)); + tor_free(decoded_link); + + done: + relay_msg_clear(&msg); + tor_free(decoded_link); +} + +struct testcase_t conflux_cell_tests[] = { + { "link", test_link, TT_FORK, NULL, NULL }, + + END_OF_TESTCASES +}; diff -Nru tor-0.4.7.16/src/test/test_conflux_pool.c tor-0.4.9.6/src/test/test_conflux_pool.c --- tor-0.4.7.16/src/test/test_conflux_pool.c 1970-01-01 00:00:00.000000000 +0000 +++ tor-0.4.9.6/src/test/test_conflux_pool.c 2026-03-25 14:30:34.000000000 +0000 @@ -0,0 +1,1351 @@ +#define CHANNEL_OBJECT_PRIVATE +#define TOR_TIMERS_PRIVATE +#define TOR_CONFLUX_PRIVATE +#define CIRCUITLIST_PRIVATE +#define NETWORKSTATUS_PRIVATE +#define CRYPT_PATH_PRIVATE +#define RELAY_PRIVATE +#define CONNECTION_PRIVATE +#define TOR_CONGESTION_CONTROL_COMMON_PRIVATE +#define TOR_CONGESTION_CONTROL_PRIVATE + +#include "core/or/or.h" +#include "test/test.h" +#include "test/log_test_helpers.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" +#include "lib/defs/time.h" +#include "core/or/relay.h" +#include "core/or/circuitlist.h" +#include "core/or/circuitstats.h" +#include "core/or/circuitbuild.h" +#include "core/or/circuituse.h" +#include "core/or/congestion_control_st.h" +#include "core/or/congestion_control_common.h" +#include "core/or/extendinfo.h" +#include "core/or/relay_msg.h" +#include "core/mainloop/netstatus.h" +#include "core/crypto/relay_crypto.h" +#include "core/or/protover.h" +#include "feature/nodelist/nodelist.h" +#include "app/config/config.h" + +#include "feature/nodelist/routerstatus_st.h" +#include "feature/nodelist/networkstatus_st.h" +#include "feature/nodelist/node_st.h" +#include "core/or/cell_st.h" +#include "core/or/crypt_path_st.h" +#include "core/or/or_circuit_st.h" +#include "core/or/origin_circuit_st.h" + +#include "core/mainloop/connection.h" +#include "core/or/connection_edge.h" +#include "core/or/edge_connection_st.h" + +#include "test/fakecircs.h" +#include "test/rng_test_helpers.h" +#include "core/or/conflux_pool.h" +#include "core/or/conflux_util.h" +#include "core/or/conflux_params.h" +#include "core/or/conflux.h" +#include "core/or/conflux_st.h" +#include "trunnel/conflux.h" +#include "lib/crypt_ops/crypto_rand.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. */ +#define MONOTIME_MOCK_START (monotime_absolute_nsec()+\ + 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); + +channel_t *new_fake_channel(void); + +static void simulate_single_hop_extend(origin_circuit_t *client, int exit); +static void free_fake_origin_circuit(origin_circuit_t *circ); +static circuit_t * get_exit_circ(circuit_t *client_circ); +static circuit_t * get_client_circ(circuit_t *exit_circ); +static void simulate_circuit_build(circuit_t *client_circ); + +static int64_t curr_mocked_time; + +static channel_t dummy_channel; + +static void +timers_advance_and_run(int64_t msec_update) +{ + curr_mocked_time += msec_update*TOR_NSEC_PER_MSEC; + monotime_coarse_set_mock_time_nsec(curr_mocked_time); + monotime_set_mock_time_nsec(curr_mocked_time); +} + +/* These lists of circuit endpoints send to eachother via + * circuit_package_relay_cell_mocked */ +static smartlist_t *client_circs; +static smartlist_t *exit_circs; +static smartlist_t *client_streams; +static smartlist_t *exit_streams; + +typedef struct { + circuit_t *client; + circuit_t *exit; +} circ_pair_t; +static smartlist_t *circ_pairs; + +static void +simulate_circuit_built(circuit_t *client, circuit_t *exit) +{ + circ_pair_t *pair = tor_malloc_zero(sizeof(circ_pair_t)); + pair->client = client; + pair->exit = exit; + smartlist_add(circ_pairs, pair); +} + +static origin_circuit_t * +circuit_establish_circuit_conflux_mock(const uint8_t *conflux_nonce, + uint8_t purpose, extend_info_t *exit_ei, + int flags) +{ + (void)exit_ei; + (void)flags; + origin_circuit_t *circ = origin_circuit_init(purpose, flags); + circ->base_.conflux_pending_nonce = tor_memdup(conflux_nonce, DIGEST256_LEN); + circ->base_.purpose = CIRCUIT_PURPOSE_CONFLUX_UNLINKED; + smartlist_add(client_circs, circ); + + // This also moves the clock forward as if these hops were opened.. + // Not a problem, unless we want to accurately test buildtimeouts + simulate_single_hop_extend(circ, 0); + simulate_single_hop_extend(circ, 0); + simulate_single_hop_extend(circ, 1); + circ->cpath->prev->ccontrol = tor_malloc_zero(sizeof(congestion_control_t)); + circ->cpath->prev->ccontrol->sendme_pending_timestamps = smartlist_new(); + circ->cpath->prev->ccontrol->sendme_inc = 31; + + return circ; +} + +static void +free_fake_origin_circuit(origin_circuit_t *circ) +{ + circuit_clear_cpath(circ); + tor_free(circ); +} + +void dummy_nop_timer(void); + +static int +circuit_package_relay_cell_mock(cell_t *cell, circuit_t *circ, + cell_direction_t cell_direction, + crypt_path_t *layer_hint, streamid_t on_stream, + const char *filename, int lineno); + +static void +circuitmux_attach_circuit_mock(circuitmux_t *cmux, circuit_t *circ, + cell_direction_t direction); + +static void +circuitmux_attach_circuit_mock(circuitmux_t *cmux, circuit_t *circ, + cell_direction_t direction) +{ + (void)cmux; + (void)circ; + (void)direction; + + return; +} +/* For use in the mock_net smartlist queue: + * this struct contains a circuit and a cell to + * deliver on it. */ +typedef struct { + circuit_t *circ; + cell_t *cell; +} cell_delivery_t; + +static smartlist_t *mock_cell_delivery = NULL; + +static int +circuit_package_relay_cell_mock(cell_t *cell, circuit_t *circ, + cell_direction_t cell_direction, + crypt_path_t *layer_hint, streamid_t on_stream, + const char *filename, int lineno) +{ + (void)cell; (void)on_stream; (void)filename; (void)lineno; + (void)cell_direction; + circuit_t *dest_circ = NULL; + + // If we have a layer hint, we are sending to the exit. Look + // up the exit circ based on our circuit index in the smartlist + if (layer_hint) { + tor_assert(CIRCUIT_IS_ORIGIN(circ)); + tt_int_op(cell_direction, OP_EQ, CELL_DIRECTION_OUT); + + // Search the circ pairs list for the pair whose client is this circ, + // and set dest_circ to the exit circ in that pair + SMARTLIST_FOREACH_BEGIN(circ_pairs, circ_pair_t *, pair) { + if (pair->client == circ) { + dest_circ = pair->exit; + break; + } + } SMARTLIST_FOREACH_END(pair); + } else { + tt_int_op(cell_direction, OP_EQ, CELL_DIRECTION_IN); + + // Search the circ pairs list for the pair whose exit is this circ, + // and set dest_circ to the client circ in that pair + SMARTLIST_FOREACH_BEGIN(circ_pairs, circ_pair_t *, pair) { + if (pair->exit == circ) { + dest_circ = pair->client; + break; + } + } SMARTLIST_FOREACH_END(pair); + } + + cell_delivery_t *delivery = tor_malloc_zero(sizeof(cell_delivery_t)); + delivery->circ = dest_circ; + delivery->cell = tor_memdup(cell, sizeof(cell_t)); + smartlist_add(mock_cell_delivery, delivery); + done: + return 0; +} + +/** Pull the next cell from the mock delivery queue and deliver it. */ +static void +process_mock_cell_delivery(void) +{ + relay_header_t rh; + relay_msg_t *msg = NULL; + + cell_delivery_t *delivery = smartlist_pop_last(mock_cell_delivery); + tor_assert(delivery); + cell_t *cell = delivery->cell; + circuit_t *dest_circ = delivery->circ; + relay_header_unpack(&rh, cell->payload); + + timers_advance_and_run(1); + + msg = relay_msg_decode_cell(RELAY_CELL_FORMAT_V0, cell); + + tor_assert(msg); + + switch (msg->command) { + case RELAY_COMMAND_CONFLUX_LINK: + tor_assert(!CIRCUIT_IS_ORIGIN(dest_circ)); + conflux_process_link(dest_circ, msg); + break; + case RELAY_COMMAND_CONFLUX_LINKED: + tor_assert(CIRCUIT_IS_ORIGIN(dest_circ)); + conflux_process_linked(dest_circ, + TO_ORIGIN_CIRCUIT(dest_circ)->cpath->prev, + msg); + break; + case RELAY_COMMAND_CONFLUX_LINKED_ACK: + tor_assert(!CIRCUIT_IS_ORIGIN(dest_circ)); + conflux_process_linked_ack(dest_circ); + break; + case RELAY_COMMAND_CONFLUX_SWITCH: + // We only test the case where the switch is initiated by the client. + // It is symmetric, so this should not matter. If we ever want to test + // the case where the switch is initiated by the exit, we will need to + // get the cpath layer hint for the client. + tor_assert(!CIRCUIT_IS_ORIGIN(dest_circ)); + conflux_process_switch_command(dest_circ, NULL, msg); + break; + } + + tor_free(delivery); + tor_free(cell); + relay_msg_free(msg); + return; +} + +static uint64_t +mock_monotime_absolute_usec(void) +{ + return 100; +} + +static int +channel_get_addr_if_possible_mock(const channel_t *chan, tor_addr_t *addr_out) +{ + (void)chan; + tt_int_op(AF_INET,OP_EQ, tor_addr_parse(addr_out, "18.0.0.1")); + return 1; + + done: + return 0; +} + +static void +circuit_mark_for_close_mock(circuit_t *circ, int reason, + int line, const char *file) +{ + (void)circ; + (void)reason; + (void)line; + (void)file; + + log_info(LD_CIRC, "Marking circuit for close at %s:%d", file, line); + + if (BUG(circ->marked_for_close)) { + log_warn(LD_BUG, + "Duplicate call to circuit_mark_for_close at %s:%d" + " (first at %s:%d)", file, line, + circ->marked_for_close_file, circ->marked_for_close); + return; + } + + circ->marked_for_close = line; + circ->marked_for_close_file = file; + circ->marked_for_close_reason = reason; + + if (CIRCUIT_IS_CONFLUX(circ)) { + conflux_circuit_has_closed(circ); + } + + // Mark the other side for close too. No idea if this even improves things; + // We might also want to make this go through the cell queue as a destroy + if (CIRCUIT_IS_ORIGIN(circ)) { + circuit_t *exit_circ = get_exit_circ(circ); + if (!exit_circ->marked_for_close) + circuit_mark_for_close_mock(get_exit_circ(circ), reason, line, file); + } else { + circuit_t *client_circ = get_client_circ(circ); + if (!client_circ->marked_for_close) + circuit_mark_for_close_mock(get_client_circ(circ), reason, line, file); + } + + // XXX: Should we do this? + //if (circuits_pending_close == NULL) + // circuits_pending_close = smartlist_new(); + //smartlist_add(circuits_pending_close, circ); +} + +static void +simulate_single_hop_extend(origin_circuit_t *client, int exit) +{ + char whatevs_key[CPATH_KEY_MATERIAL_LEN]; + char digest[DIGEST_LEN]; + tor_addr_t addr = TOR_ADDR_NULL; + + // Advance time a tiny bit so we can calculate an RTT + curr_mocked_time += 10 * TOR_NSEC_PER_MSEC; + monotime_coarse_set_mock_time_nsec(curr_mocked_time); + monotime_set_mock_time_nsec(curr_mocked_time); + + // Add a hop to cpath + crypt_path_t *hop = tor_malloc_zero(sizeof(crypt_path_t)); + cpath_extend_linked_list(&client->cpath, hop); + + hop->magic = CRYPT_PATH_MAGIC; + hop->state = CPATH_STATE_OPEN; + + // add an extend info to indicate if this node supports padding or not. + // (set the first byte of the digest for our mocked node_get_by_id) + digest[0] = exit; + + hop->extend_info = extend_info_new( + exit ? "exit" : "non-exit", + digest, NULL, NULL, + &addr, exit, NULL, exit); + + cpath_init_circuit_crypto(RELAY_CRYPTO_ALG_TOR1, hop, + whatevs_key, sizeof(whatevs_key)); + + hop->package_window = circuit_initial_package_window(); + hop->deliver_window = CIRCWINDOW_START; +} + +static void +test_setup(void) +{ + int64_t actual_mocked_monotime_start; + + MOCK(circuitmux_attach_circuit, circuitmux_attach_circuit_mock); + MOCK(channel_get_addr_if_possible, channel_get_addr_if_possible_mock); + MOCK(circuit_establish_circuit_conflux, + circuit_establish_circuit_conflux_mock); + MOCK(circuit_package_relay_cell, + circuit_package_relay_cell_mock); + MOCK(circuit_mark_for_close_, + circuit_mark_for_close_mock); + MOCK(monotime_absolute_usec, mock_monotime_absolute_usec); + testing_enable_reproducible_rng(); + + 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; + + client_circs = smartlist_new(); + exit_circs = smartlist_new(); + circ_pairs = smartlist_new(); + mock_cell_delivery = smartlist_new(); + dummy_channel.cmux = circuitmux_alloc(); + + get_circuit_build_times_mutable()->timeout_ms = 1000; + + congestion_control_set_cc_enabled(); + max_unlinked_leg_retry = UINT32_MAX; +} + +static void +test_clear_circs(void) +{ + conflux_notify_shutdown(); + SMARTLIST_FOREACH(circ_pairs, circ_pair_t *, circ_pair, { + tor_free(circ_pair); + }); + SMARTLIST_FOREACH(client_circs, circuit_t *, client_side, { + conflux_circuit_about_to_free(client_side); + circuit_free(client_side); + }); + SMARTLIST_FOREACH(exit_circs, or_circuit_t *, relay_side, { + free_fake_orcirc(relay_side); + }); + + smartlist_clear(circ_pairs); + smartlist_clear(client_circs); + smartlist_clear(exit_circs); + + if (client_streams) { + // Free each edge connection + SMARTLIST_FOREACH(client_streams, edge_connection_t *, edge_conn, { + connection_free_minimal(TO_CONN(edge_conn)); + }); + smartlist_free(client_streams); + } + + if (exit_streams) { + // Free each edge connection + SMARTLIST_FOREACH(exit_streams, edge_connection_t *, edge_conn, { + connection_free_minimal(TO_CONN(edge_conn)); + }); + smartlist_free(exit_streams); + } + + tor_assert(smartlist_len(mock_cell_delivery) == 0); + + (void)free_fake_origin_circuit; + + /* Clear shutdown flag so we can resume testing again. */ + conflux_clear_shutdown(); +} + +static void +test_teardown(void) +{ + conflux_pool_free_all(); + smartlist_free(client_circs); + smartlist_free(exit_circs); + smartlist_free(mock_cell_delivery); + circuitmux_detach_all_circuits(dummy_channel.cmux, NULL); + circuitmux_free(dummy_channel.cmux); + testing_disable_reproducible_rng(); +} + +/* Test linking a conflux circuit */ +static void +test_conflux_link(void *arg) +{ + (void) arg; + test_setup(); + + launch_new_set(2); + + // For each circuit in the client_circs list, we need to create an + // exit side circuit and simulate two extends + SMARTLIST_FOREACH(client_circs, circuit_t *, client_side, { + simulate_circuit_build(client_side); + + /* Handle network activity*/ + while (smartlist_len(mock_cell_delivery) > 0) { + process_mock_cell_delivery(); + } + }); + + tt_int_op(smartlist_len(client_circs), OP_EQ, 2); + tt_int_op(smartlist_len(exit_circs), OP_EQ, 2); + + // Test that the cells have all been delivered + tt_int_op(smartlist_len(mock_cell_delivery), OP_EQ, 0); + + // Test that the client side circuits are linked + conflux_t *cfx = ((circuit_t*)smartlist_get(client_circs, 0))->conflux; + SMARTLIST_FOREACH_BEGIN(client_circs, circuit_t *, client_side) { + tt_int_op(client_side->purpose, OP_EQ, CIRCUIT_PURPOSE_CONFLUX_LINKED); + tt_ptr_op(client_side->conflux, OP_EQ, cfx); + tt_ptr_op(client_side->conflux_pending_nonce, OP_EQ, NULL); + } SMARTLIST_FOREACH_END(client_side); + + // Test circuit teardown + SMARTLIST_FOREACH_BEGIN(client_circs, circuit_t *, client_side) { + circuit_mark_for_close(client_side, END_CIRC_REASON_FINISHED); + } SMARTLIST_FOREACH_END(client_side); + + done: + test_clear_circs(); + test_teardown(); +} + +static void +simulate_circuit_build(circuit_t *client_circ) +{ + // Create a relay circuit, and simulate the extend and open + circuit_t *relay_side = NULL; + + relay_side = (circuit_t*)new_fake_orcirc(&dummy_channel, &dummy_channel); + relay_side->purpose = CIRCUIT_PURPOSE_OR; + relay_side->n_chan = NULL; // No next hop + relay_side->ccontrol = tor_malloc_zero(sizeof(congestion_control_t)); + relay_side->ccontrol->sendme_pending_timestamps = smartlist_new(); + relay_side->ccontrol->sendme_inc = 31; + smartlist_add(exit_circs, relay_side); + simulate_circuit_built(client_circ, relay_side); + conflux_circuit_has_opened(TO_ORIGIN_CIRCUIT(client_circ)); +} + +static circuit_t * +simulate_close_retry(circuit_t *close, bool manual_launch) +{ + // Find the dest pair for the circuit in the circ pair list, + // and close it too + circuit_t *dest = NULL; + uint8_t *nonce = NULL; + + if (manual_launch) { + nonce = tor_memdup(close->conflux->nonce, DIGEST256_LEN); + } + + SMARTLIST_FOREACH_BEGIN(circ_pairs, circ_pair_t *, pair) { + if (pair->client == close) { + dest = pair->exit; + SMARTLIST_DEL_CURRENT_KEEPORDER(circ_pairs, pair); + tor_free(pair); + } else if (pair->exit == close) { + // This function should not be called on the exit side.. + tor_assert(0); + } + } SMARTLIST_FOREACH_END(pair); + + tor_assert(dest); + log_info(LD_CIRC, "Simulating close of %p->%p, dest %p->%p", + close, close->conflux, dest, dest->conflux); + + // Free all pending cells related to this close in mock_cell_delivery + SMARTLIST_FOREACH(mock_cell_delivery, cell_delivery_t *, cd, { + if (cd->circ == close || cd->circ == dest) { + SMARTLIST_DEL_CURRENT_KEEPORDER(mock_cell_delivery, cd); + tor_free(cd->cell); + tor_free(cd); + } + }); + + // When a circuit closes, both ends get notification, + // and the client will launch a new circuit. We need to find + // that circuit at the end of the list, and then simulate + // building it, and creating a relay circuit for it. + conflux_circuit_has_closed(close); + conflux_circuit_has_closed(dest); + + //tor_assert(digest256map_size(get_unlinked_pool(true)) != 0); + + // Find these legs in our circuit lists, and free them + tor_assert(CIRCUIT_IS_ORIGIN(close)); + tor_assert(!CIRCUIT_IS_ORIGIN(dest)); + SMARTLIST_FOREACH_BEGIN(client_circs, circuit_t *, client_side) { + if (client_side == close) { + SMARTLIST_DEL_CURRENT_KEEPORDER(client_circs, client_side); + conflux_circuit_about_to_free(client_side); + circuit_free(client_side); + } + } SMARTLIST_FOREACH_END(client_side); + SMARTLIST_FOREACH_BEGIN(exit_circs, or_circuit_t *, exit_side) { + if (exit_side == (or_circuit_t *)dest) { + SMARTLIST_DEL_CURRENT_KEEPORDER(exit_circs, exit_side); + free_fake_orcirc(exit_side); + } + } SMARTLIST_FOREACH_END(exit_side); + + if (manual_launch) { + // Launch a new leg for this nonce + tor_assert(nonce); + conflux_launch_leg(nonce); + tor_free(nonce); + } + + if (smartlist_len(client_circs) == 0) { + // No new circuit was launched + return NULL; + } + + // At this point, a new circuit will have launched on the client + // list. Get that circuit from the end of the list and return it + circuit_t * circ = smartlist_get(client_circs, + smartlist_len(client_circs) - 1); + + //tor_assert(circ->purpose == CIRCUIT_PURPOSE_CONFLUX_UNLINKED); + + return circ; +} + +static void +test_retry(void) +{ + log_info(LD_CIRC, "==========NEW RUN ==========="); + launch_new_set(2); + + tt_int_op(smartlist_len(client_circs), OP_EQ, 2); + circuit_t *client1 = smartlist_get(client_circs, 0); + circuit_t *client2 = smartlist_get(client_circs, 1); + + get_circuit_build_times_mutable()->timeout_ms = 1000; + + // Dice roll on which leg builds first + if (crypto_rand_int(2) == 0) { + simulate_circuit_build(client1); + simulate_circuit_build(client2); + } else { + simulate_circuit_build(client2); + simulate_circuit_build(client1); + } + + while (smartlist_len(mock_cell_delivery) > 0) { + tt_int_op(smartlist_len(client_circs), OP_EQ, 2); + tt_int_op(smartlist_len(exit_circs), OP_EQ, 2); + tt_int_op(smartlist_len(circ_pairs), OP_EQ, 2); + + if (crypto_rand_int(2) == 0) { + if (crypto_rand_int(2) == 0) { + if (client1->purpose != CIRCUIT_PURPOSE_CONFLUX_LINKED) { + client1 = simulate_close_retry(client1, false); + simulate_circuit_build(client1); + } + } else { + if (client2->purpose != CIRCUIT_PURPOSE_CONFLUX_LINKED) { + client2 = simulate_close_retry(client2, false); + simulate_circuit_build(client2); + } + } + } + + process_mock_cell_delivery(); + } + + // Test that the cells have all been delivered + tt_int_op(smartlist_len(mock_cell_delivery), OP_EQ, 0); + tt_int_op(smartlist_len(client_circs), OP_EQ, 2); + tt_int_op(smartlist_len(exit_circs), OP_EQ, 2); + tt_int_op(smartlist_len(circ_pairs), OP_EQ, 2); + + conflux_t *cfx = ((circuit_t *)smartlist_get(client_circs, 0))->conflux; + SMARTLIST_FOREACH_BEGIN(client_circs, circuit_t *, client_side) { + tt_int_op(client_side->purpose, OP_EQ, CIRCUIT_PURPOSE_CONFLUX_LINKED); + tt_ptr_op(client_side->conflux, OP_EQ, cfx); + tt_ptr_op(client_side->conflux_pending_nonce, OP_EQ, NULL); + } SMARTLIST_FOREACH_END(client_side); + + tt_int_op(digest256map_size(get_linked_pool(true)), OP_EQ, 1); + tt_int_op(digest256map_size(get_unlinked_pool(true)), OP_EQ, 0); + tt_int_op(digest256map_size(get_unlinked_pool(false)), OP_EQ, 0); + tt_int_op(digest256map_size(get_linked_pool(false)), OP_EQ, 1); + + cfx = ((circuit_t *)smartlist_get(exit_circs, 0))->conflux; + SMARTLIST_FOREACH_BEGIN(exit_circs, circuit_t *, exit_side) { + tt_ptr_op(exit_side->conflux, OP_EQ, cfx); + tt_ptr_op(exit_side->conflux_pending_nonce, OP_EQ, NULL); + } SMARTLIST_FOREACH_END(exit_side); + + // Test circuit teardown + SMARTLIST_FOREACH_BEGIN(client_circs, circuit_t *, client_side) { + tt_int_op(client_side->purpose, OP_EQ, CIRCUIT_PURPOSE_CONFLUX_LINKED); + circuit_mark_for_close(client_side, END_CIRC_REASON_FINISHED); + } SMARTLIST_FOREACH_END(client_side); + + tt_int_op(digest256map_size(get_linked_pool(true)), OP_EQ, 0); + tt_int_op(digest256map_size(get_unlinked_pool(true)), OP_EQ, 0); + tt_int_op(digest256map_size(get_unlinked_pool(false)), OP_EQ, 0); + tt_int_op(digest256map_size(get_linked_pool(false)), OP_EQ, 0); + + test_clear_circs(); + + done: + return; +} + +/* Test linking a conflux circuit with build failures */ +static void +test_conflux_link_retry(void *arg) +{ + (void) arg; + test_setup(); + + for (int i = 0; i < 500; i++) { + test_retry(); + } + + test_teardown(); +} + +#if 0 +/* Test closing both circuits in the set before the link handshake completes + * on either leg, by closing circuits before process_mock_cell_delivery. + * + * XXX: This test currently fails because conflux keeps relaunching closed + * circuits. We need to set a limit on the number of times we relaunch a + * circuit before we can fix this test. + */ +static void +test_conflux_link_fail(void *arg) +{ + (void) arg; + test_setup(); + + launch_new_set(2); + + tt_int_op(smartlist_len(client_circs), OP_EQ, 2); + circuit_t *client1 = smartlist_get(client_circs, 0); + circuit_t *client2 = smartlist_get(client_circs, 1); + + get_circuit_build_times_mutable()->timeout_ms = 1000; + + // Close both circuits before the link handshake completes + conflux_circuit_has_closed(client1); + conflux_circuit_has_closed(client2); + + tt_int_op(digest256map_size(get_linked_pool(true)), OP_EQ, 0); + tt_int_op(digest256map_size(get_unlinked_pool(true)), OP_EQ, 0); + tt_int_op(digest256map_size(get_unlinked_pool(false)), OP_EQ, 0); + tt_int_op(digest256map_size(get_linked_pool(false)), OP_EQ, 0); + done: + test_clear_circs(); + test_teardown(); +} +#endif + +// - Relink test: +// - More than 2 legs +// - Close one linked leg; relink +// - Test mismatching sequence numbers for link and data +// - This should destroy the whole set +// - RTT timeout relinking test +// - Three circuits; close 1; retry and link +static void +test_conflux_link_relink(void *arg) +{ + (void) arg; + test_setup(); + + launch_new_set(3); + + tt_int_op(smartlist_len(client_circs), OP_EQ, 3); + circuit_t *client1 = smartlist_get(client_circs, 0); + circuit_t *client2 = smartlist_get(client_circs, 1); + circuit_t *client3 = smartlist_get(client_circs, 2); + + get_circuit_build_times_mutable()->timeout_ms = 1000; + + simulate_circuit_build(client1); + simulate_circuit_build(client2); + simulate_circuit_build(client3); + + while (smartlist_len(mock_cell_delivery) > 0) { + tt_int_op(smartlist_len(client_circs), OP_EQ, 3); + tt_int_op(smartlist_len(exit_circs), OP_EQ, 3); + tt_int_op(smartlist_len(circ_pairs), OP_EQ, 3); + + process_mock_cell_delivery(); + } + + // Now test closing and relinking the third leg + client3 = simulate_close_retry(client3, true); + simulate_circuit_build(client3); + while (smartlist_len(mock_cell_delivery) > 0) { + tt_int_op(smartlist_len(client_circs), OP_EQ, 3); + tt_int_op(smartlist_len(exit_circs), OP_EQ, 3); + tt_int_op(smartlist_len(circ_pairs), OP_EQ, 3); + + process_mock_cell_delivery(); + } + + tt_int_op(digest256map_size(get_linked_pool(true)), OP_EQ, 1); + tt_int_op(digest256map_size(get_unlinked_pool(true)), OP_EQ, 0); + tt_int_op(digest256map_size(get_unlinked_pool(false)), OP_EQ, 0); + tt_int_op(digest256map_size(get_linked_pool(false)), OP_EQ, 1); + + // Now test closing all circuits and verify the conflux object is gone + simulate_close_retry(client1, false); + simulate_close_retry(client2, false); + simulate_close_retry(client3, false); + + tt_int_op(digest256map_size(get_linked_pool(true)), OP_EQ, 0); + tt_int_op(digest256map_size(get_unlinked_pool(true)), OP_EQ, 0); + tt_int_op(digest256map_size(get_unlinked_pool(false)), OP_EQ, 0); + tt_int_op(digest256map_size(get_linked_pool(false)), OP_EQ, 0); + + done: + test_clear_circs(); + test_teardown(); +} + +#if 0 +static void +test_conflux_close(void *arg) +{ + (void) arg; + test_setup(); + + launch_new_set(2); + + tt_int_op(smartlist_len(client_circs), OP_EQ, 2); + circuit_t *client1 = smartlist_get(client_circs, 0); + circuit_t *client2 = smartlist_get(client_circs, 1); + + get_circuit_build_times_mutable()->timeout_ms = 1000; + + simulate_circuit_build(client1); + simulate_circuit_build(client2); + + while (smartlist_len(mock_cell_delivery) > 0) { + tt_int_op(smartlist_len(client_circs), OP_EQ, 2); + tt_int_op(smartlist_len(exit_circs), OP_EQ, 2); + tt_int_op(smartlist_len(circ_pairs), OP_EQ, 2); + + process_mock_cell_delivery(); + } + + // There are actually 3 kinds of close: mark, mark+free, + // and purpose change. We need to test these in link_retry, but + // here our focus is on after the set is linked. + + // Additionally, we can close on an unlinked leg, or a non-critical linked + // leg, or a critical linked leg that causes teardown + // And we can close on linked legs when there are unlinked legs, or not. + + // And we can do this at the client, or the exit. + // And we can do this with a circuit that has streams, or not. + + tt_int_op(digest256map_size(get_linked_pool(true)), OP_EQ, 0); + tt_int_op(digest256map_size(get_unlinked_pool(true)), OP_EQ, 0); + tt_int_op(digest256map_size(get_unlinked_pool(false)), OP_EQ, 0); + tt_int_op(digest256map_size(get_linked_pool(false)), OP_EQ, 0); + done: + test_clear_circs(); + test_teardown(); +} +#endif + +// Test launching a new set and closing the first leg, but +// with mismatched sequence numbers (missing data) +// - Test this teardown with only linked circs, and with some +// unlinked circs +// Test mismatching sequence numbers for link and data: +// Test missing sent data from client (link cell mismatch): +// Test missing sent data from relay (linked cell mismatch): + +static circuit_t * +get_exit_circ(circuit_t *client_circ) +{ + circuit_t *exit_circ = NULL; + SMARTLIST_FOREACH_BEGIN(circ_pairs, circ_pair_t *, pair) { + if (pair->client == client_circ) { + exit_circ = pair->exit; + break; + } + } SMARTLIST_FOREACH_END(pair); + tor_assert(exit_circ); + return exit_circ; +} + +static circuit_t * +get_client_circ(circuit_t *exit_circ) +{ + circuit_t *client_circ = NULL; + SMARTLIST_FOREACH_BEGIN(circ_pairs, circ_pair_t *, pair) { + if (pair->exit == exit_circ) { + client_circ = pair->client; + break; + } + } SMARTLIST_FOREACH_END(pair); + tor_assert(client_circ); + return client_circ; +} + +static edge_connection_t * +new_client_stream(origin_circuit_t *on_circ) +{ + edge_connection_t *stream = edge_connection_new(CONN_TYPE_EXIT, AF_INET); + + stream->stream_id = get_unique_stream_id_by_circ(on_circ); + stream->on_circuit = TO_CIRCUIT(on_circ); + stream->cpath_layer = on_circ->cpath->prev; + + stream->next_stream = on_circ->p_streams; + on_circ->p_streams = stream; + conflux_update_p_streams(on_circ, stream); + + smartlist_add(client_streams, stream); + + return stream; +} + +static edge_connection_t * +new_exit_stream(circuit_t *on_circ, streamid_t stream_id) +{ + edge_connection_t *stream = edge_connection_new(CONN_TYPE_EXIT, AF_INET); + + stream->stream_id = stream_id; + stream->on_circuit = on_circ; + + stream->next_stream = TO_OR_CIRCUIT(on_circ)->n_streams; + conflux_update_n_streams(TO_OR_CIRCUIT(on_circ), stream); + + smartlist_add(exit_streams, stream); + + return stream; +} + +static void +validate_stream_counts(circuit_t *circ, int expected) +{ + int count = 0; + + conflux_validate_stream_lists(circ->conflux); + + if (CIRCUIT_IS_ORIGIN(circ)) { + origin_circuit_t *ocirc = TO_ORIGIN_CIRCUIT(circ); + tor_assert_nonfatal(circ->purpose == CIRCUIT_PURPOSE_CONFLUX_LINKED); + /* Iterate over stream list using next_stream pointer, until null */ + for (edge_connection_t *stream = ocirc->p_streams; stream; + stream = stream->next_stream) { + count++; + } + } else { + or_circuit_t *orcirc = TO_OR_CIRCUIT(circ); + /* Iterate over stream list using next_stream pointer, until null */ + for (edge_connection_t *stream = orcirc->n_streams; stream; + stream = stream->next_stream) { + count++; + } + } + tt_int_op(count, OP_EQ, expected); + + done: + return; +} + +// - Streams test +// - Attach streams +// - Fail one leg, free it, attach new leg, new stream +// - Fail both legs +// - Shutdown +// - With streams attached +static void +test_conflux_link_streams(void *arg) +{ + (void) arg; + test_setup(); + + launch_new_set(2); + + client_streams = smartlist_new(); + exit_streams = smartlist_new(); + + tt_int_op(smartlist_len(client_circs), OP_EQ, 2); + circuit_t *client1 = smartlist_get(client_circs, 0); + circuit_t *client2 = smartlist_get(client_circs, 1); + + get_circuit_build_times_mutable()->timeout_ms = 1000; + + simulate_circuit_build(client1); + simulate_circuit_build(client2); + + while (smartlist_len(mock_cell_delivery) > 0) { + tt_int_op(smartlist_len(client_circs), OP_EQ, 2); + tt_int_op(smartlist_len(exit_circs), OP_EQ, 2); + tt_int_op(smartlist_len(circ_pairs), OP_EQ, 2); + + process_mock_cell_delivery(); + } + + // Attach a stream to the client1 circuit + new_client_stream(TO_ORIGIN_CIRCUIT(client1)); + new_client_stream(TO_ORIGIN_CIRCUIT(client2)); + new_client_stream(TO_ORIGIN_CIRCUIT(client1)); + new_exit_stream(get_exit_circ(client2), 1); + new_exit_stream(get_exit_circ(client1), 1); + new_exit_stream(get_exit_circ(client1), 1); + + // Test that we can close the first leg, and attach a new one + // with a new stream + client1 = simulate_close_retry(client1, true); + simulate_circuit_build(client1); + + while (smartlist_len(mock_cell_delivery) > 0) { + tt_int_op(smartlist_len(client_circs), OP_EQ, 2); + tt_int_op(smartlist_len(exit_circs), OP_EQ, 2); + tt_int_op(smartlist_len(circ_pairs), OP_EQ, 2); + + process_mock_cell_delivery(); + } + + tt_ptr_op(client1->conflux, OP_EQ, client2->conflux); + + new_client_stream(TO_ORIGIN_CIRCUIT(client1)); + new_exit_stream(get_exit_circ(client2), 1); + + // Use Ensure that there are four streams on each circuit + validate_stream_counts(client1, 4); + validate_stream_counts(client2, 4); + validate_stream_counts(get_exit_circ(client1), 4); + validate_stream_counts(get_exit_circ(client2), 4); + + // Test that we can close all streams on either circuit, + // in any order + circuit_detach_stream(get_exit_circ(client1), + TO_OR_CIRCUIT(get_exit_circ(client1))->n_streams); + validate_stream_counts(get_exit_circ(client2), 3); + circuit_detach_stream(get_exit_circ(client2), + TO_OR_CIRCUIT(get_exit_circ(client2))->n_streams->next_stream); + validate_stream_counts(get_exit_circ(client1), 2); + circuit_detach_stream(get_exit_circ(client1), + TO_OR_CIRCUIT(get_exit_circ(client1))->n_streams); + validate_stream_counts(get_exit_circ(client1), 1); + circuit_detach_stream(get_exit_circ(client1), + TO_OR_CIRCUIT(get_exit_circ(client1))->n_streams); + validate_stream_counts(get_exit_circ(client1), 0); + + circuit_detach_stream(client1, + TO_ORIGIN_CIRCUIT(client1)->p_streams->next_stream-> + next_stream->next_stream); + circuit_detach_stream(client2, + TO_ORIGIN_CIRCUIT(client2)->p_streams); + circuit_detach_stream(client2, + TO_ORIGIN_CIRCUIT(client2)->p_streams->next_stream); + circuit_detach_stream(client2, + TO_ORIGIN_CIRCUIT(client2)->p_streams); + validate_stream_counts(client1, 0); + validate_stream_counts(client2, 0); + + done: + test_clear_circs(); + test_teardown(); +} + +// Right now this does not involve congestion control.. But it could, +// if we actually build and send real RELAY_DATA cells (and also handle them +// and SENDME cells in the mocked cell delivery) +static void +send_fake_cell(circuit_t *client_circ) +{ + circuit_t *exit_circ = get_exit_circ(client_circ); + conflux_leg_t *exit_leg = conflux_get_leg(exit_circ->conflux, + exit_circ); + + TO_ORIGIN_CIRCUIT(client_circ)->cpath->prev->ccontrol->inflight++; + conflux_note_cell_sent(client_circ->conflux, client_circ, + RELAY_COMMAND_DATA); + + exit_leg->last_seq_recv++; + exit_circ->conflux->last_seq_delivered++; +} + +static circuit_t * +send_until_switch(circuit_t *client_circ) +{ + conflux_leg_t *client_leg = conflux_get_leg(client_circ->conflux, + client_circ); + circuit_t *exit_circ = get_exit_circ(client_circ); + conflux_leg_t *exit_leg = conflux_get_leg(exit_circ->conflux, + exit_circ); + circuit_t *next_circ = client_circ; + int i = 0; + + // XXX: This is a hack so the tests pass using cc->sendme_inc + // (There is another hack in circuit_ready_to_send() that causes + // us to block early below, and return NULL for next_circ) + TO_ORIGIN_CIRCUIT(client_circ)->cpath->prev->ccontrol->sendme_inc = 0; + + while (client_circ == next_circ) { + next_circ = conflux_decide_circ_for_send(client_circ->conflux, client_circ, + RELAY_COMMAND_DATA); + tor_assert(next_circ); + send_fake_cell(next_circ); + i++; + } + + // XXX: This too: + TO_ORIGIN_CIRCUIT(client_circ)->cpath->prev->ccontrol->sendme_inc = 31; + + log_info(LD_CIRC, "Sent %d cells on client circ", i-1); + process_mock_cell_delivery(); + + circuit_t *new_client = + (circuit_t*)conflux_decide_next_circ(client_circ->conflux); + tt_ptr_op(new_client, OP_NE, client_circ); + conflux_leg_t *new_client_leg = conflux_get_leg(new_client->conflux, + new_client); + circuit_t *new_exit = get_exit_circ(new_client); + conflux_leg_t *new_exit_leg = conflux_get_leg(new_exit->conflux, + new_exit); + + // Verify sequence numbers make sense + tt_int_op(new_client_leg->last_seq_sent, OP_EQ, client_leg->last_seq_sent+1); + tt_int_op(new_client_leg->last_seq_recv, OP_EQ, client_leg->last_seq_recv); + tt_int_op(exit_leg->last_seq_sent, OP_EQ, new_exit_leg->last_seq_sent); + tt_int_op(exit_leg->last_seq_recv+1, OP_EQ, new_exit_leg->last_seq_recv); + + tt_int_op(client_leg->last_seq_sent+1, OP_EQ, new_exit_leg->last_seq_recv); + tt_int_op(client_leg->last_seq_recv, OP_EQ, new_exit_leg->last_seq_sent); + + done: + return new_client; +} + +/** + * This tests switching as well as the UDP optimization that attaches + * a third circuit and closes the slowest one. (This optimization is not + * implemented in C-Tor but must be supported at exits, for arti). + */ +static void +test_conflux_switch(void *arg) +{ + (void) arg; + test_setup(); + DEFAULT_EXIT_UX = CONFLUX_UX_HIGH_THROUGHPUT; + + launch_new_set(2); + + tt_int_op(smartlist_len(client_circs), OP_EQ, 2); + circuit_t *client1 = smartlist_get(client_circs, 0); + circuit_t *client2 = smartlist_get(client_circs, 1); + get_circuit_build_times_mutable()->timeout_ms = 1000; + + simulate_circuit_build(client1); + simulate_circuit_build(client2); + + circuit_t *exit1 = get_exit_circ(client1); + circuit_t *exit2 = get_exit_circ(client2); + circuit_t *next_circ = client1; + + while (smartlist_len(mock_cell_delivery) > 0) { + tt_int_op(smartlist_len(client_circs), OP_EQ, 2); + tt_int_op(smartlist_len(exit_circs), OP_EQ, 2); + tt_int_op(smartlist_len(circ_pairs), OP_EQ, 2); + + process_mock_cell_delivery(); + } + + // Check to make sure everything is linked`up + tt_ptr_op(client1->conflux, OP_EQ, client2->conflux); + tt_ptr_op(exit1->conflux, OP_EQ, exit2->conflux); + tt_ptr_op(client1->conflux, OP_NE, NULL); + tt_ptr_op(exit1->conflux, OP_NE, NULL); + tt_int_op(smartlist_len(client1->conflux->legs), OP_EQ, 2); + tt_int_op(smartlist_len(exit1->conflux->legs), OP_EQ, 2); + tt_int_op(client1->purpose, OP_EQ, CIRCUIT_PURPOSE_CONFLUX_LINKED); + tt_int_op(client2->purpose, OP_EQ, CIRCUIT_PURPOSE_CONFLUX_LINKED); + + tt_int_op(digest256map_size(get_linked_pool(true)), OP_EQ, 1); + tt_int_op(digest256map_size(get_unlinked_pool(true)), OP_EQ, 0); + tt_int_op(digest256map_size(get_unlinked_pool(false)), OP_EQ, 0); + tt_int_op(digest256map_size(get_linked_pool(false)), OP_EQ, 1); + tt_ptr_op(get_exit_circ(client1), OP_EQ, exit1); + tt_ptr_op(get_exit_circ(client2), OP_EQ, exit2); + + // Give circuits approximately equal RTT: + conflux_update_rtt(client1->conflux, client1, 100); + conflux_update_rtt(client2->conflux, client2, 125); + + client1->conflux->params.alg = CONFLUX_ALG_LOWRTT; + get_exit_circ(client1)->conflux->params.alg = CONFLUX_ALG_LOWRTT; + TO_ORIGIN_CIRCUIT(client1)->cpath->prev->ccontrol->cwnd = 300; + TO_ORIGIN_CIRCUIT(client2)->cpath->prev->ccontrol->cwnd = 300; + + // Keep sending fake cells until we decide to switch four times + for (int i = 0; i < 4; i++) { + next_circ = send_until_switch(next_circ); + + // XXX: This can't be set to 0 or we will decide we can switch immediately, + // because the client1 has a lower RTT + TO_ORIGIN_CIRCUIT(client1)->cpath->prev->ccontrol->inflight = 1; + + // Check to make sure everything is linked`up + tt_ptr_op(client1->conflux, OP_EQ, client2->conflux); + tt_ptr_op(exit1->conflux, OP_EQ, exit2->conflux); + tt_ptr_op(client1->conflux, OP_NE, NULL); + tt_ptr_op(exit1->conflux, OP_NE, NULL); + tt_int_op(smartlist_len(client1->conflux->legs), OP_EQ, 2); + tt_int_op(smartlist_len(exit1->conflux->legs), OP_EQ, 2); + tt_int_op(client1->purpose, OP_EQ, CIRCUIT_PURPOSE_CONFLUX_LINKED); + tt_int_op(client2->purpose, OP_EQ, CIRCUIT_PURPOSE_CONFLUX_LINKED); + + tt_int_op(digest256map_size(get_linked_pool(true)), OP_EQ, 1); + tt_int_op(digest256map_size(get_unlinked_pool(true)), OP_EQ, 0); + tt_int_op(digest256map_size(get_unlinked_pool(false)), OP_EQ, 0); + tt_int_op(digest256map_size(get_linked_pool(false)), OP_EQ, 1); + + tt_ptr_op(get_exit_circ(client1), OP_EQ, exit1); + tt_ptr_op(get_exit_circ(client2), OP_EQ, exit2); + tt_ptr_op(next_circ, OP_EQ, client2); + + next_circ = send_until_switch(next_circ); + + // Check to make sure everything is linked`up + tt_ptr_op(client1->conflux, OP_EQ, client2->conflux); + tt_ptr_op(exit1->conflux, OP_EQ, exit2->conflux); + tt_ptr_op(client1->conflux, OP_NE, NULL); + tt_ptr_op(exit1->conflux, OP_NE, NULL); + tt_int_op(smartlist_len(client1->conflux->legs), OP_EQ, 2); + tt_int_op(smartlist_len(exit1->conflux->legs), OP_EQ, 2); + tt_int_op(client1->purpose, OP_EQ, CIRCUIT_PURPOSE_CONFLUX_LINKED); + tt_int_op(client2->purpose, OP_EQ, CIRCUIT_PURPOSE_CONFLUX_LINKED); + + tt_int_op(digest256map_size(get_linked_pool(true)), OP_EQ, 1); + tt_int_op(digest256map_size(get_unlinked_pool(true)), OP_EQ, 0); + tt_int_op(digest256map_size(get_unlinked_pool(false)), OP_EQ, 0); + tt_int_op(digest256map_size(get_linked_pool(false)), OP_EQ, 1); + + tt_ptr_op(get_exit_circ(client1), OP_EQ, exit1); + tt_ptr_op(get_exit_circ(client2), OP_EQ, exit2); + tt_ptr_op(next_circ, OP_EQ, client1); + + TO_ORIGIN_CIRCUIT(client2)->cpath->prev->ccontrol->inflight = 0; + } + + // Try the UDP minRTT reconnect optimization a few times + for (int i = 0; i < 500; i++) { + tt_int_op(smartlist_len(client_circs), OP_EQ, 2); + client1 = smartlist_get(client_circs, 0); + client2 = smartlist_get(client_circs, 1); + exit1 = get_exit_circ(client1); + exit2 = get_exit_circ(client2); + + // Attach a third leg + conflux_launch_leg(client1->conflux->nonce); + + // It should be added to the end of the local test list + circuit_t *client3 = smartlist_get(client_circs, + smartlist_len(client_circs)-1); + simulate_circuit_build(client3); + + while (smartlist_len(mock_cell_delivery) > 0) { + tt_int_op(smartlist_len(client_circs), OP_EQ, 3); + tt_int_op(smartlist_len(exit_circs), OP_EQ, 3); + tt_int_op(smartlist_len(circ_pairs), OP_EQ, 3); + + process_mock_cell_delivery(); + } + + circuit_t *exit3 = get_exit_circ(client3); + + // Check to make sure everything is linked`up + tt_ptr_op(client3->conflux, OP_EQ, client2->conflux); + tt_ptr_op(exit3->conflux, OP_EQ, exit2->conflux); + tt_ptr_op(client3->conflux, OP_NE, NULL); + tt_ptr_op(exit3->conflux, OP_NE, NULL); + tt_int_op(smartlist_len(client1->conflux->legs), OP_EQ, 3); + tt_int_op(smartlist_len(exit1->conflux->legs), OP_EQ, 3); + tt_int_op(client3->purpose, OP_EQ, CIRCUIT_PURPOSE_CONFLUX_LINKED); + + tt_int_op(digest256map_size(get_linked_pool(true)), OP_EQ, 1); + tt_int_op(digest256map_size(get_unlinked_pool(true)), OP_EQ, 0); + tt_int_op(digest256map_size(get_unlinked_pool(false)), OP_EQ, 0); + tt_int_op(digest256map_size(get_linked_pool(false)), OP_EQ, 1); + + conflux_update_rtt(client3->conflux, client3, + crypto_rand_int_range(90, 200)); + TO_ORIGIN_CIRCUIT(client3)->cpath->prev->ccontrol->cwnd = 300; + + circuit_t *circ_close = NULL; + uint64_t max_rtt = 0; + // Pick the leg with the highest RTT and close it + tor_assert(client3); + tor_assert(client3->conflux); + tor_assert(client3->conflux->legs); + CONFLUX_FOR_EACH_LEG_BEGIN(client3->conflux, leg) { + if (client3->conflux->curr_leg == leg) + continue; + + if (leg->circ_rtts_usec > max_rtt) { + max_rtt = leg->circ_rtts_usec; + circ_close = leg->circ; + } + } CONFLUX_FOR_EACH_LEG_END(leg); + + // Let the second leg "send" all data and close it. + tor_assert(circ_close); + tor_assert(circ_close->conflux); + tor_assert(circ_close->conflux->legs); + CONFLUX_FOR_EACH_LEG_BEGIN(circ_close->conflux, leg) { + TO_ORIGIN_CIRCUIT(leg->circ)->cpath->prev->ccontrol->inflight = 0; + } CONFLUX_FOR_EACH_LEG_END(leg); + + // Close without manual launch (code will not relaunch for linked) + simulate_close_retry(circ_close, false); + + tt_int_op(smartlist_len(mock_cell_delivery), OP_EQ, 0); + tt_int_op(smartlist_len(client_circs), OP_EQ, 2); + tt_int_op(smartlist_len(exit_circs), OP_EQ, 2); + tt_int_op(smartlist_len(circ_pairs), OP_EQ, 2); + + // Send until we switch to the third leg + next_circ = send_until_switch(next_circ); + + // Check to make sure everything is linked`up + tt_ptr_op(next_circ->conflux, OP_NE, NULL); + tt_int_op(smartlist_len(next_circ->conflux->legs), OP_EQ, 2); + tt_int_op(next_circ->purpose, OP_EQ, CIRCUIT_PURPOSE_CONFLUX_LINKED); + + tt_int_op(digest256map_size(get_linked_pool(true)), OP_EQ, 1); + tt_int_op(digest256map_size(get_unlinked_pool(true)), OP_EQ, 0); + tt_int_op(digest256map_size(get_unlinked_pool(false)), OP_EQ, 0); + tt_int_op(digest256map_size(get_linked_pool(false)), OP_EQ, 1); + + CONFLUX_FOR_EACH_LEG_BEGIN(next_circ->conflux, leg) { + TO_ORIGIN_CIRCUIT(leg->circ)->cpath->prev->ccontrol->inflight = 0; + } CONFLUX_FOR_EACH_LEG_END(leg); + + // send until we switch back to the first leg + next_circ = send_until_switch(next_circ); + + // Check to make sure everything is linked`up + tt_ptr_op(next_circ->conflux, OP_NE, NULL); + tt_int_op(smartlist_len(next_circ->conflux->legs), OP_EQ, 2); + tt_int_op(next_circ->purpose, OP_EQ, CIRCUIT_PURPOSE_CONFLUX_LINKED); + + tt_int_op(digest256map_size(get_linked_pool(true)), OP_EQ, 1); + tt_int_op(digest256map_size(get_unlinked_pool(true)), OP_EQ, 0); + tt_int_op(digest256map_size(get_unlinked_pool(false)), OP_EQ, 0); + tt_int_op(digest256map_size(get_linked_pool(false)), OP_EQ, 1); + } + + done: + test_clear_circs(); + test_teardown(); + return; + } + +struct testcase_t conflux_pool_tests[] = { + { "link", test_conflux_link, TT_FORK, NULL, NULL }, + { "link_retry", test_conflux_link_retry, TT_FORK, NULL, NULL }, + { "link_relink", test_conflux_link_relink, TT_FORK, NULL, NULL }, + { "link_streams", test_conflux_link_streams, TT_FORK, NULL, NULL }, + { "switch", test_conflux_switch, TT_FORK, NULL, NULL }, + // XXX: These two currently fail, because they are not finished: + //{ "link_fail", test_conflux_link_fail, TT_FORK, NULL, NULL }, + //{ "close", test_conflux_close, TT_FORK, NULL, NULL }, + END_OF_TESTCASES +}; diff -Nru tor-0.4.7.16/src/test/test_congestion_control.c tor-0.4.9.6/src/test/test_congestion_control.c --- tor-0.4.7.16/src/test/test_congestion_control.c 1970-01-01 00:00:00.000000000 +0000 +++ tor-0.4.9.6/src/test/test_congestion_control.c 2026-03-25 14:30:34.000000000 +0000 @@ -0,0 +1,390 @@ +#include "core/or/or.h" +#include "test/test.h" +#include "test/log_test_helpers.h" +#include "lib/testsupport/testsupport.h" +#include "test/fakecircs.h" +#include "test/rng_test_helpers.h" + +#include "lib/time/compat_time.h" + +#include "core/or/circuitlist.h" +#include "core/or/circuitmux.h" +#include "core/or/channel.h" + +#define TOR_CONGESTION_CONTROL_COMMON_PRIVATE +#define TOR_CONGESTION_CONTROL_PRIVATE +#include "core/or/congestion_control_st.h" +#include "core/or/congestion_control_common.h" +#include "core/or/congestion_control_vegas.h" + +void test_congestion_control_rtt(void *arg); +void test_congestion_control_clock(void *arg); +void test_congestion_control_vegas_cwnd(void *arg); + +static void +circuitmux_attach_circuit_mock(circuitmux_t *cmux, circuit_t *circ, + cell_direction_t direction); + +static void +circuitmux_attach_circuit_mock(circuitmux_t *cmux, circuit_t *circ, + cell_direction_t direction) +{ + (void)cmux; + (void)circ; + (void)direction; + + return; +} + +/* =============== Clock Heuristic Test Vectors =============== */ + +typedef struct clock_vec +{ + uint64_t old_delta_in; + uint64_t new_delta_in; + bool in_slow_start_in; + bool cached_result_out; + bool result_out; +} clock_vec_t; + +static void +run_clock_test_vec(congestion_control_t *cc, + clock_vec_t *vec, size_t vec_len) +{ + for (size_t i = 0; i < vec_len; i++) { + cc->in_slow_start = vec[i].in_slow_start_in; + cc->ewma_rtt_usec = vec[i].old_delta_in*1000; + bool ret = time_delta_stalled_or_jumped(cc, + vec[i].old_delta_in, + vec[i].new_delta_in); + + tt_int_op(ret, OP_EQ, vec[i].result_out); + tt_int_op(is_monotime_clock_broken, OP_EQ, vec[i].cached_result_out); + } + + done: + is_monotime_clock_broken = false; +} + +/** + * This test verifies the behavior of Section 2.1.1 of + * Prop#324 (CLOCK_HEURISTICS). + * + * It checks that we declare the clock value stalled, + * and cache that value, on various time deltas. + * + * It also verifies that our heuristics behave correctly + * with respect to slow start and large clock jumps/stalls. + */ +void +test_congestion_control_clock(void *arg) +{ + (void)arg; + clock_vec_t vect1[] = + { + {0, 1, 1, 0, 0}, // old delta 0, slow start -> false + {0, 0, 1, 1, 1}, // New delta 0 -> cache true, return true + {1, 1, 1, 1, 0}, // In slow start -> keep cache, but return false + {1, 4999, 0, 0, 0}, // Not slow start, edge -> update cache, and false + {4999, 1, 0, 0, 0}, // Not slow start, other edge -> false + {5001, 1, 0, 0, 0}, // Not slow start w/ -5000x -> use cache (false) + {5001, 0, 0, 1, 1}, // New delta 0 -> cache true, return true + {5001, 1, 0, 1, 1}, // Not slow start w/ -5000x -> use cache (true) + {5001, 1, 1, 1, 0}, // In slow start w/ -5000x -> false + {0, 5001, 0, 1, 0}, // Not slow start w/ no EWMA -> false + {1, 5001, 1, 1, 0}, // In slow start w/ +5000x -> false + {1, 1, 0, 0, 0}, // Not slow start -> update cache to false + {5001, 1, 0, 0, 0}, // Not slow start w/ -5000x -> use cache (false) + {1, 5001, 0, 0, 1}, // Not slow start w/ +5000x -> true + {0, 5001, 0, 0, 0}, // Not slow start w/ no EWMA -> false + {5001, 1, 1, 0, 0}, // In slow start w/ -5000x change -> false + {1, 1, 0, 0, 0} // Not slow start -> false + }; + + circuit_params_t params; + + params.cc_enabled = 1; + params.sendme_inc_cells = TLS_RECORD_MAX_CELLS; + cc_alg = CC_ALG_VEGAS; + congestion_control_t *cc = congestion_control_new(¶ms, CC_PATH_EXIT); + + run_clock_test_vec(cc, vect1, sizeof(vect1)/sizeof(clock_vec_t)); + + congestion_control_free(cc); +} + +/* =========== RTT Test Vectors ================== */ + +typedef struct rtt_vec { + uint64_t sent_usec_in; + uint64_t got_sendme_usec_in; + uint64_t cwnd_in; + bool ss_in; + uint64_t curr_rtt_usec_out; + uint64_t ewma_rtt_usec_out; + uint64_t min_rtt_usec_out; +} rtt_vec_t; + +static void +run_rtt_test_vec(congestion_control_t *cc, + rtt_vec_t *vec, size_t vec_len) +{ + for (size_t i = 0; i < vec_len; i++) { + enqueue_timestamp(cc->sendme_pending_timestamps, + vec[i].sent_usec_in); + } + + for (size_t i = 0; i < vec_len; i++) { + cc->cwnd = vec[i].cwnd_in; + cc->in_slow_start = vec[i].ss_in; + uint64_t curr_rtt_usec = congestion_control_update_circuit_rtt(cc, + vec[i].got_sendme_usec_in); + + tt_int_op(curr_rtt_usec, OP_EQ, vec[i].curr_rtt_usec_out); + tt_int_op(cc->min_rtt_usec, OP_EQ, vec[i].min_rtt_usec_out); + tt_int_op(cc->ewma_rtt_usec, OP_EQ, vec[i].ewma_rtt_usec_out); + } + done: + is_monotime_clock_broken = false; +} + +/** + * This test validates current, EWMA, and minRTT calculation + * from Sections 2.1 of Prop#324. + * + * We also do NOT exercise the sendme pacing code here. See + * test_sendme_is_next() for that, in test_sendme.c. + */ +void +test_congestion_control_rtt(void *arg) +{ + (void)arg; + rtt_vec_t vect1[] = { + {100000, 200000, 124, 1, 100000, 100000, 100000}, + {200000, 300000, 124, 1, 100000, 100000, 100000}, + {350000, 500000, 124, 1, 150000, 133333, 100000}, + {500000, 550000, 124, 1, 50000, 77777, 77777}, + {600000, 700000, 124, 1, 100000, 92592, 77777}, + {700000, 750000, 124, 1, 50000, 64197, 64197}, + {750000, 875000, 124, 0, 125000, 104732, 104732}, + {875000, 900000, 124, 0, 25000, 51577, 104732}, + {900000, 950000, 200, 0, 50000, 50525, 50525} + }; + + circuit_params_t params; + congestion_control_t *cc = NULL; + + params.cc_enabled = 1; + params.sendme_inc_cells = TLS_RECORD_MAX_CELLS; + cc_alg = CC_ALG_VEGAS; + + cc = congestion_control_new(¶ms, CC_PATH_EXIT); + run_rtt_test_vec(cc, vect1, sizeof(vect1)/sizeof(rtt_vec_t)); + congestion_control_free(cc); + + return; +} + +/* =========== Vegas CWND Test Vectors ============== */ + +typedef struct cwnd_vec { + uint64_t sent_usec_in; + uint64_t got_sendme_usec_in; + bool or_conn_blocked_in; + uint64_t inflight_in; + uint64_t ewma_rtt_usec_out; + uint64_t min_rtt_usec_out; + uint64_t cwnd_out; + bool in_slow_start_out; + bool cwnd_full_out; + bool blocked_chan_out; +} cwnd_vec_t; + +static void +run_vegas_cwnd_test_vec(congestion_control_t *cc, + circuit_t *circ, + cwnd_vec_t *vec, size_t vec_len) +{ + for (size_t i = 0; i < vec_len; i++) { + enqueue_timestamp(cc->sendme_pending_timestamps, + vec[i].sent_usec_in); + } + + for (size_t i = 0; i < vec_len; i++) { + log_notice(LD_CIRC, "Step %d", (int)i); + monotime_set_mock_time_nsec(vec[i].got_sendme_usec_in*1000); + circ->circuit_blocked_on_p_chan = vec[i].or_conn_blocked_in; + cc->inflight = vec[i].inflight_in; + + congestion_control_vegas_process_sendme(cc, circ); + + /* If the or conn was blocked, ensure we updated our + * CC state */ + if (vec[i].or_conn_blocked_in) { + tt_int_op(cc->next_cc_event, OP_EQ, CWND_UPDATE_RATE(cc)); + } + + tt_int_op(cc->ewma_rtt_usec, OP_EQ, vec[i].ewma_rtt_usec_out); + tt_int_op(cc->min_rtt_usec, OP_EQ, vec[i].min_rtt_usec_out); + tt_int_op(cc->cwnd, OP_EQ, vec[i].cwnd_out); + + tt_int_op(cc->in_slow_start, OP_EQ, vec[i].in_slow_start_out); + tt_int_op(cc->cwnd_full, OP_EQ, vec[i].cwnd_full_out); + tt_int_op(cc->blocked_chan, OP_EQ, vec[i].blocked_chan_out); + } + + done: + is_monotime_clock_broken = false; +} + +/** + * This test validates congestion window updates for the + * TOR_VEGAS congestion control algorithm, from Section 3.3 + * of Prop#324. + * + * It tests updates as a function of the timestamp of the + * cell that would trigger a sendme and the sendme arrival + * timestamp, and as a function of orconn blocking. + * + * It ensures that at least one test vector caused a cwnd update + * due to a blocked OR connection. The orconn blocking logic is + * simulated -- we do NOT actually exercise the orconn code here. + * + * We also do NOT exercise the sendme pacing code here. See + * test_sendme_is_next() for that, in test_sendme.c. + * + * We also do NOT exercise the negotiation code here. See + * test_ntor3_handshake() for that, in test_ntor_v3.c. + */ +void +test_congestion_control_vegas_cwnd(void *arg) +{ + (void)arg; + circuit_params_t params; + /* Replay of RTT edge case checks, plus some extra to exit + * slow start via RTT, and exercise full/not full */ + cwnd_vec_t vect1[] = { + {100000, 200000, 0, 124, 100000, 100000, 155, 1, 0, 0}, + {200000, 300000, 0, 155, 100000, 100000, 186, 1, 1, 0}, + {350000, 500000, 0, 186, 133333, 100000, 217, 1, 1, 0}, + {500000, 550000, 0, 217, 77777, 77777, 248, 1, 1, 0}, + {600000, 700000, 0, 248, 92592, 77777, 279, 1, 1, 0}, + {700000, 750000, 0, 279, 64197, 64197, 310, 1, 0, 0}, // Fullness expiry + {750000, 875000, 0, 310, 104732, 64197, 341, 1, 1, 0}, + {875000, 900000, 0, 341, 51577, 51577, 372, 1, 1, 0}, + {900000, 950000, 0, 279, 50525, 50525, 403, 1, 1, 0}, + {950000, 1000000, 0, 279, 50175, 50175, 434, 1, 1, 0}, + {1000000, 1050000, 0, 279, 50058, 50058, 465, 1, 1, 0}, + {1050000, 1100000, 0, 279, 50019, 50019, 496, 1, 1, 0}, + {1100000, 1150000, 0, 279, 50006, 50006, 527, 1, 1, 0}, + {1150000, 1200000, 0, 279, 50002, 50002, 558, 1, 1, 0}, + {1200000, 1250000, 0, 550, 50000, 50000, 589, 1, 1, 0}, + {1250000, 1300000, 0, 550, 50000, 50000, 620, 1, 0, 0}, // Fullness expiry + {1300000, 1350000, 0, 550, 50000, 50000, 635, 1, 1, 0}, + {1350000, 1400000, 0, 550, 50000, 50000, 650, 1, 1, 0}, + {1400000, 1450000, 0, 150, 50000, 50000, 650, 1, 0, 0}, // cwnd not full + {1450000, 1500000, 0, 150, 50000, 50000, 650, 1, 0, 0}, // cwnd not full + {1500000, 1550000, 0, 550, 50000, 50000, 664, 1, 1, 0}, // cwnd full + {1500000, 1600000, 0, 550, 83333, 50000, 584, 0, 1, 0}, // gamma exit + {1600000, 1650000, 0, 550, 61111, 50000, 585, 0, 1, 0}, // alpha + {1650000, 1700000, 0, 550, 53703, 50000, 586, 0, 1, 0}, + {1700000, 1750000, 0, 100, 51234, 50000, 586, 0, 0, 0}, // alpha, not full + {1750000, 1900000, 0, 100, 117078, 50000, 559, 0, 0, 0}, // delta, not full + {1900000, 2000000, 0, 100, 105692, 50000, 558, 0, 0, 0}, // beta, not full + {2000000, 2075000, 0, 500, 85230, 50000, 558, 0, 1, 0}, // no change + {2075000, 2125000, 1, 500, 61743, 50000, 557, 0, 1, 1}, // beta, blocked + {2125000, 2150000, 0, 500, 37247, 37247, 558, 0, 1, 0}, // alpha + {2150000, 2350000, 0, 500, 145749, 37247, 451, 0, 1, 0} // delta + }; + /* Test exiting slow start via blocked orconn */ + cwnd_vec_t vect2[] = { + {100000, 200000, 0, 124, 100000, 100000, 155, 1, 0, 0}, + {200000, 300000, 0, 155, 100000, 100000, 186, 1, 1, 0}, + {350000, 500000, 0, 186, 133333, 100000, 217, 1, 1, 0}, + {500000, 550000, 1, 217, 77777, 77777, 403, 0, 1, 1}, // ss exit, blocked + {600000, 700000, 0, 248, 92592, 77777, 404, 0, 1, 0}, // alpha + {700000, 750000, 1, 404, 64197, 64197, 403, 0, 0, 1}, // blocked beta + {750000, 875000, 0, 403, 104732, 64197, 404, 0, 1, 0} + }; + /* Real upload 1 */ + cwnd_vec_t vect3[] = { + { 18258527, 19002938, 0, 83, 744411, 744411, 155, 1, 0, 0 }, + { 18258580, 19254257, 0, 52, 911921, 744411, 186, 1, 1, 0 }, + { 20003224, 20645298, 0, 164, 732023, 732023, 217, 1, 1, 0 }, + { 20003367, 21021444, 0, 133, 922725, 732023, 248, 1, 1, 0 }, + { 20003845, 21265508, 0, 102, 1148683, 732023, 279, 1, 1, 0 }, + { 20003975, 21429157, 0, 71, 1333015, 732023, 310, 1, 0, 0 }, + { 20004309, 21707677, 0, 40, 1579917, 732023, 310, 1, 0, 0 } + }; + /* Real upload 2 */ + cwnd_vec_t vect4[] = { + { 358297091, 358854163, 0, 83, 557072, 557072, 155, 1, 0, 0 }, + { 358297649, 359123845, 0, 52, 736488, 557072, 186, 1, 1, 0 }, + { 359492879, 359995330, 0, 186, 580463, 557072, 217, 1, 1, 0 }, + { 359493043, 360489243, 0, 217, 857621, 557072, 248, 1, 1, 0 }, + { 359493232, 360489673, 0, 248, 950167, 557072, 279, 1, 1, 0 }, + { 359493795, 360489971, 0, 279, 980839, 557072, 310, 1, 0, 0 }, + { 359493918, 360490248, 0, 310, 991166, 557072, 341, 1, 1, 0 }, + { 359494029, 360716465, 0, 341, 1145346, 557072, 372, 1, 1, 0 }, + { 359996888, 360948867, 0, 372, 1016434, 557072, 403, 1, 1, 0 }, + { 359996979, 360949330, 0, 403, 973712, 557072, 434, 1, 1, 0 }, + { 360489528, 361113615, 0, 434, 740628, 557072, 465, 1, 1, 0 }, + { 360489656, 361281604, 0, 465, 774841, 557072, 496, 1, 1, 0 }, + { 360489837, 361500461, 0, 496, 932029, 557072, 482, 0, 1, 0 }, + { 360489963, 361500631, 0, 482, 984455, 557072, 482, 0, 1, 0 }, + { 360490117, 361842481, 0, 482, 1229727, 557072, 481, 0, 1, 0 } + }; + + congestion_control_t *cc = NULL; + channel_t dummy_channel = {0}; + + MOCK(circuitmux_attach_circuit, circuitmux_attach_circuit_mock); + testing_enable_reproducible_rng(); + + monotime_init(); + monotime_enable_test_mocking(); + monotime_set_mock_time_nsec(0); + + dummy_channel.cmux = circuitmux_alloc(); + circuit_t *circ = TO_CIRCUIT(new_fake_orcirc(&dummy_channel, + &dummy_channel)); + circ->purpose = CIRCUIT_PURPOSE_OR; + + params.cc_enabled = 1; + params.sendme_inc_cells = TLS_RECORD_MAX_CELLS; + cc_alg = CC_ALG_VEGAS; + + cc = congestion_control_new(¶ms, CC_PATH_EXIT); + run_vegas_cwnd_test_vec(cc, circ, vect1, + sizeof(vect1)/sizeof(cwnd_vec_t)); + congestion_control_free(cc); + + cc = congestion_control_new(¶ms, CC_PATH_EXIT); + run_vegas_cwnd_test_vec(cc, circ, vect2, + sizeof(vect2)/sizeof(cwnd_vec_t)); + congestion_control_free(cc); + + cc = congestion_control_new(¶ms, CC_PATH_EXIT); + run_vegas_cwnd_test_vec(cc, circ, vect3, + sizeof(vect3)/sizeof(cwnd_vec_t)); + congestion_control_free(cc); + + cc = congestion_control_new(¶ms, CC_PATH_EXIT); + run_vegas_cwnd_test_vec(cc, circ, vect4, + sizeof(vect4)/sizeof(cwnd_vec_t)); + congestion_control_free(cc); + + //done: + circuitmux_free(dummy_channel.cmux); + return; +} + +#define TEST_CONGESTION_CONTROL(name, flags) \ + { #name, test_##name, (flags), NULL, NULL } + +struct testcase_t congestion_control_tests[] = { + TEST_CONGESTION_CONTROL(congestion_control_clock, TT_FORK), + TEST_CONGESTION_CONTROL(congestion_control_rtt, TT_FORK), + TEST_CONGESTION_CONTROL(congestion_control_vegas_cwnd, TT_FORK), + END_OF_TESTCASES +}; diff -Nru tor-0.4.7.16/src/test/test_connection.c tor-0.4.9.6/src/test/test_connection.c --- tor-0.4.7.16/src/test/test_connection.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/test/test_connection.c 2026-03-25 14:30:34.000000000 +0000 @@ -22,6 +22,7 @@ #include "feature/dircommon/directory.h" #include "core/or/connection_or.h" #include "lib/net/resolve.h" +#include "lib/evloop/compat_libevent.h" #include "test/test_connection.h" #include "test/test_helpers.h" @@ -113,14 +114,8 @@ /* We didn't call tor_libevent_initialize(), so event_base was NULL, * so we can't rely on connection_unregister_events() use of event_del(). */ - if (conn->linked_conn->read_event) { - tor_free(conn->linked_conn->read_event); - conn->linked_conn->read_event = NULL; - } - if (conn->linked_conn->write_event) { - tor_free(conn->linked_conn->write_event); - conn->linked_conn->write_event = NULL; - } + tor_event_free(conn->linked_conn->read_event); + tor_event_free(conn->linked_conn->write_event); if (!conn->linked_conn->marked_for_close) { connection_close_immediate(conn->linked_conn); @@ -142,14 +137,8 @@ /* We didn't set the events up properly, so we can't use event_del() in * close_closeable_connections() > connection_free() * > connection_unregister_events() */ - if (conn->read_event) { - tor_free(conn->read_event); - conn->read_event = NULL; - } - if (conn->write_event) { - tor_free(conn->write_event); - conn->write_event = NULL; - } + tor_event_free(conn->read_event); + tor_event_free(conn->write_event); if (!conn->marked_for_close) { connection_close_immediate(conn); diff -Nru tor-0.4.7.16/src/test/test_crypto.c tor-0.4.9.6/src/test/test_crypto.c --- tor-0.4.7.16/src/test/test_crypto.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/test/test_crypto.c 2026-03-25 14:30:34.000000000 +0000 @@ -6,10 +6,14 @@ #include "orconfig.h" #define CRYPTO_CURVE25519_PRIVATE #define CRYPTO_RAND_PRIVATE +#define USE_AES_RAW +#define TOR_AES_PRIVATE #include "core/or/or.h" #include "test/test.h" #include "lib/crypt_ops/aes.h" #include "siphash.h" +#include "ext/compat_blake2.h" +#include "ext/equix/hashx/include/hashx.h" #include "lib/crypt_ops/crypto_curve25519.h" #include "lib/crypt_ops/crypto_dh.h" #include "lib/crypt_ops/crypto_ed25519.h" @@ -19,6 +23,7 @@ #include "lib/crypt_ops/crypto_init.h" #include "ed25519_vectors.inc" #include "test/log_test_helpers.h" +#include "ext/polyval/polyval.h" #ifdef HAVE_SYS_STAT_H #include @@ -41,10 +46,10 @@ crypto_dh_t *dh1 = crypto_dh_new(DH_TYPE_CIRCUIT); crypto_dh_t *dh1_dup = NULL; crypto_dh_t *dh2 = crypto_dh_new(DH_TYPE_CIRCUIT); - char p1[DH1024_KEY_LEN]; - char p2[DH1024_KEY_LEN]; - char s1[DH1024_KEY_LEN]; - char s2[DH1024_KEY_LEN]; + char p1[DH2048_KEY_LEN]; + char p2[DH2048_KEY_LEN]; + char s1[DH2048_KEY_LEN]; + char s2[DH2048_KEY_LEN]; ssize_t s1len, s2len; #ifdef ENABLE_OPENSSL crypto_dh_t *dh3 = NULL; @@ -180,27 +185,23 @@ { /* Make sure that our crypto library can handshake with openssl. */ dh3 = crypto_dh_new(DH_TYPE_TLS); - tt_assert(!crypto_dh_get_public(dh3, p1, DH1024_KEY_LEN)); + tt_assert(!crypto_dh_get_public(dh3, p1, sizeof(p1))); dh4 = crypto_dh_new_openssl_tls(); tt_assert(DH_generate_key(dh4)); const BIGNUM *pk=NULL; -#ifdef OPENSSL_1_1_API const BIGNUM *sk=NULL; DH_get0_key(dh4, &pk, &sk); -#else - pk = dh4->pub_key; -#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_LE, DH_TLS_KEY_BITS / 8); tt_int_op(BN_num_bytes(pk), OP_GT, 0); memset(p2, 0, sizeof(p2)); /* right-pad. */ - BN_bn2bin(pk, (unsigned char *)(p2+DH1024_KEY_LEN-BN_num_bytes(pk))); + BN_bn2bin(pk, (unsigned char *)(p2+sizeof(p2)-BN_num_bytes(pk))); - s1len = crypto_dh_handshake(LOG_WARN, dh3, p2, DH1024_KEY_LEN, + s1len = crypto_dh_handshake(LOG_WARN, dh3, p2, DH_TLS_KEY_BITS / 8, (unsigned char *)s1, sizeof(s1)); - pubkey_tmp = BN_bin2bn((unsigned char *)p1, DH1024_KEY_LEN, NULL); + pubkey_tmp = BN_bin2bn((unsigned char *)p1, DH_TLS_KEY_BITS / 8, NULL); s2len = DH_compute_key((unsigned char *)s2, pubkey_tmp, dh4); tt_int_op(s1len, OP_EQ, s2len); @@ -258,14 +259,12 @@ static void test_crypto_aes128(void *arg) { + (void)arg; char *data1 = NULL, *data2 = NULL, *data3 = NULL; crypto_cipher_t *env1 = NULL, *env2 = NULL; int i, j; char *mem_op_hex_tmp=NULL; char key[CIPHER_KEY_LEN]; - int use_evp = !strcmp(arg,"evp"); - evaluate_evp_for_aes(use_evp); - evaluate_ctr_for_aes(); data1 = tor_malloc(1024); data2 = tor_malloc(1024); @@ -1043,6 +1042,7 @@ { const char msg[] = "i am in a library somewhere using my computer"; const char key[] = "i'm from the past talking to the future."; + char *mem_op_hex_tmp = NULL; uint8_t hmac_test[DIGEST256_LEN]; char hmac_manual[DIGEST256_LEN]; @@ -1077,7 +1077,12 @@ /* Now compare the two results */ tt_mem_op(hmac_test, OP_EQ, hmac_manual, DIGEST256_LEN); - done: ; + /* Check against a known correct value (computed from python) */ + test_memeq_hex(hmac_test, + "753fba6d87d49497238a512a3772dd29" + "1e55f7d1cd332c9fb5c967c7a10a13ca"); + done: + tor_free(mem_op_hex_tmp); } /** Run unit tests for our public key crypto functions */ @@ -1627,14 +1632,12 @@ static void test_crypto_aes_iv(void *arg) { + (void)arg; char *plain, *encrypted1, *encrypted2, *decrypted1, *decrypted2; char plain_1[1], plain_15[15], plain_16[16], plain_17[17]; char key1[16], key2[16]; ssize_t encrypted_size, decrypted_size; - int use_evp = !strcmp(arg,"evp"); - evaluate_evp_for_aes(use_evp); - plain = tor_malloc(4095); encrypted1 = tor_malloc(4095 + 1 + 16); encrypted2 = tor_malloc(4095 + 1 + 16); @@ -2844,6 +2847,181 @@ ; } +static void +test_crypto_blake2b(void *arg) +{ + (void)arg; + + /* There is no official blake2b test vector set, but these are inspired + * by RFC7693 and OpenSSL. Note that we need to test shorter hash lengths + * separately even though they are implemented by truncating a 512-bit + * hash, because the requested length is included in the hash initial state. + */ + static const struct { + const char *in_literal; + const char *out_hex; + } vectors[] = { + { "", + "786a02f742015903c6c6fd852552d272912f4740e15847618a86e217f71f5419" + "d25e1031afee585313896444934eb04b903a685b1448b755d56f701afe9be2ce" + }, + { "a", + "333fcb4ee1aa7c115355ec66ceac917c8bfd815bf7587d325aec1864edd24e34" + "d5abe2c6b1b5ee3face62fed78dbef802f2a85cb91d455a8f5249d330853cb3c" + }, + { "ab", + "b32c0573d242b3a987d8f66bd43266b7925cefab3a854950641a81ef6a3f4b97" + "928443850545770f64abac2a75f18475653fa3d9a52c66a840da3b8617ae9607" + }, + { "abc", + "ba80a53f981c4d0d6a2797b69f12f6e94c212f14685ac4b74b12bb6fdbffa2d1" + "7d87c5392aab792dc252d5de4533cc9518d38aa8dbf1925ab92386edd4009923" + }, + { "", "2e" }, + { "a", "de" }, + { "ab", "0e" }, + { "abc", "6b" }, + { "", "1271cf25" }, + { "a", "ca234c55" }, + { "ab", "3ae897a7" }, + { "abc", "63906248" }, + { "A somewhat longer test vector for blake2b xxxxxxxxxxxxxxxxxxxxxx" + "yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz.", + "1d27b0988061a82ff7563a55f9289ff3d878783e688d9e001b3c4b99b675c7f7" + "1d4ae57805c6a8e670eb8145ba97960a7859451ab7b1558a60e5b7660d2f4639" + }, + { "A somewhat longer test vector for blake2b xxxxxxxxxxxxxxxxxxxxxx" + "yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz.", + "48600bb0" + } + }; + + static const struct { + int update_size; + } variations[] = { + {BLAKE2B_BLOCKBYTES*2}, + {BLAKE2B_BLOCKBYTES}, + {BLAKE2B_BLOCKBYTES-1}, + {1}, + {2}, + {3} + }; + + const size_t num_vectors = sizeof vectors / sizeof vectors[0]; + const size_t num_variations = sizeof variations / sizeof variations[0]; + + for (unsigned vec_i = 0; vec_i < num_vectors; vec_i++) { + const char *in_literal = vectors[vec_i].in_literal; + const char *out_hex = vectors[vec_i].out_hex; + const size_t in_len = strlen(in_literal); + const size_t out_hex_len = strlen(out_hex); + const size_t hash_size = out_hex_len / 2; + + int retval = -1; + uint8_t out_expected[BLAKE2B_OUTBYTES] = { 0 }; + tt_int_op(out_hex_len, OP_EQ, 2 * hash_size); + tt_int_op(hash_size, OP_LE, sizeof out_expected); + retval = base16_decode((char*)out_expected, hash_size, + out_hex, out_hex_len); + tt_int_op(retval, OP_EQ, hash_size); + + for (size_t vari_i = 0; vari_i < num_variations; vari_i++) { + const size_t update_size = variations[vari_i].update_size; + uint8_t out_actual[BLAKE2B_OUTBYTES] = { 0 }; + + blake2b_state b2_state; + retval = blake2b_init(&b2_state, hash_size); + tt_int_op(retval, OP_EQ, 0); + + for (size_t in_off = 0; in_off < in_len;) { + const size_t this_update = MIN(update_size, in_len - in_off); + blake2b_update(&b2_state, (uint8_t*)in_literal + in_off, this_update); + in_off += this_update; + } + + memset(out_actual, 0xa5, sizeof out_actual); + blake2b_final(&b2_state, out_actual, hash_size); + tt_mem_op(out_actual, OP_EQ, out_expected, hash_size); + } + } + + done: + ; +} + +static void +test_crypto_hashx(void *arg) +{ + (void)arg; + + /* Specifically test the embedded instance of HashX inside Equi-X. + * It uses a non-default setting of HASHX_SIZE=8 */ + static const struct { + const char *seed_literal; + uint64_t hash_input; + const char *out_hex; + } vectors[] = { + { "", 0, "466cc2021c268560" }, + { "a", 0, "b2a110ee695c475c" }, + { "ab", 0, "57c77f7e0d2c1727" }, + { "abc", 0, "ef560991338086d1" }, + { "", 999, "304068b62bc4874e" }, + { "a", 999, "c8b66a8eb4bba304" }, + { "ab", 999, "26c1f7031f0b3645" }, + { "abc", 999, "de84f9d286b39ab5" }, + { "abc", UINT64_MAX, "f756c266a3cb3b5a" } + }; + + static const struct { + hashx_type type; + } variations[] = { + { HASHX_TYPE_INTERPRETED }, +#if defined(_M_X64) || defined(__x86_64__) || defined(__aarch64__) + { HASHX_TYPE_COMPILED }, +#endif + }; + + const unsigned num_vectors = sizeof vectors / sizeof vectors[0]; + const unsigned num_variations = sizeof variations / sizeof variations[0]; + hashx_ctx *ctx = NULL; + + for (unsigned vec_i = 0; vec_i < num_vectors; vec_i++) { + const char *seed_literal = vectors[vec_i].seed_literal; + const uint64_t hash_input = vectors[vec_i].hash_input; + const char *out_hex = vectors[vec_i].out_hex; + const size_t seed_len = strlen(seed_literal); + const size_t out_hex_len = strlen(out_hex); + + int retval = -1; + uint8_t out_expected[HASHX_SIZE] = { 0 }; + tt_int_op(out_hex_len, OP_EQ, 2 * HASHX_SIZE); + retval = base16_decode((char*)out_expected, HASHX_SIZE, + out_hex, out_hex_len); + tt_int_op(retval, OP_EQ, HASHX_SIZE); + + for (unsigned vari_i = 0; vari_i < num_variations; vari_i++) { + uint8_t out_actual[HASHX_SIZE] = { 0 }; + + hashx_free(ctx); + ctx = hashx_alloc(variations[vari_i].type); + + tt_ptr_op(ctx, OP_NE, NULL); + retval = hashx_make(ctx, seed_literal, seed_len); + tt_int_op(retval, OP_EQ, HASHX_OK); + + memset(out_actual, 0xa5, sizeof out_actual); + retval = hashx_exec(ctx, hash_input, out_actual); + tt_int_op(retval, OP_EQ, HASHX_OK); + tt_mem_op(out_actual, OP_EQ, out_expected, sizeof out_actual); + } + } + + done: + hashx_free(ctx); +} + /* We want the likelihood that the random buffer exhibits any regular pattern * to be far less than the memory bit error rate in the int return value. * Using 2048 bits provides a failure rate of 1/(3 * 10^616), and we call @@ -3009,6 +3187,253 @@ ; } +static void +test_crypto_polyval(void *arg) +{ + (void)arg; + polyval_t pv; + uint8_t key[16]; + uint8_t input[48]; + uint8_t output[16]; + uint8_t output2[16]; + char *mem_op_hex_tmp=NULL; + uint8_t *longer = NULL; + + // From RFC 8452 + const char *key_hex = "25629347589242761d31f826ba4b757b"; + const char *input_hex = + "4f4f95668c83dfb6401762bb2d01a262" + "d1a24ddd2721d006bbe45f20d3c9f362"; + memset(input, 0, sizeof(input)); + base16_decode((char*)key,sizeof(key), key_hex, strlen(key_hex)); + base16_decode((char*)input,sizeof(input), input_hex, strlen(input_hex)); + + // Two blocks, directly. + polyval_init(&pv, key); + polyval_add_block(&pv, input); + polyval_add_block(&pv, input+16); + polyval_get_tag(&pv, output); + test_memeq_hex(output, "f7a3b47b846119fae5b7866cf5e5b77e"); + // Two blocks, as a string. + polyval_reset(&pv); + polyval_add_zpad(&pv, input, 32); + polyval_get_tag(&pv, output); + test_memeq_hex(output, "f7a3b47b846119fae5b7866cf5e5b77e"); + + // Now make sure that zero-padding works. + input[32] = 77; + polyval_reset(&pv); + polyval_add_block(&pv, input); + polyval_add_block(&pv, input+16); + polyval_add_block(&pv, input+32); + polyval_get_tag(&pv, output); + + polyval_reset(&pv); + polyval_add_zpad(&pv, input, 33); + polyval_get_tag(&pv, output2); + tt_mem_op(output, OP_EQ, output2, 16); + + // Try a long input both ways, and make sure the answer is the same. + longer = tor_malloc_zero(4096); + crypto_rand((char *)longer, 4090); // leave zeros at the end. + polyval_reset(&pv); + polyval_add_zpad(&pv, longer, 4090); + polyval_get_tag(&pv, output); + + polyval_reset(&pv); + const uint8_t *cp; + for (cp = longer; cp < longer + 4096; cp += 16) { + polyval_add_block(&pv, cp); + } + polyval_get_tag(&pv, output2); + tt_mem_op(output, OP_EQ, output2, 16); + + // Now the same with polyvalx. + polyvalx_t pvx; + polyvalx_init(&pvx, key); + polyvalx_add_zpad(&pvx, longer, 4090); + polyvalx_get_tag(&pvx, output2); + tt_mem_op(output, OP_EQ, output2, 16); + + polyvalx_reset(&pvx); + for (cp = longer; cp < longer + 4096; cp += 16) { + polyvalx_add_block(&pvx, cp); + } + polyvalx_get_tag(&pvx, output2); + tt_mem_op(output, OP_EQ, output2, 16); + + done: + tor_free(mem_op_hex_tmp); + tor_free(longer); +} + +static void +test_aes_raw_one(int keybits, + const char *key_hex, + const char *plaintext_hex, + const char *ciphertext_hex) +{ + aes_raw_t *enc = NULL; + aes_raw_t *dec = NULL; + uint8_t key[32]; // max key size. + uint8_t pt[16], ct[16], block[16]; + tt_int_op(keybits, OP_EQ, strlen(key_hex) * 8 / 2); + base16_decode((char*)key, sizeof(key), key_hex, strlen(key_hex)); + base16_decode((char*)pt, sizeof(pt), plaintext_hex, strlen(plaintext_hex)); + base16_decode((char*)ct, sizeof(ct), ciphertext_hex, strlen(ciphertext_hex)); + + enc = aes_raw_new(key, keybits, true); + dec = aes_raw_new(key, keybits, false); + memcpy(block, pt, sizeof(pt)); + aes_raw_encrypt(enc, block); + tt_mem_op(block, OP_EQ, ct, 16); + aes_raw_decrypt(dec, block); + tt_mem_op(block, OP_EQ, pt, 16); + + done: + aes_raw_free(enc); + aes_raw_free(dec); +} + +static void +test_crypto_aes_raw(void *arg) +{ + (void)arg; + +#define T test_aes_raw_one + + /* From https://csrc.nist.gov/CSRC/media/Projects/ + Cryptographic-Algorithm-Validation-Program/documents/aes/AESAVS.pdf */ + const char *z128 = + "00000000000000000000000000000000"; + const char *z192 = + "00000000000000000000000000000000" + "0000000000000000"; + const char *z256 = + "00000000000000000000000000000000" + "00000000000000000000000000000000"; + + T(128, z128, + "f34481ec3cc627bacd5dc3fb08f273e6", + "0336763e966d92595a567cc9ce537f5e"); + T(192, z192, + "1b077a6af4b7f98229de786d7516b639", + "275cfc0413d8ccb70513c3859b1d0f72"); + T(256, z256, + "014730f80ac625fe84f026c60bfd547d", + "5c9d844ed46f9885085e5d6a4f94c7d7"); + T(128, + "10a58869d74be5a374cf867cfb473859", z128, + "6d251e6944b051e04eaa6fb4dbf78465"); + T(192, + "e9f065d7c13573587f7875357dfbb16c53489f6a4bd0f7cd", z128, + "0956259c9cd5cfd0181cca53380cde06"); + T(256, + "c47b0294dbbbee0fec4757f22ffeee35" + "87ca4730c3d33b691df38bab076bc558", z128, + "46f2fb342d6f0ab477476fc501242c5f"); + +#undef T +} + +/** Make sure that we can set keys on live AES instances correctly. */ +static void +test_crypto_aes_keymanip_cnt(void *arg) +{ + (void) arg; + uint8_t k1[16] = "123456780123678"; + uint8_t k2[16] = "abcdefghijklmno"; + int kbits = 128; + uint8_t iv1[16]= "{return 4;}////"; + uint8_t iv2[16] = {0}; + uint8_t buf[128] = {0}; + uint8_t buf2[128] = {0}; + + aes_cnt_cipher_t *aes = aes_new_cipher(k1, iv1, kbits); + aes_crypt_inplace(aes, (char*)buf, sizeof(buf)); + + aes_cnt_cipher_t *aes2 = aes_new_cipher(k2, iv2, kbits); + // 128-5 to make sure internal buf is cleared when we set key. + aes_crypt_inplace(aes2, (char*)buf2, sizeof(buf2)-5); + aes_cipher_set_key(aes2, k1, kbits); + aes_cipher_set_iv_aligned(aes2, iv1); // should work in this case. + memset(buf2, 0, sizeof(buf2)); + aes_crypt_inplace(aes2, (char*)buf2, sizeof(buf2)); + tt_mem_op(buf, OP_EQ, buf2, sizeof(buf)); + + done: + aes_cipher_free(aes); + aes_cipher_free(aes2); +} + +static void +test_crypto_aes_keymanip_ecb(void *arg) +{ + (void) arg; + uint8_t k1[16] = "123456780123678"; + uint8_t k2[16] = "abcdefghijklmno"; + int kbits = 128; + uint8_t buf_orig[16] = {1,2,3,0}; + uint8_t buf1[16]; + uint8_t buf2[16]; + + aes_raw_t *aes1 = aes_raw_new(k1, kbits, true); + aes_raw_t *aes2 = aes_raw_new(k1, kbits, false); + aes_raw_set_key(&aes2, k2, kbits, false); + + memcpy(buf1, buf_orig, 16); + memcpy(buf2, buf_orig, 16); + + aes_raw_encrypt(aes1, buf1); + aes_raw_encrypt(aes1, buf2); + tt_mem_op(buf1, OP_EQ, buf2, 16); + + aes_raw_decrypt(aes2, buf1); + aes_raw_set_key(&aes2, k1, kbits, false); + aes_raw_decrypt(aes2, buf2); + + tt_mem_op(buf1, OP_NE, buf2, 16); + tt_mem_op(buf2, OP_EQ, buf_orig, 16); + + done: + aes_raw_free(aes1); + aes_raw_free(aes2); +} + +static void +test_crypto_aes_cnt_set_iv(void *arg) +{ + (void)arg; + uint8_t k1[16] = "123456780123678"; + uint8_t iv_zero[16] = {0}; + int kbits = 128; + const int iters = 100; + uint8_t buf1[128]; + uint8_t buf2[128]; + + aes_cnt_cipher_t *aes1, *aes2 = NULL; + aes1 = aes_new_cipher(k1, iv_zero, kbits); + + for (int i = 0; i < iters; ++i) { + uint8_t iv[16]; + crypto_rand((char*) iv, sizeof(iv)); + memset(buf1, 0, sizeof(buf1)); + memset(buf2, 0, sizeof(buf2)); + + aes_cipher_set_iv_aligned(aes1, iv); + aes2 = aes_new_cipher(k1, iv, kbits); + + aes_crypt_inplace(aes1, (char*)buf1, sizeof(buf1)); + aes_crypt_inplace(aes2, (char*)buf1, sizeof(buf2)); + tt_mem_op(buf1, OP_EQ, buf2, sizeof(buf1)); + + aes_cipher_free(aes2); + } + done: + aes_cipher_free(aes1); + aes_cipher_free(aes2); +} + #ifndef COCCI #define CRYPTO_LEGACY(name) \ { #name, test_crypto_ ## name , 0, NULL, NULL } @@ -3025,8 +3450,7 @@ struct testcase_t crypto_tests[] = { CRYPTO_LEGACY(formats), { "openssl_version", test_crypto_openssl_version, TT_FORK, NULL, NULL }, - { "aes_AES", test_crypto_aes128, TT_FORK, &passthrough_setup, (void*)"aes" }, - { "aes_EVP", test_crypto_aes128, TT_FORK, &passthrough_setup, (void*)"evp" }, + { "aes", test_crypto_aes128, TT_FORK, NULL, NULL }, { "aes128_ctr_testvec", test_crypto_aes_ctr_testvec, 0, &passthrough_setup, (void*)"128" }, { "aes192_ctr_testvec", test_crypto_aes_ctr_testvec, 0, @@ -3047,10 +3471,7 @@ { "sha3_xof", test_crypto_sha3_xof, TT_FORK, NULL, NULL}, { "mac_sha3", test_crypto_mac_sha3, TT_FORK, NULL, NULL}, CRYPTO_LEGACY(dh), - { "aes_iv_AES", test_crypto_aes_iv, TT_FORK, &passthrough_setup, - (void*)"aes" }, - { "aes_iv_EVP", test_crypto_aes_iv, TT_FORK, &passthrough_setup, - (void*)"evp" }, + { "aes_iv_EVP", test_crypto_aes_iv, TT_FORK, NULL, NULL }, CRYPTO_LEGACY(base32_decode), { "kdf_TAP", test_crypto_kdf_TAP, 0, NULL, NULL }, { "hkdf_sha256", test_crypto_hkdf_sha256, 0, NULL, NULL }, @@ -3073,6 +3494,13 @@ ED25519_TEST(validation, 0), { "ed25519_storage", test_crypto_ed25519_storage, 0, NULL, NULL }, { "siphash", test_crypto_siphash, 0, NULL, NULL }, + { "blake2b", test_crypto_blake2b, 0, NULL, NULL }, + { "hashx", test_crypto_hashx, 0, NULL, NULL }, { "failure_modes", test_crypto_failure_modes, TT_FORK, NULL, NULL }, + { "polyval", test_crypto_polyval, 0, NULL, NULL }, + { "aes_raw", test_crypto_aes_raw, 0, NULL, NULL }, + { "aes_keymanip_cnt", test_crypto_aes_keymanip_cnt, 0, NULL, NULL }, + { "aes_keymanip_ecb", test_crypto_aes_keymanip_ecb, 0, NULL, NULL }, + { "aes_cnt_set_iv", test_crypto_aes_cnt_set_iv, 0, NULL, NULL }, END_OF_TESTCASES }; diff -Nru tor-0.4.7.16/src/test/test_crypto_cgo.c tor-0.4.9.6/src/test/test_crypto_cgo.c --- tor-0.4.7.16/src/test/test_crypto_cgo.c 1970-01-01 00:00:00.000000000 +0000 +++ tor-0.4.9.6/src/test/test_crypto_cgo.c 2026-03-25 14:30:34.000000000 +0000 @@ -0,0 +1,647 @@ +/* Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2021, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#define RELAY_CRYPTO_CGO_PRIVATE +#define USE_AES_RAW + +#include "orconfig.h" +#include "core/or/or.h" +#include "test/test.h" +#include "lib/cc/compat_compiler.h" +#include "lib/crypt_ops/aes.h" +#include "ext/polyval/polyval.h" +#include "core/crypto/relay_crypto_cgo.h" +#include "lib/crypt_ops/crypto_rand.h" +#include "lib/crypt_ops/crypto_util.h" +#include "core/or/cell_st.h" + +#include "test/cgo_vectors.inc" + +static const int AESBITS[] = { 128, 192, 256 }; + +static void +test_crypto_cgo_et_roundtrip(void *arg) +{ + (void)arg; + uint8_t key[32 + 16]; // max + uint8_t tweak_h[16]; + uint8_t tweak_x_r[493]; + uint8_t block[16], block_orig[16]; + cgo_et_t et1, et2; + memset(&et1, 0, sizeof(et1)); + memset(&et2, 0, sizeof(et2)); + + et_tweak_t tweak = { + .uiv = { + .h = tweak_h, + .cmd = 7, + }, + .x_r = tweak_x_r, + }; + + for (int bi = 0; bi < (int) ARRAY_LENGTH(AESBITS); ++bi) { + const int aesbits = AESBITS[bi]; + + for (int i = 0; i < 16; ++i) { + crypto_rand((char*)key, sizeof(key)); + crypto_rand((char*)tweak_h, sizeof(tweak_h)); + crypto_rand((char*)tweak_x_r, sizeof(tweak_x_r)); + crypto_rand((char*)block_orig, sizeof(block_orig)); + memcpy(block, block_orig, 16); + cgo_et_init(&et1, aesbits, true, key); + cgo_et_init(&et2, aesbits, false, key); + + // encrypt-then-decrypt should round-trip. + cgo_et_encrypt(&et1, tweak, block); + tt_mem_op(block, OP_NE, block_orig, 16); + cgo_et_decrypt(&et2, tweak, block); + tt_mem_op(block, OP_EQ, block_orig, 16); + + // decrypt-then-encrypt should round-trip. + cgo_et_decrypt(&et2, tweak, block); + tt_mem_op(block, OP_NE, block_orig, 16); + cgo_et_encrypt(&et1, tweak, block); + tt_mem_op(block, OP_EQ, block_orig, 16); + + cgo_et_clear(&et1); + cgo_et_clear(&et2); + } + } + done: + cgo_et_clear(&et1); + cgo_et_clear(&et2); +} + +static void +test_crypto_cgo_uiv_roundtrip(void *arg) +{ + (void)arg; + uint8_t key[64 + 32]; // max + uint8_t tweak_h[16]; + uint8_t cell[509], cell_orig[509]; + cgo_uiv_t uiv1, uiv2; + memset(&uiv1, 0, sizeof(uiv1)); + memset(&uiv2, 0, sizeof(uiv2)); + + uiv_tweak_t tweak = { + .h = tweak_h, + .cmd = 4, + }; + + for (int bi = 0; bi < (int) ARRAY_LENGTH(AESBITS); ++bi) { + const int aesbits = AESBITS[bi]; + + for (int i = 0; i < 16; ++i) { + crypto_rand((char*)key, sizeof(key)); + crypto_rand((char*)tweak_h, sizeof(tweak_h)); + crypto_rand((char*)cell_orig, sizeof(cell_orig)); + memcpy(cell, cell_orig, sizeof(cell_orig)); + + cgo_uiv_init(&uiv1, aesbits, true, key); + cgo_uiv_init(&uiv2, aesbits, false, key); + + // encrypt-then-decrypt should round-trip. + cgo_uiv_encrypt(&uiv1, tweak, cell); + tt_mem_op(cell, OP_NE, cell_orig, sizeof(cell)); + cgo_uiv_decrypt(&uiv2, tweak, cell); + tt_mem_op(cell, OP_EQ, cell_orig, sizeof(cell)); + + // decrypt-then-encrypt should round-trip. + cgo_uiv_decrypt(&uiv2, tweak, cell); + tt_mem_op(cell, OP_NE, cell_orig, sizeof(cell)); + cgo_uiv_encrypt(&uiv1, tweak, cell); + tt_mem_op(cell, OP_EQ, cell_orig, sizeof(cell)); + + cgo_uiv_clear(&uiv1); + cgo_uiv_clear(&uiv2); + } + } + done: + cgo_uiv_clear(&uiv1); + cgo_uiv_clear(&uiv2); +} + +#define UNHEX(out,inp) STMT_BEGIN { \ + size_t inplen = strlen(inp); \ + tt_int_op(sizeof(out), OP_EQ, inplen / 2); \ + int r = base16_decode((char*)(out), sizeof(out), inp, inplen); \ + tt_int_op(r, OP_EQ, sizeof(out)); \ + } STMT_END + +#define UNHEX2(out,inp1,inp2) STMT_BEGIN { \ + tor_free(unhex_tmp); \ + tor_asprintf(&unhex_tmp, "%s%s", inp1, inp2); \ + UNHEX(out, unhex_tmp); \ + } STMT_END + +static void +test_crypto_cgo_et_testvec(void *arg) +{ + (void)arg; + cgo_et_t et; + memset(&et, 0, sizeof(et)); + + for (int i = 0; i < (int)ARRAY_LENGTH(ET_TESTVECS); ++i) { + const struct et_testvec *tv = &ET_TESTVECS[i]; + uint8_t keys[32]; + uint8_t tweaks[16 + 1 + 493]; + uint8_t block[16], expect[16]; + UNHEX(keys, tv->keys); + UNHEX(tweaks, tv->tweaks); + UNHEX(block, tv->block); + UNHEX(expect, tv->expect); + + et_tweak_t tweak = { + .uiv = { + .h = tweaks, + .cmd = tweaks[16], + }, + .x_r = tweaks + 17, + }; + + cgo_et_init(&et, 128, tv->encrypt, keys); + if (tv->encrypt) { + cgo_et_encrypt(&et, tweak, block); + } else { + cgo_et_decrypt(&et, tweak, block); + } + cgo_et_clear(&et); + + tt_mem_op(block, OP_EQ, expect, 16); + } + + done: + cgo_et_clear(&et); +} + +static void +test_crypto_cgo_prf_testvec(void *arg) +{ + (void)arg; + cgo_prf_t prf; + memset(&prf, 0, sizeof(prf)); + + for (int i = 0; i < (int)ARRAY_LENGTH(PRF_TESTVECS); ++i) { + const struct prf_testvec *tv = &PRF_TESTVECS[i]; + uint8_t keys[32]; + uint8_t input[16]; + uint8_t expect_t0[493]; + uint8_t expect_t1[80]; + uint8_t output[493]; // max + UNHEX(keys, tv->keys); + UNHEX(input, tv->input); + + cgo_prf_init(&prf, 128, keys); + if (tv->t == 0) { + UNHEX(expect_t0, tv->expect); + memset(output, 0, sizeof(output)); + cgo_prf_xor_t0(&prf, input, output); + tt_mem_op(output, OP_EQ, expect_t0, PRF_T0_DATA_LEN); + } else { + tt_int_op(tv->t, OP_EQ, 1); + UNHEX(expect_t1, tv->expect); + cgo_prf_gen_t1(&prf, input, output, sizeof(expect_t1)); + tt_mem_op(output, OP_EQ, expect_t1, sizeof(expect_t1)); + } + cgo_prf_clear(&prf); + } + done: + cgo_prf_clear(&prf); +} + +static void +test_crypto_cgo_uiv_testvec(void *arg) +{ + (void)arg; + cgo_uiv_t uiv; + memset(&uiv, 0, sizeof(uiv)); + + for (int i = 0; i < (int)ARRAY_LENGTH(UIV_TESTVECS); ++i) { + const struct uiv_testvec *tv = &UIV_TESTVECS[i]; + uint8_t keys[64]; + uint8_t tweaks[17]; + uint8_t x_l[16], x_r[493]; + uint8_t y_l[16], y_r[493]; + uint8_t cell[509]; + UNHEX(keys, tv->keys); + UNHEX(tweaks, tv->tweaks); + UNHEX(x_l, tv->x_l); + UNHEX(x_r, tv->x_r); + UNHEX(y_l, tv->y.y_l); + UNHEX(y_r, tv->y.y_r); + + uiv_tweak_t tweak = { + .h = tweaks, + .cmd = tweaks[16] + }; + memcpy(cell, x_l, 16); + memcpy(cell+16, x_r, 493); + + cgo_uiv_init(&uiv, 128, tv->encrypt, keys); + if (tv->encrypt) { + cgo_uiv_encrypt(&uiv, tweak, cell); + } else { + cgo_uiv_decrypt(&uiv, tweak, cell); + } + cgo_uiv_clear(&uiv); + + tt_mem_op(cell, OP_EQ, y_l, 16); + tt_mem_op(cell+16, OP_EQ, y_r, 493); + } + + done: + cgo_uiv_clear(&uiv); +} + +#include "core/crypto/relay_crypto_st.h" + +static void +test_crypto_cgo_uiv_update_testvec(void *arg) +{ + (void)arg; + cgo_uiv_t uiv; + cgo_uiv_t uiv2; + memset(&uiv, 0, sizeof(uiv)); + memset(&uiv2, 0, sizeof(uiv2)); + + uint8_t tw[16]; + memset(tw, 42, sizeof(tw)); + uiv_tweak_t tweak = { + .h = tw, + .cmd = 42 + }; + + for (int i = 0; i < (int)ARRAY_LENGTH(UIV_UPDATE_TESTVECS); ++i) { + const struct uiv_update_testvec *tv = &UIV_UPDATE_TESTVECS[i]; + uint8_t keys[64]; + uint8_t nonce[16]; + uint8_t new_keys[64]; + uint8_t new_nonce[16]; + UNHEX(keys, tv->keys); + UNHEX(nonce, tv->nonce); + UNHEX(new_keys, tv->output.new_keys); + UNHEX(new_nonce, tv->output.new_nonce); + + cgo_uiv_init(&uiv, 128, true, keys); + cgo_uiv_update(&uiv, 128, true, nonce); + // Make sure that the recorded keys are what we expect. + tt_mem_op(uiv.uiv_keys_, OP_EQ, new_keys, 64); + tt_mem_op(nonce, OP_EQ, new_nonce, 16); + + // Construct a new UIV from these keys and make sure it acts like this one. + uint8_t cell[509], cell2[509]; + crypto_rand((char*)cell, sizeof(cell)); + memcpy(cell2, cell, 509); + cgo_uiv_init(&uiv2, 128, true, uiv.uiv_keys_); + cgo_uiv_encrypt(&uiv, tweak, cell); + cgo_uiv_encrypt(&uiv2, tweak, cell2); + tt_mem_op(cell, OP_EQ, cell2, 509); + + cgo_uiv_clear(&uiv); + cgo_uiv_clear(&uiv2); + } + done: + cgo_uiv_clear(&uiv); + cgo_uiv_clear(&uiv2); +} + +static void +test_crypto_cgo_fwd(void *arg) +{ + (void)arg; + + #define N_HOPS 3 + uint8_t key_material[N_HOPS][112]; // max. + cgo_crypt_t *client[N_HOPS]; + cgo_crypt_t *relays[N_HOPS]; + + memset(client, 0, sizeof(client)); + memset(relays, 0, sizeof(relays)); + + for (int bi = 0; bi < (int) ARRAY_LENGTH(AESBITS); ++bi) { + const int aesbits = AESBITS[bi]; + + size_t klen = cgo_key_material_len(aesbits); + tt_uint_op(klen, OP_LE, sizeof(key_material[0])); + crypto_rand((char*)&key_material, sizeof(key_material)); + for (int i = 0; i < N_HOPS; ++i) { + client[i] = cgo_crypt_new(CGO_MODE_CLIENT_FORWARD, + aesbits, key_material[i], klen); + relays[i] = cgo_crypt_new(CGO_MODE_RELAY_FORWARD, + aesbits, key_material[i], klen); + } + for (int trial = 0; trial < 64; ++trial) { + int target_hop = crypto_rand_int(3); + cell_t cell, cell_orig; + uint8_t tag_client[SENDME_TAG_LEN_CGO]; + const uint8_t *tagp = NULL; + + memset(&cell, 0, sizeof(cell)); + if (crypto_rand_int(2) == 0) { + cell.command = CELL_RELAY; + } else { + cell.command = CELL_RELAY_EARLY; + } + crypto_rand((char*) cell.payload+SENDME_TAG_LEN_CGO, + sizeof(cell.payload)-SENDME_TAG_LEN_CGO); + memcpy(&cell_orig, &cell, sizeof(cell)); + + // First the client encrypts the cell... + cgo_crypt_client_originate(client[target_hop], &cell, &tagp); + tt_assert(tagp); + memcpy(tag_client, tagp, SENDME_TAG_LEN_CGO); + for (int i = target_hop - 1; i >= 0; --i) { + cgo_crypt_client_forward(client[i], &cell); + } + + // Now the relays handle the cell... + bool cell_recognized = false; + for (int i = 0; i < N_HOPS; ++i) { + tagp = NULL; + cgo_crypt_relay_forward(relays[i], &cell, &tagp); + if (tagp) { + tt_int_op(i, OP_EQ, target_hop); + tt_mem_op(tagp, OP_EQ, tag_client, SENDME_TAG_LEN_CGO); + cell_recognized = true; + break; + } + } + tt_assert(cell_recognized); + tt_int_op(cell.command, OP_EQ, cell_orig.command); + tt_mem_op(cell.payload + SENDME_TAG_LEN_CGO, OP_EQ, + cell_orig.payload + SENDME_TAG_LEN_CGO, + sizeof(cell.payload) - SENDME_TAG_LEN_CGO); + } + for (int i = 0; i < N_HOPS; ++i) { + cgo_crypt_free(client[i]); + cgo_crypt_free(relays[i]); + } + } + + done: + for (int i = 0; i < N_HOPS; ++i) { + cgo_crypt_free(client[i]); + cgo_crypt_free(relays[i]); + } +#undef N_HOPS +} + +static void +test_crypto_cgo_rev(void *arg) +{ + (void)arg; + + #define N_HOPS 3 + uint8_t key_material[N_HOPS][112]; // max. + cgo_crypt_t *client[N_HOPS]; + cgo_crypt_t *relays[N_HOPS]; + + memset(client, 0, sizeof(client)); + memset(relays, 0, sizeof(relays)); + + for (int bi = 0; bi < (int) ARRAY_LENGTH(AESBITS); ++bi) { + const int aesbits = AESBITS[bi]; + + size_t klen = cgo_key_material_len(aesbits); + tt_uint_op(klen, OP_LE, sizeof(key_material[0])); + crypto_rand((char*)&key_material, sizeof(key_material)); + for (int i = 0; i < N_HOPS; ++i) { + client[i] = cgo_crypt_new(CGO_MODE_CLIENT_BACKWARD, + aesbits, key_material[i], klen); + relays[i] = cgo_crypt_new(CGO_MODE_RELAY_BACKWARD, + aesbits, key_material[i], klen); + } + for (int trial = 0; trial < 64; ++trial) { + int origin_hop = crypto_rand_int(3); + cell_t cell, cell_orig; + uint8_t tag_relay[SENDME_TAG_LEN_CGO]; + const uint8_t *tagp = NULL; + + memset(&cell, 0, sizeof(cell)); + cell.command = CELL_RELAY; + crypto_rand((char*) cell.payload+SENDME_TAG_LEN_CGO, + sizeof(cell.payload)-SENDME_TAG_LEN_CGO); + memcpy(&cell_orig, &cell, sizeof(cell)); + + // First the specified relay encrypts the cell... + cgo_crypt_relay_originate(relays[origin_hop], &cell, &tagp); + tt_assert(tagp); + memcpy(tag_relay, tagp, SENDME_TAG_LEN_CGO); + for (int i = origin_hop - 1; i >= 0; --i) { + cgo_crypt_relay_backward(relays[i], &cell); + } + + // Now the client handles the cell. + bool cell_recognized = false; + for (int i = 0; i < N_HOPS; ++i) { + tagp = NULL; + cgo_crypt_client_backward(client[i], &cell, &tagp); + if (tagp) { + tt_int_op(i, OP_EQ, origin_hop); + tt_mem_op(tagp, OP_EQ, tag_relay, SENDME_TAG_LEN_CGO); + cell_recognized = true; + break; + } + } + tt_assert(cell_recognized); + tt_int_op(cell.command, OP_EQ, cell_orig.command); + tt_mem_op(cell.payload + SENDME_TAG_LEN_CGO, OP_EQ, + cell_orig.payload + SENDME_TAG_LEN_CGO, + sizeof(cell.payload) - SENDME_TAG_LEN_CGO); + } + for (int i = 0; i < N_HOPS; ++i) { + cgo_crypt_free(client[i]); + cgo_crypt_free(relays[i]); + } + } + + done: + for (int i = 0; i < N_HOPS; ++i) { + cgo_crypt_free(client[i]); + cgo_crypt_free(relays[i]); + } +#undef N_HOPS +} + +static void +test_crypto_cgo_relay_testvec(void *arg) +{ + (void)arg; + char *unhex_tmp = NULL; + cgo_crypt_t *cgo = NULL; + for (int i = 0; i < (int)ARRAY_LENGTH(CGO_RELAY_TESTVECS); ++i) { + const struct cgo_relay_testvec *tv = &CGO_RELAY_TESTVECS[i]; + const int aesbits = 128; + uint8_t keys[80], expect_keys[80], expect_tprime[SENDME_TAG_LEN_CGO], + cmd[1]; + cell_t cell; + cell_t expect_cell; + tt_int_op(sizeof(keys), OP_EQ, cgo_key_material_len(aesbits)); + UNHEX2(keys, tv->state_in.keys, tv->state_in.nonce); + cgo_mode_t mode = + tv->inbound ? CGO_MODE_RELAY_BACKWARD : CGO_MODE_RELAY_FORWARD; + cgo = cgo_crypt_new(mode, aesbits, keys, sizeof(keys)); + tt_assert(cgo); + UNHEX(cgo->tprime, tv->state_in.tprime); + memset(&cell, 0, sizeof(cell)); + UNHEX(cmd, tv->cmd); + cell.command = cmd[0]; + UNHEX2(cell.payload, tv->tag, tv->msg); + + memset(&expect_cell, 0, sizeof(expect_cell)); + expect_cell.command = cell.command; + UNHEX2(expect_cell.payload, + tv->output.result.t_out, tv->output.result.msg_out); + UNHEX2(expect_keys, + tv->output.state.keys, tv->output.state.nonce); + UNHEX(expect_tprime, tv->output.state.tprime); + + if (tv->inbound) { + cgo_crypt_relay_backward(cgo, &cell); + } else { + const uint8_t *tagp = NULL; + cgo_crypt_relay_forward(cgo, &cell, &tagp); + tt_ptr_op(tagp, OP_EQ, NULL); + } + + tt_mem_op(cell.payload, OP_EQ, expect_cell.payload, sizeof(cell.payload)); + tt_mem_op(cgo->uiv.uiv_keys_, OP_EQ, expect_keys, 64); + tt_mem_op(cgo->nonce, OP_EQ, expect_keys + 64, 16); + tt_mem_op(cgo->tprime, OP_EQ, expect_tprime, 16); + + cgo_crypt_free(cgo); + } + done: + tor_free(unhex_tmp); + cgo_crypt_free(cgo); +} + +static void +test_crypto_cgo_relay_originate_testvec(void *arg) +{ + (void)arg; + char *unhex_tmp = NULL; + cgo_crypt_t *cgo = NULL; + for (int i = 0; i < (int)ARRAY_LENGTH(CGO_RELAY_ORIGINATE_TESTVECS); ++i) { + const struct cgo_relay_originate_testvec *tv = + &CGO_RELAY_ORIGINATE_TESTVECS[i]; + const int aesbits = 128; + uint8_t keys[80], expect_keys[80], expect_tprime[SENDME_TAG_LEN_CGO], + cmd[1]; + cell_t cell; + cell_t expect_cell; + tt_int_op(sizeof(keys), OP_EQ, cgo_key_material_len(aesbits)); + UNHEX2(keys, tv->state_in.keys, tv->state_in.nonce); + cgo = cgo_crypt_new(CGO_MODE_RELAY_BACKWARD, aesbits, keys, sizeof(keys)); + tt_assert(cgo); + UNHEX(cgo->tprime, tv->state_in.tprime); + memset(&cell, 0, sizeof(cell)); + UNHEX(cmd, tv->cmd); + cell.command = cmd[0]; + UNHEX2(cell.payload, "00000000000000000000000000000000", tv->msg); + + memset(&expect_cell, 0, sizeof(expect_cell)); + expect_cell.command = cell.command; + UNHEX2(expect_cell.payload, + tv->output.result.t_out, tv->output.result.msg_out); + UNHEX2(expect_keys, + tv->output.state.keys, tv->output.state.nonce); + UNHEX(expect_tprime, tv->output.state.tprime); + + const uint8_t *tagp = NULL; + cgo_crypt_relay_originate(cgo, &cell, &tagp); + tt_ptr_op(tagp, OP_NE, NULL); + + tt_mem_op(cell.payload, OP_EQ, expect_cell.payload, sizeof(cell.payload)); + tt_mem_op(cgo->uiv.uiv_keys_, OP_EQ, expect_keys, 64); + tt_mem_op(cgo->nonce, OP_EQ, expect_keys + 64, 16); + tt_mem_op(cgo->tprime, OP_EQ, expect_tprime, 16); + + cgo_crypt_free(cgo); + } + done: + tor_free(unhex_tmp); + cgo_crypt_free(cgo); +} + +static void +test_crypto_cgo_client_originate_testvec(void *arg) +{ + (void) arg; + char *unhex_tmp = NULL; + cgo_crypt_t *cgo[3] = { NULL, NULL, NULL }; + for (int tv_i = 0; tv_i < (int)ARRAY_LENGTH(CGO_CLIENT_ORIGINATE_TESTVECS); + ++tv_i) { + const struct cgo_client_originate_testvec *tv = + &CGO_CLIENT_ORIGINATE_TESTVECS[tv_i]; + const int aesbits = 128; + uint8_t keys[80], expect_keys[80], expect_tprime[SENDME_TAG_LEN_CGO], + cmd[1]; + cell_t cell; + cell_t expect_cell; + for (int i = 0; i < 3; ++i) { + tt_int_op(sizeof(keys), OP_EQ, cgo_key_material_len(aesbits)); + UNHEX2(keys, tv->state_in[i].keys, tv->state_in[i].nonce); + cgo[i] = cgo_crypt_new(CGO_MODE_CLIENT_FORWARD, + aesbits, keys, sizeof(keys)); + tt_assert(cgo[i]); + UNHEX(cgo[i]->tprime, tv->state_in[i].tprime); + } + + memset(&cell, 0, sizeof(cell)); + UNHEX(cmd, tv->cmd); + cell.command = cmd[0]; + UNHEX2(cell.payload, "00000000000000000000000000000000", tv->msg); + + memset(&expect_cell, 0, sizeof(expect_cell)); + expect_cell.command = cell.command; + UNHEX2(expect_cell.payload, + tv->output.result.t_out, tv->output.result.msg_out); + + tt_int_op(tv->target_hop, OP_GE, 1); // Hop is 0-indexed. + int target_hop = tv->target_hop - 1; + const uint8_t *tagp = NULL; + cgo_crypt_client_originate(cgo[target_hop], &cell, &tagp); + tt_ptr_op(tagp, OP_NE, NULL); + for (int i = target_hop - 1; i >= 0; --i) { + cgo_crypt_client_forward(cgo[i], &cell); + } + tt_mem_op(cell.payload, OP_EQ, expect_cell.payload, sizeof(cell.payload)); + + for (int i = 0; i < 3; ++i) { + UNHEX2(expect_keys, + tv->output.state[i].keys, tv->output.state[i].nonce); + UNHEX(expect_tprime, tv->output.state[i].tprime); + + tt_mem_op(cgo[i]->uiv.uiv_keys_, OP_EQ, expect_keys, 64); + tt_mem_op(cgo[i]->nonce, OP_EQ, expect_keys + 64, 16); + tt_mem_op(cgo[i]->tprime, OP_EQ, expect_tprime, 16); + } + + for (int i = 0; i < 3; ++i) + cgo_crypt_free(cgo[i]); + } + done: + tor_free(unhex_tmp); + for (int i = 0; i < 3; ++i) + cgo_crypt_free(cgo[i]); +} + +struct testcase_t crypto_cgo_tests[] = { + { "et_roundtrip", test_crypto_cgo_et_roundtrip, 0, NULL, NULL }, + { "et_testvec", test_crypto_cgo_et_testvec, 0, NULL, NULL }, + { "prf_testvec", test_crypto_cgo_prf_testvec, 0, NULL, NULL }, + { "uiv_roundtrip", test_crypto_cgo_uiv_roundtrip, 0, NULL, NULL }, + { "uiv_testvec", test_crypto_cgo_uiv_testvec, 0, NULL, NULL }, + { "uiv_update_testvec", test_crypto_cgo_uiv_update_testvec, 0, NULL, NULL }, + { "cgo_fwd", test_crypto_cgo_fwd, 0, NULL, NULL, }, + { "cgo_rev", test_crypto_cgo_rev, 0, NULL, NULL, }, + { "cgo_relay_testvec", test_crypto_cgo_relay_testvec, 0, NULL, NULL }, + { "cgo_relay_originate_testvec", test_crypto_cgo_relay_originate_testvec, + 0, NULL, NULL }, + { "cgo_client_originate_testvec", test_crypto_cgo_client_originate_testvec, + 0, NULL, NULL }, + END_OF_TESTCASES +}; diff -Nru tor-0.4.7.16/src/test/test_crypto_ope.c tor-0.4.9.6/src/test/test_crypto_ope.c --- tor-0.4.7.16/src/test/test_crypto_ope.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/test/test_crypto_ope.c 2026-03-25 14:30:34.000000000 +0000 @@ -28,7 +28,7 @@ const int TEST_VALS[] = { 5, 500, 1023, 1024, 1025, 2046, 2047, 2048, 2049, 10000, OPE_INPUT_MAX }; unsigned i; - const uint8_t key[32] = "A fixed key, chosen arbitrarily."; + NONSTRING const uint8_t key[32] = "A fixed key, chosen arbitrarily."; ope = crypto_ope_new(key); tt_assert(ope); @@ -56,7 +56,7 @@ (void)arg; crypto_ope_t *ope = NULL; - const uint8_t key[32] = "A fixed key, chosen arbitrarily."; + NONSTRING const uint8_t key[32] = "A fixed key, chosen arbitrarily."; ope = crypto_ope_new(key); tt_u64_op(UINT64_MAX, OP_EQ, crypto_ope_encrypt(ope,INT_MIN)); diff -Nru tor-0.4.7.16/src/test/test_crypto_openssl.c tor-0.4.9.6/src/test/test_crypto_openssl.c --- tor-0.4.7.16/src/test/test_crypto_openssl.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/test/test_crypto_openssl.c 2026-03-25 14:30:34.000000000 +0000 @@ -49,11 +49,6 @@ ; } -#ifndef OPENSSL_1_1_API -#define EVP_ENCODE_CTX_new() tor_malloc_zero(sizeof(EVP_ENCODE_CTX)) -#define EVP_ENCODE_CTX_free(ctx) tor_free(ctx) -#endif - /** Encode src into dest with OpenSSL's EVP Encode interface, returning the * length of the encoded data in bytes. */ diff -Nru tor-0.4.7.16/src/test/test_crypto_slow.c tor-0.4.9.6/src/test/test_crypto_slow.c --- tor-0.4.7.16/src/test/test_crypto_slow.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/test/test_crypto_slow.c 2026-03-25 14:30:34.000000000 +0000 @@ -7,6 +7,7 @@ #define CRYPTO_S2K_PRIVATE #include "core/or/or.h" #include "test/test.h" +#include "ext/equix/include/equix.h" #include "lib/crypt_ops/crypto_curve25519.h" #include "lib/crypt_ops/crypto_ed25519.h" #include "lib/crypt_ops/crypto_s2k.h" @@ -584,6 +585,139 @@ ; } +static void +test_crypto_equix(void *arg) +{ + (void)arg; + + static const struct { + const char *challenge_literal; + size_t num_solutions; + equix_solution solutions[EQUIX_MAX_SOLS]; + } vectors[] = { + { "zzz", 1, { + {{ 0xae21, 0xd392, 0x3215, 0xdd9c, 0x2f08, 0x93df, 0x232c, 0xe5dc }}, + }}, + { "rrr", 1, { + {{ 0x0873, 0x57a8, 0x73e0, 0x912e, 0x1ca8, 0xad96, 0x9abd, 0xd7de }}, + }}, + { "qqq", 0, {{{ 0 }}} }, + { "0123456789", 0, {{{ 0 }}} }, + { "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz", 0, {{{ 0 }}} }, + { "", 3, { + {{ 0x0098, 0x3a4d, 0xc489, 0xcfba, 0x7ef3, 0xa498, 0xa00f, 0xec20 }}, + {{ 0x78d8, 0x8611, 0xa4df, 0xec19, 0x0927, 0xa729, 0x842f, 0xf771 }}, + {{ 0x54b5, 0xcc11, 0x1593, 0xe624, 0x9357, 0xb339, 0xb138, 0xed99 }}, + }}, + { "a", 3, { + {{ 0x4b38, 0x8c81, 0x9255, 0xad99, 0x5ce7, 0xeb3e, 0xc635, 0xee38 }}, + {{ 0x3f9e, 0x659b, 0x9ae6, 0xb891, 0x63ae, 0x777c, 0x06ca, 0xc593 }}, + {{ 0x2227, 0xa173, 0x365a, 0xb47d, 0x1bb2, 0xa077, 0x0d5e, 0xf25f }}, + }}, + { "abc", 2, { + {{ 0x371f, 0x8865, 0x8189, 0xfbc3, 0x26df, 0xe4c0, 0xab39, 0xfe5a }}, + {{ 0x2101, 0xb88f, 0xc525, 0xccb3, 0x5785, 0xa41e, 0x4fba, 0xed18 }}, + }}, + { "abce", 4, { + {{ 0x4fca, 0x72eb, 0x101f, 0xafab, 0x1add, 0x2d71, 0x75a3, 0xc978 }}, + {{ 0x17f1, 0x7aa6, 0x23e3, 0xab00, 0x7e2f, 0x917e, 0x16da, 0xda9e }}, + {{ 0x70ee, 0x7757, 0x8a54, 0xbd2b, 0x90e4, 0xe31e, 0x2085, 0xe47e }}, + {{ 0x62c5, 0x86d1, 0x5752, 0xe1f0, 0x12da, 0x8f33, 0x7336, 0xf161 }}, + }}, + { "01234567890123456789", 5, { + {{ 0x4803, 0x6775, 0xc5c9, 0xd1b0, 0x1bc3, 0xe4f6, 0x4027, 0xf5ad }}, + {{ 0x5a8a, 0x9542, 0xef99, 0xf0b9, 0x4905, 0x4e29, 0x2da5, 0xfbd5 }}, + {{ 0x4c79, 0xc935, 0x2bcb, 0xcd0f, 0x0362, 0x9fa9, 0xa62e, 0xf83a }}, + {{ 0x5878, 0x6edf, 0x1e00, 0xf5e3, 0x43de, 0x9212, 0xd01e, 0xfd11 }}, + {{ 0x0b69, 0x2d17, 0x01be, 0x6cb4, 0x0fba, 0x4a9e, 0x8d75, 0xa50f }}, + }}, + }; + + static const struct { + equix_ctx_flags flags; + equix_result expected; + equix_solution_flags sol_flags; + } variations[] = { + {0, EQUIX_OK, 0}, + {0, EQUIX_FAIL_ORDER, 0}, + {0, EQUIX_FAIL_PARTIAL_SUM, 0}, +#if defined(_M_X64) || defined(__x86_64__) || defined(__aarch64__) + { EQUIX_CTX_MUST_COMPILE, EQUIX_OK, + EQUIX_SOLVER_DID_USE_COMPILER + }, + { EQUIX_CTX_MUST_COMPILE, EQUIX_FAIL_ORDER, + EQUIX_SOLVER_DID_USE_COMPILER + }, + { EQUIX_CTX_MUST_COMPILE, EQUIX_FAIL_PARTIAL_SUM, + EQUIX_SOLVER_DID_USE_COMPILER + }, +#endif + }; + + const unsigned num_vectors = sizeof vectors / sizeof vectors[0]; + const unsigned num_variations = sizeof variations / sizeof variations[0]; + + for (unsigned vec_i = 0; vec_i < num_vectors; vec_i++) { + const char *challenge_literal = vectors[vec_i].challenge_literal; + const size_t challenge_len = strlen(challenge_literal); + + const size_t num_sols = vectors[vec_i].num_solutions; + const equix_solution *sols_expected = vectors[vec_i].solutions; + + for (unsigned vari_i = 0; vari_i < num_variations; vari_i++) { + const equix_ctx_flags flags = variations[vari_i].flags; + const equix_solution_flags sol_flags = variations[vari_i].sol_flags; + const equix_result expected = variations[vari_i].expected; + + equix_solutions_buffer output; + equix_ctx *solve_ctx = NULL, *verify_ctx = NULL; + + solve_ctx = equix_alloc(EQUIX_CTX_SOLVE | flags); + tt_ptr_op(solve_ctx, OP_NE, NULL); + + /* Solve phase: Make sure the test vector matches */ + memset(&output, 0xa5, sizeof output); + equix_result result; + result = equix_solve(solve_ctx, challenge_literal, + challenge_len, &output); + equix_free(solve_ctx); + tt_int_op(result, OP_EQ, EQUIX_OK); + tt_int_op(output.count, OP_EQ, num_sols); + tt_int_op(output.flags, OP_EQ, sol_flags); + tt_mem_op(output.sols, OP_EQ, sols_expected, + num_sols * sizeof(equix_solution)); + + verify_ctx = equix_alloc(EQUIX_CTX_VERIFY | flags); + tt_ptr_op(verify_ctx, OP_NE, NULL); + + /* Use each solution for positive and negative tests of verify */ + for (size_t sol_i = 0; sol_i < num_sols; sol_i++) { + equix_idx tmp_idx; + equix_solution *sol = &output.sols[sol_i]; + + if (expected == EQUIX_FAIL_ORDER) { + /* Swap two otherwise valid indices, to trigger an order error */ + tmp_idx = sol->idx[0]; + sol->idx[0] = sol->idx[1]; + sol->idx[1] = tmp_idx; + } else if (expected == EQUIX_FAIL_PARTIAL_SUM) { + /* Most changes to the solution will cause a partial sum error */ + sol->idx[0]++; + } + + result = equix_verify(verify_ctx, challenge_literal, + challenge_len, sol); + tt_int_op(expected, OP_EQ, result); + } + + equix_free(verify_ctx); + } + } + + done: + ; +} + #ifndef COCCI #define CRYPTO_LEGACY(name) \ { #name, test_crypto_ ## name , 0, NULL, NULL } @@ -619,5 +753,6 @@ { "pbkdf2_vectors", test_crypto_pbkdf2_vectors, 0, NULL, NULL }, { "pwbox", test_crypto_pwbox, 0, NULL, NULL }, ED25519_TEST(fuzz_donna, TT_FORK), + { "equix", test_crypto_equix, 0, NULL, NULL }, END_OF_TESTCASES }; diff -Nru tor-0.4.7.16/src/test/test_dir.c tor-0.4.9.6/src/test/test_dir.c --- tor-0.4.7.16/src/test/test_dir.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/test/test_dir.c 2026-03-25 14:30:34.000000000 +0000 @@ -21,6 +21,8 @@ #define RELAY_PRIVATE #define ROUTERLIST_PRIVATE #define ROUTER_PRIVATE +#define ROUTERKEYS_PRIVATE +#define ROUTERPARSE_PRIVATE #define UNPARSEABLE_PRIVATE #define VOTEFLAGS_PRIVATE @@ -217,7 +219,7 @@ r1->ipv4_dirport = dir_port; r1->supports_tunnelled_dir_requests = 1; - router_set_rsa_onion_pkey(pk1, &r1->onion_pkey, &r1->onion_pkey_len); + router_set_rsa_onion_pkey(pk1, &r1->tap_onion_pkey, &r1->tap_onion_pkey_len); r1->identity_pkey = pk2; r1->bandwidthrate = bandwidthrate; @@ -382,8 +384,8 @@ { char *block = NULL; tor_assert(r1); - crypto_pk_t *pk_tmp = router_get_rsa_onion_pkey(r1->onion_pkey, - r1->onion_pkey_len); + crypto_pk_t *pk_tmp = router_get_rsa_onion_pkey(r1->tap_onion_pkey, + r1->tap_onion_pkey_len); block = get_new_rsa_key_block("onion-key", pk_tmp); crypto_pk_free(pk_tmp); return block; @@ -587,8 +589,8 @@ 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); + mocked_onionkey = router_get_rsa_onion_pkey(r1->tap_onion_pkey, + r1->tap_onion_pkey_len); } MOCK(get_onion_key, mock_get_onion_key); } @@ -643,10 +645,12 @@ 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); \ + crypto_pk_t *rp1_onion_pkey = router_get_rsa_onion_pkey( \ + rp1->tap_onion_pkey, \ + rp1->tap_onion_pkey_len); \ + crypto_pk_t *r1_onion_pkey = router_get_rsa_onion_pkey( \ + r1->tap_onion_pkey, \ + r1->tap_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); \ @@ -862,8 +866,21 @@ tt_str_op(buf, OP_EQ, buf2); tor_free(buf); + /* We make a couple of changes now before we make the desc that we're going + * to parse and check the signature on. */ setup_mock_configured_ports(r2->ipv4_orport, 0); + ed25519_keypair_t family_1; + ed25519_keypair_t family_2; + ed25519_keypair_generate(&family_1, 0); + ed25519_keypair_generate(&family_2, 0); + { + smartlist_t *family_keys = smartlist_new(); + smartlist_add(family_keys, tor_memdup(&family_1, sizeof(family_1))); + smartlist_add(family_keys, tor_memdup(&family_2, sizeof(family_2))); + set_family_id_keys(family_keys); // takes ownership. + } + buf = router_dump_router_to_string(r2, r2->identity_pkey, r2_onion_pkey, &r2_onion_keypair, &kp2); @@ -881,6 +898,20 @@ r2->onion_curve25519_pkey->public_key, CURVE25519_PUBKEY_LEN); + // Check family ids. + tt_assert(rp2->family_ids != NULL); + tt_int_op(smartlist_len(rp2->family_ids), OP_EQ, 2); + { + char k[ED25519_BASE64_LEN+1]; + char b[sizeof(k)+16]; + ed25519_public_to_base64(k, &family_1.pubkey); + tor_snprintf(b, sizeof(b), "ed25519:%s", k); + tt_assert(smartlist_contains_string(rp2->family_ids, b)); + ed25519_public_to_base64(k, &family_2.pubkey); + tor_snprintf(b, sizeof(b), "ed25519:%s", k); + tt_assert(smartlist_contains_string(rp2->family_ids, b)); + } + CHECK_PARSED_EXIT_POLICY(rp2); tor_free(buf); @@ -1303,6 +1334,72 @@ #undef ADD } +/* Made with chutney and a patched tor: Has no onion-key or + * onion-key-crosscert */ +static const char ROUTERDESC_NO_ONION_KEY[] = +"router test001a 127.0.0.1 5001 0 7001\n" +"identity-ed25519\n" +"-----BEGIN ED25519 CERT-----\n" +"AQQAB0xWARbCJfDrX0OTtpM0fDxU9cLweMnZeUq/KBfAN1wwWHtMAQAgBADBQJ1o\n" +"ClrXUenWC90FYEUQDpMSdxdxKlrR83rYy+keGe61WQHYP0ebowJC19UvPnYryLeA\n" +"Gnhko2WwmbUDGicdnY4j2VSFU15oxBjln65IznZJyiZM4zGE1GkNZzKGmQY=\n" +"-----END ED25519 CERT-----\n" +"master-key-ed25519 wUCdaApa11Hp1gvdBWBFEA6TEncXcSpa0fN62MvpHhk\n" +"or-address [::]:5001\n" +"platform Tor 0.4.9.0-alpha-dev on Linux\n" +"proto Conflux=1 Cons=1-2 Desc=1-2 DirCache=2 FlowCtrl=1-2 HSDir=2 " + "HSIntro=4-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Padding=2 " + "Relay=1-4\n" +"published 2024-06-24 21:34:22\n" +"fingerprint FD3A 6FA4 E716 C379 3CBA FEC3 39EA 01C8 B49D 7189\n" +"uptime 0\n" +"bandwidth 1073741824 1073741824 0\n" +"extra-info-digest 9946CAC41485EDFFDD83F7DAF1A088C30563126C " + "lpAMRlRTy9QR2xVCu1nnnxOHA2I05TTKvCSPPcr1geo\n" +"caches-extra-info\n" +"signing-key\n" +"-----BEGIN RSA PUBLIC KEY-----\n" +"MIGJAoGBALcIIij7gNpvSZPvaCLDDNyyQZq7fR0aXiHgmiIc5hYVcBl+zF5sTX6a\n" +"jQF+GQdbSHcRzA1IMWPXnA7+nGOxSNayrQwExuf7ESsBaQHU81/dmV+rgTwtcd3K\n" +"9lobTQUm+idLvGjVF5P1XJkduPvURIgpIfXT1ZHJUQhwxWSw8MmnAgMBAAE=\n" +"-----END RSA PUBLIC KEY-----\n" +"ntor-onion-key-crosscert 1\n" +"-----BEGIN ED25519 CERT-----\n" +"AQoAB0wmAcFAnWgKWtdR6dYL3QVgRRAOkxJ3F3EqWtHzetjL6R4ZAFPSCMLyQ82v\n" +"dvcpZDa7C/qp8TsJn2Z8v77RjRc2QD1KYDzGfg5euwlB1lu8+IR38l3mmC1PXXhe\n" +"ZB84q4aUdAA=\n" +"-----END ED25519 CERT-----\n" +"hidden-service-dir\n" +"contact auth1@test.test\n" +"ntor-onion-key m0dedSB2vjtvz08bNu+LCdIApVuspRlzXbsphXZ62zQ\n" +"reject *:*\n" +"tunnelled-dir-server\n" +"router-sig-ed25519 VMwmiN9KhWWFSFSuVZxG1g46mb2QhMhv0UlatvPKyAV+1jPl" + "EbDFaO1Qur0335Rn0ToysC6UqB1p78pefX67Aw\n" +"router-signature\n" +"-----BEGIN SIGNATURE-----\n" +"q9Hxy4FJVIK2ks/ByBv8P1p7Pc68ie/TTlDN+tce9opPlijy9+ze9/Gd2SKonRm1\n" +"J+WBj/kKYKw+YoUExIT0qMfa6QTCOe/ecp1sNmgeW0YfloP4Nv8goi3S0k4yrPk/\n" +"qw6TIXGYJpvrdR1Qe7+MEl2K1Okqsy5amtOU400lYRA=\n" +"-----END SIGNATURE-----\n" + ; + +static void +test_dir_parse_no_onion_keyrouter_list(void *arg) +{ + (void) arg; + + routerinfo_t *ri = + router_parse_entry_from_string(ROUTERDESC_NO_ONION_KEY, NULL, + 0, 1, 0, NULL); + + tt_assert(ri); + tt_assert(ri->tap_onion_pkey == NULL); + + done: + routerinfo_free(ri); +} + static download_status_t dls_minimal; static download_status_t dls_maximal; static download_status_t dls_bad_fingerprint; @@ -2072,6 +2169,8 @@ int i; const char *lines_pass[] = { "node_id=$557365204145532d32353620696e73746561642e bw=1024\n", + /* check whether node_id does not need the dollar sign at the start */ + "node_id=557365204145532d32353620696e73746561642e bw=1024\n", "node_id=$557365204145532d32353620696e73746561642e\t bw=1024 \n", " node_id=$557365204145532d32353620696e73746561642e bw=1024\n", "\tnoise\tnode_id=$557365204145532d32353620696e73746561642e " @@ -2129,7 +2228,6 @@ " node_id= ", "node_id==$557365204145532d32353620696e73746561642e bw==1024\n", "node_id=$55736520414552d32353620696e73746561642e bw=1024\n", - "node_id=557365204145532d32353620696e73746561642e bw=1024\n", "node_id= $557365204145532d32353620696e73746561642e bw=0.23\n", /* Test that a line with vote=0 will fail too, so that it is ignored. */ @@ -2543,7 +2641,7 @@ smartlist_len(bw_file_headers)); /* force bw_file_headers to be bigger than * MAX_BW_FILE_HEADER_COUNT_IN_VOTE */ - char line[8] = "foo=bar\0"; + NONSTRING char line[8] = "foo=bar\0"; smartlist_add_strdup(bw_file_headers, line); tt_int_op(MAX_BW_FILE_HEADER_COUNT_IN_VOTE, OP_LT, smartlist_len(bw_file_headers)); @@ -2971,7 +3069,7 @@ (voter == 1)) { /* Check the first routerstatus. */ tt_str_op(vrs->version,OP_EQ, "0.1.2.14"); - tt_int_op(rs->published_on,OP_EQ, now-1500); + tt_int_op(vrs->published_on,OP_EQ, now-1500); tt_str_op(rs->nickname,OP_EQ, "router2"); tt_mem_op(rs->identity_digest,OP_EQ, "\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3" @@ -2996,7 +3094,7 @@ if (voter == 1) { /* Check the second routerstatus. */ tt_str_op(vrs->version,OP_EQ, "0.2.0.5"); - tt_int_op(rs->published_on,OP_EQ, now-1000); + tt_int_op(vrs->published_on,OP_EQ, now-1000); tt_str_op(rs->nickname,OP_EQ, "router1"); } tt_mem_op(rs->descriptor_digest,OP_EQ, "MMMMMMMMMMMMMMMMMMMM", DIGEST_LEN); @@ -3057,6 +3155,7 @@ static void test_routerstatus_for_v3ns(routerstatus_t *rs, time_t now) { + (void)now; tor_addr_t addr_ipv6; tt_assert(rs); @@ -3093,7 +3192,6 @@ DIGEST_LEN); tt_str_op(rs->nickname,OP_EQ, "router1"); tt_mem_op(rs->descriptor_digest,OP_EQ, "MMMMMMMMMMMMMMMMMMMM", DIGEST_LEN); - tt_int_op(rs->published_on,OP_EQ, now-1000); tt_assert(tor_addr_eq_ipv4h(&rs->ipv4_addr, 0x99009901)); tt_int_op(rs->ipv4_orport,OP_EQ, 443); tt_int_op(rs->ipv4_dirport,OP_EQ, 0); @@ -3968,7 +4066,7 @@ vrs = tor_malloc_zero(sizeof(vote_routerstatus_t)); rs = &vrs->status; vrs->version = tor_strdup("0.1.2.14"); - rs->published_on = now-1500; + vrs->published_on = now-1500; strlcpy(rs->nickname, "router2", sizeof(rs->nickname)); memset(rs->identity_digest, 3, DIGEST_LEN); memset(rs->descriptor_digest, 78, DIGEST_LEN); @@ -3993,7 +4091,7 @@ vrs = tor_malloc_zero(sizeof(vote_routerstatus_t)); rs = &vrs->status; vrs->version = tor_strdup("0.2.0.5"); - rs->published_on = now-1000; + vrs->published_on = now-1000; strlcpy(rs->nickname, "router1", sizeof(rs->nickname)); memset(rs->identity_digest, 5, DIGEST_LEN); memset(rs->descriptor_digest, 77, DIGEST_LEN); @@ -4020,7 +4118,7 @@ vrs = tor_malloc_zero(sizeof(vote_routerstatus_t)); rs = &vrs->status; vrs->version = tor_strdup("0.1.0.3"); - rs->published_on = now-1000; + vrs->published_on = now-1000; strlcpy(rs->nickname, "router3", sizeof(rs->nickname)); memset(rs->identity_digest, 0x33, DIGEST_LEN); memset(rs->descriptor_digest, 79, DIGEST_LEN); @@ -4046,7 +4144,7 @@ vrs = tor_malloc_zero(sizeof(vote_routerstatus_t)); rs = &vrs->status; vrs->version = tor_strdup("0.1.6.3"); - rs->published_on = now-1000; + vrs->published_on = now-1000; strlcpy(rs->nickname, "router4", sizeof(rs->nickname)); memset(rs->identity_digest, 0x34, DIGEST_LEN); memset(rs->descriptor_digest, 47, DIGEST_LEN); @@ -4078,7 +4176,7 @@ if (vrs) { vrs->microdesc = tor_malloc_zero(sizeof(vote_microdesc_hash_t)); tor_asprintf(&vrs->microdesc->microdesc_hash_line, - "m 25,26,27,28 " + "m 32,33 " "sha256=xyzajkldsdsajdadlsdjaslsdksdjlsdjsdaskdaaa%d\n", idx); } @@ -4102,9 +4200,8 @@ tt_assert(v->supported_methods); SMARTLIST_FOREACH(v->supported_methods, char *, c, tor_free(c)); smartlist_clear(v->supported_methods); - /* Method 17 is MIN_METHOD_TO_CLIP_UNMEASURED_BW_KB */ smartlist_split_string(v->supported_methods, - "25 26 27 28", + "32 33", NULL, 0, -1); /* If we're using a non-default clip bandwidth, add it to net_params */ if (alternate_clip_bw > 0) { @@ -4146,7 +4243,7 @@ * cutoff. */ tt_str_op(vrs->version,OP_EQ, "0.1.2.14"); - tt_int_op(rs->published_on,OP_EQ, now-1500); + tt_int_op(vrs->published_on,OP_EQ, now-1500); tt_str_op(rs->nickname,OP_EQ, "router2"); tt_mem_op(rs->identity_digest,OP_EQ, "\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3" @@ -4170,7 +4267,7 @@ * cutoff. */ tt_str_op(vrs->version,OP_EQ, "0.2.0.5"); - tt_int_op(rs->published_on,OP_EQ, now-1000); + tt_int_op(vrs->published_on,OP_EQ, now-1000); tt_str_op(rs->nickname,OP_EQ, "router1"); tt_mem_op(rs->identity_digest,OP_EQ, "\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5" @@ -4245,6 +4342,7 @@ static void test_routerstatus_for_umbw(routerstatus_t *rs, time_t now) { + (void)now; tor_addr_t addr_ipv6; uint32_t max_unmeasured_bw_kb = (alternate_clip_bw > 0) ? alternate_clip_bw : DEFAULT_MAX_UNMEASURED_BW_KB; @@ -4285,7 +4383,6 @@ DIGEST_LEN); tt_str_op(rs->nickname,OP_EQ, "router1"); tt_mem_op(rs->descriptor_digest,OP_EQ, "MMMMMMMMMMMMMMMMMMMM", DIGEST_LEN); - tt_int_op(rs->published_on,OP_EQ, now-1000); tt_assert(tor_addr_eq_ipv4h(&rs->ipv4_addr, 0x99009901)); tt_int_op(rs->ipv4_orport,OP_EQ, 443); tt_int_op(rs->ipv4_dirport,OP_EQ, 0); @@ -4385,7 +4482,6 @@ (void)arg; memset(&rs, 0, sizeof(rs)); - rs.published_on = 1364925198; strlcpy(rs.nickname, "TetsuoMilk", sizeof(rs.nickname)); memcpy(rs.identity_digest, "Stately, plump Buck ", DIGEST_LEN); memcpy(rs.descriptor_digest, "Mulligan came up fro", DIGEST_LEN); @@ -4403,7 +4499,7 @@ tt_assert(s); tt_str_op(s, OP_EQ, "r TetsuoMilk U3RhdGVseSwgcGx1bXAgQnVjayA " - "TXVsbGlnYW4gY2FtZSB1cCBmcm8 2013-04-02 17:53:18 " + "TXVsbGlnYW4gY2FtZSB1cCBmcm8 2038-01-01 00:00:00 " "32.48.64.80 9001 9002\n" "s Exit Fast Running V2Dir\n" "w Bandwidth=1000\n"); @@ -4450,14 +4546,17 @@ char *fname = tor_strdup(get_fname("V3BandwidthsFile")); /* Initialize to a wrong digest. */ - uint8_t digest[DIGEST256_LEN] = "01234567890123456789abcdefghijkl"; + NONSTRING + uint8_t digest[DIGEST256_LEN] = "01234567890123456789abcdefghijkl"; /* Digest of an empty string. Initialize to a wrong digest. */ - char digest_empty_str[DIGEST256_LEN] = "01234567890123456789abcdefghijkl"; + NONSTRING + char digest_empty_str[DIGEST256_LEN] = "01234567890123456789abcdefghijkl"; crypto_digest256(digest_empty_str, "", 0, DIGEST_SHA256); /* Digest of the content. Initialize to a wrong digest. */ - char digest_expected[DIGEST256_LEN] = "01234567890123456789abcdefghijkl"; + NONSTRING + char digest_expected[DIGEST256_LEN] = "01234567890123456789abcdefghijkl"; crypto_digest256(digest_expected, content, strlen(content), DIGEST_SHA256); /* When the bandwidth file can not be found. */ @@ -5265,7 +5364,7 @@ tt_str_op(dir_conn_purpose_to_string(purpose), OP_EQ, expected); EXPECT_CONN_PURPOSE(DIR_PURPOSE_UPLOAD_DIR, "server descriptor upload"); - EXPECT_CONN_PURPOSE(DIR_PURPOSE_UPLOAD_VOTE, "server vote upload"); + EXPECT_CONN_PURPOSE(DIR_PURPOSE_UPLOAD_VOTE, "consensus vote upload"); EXPECT_CONN_PURPOSE(DIR_PURPOSE_UPLOAD_SIGNATURES, "consensus signature upload"); EXPECT_CONN_PURPOSE(DIR_PURPOSE_FETCH_SERVERDESC, "server descriptor fetch"); @@ -7201,6 +7300,126 @@ crypto_pk_free(pk); } +static void +test_dir_parse_family_cert(void *arg) +{ + (void)arg; + ed25519_keypair_t kp_family; + ed25519_keypair_t kp_id; + char family_b64[ED25519_BASE64_LEN+1]; + tor_cert_t *cert = NULL; + int r; + + time_t now = 1739288377; + time_t lifetime = 86400; + time_t got_expiration = -1; + char *got_family_id = NULL; + char *expect_family_id = NULL; + + setup_capture_of_logs(LOG_WARN); + + ed25519_keypair_generate(&kp_family, 0); + ed25519_keypair_generate(&kp_id, 0); + ed25519_public_to_base64(family_b64, &kp_family.pubkey); + tor_asprintf(&expect_family_id, "ed25519:%s", family_b64); + + // Wrong type. + cert = tor_cert_create_ed25519(&kp_family, + CERT_TYPE_ID_SIGNING, + &kp_id.pubkey, + now, lifetime, + CERT_FLAG_INCLUDE_SIGNING_KEY); + tt_assert(cert); + r = check_one_family_cert(cert->encoded, cert->encoded_len, + &kp_id.pubkey, + &got_family_id, + &got_expiration); + tt_ptr_op(got_family_id, OP_EQ, NULL); + tt_int_op(r, OP_EQ, -1); + expect_single_log_msg_containing("Wrong cert type"); + mock_clean_saved_logs(); + tor_cert_free(cert); + + // Family key not included. + cert = tor_cert_create_ed25519(&kp_family, + CERT_TYPE_FAMILY_V_IDENTITY, + &kp_id.pubkey, + now, lifetime, + 0); + tt_assert(cert); + r = check_one_family_cert(cert->encoded, cert->encoded_len, + &kp_id.pubkey, + &got_family_id, + &got_expiration); + tt_ptr_op(got_family_id, OP_EQ, NULL); + tt_int_op(r, OP_EQ, -1); + expect_single_log_msg_containing("Missing family key"); + mock_clean_saved_logs(); + tor_cert_free(cert); + + // Certified key isn't correct + cert = tor_cert_create_ed25519(&kp_family, + CERT_TYPE_FAMILY_V_IDENTITY, + &kp_family.pubkey, + now, lifetime, + CERT_FLAG_INCLUDE_SIGNING_KEY); + tt_assert(cert); + r = check_one_family_cert(cert->encoded, cert->encoded_len, + &kp_id.pubkey, + &got_family_id, + &got_expiration); + tt_ptr_op(got_family_id, OP_EQ, NULL); + tt_int_op(r, OP_EQ, -1); + expect_single_log_msg_containing("Key mismatch"); + mock_clean_saved_logs(); + tor_cert_free(cert); + + // Signature is bogus. + cert = tor_cert_create_ed25519(&kp_family, + CERT_TYPE_FAMILY_V_IDENTITY, + &kp_id.pubkey, + now, lifetime, + CERT_FLAG_INCLUDE_SIGNING_KEY); + tt_assert(cert); + cert->encoded[cert->encoded_len-1] ^= 0x77; // corrupt the signature + r = check_one_family_cert(cert->encoded, cert->encoded_len, + &kp_id.pubkey, + &got_family_id, + &got_expiration); + tt_ptr_op(got_family_id, OP_EQ, NULL); + tt_int_op(r, OP_EQ, -1); + expect_single_log_msg_containing("Invalid signature"); + mock_clean_saved_logs(); + tor_cert_free(cert); + + // Everything is okay! + cert = tor_cert_create_ed25519(&kp_family, + CERT_TYPE_FAMILY_V_IDENTITY, + &kp_id.pubkey, + now, lifetime, + CERT_FLAG_INCLUDE_SIGNING_KEY); + tt_assert(cert); + got_expiration = -1; + r = check_one_family_cert(cert->encoded, cert->encoded_len, + &kp_id.pubkey, + &got_family_id, + &got_expiration); + expect_no_log_entry(); + tt_int_op(r, OP_EQ, 0); + tt_int_op(got_expiration, OP_NE, -1); + // Cert expirations have 1-hour granularity + tt_int_op(got_expiration, OP_GE, now + lifetime); + tt_int_op(got_expiration, OP_LT, now + lifetime + 3601); + tt_str_op(got_family_id, OP_EQ, expect_family_id); + tt_assert(!strchr(got_family_id, '=')); // not family + + done: + tor_cert_free(cert); + tor_free(got_family_id); + tor_free(expect_family_id); + teardown_capture_of_logs(); +} + #ifndef COCCI #define DIR_LEGACY(name) \ { #name, test_dir_ ## name , TT_FORK, NULL, NULL } @@ -7228,6 +7447,7 @@ DIR(routerinfo_parsing, 0), DIR(extrainfo_parsing, 0), DIR(parse_router_list, TT_FORK), + DIR(parse_no_onion_keyrouter_list, TT_FORK), DIR(load_routers, TT_FORK), DIR(load_extrainfo, TT_FORK), DIR(getinfo_extra, 0), @@ -7286,5 +7506,6 @@ DIR(dirserv_router_get_status, TT_FORK), DIR(dirserv_would_reject_router, TT_FORK), DIR(dirserv_add_own_fingerprint, TT_FORK), + DIR(parse_family_cert, TT_FORK), END_OF_TESTCASES }; diff -Nru tor-0.4.7.16/src/test/test_dir_common.c tor-0.4.9.6/src/test/test_dir_common.c --- tor-0.4.7.16/src/test/test_dir_common.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/test/test_dir_common.c 2026-03-25 14:30:34.000000000 +0000 @@ -93,7 +93,7 @@ vrs = tor_malloc_zero(sizeof(vote_routerstatus_t)); rs = &vrs->status; vrs->version = tor_strdup("0.1.2.14"); - rs->published_on = now-1500; + vrs->published_on = now-1500; strlcpy(rs->nickname, "router2", sizeof(rs->nickname)); memset(rs->identity_digest, TEST_DIR_ROUTER_ID_1, DIGEST_LEN); memset(rs->descriptor_digest, TEST_DIR_ROUTER_DD_1, DIGEST_LEN); @@ -111,7 +111,7 @@ vrs = tor_malloc_zero(sizeof(vote_routerstatus_t)); rs = &vrs->status; vrs->version = tor_strdup("0.2.0.5"); - rs->published_on = now-1000; + vrs->published_on = now-1000; strlcpy(rs->nickname, "router1", sizeof(rs->nickname)); memset(rs->identity_digest, TEST_DIR_ROUTER_ID_2, DIGEST_LEN); memset(rs->descriptor_digest, TEST_DIR_ROUTER_DD_2, DIGEST_LEN); @@ -130,7 +130,7 @@ vrs = tor_malloc_zero(sizeof(vote_routerstatus_t)); rs = &vrs->status; vrs->version = tor_strdup("0.1.0.3"); - rs->published_on = now-1000; + vrs->published_on = now-1000; strlcpy(rs->nickname, "router3", sizeof(rs->nickname)); memset(rs->identity_digest, TEST_DIR_ROUTER_ID_3, DIGEST_LEN); memset(rs->descriptor_digest, TEST_DIR_ROUTER_DD_3, DIGEST_LEN); @@ -147,7 +147,7 @@ vrs = tor_malloc_zero(sizeof(vote_routerstatus_t)); rs = &vrs->status; vrs->version = tor_strdup("0.1.6.3"); - rs->published_on = now-1000; + vrs->published_on = now-1000; strlcpy(rs->nickname, "router4", sizeof(rs->nickname)); memset(rs->identity_digest, TEST_DIR_ROUTER_ID_4, DIGEST_LEN); memset(rs->descriptor_digest, TEST_DIR_ROUTER_DD_4, DIGEST_LEN); diff -Nru tor-0.4.7.16/src/test/test_dir_handle_get.c tor-0.4.9.6/src/test/test_dir_handle_get.c --- tor-0.4.7.16/src/test/test_dir_handle_get.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/test/test_dir_handle_get.c 2026-03-25 14:30:34.000000000 +0000 @@ -2073,7 +2073,7 @@ conn = new_dir_conn(); tt_int_op(0, OP_EQ, directory_handle_command_get(conn, - GET("/tor/status-vote/next/bandwdith"), NULL, 0)); + GET("/tor/status-vote/next/bandwidth"), NULL, 0)); fetch_from_buf_http(TO_CONN(conn)->outbuf, &header, MAX_HEADERS_SIZE, NULL, NULL, 1, 0); diff -Nru tor-0.4.7.16/src/test/test_dirvote.c tor-0.4.9.6/src/test/test_dirvote.c --- tor-0.4.7.16/src/test/test_dirvote.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/test/test_dirvote.c 2026-03-25 14:30:34.000000000 +0000 @@ -656,30 +656,6 @@ ROUTER_FREE(pppp); } -static void -test_dirvote_parse_param_buggy(void *arg) -{ - (void)arg; - - /* Tests for behavior with bug emulation to migrate away from bug 19011. */ - tt_i64_op(extract_param_buggy("blah blah", "bwweightscale", 10000), - OP_EQ, 10000); - tt_i64_op(extract_param_buggy("bwweightscale=7", "bwweightscale", 10000), - OP_EQ, 7); - tt_i64_op(extract_param_buggy("bwweightscale=7 foo=9", - "bwweightscale", 10000), - OP_EQ, 10000); - tt_i64_op(extract_param_buggy("foo=7 bwweightscale=777 bar=9", - "bwweightscale", 10000), - OP_EQ, 10000); - tt_i64_op(extract_param_buggy("foo=7 bwweightscale=1234", - "bwweightscale", 10000), - OP_EQ, 1234); - - done: - ; -} - #define NODE(name, flags) \ { \ #name, test_dirvote_##name, (flags), NULL, NULL \ @@ -692,5 +668,4 @@ NODE(get_sybil_by_ip_version_ipv4, TT_FORK), NODE(get_sybil_by_ip_version_ipv6, TT_FORK), NODE(get_all_possible_sybil, TT_FORK), - NODE(parse_param_buggy, 0), END_OF_TESTCASES}; diff -Nru tor-0.4.7.16/src/test/test_dos.c tor-0.4.9.6/src/test/test_dos.c --- tor-0.4.7.16/src/test/test_dos.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/test/test_dos.c 2026-03-25 14:30:34.000000000 +0000 @@ -9,6 +9,7 @@ #include "core/or/dos.h" #include "core/or/circuitlist.h" #include "lib/crypt_ops/crypto_rand.h" +#include "lib/time/compat_time.h" #include "feature/stats/geoip_stats.h" #include "core/or/channel.h" #include "feature/nodelist/microdesc.h" @@ -23,6 +24,8 @@ #include "test/test.h" #include "test/log_test_helpers.h" +static const uint64_t BILLION = 1000000000; + static networkstatus_t *dummy_ns = NULL; static networkstatus_t * mock_networkstatus_get_latest_consensus(void) @@ -58,14 +61,19 @@ static void test_dos_conn_creation(void *arg) { + uint64_t monotime_now = 0xfffffffe; + (void) arg; + monotime_enable_test_mocking(); + monotime_coarse_set_mock_time_nsec(monotime_now); MOCK(get_param_cc_enabled, mock_enable_dos_protection); MOCK(get_param_conn_enabled, mock_enable_dos_protection); /* Initialize test data */ or_connection_t or_conn; - time_t now = 1281533250; /* 2010-08-11 13:27:30 UTC */ + memset(&or_conn, 0, sizeof or_conn); + time_t wallclock_now = 1281533250; /* 2010-08-11 13:27:30 UTC */ tt_int_op(AF_INET,OP_EQ, tor_addr_parse(&TO_CONN(&or_conn)->addr, "18.0.0.1")); tor_addr_t *addr = &TO_CONN(&or_conn)->addr; @@ -75,13 +83,15 @@ uint32_t max_concurrent_conns = get_param_conn_max_concurrent_count(NULL); /* Introduce new client */ - geoip_note_client_seen(GEOIP_CLIENT_CONNECT, addr, NULL, now); + geoip_note_client_seen(GEOIP_CLIENT_CONNECT, addr, NULL, wallclock_now); { /* Register many conns from this client but not enough to get it blocked */ unsigned int i; for (i = 0; i < max_concurrent_conns; i++) { /* Don't trigger the connect() rate limitation so advance the clock 1 * second for each connection. */ - update_approx_time(++now); + monotime_coarse_set_mock_time_nsec(monotime_now += BILLION); + update_approx_time(++wallclock_now); + or_conn.tracked_for_dos_mitigation = 0; dos_new_client_conn(&or_conn, NULL); } } @@ -91,12 +101,14 @@ dos_conn_addr_get_defense_type(addr)); /* Register another conn and check that new conns are not allowed anymore */ + or_conn.tracked_for_dos_mitigation = 0; dos_new_client_conn(&or_conn, NULL); tt_int_op(DOS_CONN_DEFENSE_CLOSE, OP_EQ, dos_conn_addr_get_defense_type(addr)); /* Close a client conn and see that a new conn will be permitted again */ dos_close_client_conn(&or_conn); + or_conn.tracked_for_dos_mitigation = 0; tt_int_op(DOS_CONN_DEFENSE_NONE, OP_EQ, dos_conn_addr_get_defense_type(addr)); @@ -107,6 +119,7 @@ done: dos_free_all(); + monotime_disable_test_mocking(); } /** Helper mock: Place a fake IP addr for this channel in addr_out */ @@ -141,6 +154,7 @@ /* Initialize test data */ or_connection_t or_conn; + memset(&or_conn, 0, sizeof or_conn); time_t now = 1281533250; /* 2010-08-11 13:27:30 UTC */ tt_int_op(AF_INET,OP_EQ, tor_addr_parse(&TO_CONN(&or_conn)->addr, "18.0.0.1")); @@ -156,6 +170,7 @@ * circuit counting subsystem */ geoip_note_client_seen(GEOIP_CLIENT_CONNECT, addr, NULL, now); for (i = 0; i < min_conc_conns_for_cc ; i++) { + or_conn.tracked_for_dos_mitigation = 0; dos_new_client_conn(&or_conn, NULL); } @@ -205,6 +220,7 @@ channel_init(chan); chan->is_client = 1; or_connection_t or_conn; + memset(&or_conn, 0, sizeof or_conn); tt_int_op(AF_INET,OP_EQ, tor_addr_parse(&TO_CONN(&or_conn)->addr, "18.0.0.1")); tor_addr_t *addr = &TO_CONN(&or_conn)->addr; @@ -421,12 +437,12 @@ dos_free_all(); } -/* Test if we avoid counting a known relay. */ +/* Test if we avoid counting a known relay. (We no longer do) */ static void test_known_relay(void *arg) { clientmap_entry_t *entry = NULL; - routerstatus_t *rs = NULL; microdesc_t *md = NULL; routerinfo_t *ri = NULL; + routerstatus_t *rs = NULL; (void) arg; @@ -446,6 +462,7 @@ /* Setup an OR conn so we can pass it to the DoS subsystem. */ or_connection_t or_conn; + memset(&or_conn, 0, sizeof or_conn); tor_addr_parse(&TO_CONN(&or_conn)->addr, "42.42.42.42"); rs = tor_malloc_zero(sizeof(*rs)); @@ -462,34 +479,24 @@ * client connection. */ geoip_note_client_seen(GEOIP_CLIENT_CONNECT, &TO_CONN(&or_conn)->addr, NULL, 0); - /* Suppose we have 5 connections in rapid succession, the counter should - * always be 0 because we should ignore this. */ - dos_new_client_conn(&or_conn, NULL); - dos_new_client_conn(&or_conn, NULL); + /* Suppose we have 5 connections in rapid succession */ dos_new_client_conn(&or_conn, NULL); + or_conn.tracked_for_dos_mitigation = 0; dos_new_client_conn(&or_conn, NULL); + or_conn.tracked_for_dos_mitigation = 0; dos_new_client_conn(&or_conn, NULL); - entry = geoip_lookup_client(&TO_CONN(&or_conn)->addr, NULL, - GEOIP_CLIENT_CONNECT); - tt_assert(entry); - /* We should have a count of 0. */ - tt_uint_op(entry->dos_stats.conn_stats.concurrent_count, OP_EQ, 0); - - /* To make sure that his is working properly, make a unknown client - * connection and see if we do get it. */ - tor_addr_parse(&TO_CONN(&or_conn)->addr, "42.42.42.43"); - geoip_note_client_seen(GEOIP_CLIENT_CONNECT, &TO_CONN(&or_conn)->addr, - NULL, 0); + or_conn.tracked_for_dos_mitigation = 0; dos_new_client_conn(&or_conn, NULL); + or_conn.tracked_for_dos_mitigation = 0; dos_new_client_conn(&or_conn, NULL); entry = geoip_lookup_client(&TO_CONN(&or_conn)->addr, NULL, GEOIP_CLIENT_CONNECT); tt_assert(entry); - /* We should have a count of 2. */ - tt_uint_op(entry->dos_stats.conn_stats.concurrent_count, OP_EQ, 2); + /* We should have a count of 5. */ + tt_uint_op(entry->dos_stats.conn_stats.concurrent_count, OP_EQ, 5); done: - routerstatus_free(rs); routerinfo_free(ri); microdesc_free(md); + routerstatus_free(rs); smartlist_clear(dummy_ns->routerstatus_list); networkstatus_vote_free(dummy_ns); dos_free_all(); @@ -511,6 +518,7 @@ /* Initialize test data */ or_connection_t or_conn; + memset(&or_conn, 0, sizeof or_conn); time_t now = 1281533250; /* 2010-08-11 13:27:30 UTC */ tt_int_op(AF_INET,OP_EQ, tor_addr_parse(&TO_CONN(&or_conn)->addr, "18.0.0.1")); @@ -526,6 +534,7 @@ { /* Register many conns from this client but not enough to get it blocked */ unsigned int i; for (i = 0; i < burst_conn - 1; i++) { + or_conn.tracked_for_dos_mitigation = 0; dos_new_client_conn(&or_conn, NULL); } } @@ -536,6 +545,7 @@ /* Register another conn and check that new conns are not allowed anymore. * We should have reached our burst. */ + or_conn.tracked_for_dos_mitigation = 0; dos_new_client_conn(&or_conn, NULL); tt_int_op(DOS_CONN_DEFENSE_CLOSE, OP_EQ, dos_conn_addr_get_defense_type(addr)); diff -Nru tor-0.4.7.16/src/test/test_entrynodes.c tor-0.4.9.6/src/test/test_entrynodes.c --- tor-0.4.7.16/src/test/test_entrynodes.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/test/test_entrynodes.c 2026-03-25 14:30:34.000000000 +0000 @@ -24,6 +24,7 @@ #include "feature/dirclient/dirclient.h" #include "feature/client/entrynodes.h" #include "feature/nodelist/nodelist.h" +#include "feature/nodelist/nodefamily.h" #include "feature/nodelist/networkstatus.h" #include "core/or/policies.h" #include "feature/nodelist/routerlist.h" @@ -1942,8 +1943,10 @@ tt_ptr_op(g2, OP_EQ, g); /* But if we impose a restriction, we don't get the same guard */ + get_options_mutable()->EnforceDistinctSubnets = 0; rst = guard_create_exit_restriction((uint8_t*)g->identity); g2 = select_entry_guard_for_circuit(gs, GUARD_USAGE_TRAFFIC, rst, &state); + tt_assert(g2); tt_ptr_op(g2, OP_NE, g); done: @@ -2323,6 +2326,75 @@ } static void +test_entry_guard_select_for_circuit_exit_family_restriction(void *arg) +{ + (void) arg; + entry_guard_restriction_t *rst = NULL; + entry_guard_restriction_t *rst2 = NULL; + guard_selection_t *gs = guard_selection_new("default", GS_TYPE_NORMAL); + int retval; + unsigned state = 9999; + + /* Create our circuit */ + circuit_t *circ = dummy_origin_circuit_new(30); + origin_circuit_t *oc = TO_ORIGIN_CIRCUIT(circ); + oc->build_state = tor_malloc_zero(sizeof(cpath_build_state_t)); + + /* First pick the exit and pin it on the build_state */ + retval = onion_pick_cpath_exit(oc, NULL); + tt_int_op(retval, OP_EQ, 0); + + /* Then pick a guard */ + entry_guards_update_primary(gs); + entry_guard_t *g = select_entry_guard_for_circuit(gs, GUARD_USAGE_TRAFFIC, + NULL, &state); + + tt_assert(g); + tt_assert(g->is_primary); + tt_uint_op(state, OP_EQ, GUARD_CIRC_STATE_USABLE_ON_COMPLETION); + tt_i64_op(g->last_tried_to_connect, OP_EQ, approx_time()); + + /* Add the guard and the exit to each others' families */ + get_options_mutable()->EnforceDistinctSubnets = 0; + const char* exit_id = + (const char*)build_state_get_exit_rsa_id(oc->build_state); + const node_t *exit = node_get_by_id(exit_id); + const node_t *guard = node_get_by_id(g->identity); + exit->md->family = nodefamily_parse((const char*)g->nickname, + node_get_rsa_id_digest(exit),0); + guard->md->family = + nodefamily_parse((const char*)exit->rs->nickname, + node_get_rsa_id_digest(guard),0); + tt_assert(nodefamily_contains_nickname(exit->md->family, + (const char*)g->nickname)); + + /* We should get a different guard, after adding the exit restriction */ + rst = guard_create_exit_restriction((const uint8_t*)exit_id); + entry_guard_t *g2 = + select_entry_guard_for_circuit(gs, GUARD_USAGE_TRAFFIC, rst, &state); + tt_assert(g2); + tt_assert(g2->is_primary); + tt_uint_op(state, OP_EQ, GUARD_CIRC_STATE_USABLE_ON_COMPLETION); + tt_i64_op(g2->last_tried_to_connect, OP_EQ, approx_time()); + tt_ptr_op(g2, OP_NE, g); + + /* Now check that conflux circuits satisfy the exit family restriction */ + rst2 = guard_create_conflux_restriction(oc, (const uint8_t*)exit_id); + g2 = select_entry_guard_for_circuit(gs, GUARD_USAGE_TRAFFIC, rst2, &state); + tt_assert(g2); + tt_assert(g2->is_primary); + tt_uint_op(state, OP_EQ, GUARD_CIRC_STATE_USABLE_ON_COMPLETION); + tt_i64_op(g2->last_tried_to_connect, OP_EQ, approx_time()); + tt_ptr_op(g2, OP_NE, g); + + done: + circuit_free_(circ); + guard_selection_free(gs); + entry_guard_restriction_free(rst); + entry_guard_restriction_free(rst2); +} + +static void test_entry_guard_select_and_cancel(void *arg) { (void) arg; @@ -2982,7 +3054,7 @@ oc->build_state = tor_malloc_zero(sizeof(cpath_build_state_t)); /* First pick the exit and pin it on the build_state */ - retval = onion_pick_cpath_exit(oc, NULL, 0); + retval = onion_pick_cpath_exit(oc, NULL); tt_int_op(retval, OP_EQ, 0); /* Extend path 3 times. First we pick guard, then middle, then exit. */ @@ -3050,7 +3122,7 @@ /* First pick the exit and pin it on the build_state */ tt_int_op(oc->build_state->desired_path_len, OP_EQ, 0); - retval = onion_pick_cpath_exit(oc, NULL, 0); + retval = onion_pick_cpath_exit(oc, NULL); tt_int_op(retval, OP_EQ, 0); /* Ensure that vanguards make 4-hop circuits by default */ @@ -3199,6 +3271,7 @@ BFN_TEST(select_for_circuit_highlevel_primary), BFN_TEST(select_for_circuit_highlevel_confirm_other), BFN_TEST(select_for_circuit_highlevel_primary_retry), + BFN_TEST(select_for_circuit_exit_family_restriction), BFN_TEST(select_and_cancel), BFN_TEST(drop_guards), BFN_TEST(outdated_dirserver_exclusion), diff -Nru tor-0.4.7.16/src/test/test_extorport.c tor-0.4.9.6/src/test/test_extorport.c --- tor-0.4.7.16/src/test/test_extorport.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/test/test_extorport.c 2026-03-25 14:30:34.000000000 +0000 @@ -166,7 +166,7 @@ size_t reply_len=0; char hmac1[32], hmac2[32]; - const char client_nonce[32] = + NONSTRING const char client_nonce[32] = "Who is the third who walks alway"; char server_hash_input[] = "ExtORPort authentication server-to-client hash" diff -Nru tor-0.4.7.16/src/test/test_geoip.c tor-0.4.9.6/src/test/test_geoip.c --- tor-0.4.7.16/src/test/test_geoip.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/test/test_geoip.c 2026-03-25 14:30:34.000000000 +0000 @@ -58,7 +58,8 @@ "dirreq-stats-end 2010-08-12 13:27:30 (86400 s)\n" "dirreq-v3-ips ab=8\n" "dirreq-v3-reqs ab=8\n" - "dirreq-v3-resp ok=0,not-enough-sigs=0,unavailable=0,not-found=0," + "dirreq-v3-resp " + "served=0,ok=0,not-enough-sigs=0,unavailable=0,not-found=0," "not-modified=0,busy=0\n" "dirreq-v3-direct-dl complete=0,timeout=0,running=0\n" "dirreq-v3-tunneled-dl complete=0,timeout=0,running=0\n", @@ -66,7 +67,8 @@ "dirreq-stats-end 2010-08-12 13:27:30 (86400 s)\n" "dirreq-v3-ips \n" "dirreq-v3-reqs \n" - "dirreq-v3-resp ok=0,not-enough-sigs=0,unavailable=0,not-found=0," + "dirreq-v3-resp " + "served=0,ok=0,not-enough-sigs=0,unavailable=0,not-found=0," "not-modified=0,busy=0\n" "dirreq-v3-direct-dl complete=0,timeout=0,running=0\n" "dirreq-v3-tunneled-dl complete=0,timeout=0,running=0\n", @@ -74,7 +76,8 @@ "dirreq-stats-end 2010-08-12 13:27:30 (86400 s)\n" "dirreq-v3-ips \n" "dirreq-v3-reqs \n" - "dirreq-v3-resp ok=8,not-enough-sigs=0,unavailable=0,not-found=0," + "dirreq-v3-resp " + "served=8,ok=8,not-enough-sigs=0,unavailable=0,not-found=0," "not-modified=0,busy=0\n" "dirreq-v3-direct-dl complete=0,timeout=0,running=0\n" "dirreq-v3-tunneled-dl complete=0,timeout=0,running=0\n", @@ -82,7 +85,8 @@ "dirreq-stats-end 2010-08-12 13:27:30 (86400 s)\n" "dirreq-v3-ips \n" "dirreq-v3-reqs \n" - "dirreq-v3-resp ok=8,not-enough-sigs=0,unavailable=0,not-found=0," + "dirreq-v3-resp " + "served=8,ok=8,not-enough-sigs=0,unavailable=0,not-found=0," "not-modified=0,busy=0\n" "dirreq-v3-direct-dl complete=0,timeout=0,running=0\n" "dirreq-v3-tunneled-dl complete=0,timeout=0,running=4\n", @@ -230,6 +234,7 @@ /* Note a successful network status response and make sure that it * appears in the history string. */ + geoip_note_ns_response(GEOIP_SERVED); geoip_note_ns_response(GEOIP_SUCCESS); s = geoip_format_dirreq_stats(now + 86400); tt_str_op(dirreq_stats_3,OP_EQ, s); diff -Nru tor-0.4.7.16/src/test/test_hs_cache.c tor-0.4.9.6/src/test/test_hs_cache.c --- tor-0.4.7.16/src/test/test_hs_cache.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/test/test_hs_cache.c 2026-03-25 14:30:34.000000000 +0000 @@ -90,7 +90,7 @@ tt_str_op(desc_out, OP_EQ, desc1_str); /* Tell our OOM to run and to at least remove a byte which will result in * removing the descriptor from our cache. */ - oom_size = hs_cache_handle_oom(time(NULL), 1); + oom_size = hs_cache_handle_oom(1); tt_int_op(oom_size, OP_GE, 1); ret = hs_cache_lookup_as_dir(3, helper_get_hsdir_query(desc1), NULL); tt_int_op(ret, OP_EQ, 0); @@ -127,7 +127,7 @@ NULL); tt_int_op(ret, OP_EQ, 0); /* Cleanup our entire cache. */ - oom_size = hs_cache_handle_oom(time(NULL), 1); + oom_size = hs_cache_handle_oom(1); tt_int_op(oom_size, OP_GE, 1); hs_descriptor_free(desc_zero_lifetime); tor_free(desc_zero_lifetime_str); @@ -224,6 +224,61 @@ tor_free(desc1_str); } +static void +test_clean_oom_as_dir(void *arg) +{ + size_t ret; + char *desc1_str = NULL, *desc2_str = NULL; + hs_descriptor_t *desc1 = NULL, *desc2 = NULL; + ed25519_keypair_t signing_kp1, signing_kp2; + + (void) arg; + + init_test(); + + /* Generate two valid descriptors. */ + ret = ed25519_keypair_generate(&signing_kp1, 0); + tt_int_op(ret, OP_EQ, 0); + ret = ed25519_keypair_generate(&signing_kp2, 0); + tt_int_op(ret, OP_EQ, 0); + desc1 = hs_helper_build_hs_desc_with_ip(&signing_kp1); + tt_assert(desc1); + desc2 = hs_helper_build_hs_desc_with_ip(&signing_kp2); + tt_assert(desc2); + ret = hs_desc_encode_descriptor(desc1, &signing_kp1, NULL, &desc1_str); + tt_int_op(ret, OP_EQ, 0); + ret = hs_cache_store_as_dir(desc1_str); + tt_int_op(ret, OP_EQ, 0); + ret = hs_desc_encode_descriptor(desc2, &signing_kp2, NULL, &desc2_str); + tt_int_op(ret, OP_EQ, 0); + ret = hs_cache_store_as_dir(desc2_str); + tt_int_op(ret, OP_EQ, 0); + + /* Set the downloaded count to 42 for the second one. */ + dir_set_downloaded(&desc2->plaintext_data.blinded_pubkey, 42); + const hs_cache_dir_descriptor_t *entry = + lookup_v3_desc_as_dir(desc2->plaintext_data.blinded_pubkey.pubkey); + tt_u64_op(entry->n_downloaded, OP_EQ, 42); + + /* Spin the OOM cleanup for only 1 descriptor (very low amount of bytes). We + * expect desc1 to be cleaned up because its downloaded counter is 0. */ + size_t removed = hs_cache_handle_oom(1); + tt_size_op(removed, OP_GT, 0); + + /* Desc1 is gone. */ + entry = lookup_v3_desc_as_dir(desc1->plaintext_data.blinded_pubkey.pubkey); + tt_assert(!entry); + /* Desc2 is still there. */ + entry = lookup_v3_desc_as_dir(desc2->plaintext_data.blinded_pubkey.pubkey); + tt_assert(entry); + + done: + hs_descriptor_free(desc1); + hs_descriptor_free(desc2); + tor_free(desc1_str); + tor_free(desc2_str); +} + /* Test helper: Fetch an HS descriptor from an HSDir (for the hidden service with blinded_key. Return the received descriptor string. */ static char * @@ -705,6 +760,8 @@ NULL, NULL }, { "clean_as_dir", test_clean_as_dir, TT_FORK, NULL, NULL }, + { "clean_oom_as_dir", test_clean_oom_as_dir, TT_FORK, + NULL, NULL }, { "hsdir_revision_counter_check", test_hsdir_revision_counter_check, TT_FORK, NULL, NULL }, { "upload_and_download_hs_desc", test_upload_and_download_hs_desc, TT_FORK, diff -Nru tor-0.4.7.16/src/test/test_hs_client.c tor-0.4.9.6/src/test/test_hs_client.c --- tor-0.4.7.16/src/test/test_hs_client.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/test/test_hs_client.c 2026-03-25 14:30:34.000000000 +0000 @@ -15,6 +15,7 @@ #define CIRCUITLIST_PRIVATE #define CONNECTION_PRIVATE #define CRYPT_PATH_PRIVATE +#define TOR_CONGESTION_CONTROL_COMMON_PRIVATE #include "test/test.h" #include "test/test_helpers.h" @@ -54,7 +55,7 @@ #include "core/or/origin_circuit_st.h" #include "core/or/socks_request_st.h" -#define TOR_CONGESTION_CONTROL_PRIVATE +#include "core/or/congestion_control_st.h" #include "core/or/congestion_control_common.h" static int @@ -177,6 +178,7 @@ /* prop224: Setup hs ident on the circuit */ or_circ->hs_ident = hs_ident_circuit_new(&service_pk); + or_circ->hs_ident->intro_auth_pk.pubkey[0] = 42; TO_CIRCUIT(or_circ)->state = CIRCUIT_STATE_OPEN; @@ -244,12 +246,14 @@ 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->pvt_crypto.f_digest), + tt_int_op(crypto_digest_get_algorithm( + or_circ->cpath->pvt_crypto.c.tor1.f_digest), OP_EQ, DIGEST_SHA3_256); - tt_int_op(crypto_digest_get_algorithm(or_circ->cpath->pvt_crypto.b_digest), + tt_int_op(crypto_digest_get_algorithm( + or_circ->cpath->pvt_crypto.c.tor1.b_digest), OP_EQ, DIGEST_SHA3_256); - tt_assert(or_circ->cpath->pvt_crypto.f_crypto); - tt_assert(or_circ->cpath->pvt_crypto.b_crypto); + tt_assert(or_circ->cpath->pvt_crypto.c.tor1.f_crypto); + tt_assert(or_circ->cpath->pvt_crypto.c.tor1.b_crypto); /* Ensure that circ purpose was changed */ tt_int_op(or_circ->base_.purpose, OP_EQ, CIRCUIT_PURPOSE_C_REND_JOINED); @@ -1090,7 +1094,7 @@ char *desc_encoded = NULL; circuit_t *circ = NULL; origin_circuit_t *ocirc = NULL; - tor_addr_t addr; + tor_addr_t addr = TOR_ADDR_NULL; ed25519_keypair_t service_kp; ed25519_keypair_t signing_kp; entry_connection_t *socks_conn = NULL; @@ -1186,10 +1190,11 @@ circ->purpose = CIRCUIT_PURPOSE_C_REND_READY; ocirc = TO_ORIGIN_CIRCUIT(circ); ocirc->hs_ident = hs_ident_circuit_new(&service_kp.pubkey); + ocirc->hs_ident->intro_auth_pk.pubkey[0] = 42; ocirc->build_state = tor_malloc_zero(sizeof(cpath_build_state_t)); /* Code path will log this exit so build it. */ ocirc->build_state->chosen_exit = extend_info_new("TestNickname", digest, - NULL, NULL, NULL, &addr, + NULL, NULL, &addr, 4242, NULL, false); /* Attach socks connection to this rendezvous circuit. */ ocirc->p_streams = ENTRY_TO_EDGE_CONN(socks_conn); @@ -1263,7 +1268,7 @@ circuit_t *circ = NULL; ed25519_keypair_t service_kp, intro_kp; origin_circuit_t *ocirc = NULL; - tor_addr_t addr; + tor_addr_t addr = TOR_ADDR_NULL; const hs_cache_intro_state_t *entry; (void) arg; @@ -1284,7 +1289,7 @@ ocirc->build_state = tor_malloc_zero(sizeof(cpath_build_state_t)); /* Code path will log this exit so build it. */ ocirc->build_state->chosen_exit = extend_info_new("TestNickname", digest, - NULL, NULL, NULL, &addr, + NULL, NULL, &addr, 4242, NULL, false); ed25519_pubkey_copy(ô->hs_ident->intro_auth_pk, &intro_kp.pubkey); @@ -1311,7 +1316,7 @@ ocirc->build_state = tor_malloc_zero(sizeof(cpath_build_state_t)); /* Code path will log this exit so build it. */ ocirc->build_state->chosen_exit = extend_info_new("TestNickname", digest, - NULL, NULL, NULL, &addr, + NULL, NULL, &addr, 4242, NULL, false); ed25519_pubkey_copy(ô->hs_ident->intro_auth_pk, &intro_kp.pubkey); @@ -1334,7 +1339,7 @@ ocirc->build_state = tor_malloc_zero(sizeof(cpath_build_state_t)); /* Code path will log this exit so build it. */ ocirc->build_state->chosen_exit = extend_info_new("TestNickname", digest, - NULL, NULL, NULL, &addr, + NULL, NULL, &addr, 4242, NULL, false); ed25519_pubkey_copy(ô->hs_ident->intro_auth_pk, &intro_kp.pubkey); diff -Nru tor-0.4.7.16/src/test/test_hs_common.c tor-0.4.9.6/src/test/test_hs_common.c --- tor-0.4.7.16/src/test/test_hs_common.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/test/test_hs_common.c 2026-03-25 14:30:34.000000000 +0000 @@ -645,6 +645,19 @@ tt_mem_op(cached_disaster_srv_one, OP_EQ, srv_one, DIGEST256_LEN); tt_mem_op(cached_disaster_srv_two, OP_EQ, srv_two, DIGEST256_LEN); + /* For at least one SRV, check that its result was as expected. */ + { + uint8_t srv1_expected[32]; + crypto_digest256( + (char*)srv1_expected, + "shared-random-disaster\0\0\0\0\0\0\x05\xA0\0\0\0\0\0\0\0\1", + strlen("shared-random-disaster")+16, + DIGEST_SHA3_256); + tt_mem_op(srv_one, OP_EQ, srv1_expected, DIGEST256_LEN); + tt_str_op(hex_str((char*)srv_one, DIGEST256_LEN), OP_EQ, + "F8A4948707653837FA44ABB5BBC75A12F6F101E7F8FAF699B9715F4965D3507D"); + } + /* Ask for an SRV that has already been computed */ get_disaster_srv(2, srv_two); /* and check that the cache entries have not changed */ @@ -1509,6 +1522,67 @@ } } +static void +test_blinding_basics(void *arg) +{ + (void)arg; + char *mem_op_hex_tmp = NULL; + const uint64_t time_period = 1234; + ed25519_keypair_t keypair; + + time_t instant; + tt_int_op(0, OP_EQ, parse_iso_time("1973-05-20 01:50:33", &instant)); + tt_int_op(1440, OP_EQ, get_time_period_length()); // in minutes, remember. + tt_int_op(time_period, OP_EQ, hs_get_time_period_num(instant)); + + const char pubkey_hex[] = + "833990B085C1A688C1D4C8B1F6B56AFAF5A2ECA674449E1D704F83765CCB7BC6"; + const char seckey_hex[] = + "D8C7FF0E31295B66540D789AF3E3DF992038A9592EEA01D8B7CBA06D6E66D159" + "4D6167696320576F7264733A20737065697373636F62616C742062697669756D"; + base16_decode((char*)keypair.pubkey.pubkey, sizeof(keypair.pubkey.pubkey), + pubkey_hex, strlen(pubkey_hex)); + base16_decode((char*)keypair.seckey.seckey, sizeof(keypair.seckey.seckey), + seckey_hex, strlen(seckey_hex)); + + uint64_t period_len = get_time_period_length(); + tt_u64_op(period_len, OP_EQ, 1440); + uint8_t params[32]; + build_blinded_key_param(&keypair.pubkey, NULL, 0, + time_period, 1440, + params); + test_memeq_hex(params, + "379E50DB31FEE6775ABD0AF6FB7C371E" + "060308F4F847DB09FE4CFE13AF602287"); + + ed25519_public_key_t blinded_public; + hs_build_blinded_pubkey(&keypair.pubkey, NULL, 0, time_period, + &blinded_public); + hs_subcredential_t subcred; + hs_get_subcredential(&keypair.pubkey, &blinded_public, &subcred); + + test_memeq_hex(blinded_public.pubkey, + "3A50BF210E8F9EE955AE0014F7A6917F" + "B65EBF098A86305ABB508D1A7291B6D5"); + test_memeq_hex(subcred.subcred, + "635D55907816E8D76398A675A50B1C2F" + "3E36B42A5CA77BA3A0441285161AE07D"); + + ed25519_keypair_t blinded_keypair; + hs_build_blinded_keypair(&keypair, NULL, 0, time_period, + &blinded_keypair); + tt_mem_op(blinded_public.pubkey, OP_EQ, blinded_keypair.pubkey.pubkey, + ED25519_PUBKEY_LEN); + test_memeq_hex(blinded_keypair.seckey.seckey, + "A958DC83AC885F6814C67035DE817A2C" + "604D5D2F715282079448F789B656350B" + "4540FE1F80AA3F7E91306B7BF7A8E367" + "293352B14A29FDCC8C19F3558075524B"); + + done: + tor_free(mem_op_hex_tmp); +} + /** Pick an HSDir for service with onion_identity_pk as a client. Put * its identity digest in hsdir_digest_out. */ static void @@ -1843,6 +1917,7 @@ } struct testcase_t hs_common_tests[] = { + { "blinding_basics", test_blinding_basics, TT_FORK, NULL, NULL }, { "build_address", test_build_address, TT_FORK, NULL, NULL }, { "validate_address", test_validate_address, TT_FORK, diff -Nru tor-0.4.7.16/src/test/test_hs_control.c tor-0.4.9.6/src/test/test_hs_control.c --- tor-0.4.7.16/src/test/test_hs_control.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/test/test_hs_control.c 2026-03-25 14:30:34.000000000 +0000 @@ -23,6 +23,7 @@ #include "app/config/config.h" #include "feature/hs/hs_common.h" #include "feature/hs/hs_client.h" +#include "feature/hs/hs_config.h" #include "feature/hs/hs_control.h" #include "feature/nodelist/nodelist.h" @@ -628,7 +629,7 @@ tor_free(args); tor_free(cp1); - /* Overwrite the credentials and check that they got overwrited. */ + /* Overwrite the credentials and check that they got overwritten. */ args = tor_strdup("2fvhjskjet3n5syd6yfg5lhvwcs62bojmthr35ko5bllr3iqdb4ctdyd " "x25519:UDRvZLvcJo0QRLvDfkpgbtsqbkhIUQZyeo2FNBrgS18= " "Flags=Permanent"); @@ -829,8 +830,12 @@ list_good = smartlist_new(); smartlist_add(list_good, client_good); - add_onion_helper_add_service(HS_VERSION_THREE, &sk_good, portcfgs, 1, 1, - list_good, &address_out_good); + add_onion_helper_add_service( + HS_VERSION_THREE, &sk_good, portcfgs, 1, 1, + /*pow_defenses_enabled=*/1, + /*pow_queue_rate=*/HS_CONFIG_V3_POW_QUEUE_RATE, + /*pow_queue_burst=*/HS_CONFIG_V3_POW_QUEUE_BURST, + list_good, &address_out_good); service_good = find_service(global_map, &pk_good); tt_int_op(smartlist_len(service_good->config.clients), OP_EQ, 1); @@ -845,8 +850,12 @@ portcfgs = smartlist_new(); smartlist_add(portcfgs, portcfg); - add_onion_helper_add_service(HS_VERSION_THREE, &sk_bad, portcfgs, 1, 1, - list_bad, &address_out_bad); + add_onion_helper_add_service( + HS_VERSION_THREE, &sk_bad, portcfgs, 1, 1, + /*pow_defenses_enabled=*/1, + /*pow_queue_rate=*/HS_CONFIG_V3_POW_QUEUE_RATE, + /*pow_queue_burst=*/HS_CONFIG_V3_POW_QUEUE_BURST, + list_bad, &address_out_bad); service_bad = find_service(global_map, &pk_bad); diff -Nru tor-0.4.7.16/src/test/test_hs_descriptor.c tor-0.4.9.6/src/test/test_hs_descriptor.c --- tor-0.4.7.16/src/test/test_hs_descriptor.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/test/test_hs_descriptor.c 2026-03-25 14:30:34.000000000 +0000 @@ -7,6 +7,7 @@ */ #define HS_DESCRIPTOR_PRIVATE +#define TOR_CONGESTION_CONTROL_COMMON_PRIVATE #include "lib/crypt_ops/crypto_ed25519.h" #include "lib/crypt_ops/crypto_format.h" @@ -25,6 +26,7 @@ #include "test/rng_test_helpers.h" #define TOR_CONGESTION_CONTROL_PRIVATE +#include "core/or/congestion_control_st.h" #include "core/or/congestion_control_common.h" #ifdef HAVE_CFLAG_WOVERLENGTH_STRINGS @@ -364,6 +366,75 @@ hs_helper_desc_equal(desc, decoded); } + /* Decode a descriptor without auth clients, and with PoW data added via + * test_extra_plaintext to test both the normal case of PoW decoding and the + * extra plaintext mechanism itself. */ + { + tor_assert(!desc->encrypted_data.pow_params); + + char pow_seed_base64[HS_POW_SEED_LEN*2]; + uint8_t pow_seed[HS_POW_SEED_LEN]; + crypto_strongest_rand(pow_seed, sizeof pow_seed); + tt_int_op(base64_encode_nopad(pow_seed_base64, sizeof pow_seed_base64, + pow_seed, sizeof pow_seed), OP_GT, 0); + + time_t expiration_time = time(NULL); + char time_buf[ISO_TIME_LEN + 1]; + format_iso_time_nospace(time_buf, expiration_time); + + const unsigned suggested_effort = 123456; + char *extra_plaintext = NULL; + tor_asprintf(&extra_plaintext, + "pow-params v1 %s %u %s\n", + pow_seed_base64, suggested_effort, time_buf); + + tor_free(encoded); + desc->encrypted_data.test_extra_plaintext = extra_plaintext; + ret = hs_desc_encode_descriptor(desc, &signing_kp, NULL, &encoded); + tor_free(extra_plaintext); + desc->encrypted_data.test_extra_plaintext = extra_plaintext; + + tt_int_op(ret, OP_EQ, 0); + tt_assert(encoded); + + desc->encrypted_data.pow_params = + tor_malloc_zero(sizeof(hs_pow_desc_params_t)); + desc->encrypted_data.pow_params->type = HS_POW_DESC_V1; + memcpy(desc->encrypted_data.pow_params->seed, pow_seed, HS_POW_SEED_LEN); + desc->encrypted_data.pow_params->suggested_effort = suggested_effort; + desc->encrypted_data.pow_params->expiration_time = expiration_time; + + hs_descriptor_free(decoded); + ret = hs_desc_decode_descriptor(encoded, &subcredential, NULL, &decoded); + tt_int_op(ret, OP_EQ, HS_DESC_DECODE_OK); + tt_assert(decoded); + + hs_helper_desc_equal(desc, decoded); + + tor_free(desc->encrypted_data.pow_params); + } + + /* Now a version of the above that's expected to fail. This reproduces the + * issue from ticket tor#40793, in which pow_params gets too few parameters + * but this would cause an assert instead of an early validation fail. + * Make sure it fails to parse. Prior to the fix for #40793 this fails + * an assertion instead. */ + { + tor_free(encoded); + tor_assert(!desc->encrypted_data.pow_params); + desc->encrypted_data.test_extra_plaintext = "pow-params v1 a a\n"; + ret = hs_desc_encode_descriptor(desc, &signing_kp, NULL, &encoded); + desc->encrypted_data.test_extra_plaintext = NULL; + + tt_int_op(ret, OP_EQ, 0); + tt_assert(encoded); + + hs_descriptor_free(decoded); + ret = hs_desc_decode_descriptor(encoded, &subcredential, NULL, &decoded); + tt_int_op(ret, OP_EQ, HS_DESC_DECODE_ENCRYPTED_ERROR); + tt_assert(!decoded); + } + done: hs_descriptor_free(desc); hs_descriptor_free(desc_no_ip); @@ -845,30 +916,21 @@ { (void)arg; - /* Test basic operation: factors of 2X in either direction are OK */ + /* Test basic operation: +/- 1 in either direction are OK */ cc_sendme_inc = 31; - tt_assert(congestion_control_validate_sendme_increment(15)); - tt_assert(congestion_control_validate_sendme_increment(62)); + tt_assert(congestion_control_validate_sendme_increment(30)); + tt_assert(congestion_control_validate_sendme_increment(32)); - /* Test basic operation: Exceeding 2X fails */ + /* Test basic operation: Exceeding +/- 1 fails */ cc_sendme_inc = 31; - tt_assert(!congestion_control_validate_sendme_increment(14)); - tt_assert(!congestion_control_validate_sendme_increment(63)); + tt_assert(!congestion_control_validate_sendme_increment(29)); + tt_assert(!congestion_control_validate_sendme_increment(33)); /* Test potential overflow conditions */ - cc_sendme_inc = 129; - tt_assert(congestion_control_validate_sendme_increment(255)); - tt_assert(congestion_control_validate_sendme_increment(64)); - tt_assert(!congestion_control_validate_sendme_increment(63)); - - cc_sendme_inc = 127; - tt_assert(!congestion_control_validate_sendme_increment(255)); - tt_assert(congestion_control_validate_sendme_increment(254)); - - cc_sendme_inc = 255; + cc_sendme_inc = 254; tt_assert(congestion_control_validate_sendme_increment(255)); - tt_assert(congestion_control_validate_sendme_increment(127)); - tt_assert(!congestion_control_validate_sendme_increment(126)); + tt_assert(congestion_control_validate_sendme_increment(253)); + tt_assert(!congestion_control_validate_sendme_increment(252)); /* Test 0 case */ cc_sendme_inc = 1; diff -Nru tor-0.4.7.16/src/test/test_hs_dos.c tor-0.4.9.6/src/test/test_hs_dos.c --- tor-0.4.7.16/src/test/test_hs_dos.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/test/test_hs_dos.c 2026-03-25 14:30:34.000000000 +0000 @@ -16,6 +16,7 @@ #include "test/log_test_helpers.h" #include "app/config/config.h" +#include "lib/time/compat_time.h" #include "core/or/circuitlist.h" #include "core/or/circuituse.h" @@ -45,7 +46,8 @@ static void test_can_send_intro2(void *arg) { - uint32_t now = (uint32_t) approx_time(); + static const uint64_t BILLION = 1000000000; + uint64_t now = 12345; or_circuit_t *or_circ = NULL; (void) arg; @@ -55,6 +57,8 @@ get_options_mutable()->ORPort_set = 1; setup_mock_consensus(); + monotime_enable_test_mocking(); + monotime_coarse_set_mock_time_nsec(now); or_circ = or_circuit_new(1, NULL); @@ -68,7 +72,7 @@ /* Simulate that 10 cells have arrived in 1 second. There should be no * refill since the bucket is already at maximum on the first cell. */ - update_approx_time(++now); + monotime_coarse_set_mock_time_nsec(now += BILLION); for (int i = 0; i < 10; i++) { tt_int_op(true, OP_EQ, hs_dos_can_send_intro2(or_circ)); } @@ -76,7 +80,7 @@ get_intro2_burst_consensus_param(NULL) - 10); /* Fully refill the bucket minus 1 cell. */ - update_approx_time(++now); + monotime_coarse_set_mock_time_nsec(now += BILLION); tt_int_op(true, OP_EQ, hs_dos_can_send_intro2(or_circ)); tt_uint_op(token_bucket_ctr_get(&or_circ->introduce2_bucket), OP_EQ, get_intro2_burst_consensus_param(NULL) - 1); @@ -84,7 +88,7 @@ /* Receive an INTRODUCE2 at each second. We should have the bucket full * since at every second it gets refilled. */ for (int i = 0; i < 10; i++) { - update_approx_time(++now); + monotime_coarse_set_mock_time_nsec(now += BILLION); tt_int_op(true, OP_EQ, hs_dos_can_send_intro2(or_circ)); } /* Last check if we can send the cell decrements the bucket so minus 1. */ @@ -92,7 +96,8 @@ get_intro2_burst_consensus_param(NULL) - 1); /* Manually reset bucket for next test. */ - token_bucket_ctr_reset(&or_circ->introduce2_bucket, now); + token_bucket_ctr_reset(&or_circ->introduce2_bucket, + (uint32_t) monotime_coarse_absolute_sec()); tt_uint_op(token_bucket_ctr_get(&or_circ->introduce2_bucket), OP_EQ, get_intro2_burst_consensus_param(NULL)); @@ -115,7 +120,7 @@ } /* One second has passed, we should have the rate minus 1 cell added. */ - update_approx_time(++now); + monotime_coarse_set_mock_time_nsec(now += BILLION); tt_int_op(true, OP_EQ, hs_dos_can_send_intro2(or_circ)); tt_uint_op(token_bucket_ctr_get(&or_circ->introduce2_bucket), OP_EQ, get_intro2_rate_consensus_param(NULL) - 1); @@ -125,6 +130,7 @@ hs_free_all(); free_mock_consensus(); + monotime_disable_test_mocking(); } static void diff -Nru tor-0.4.7.16/src/test/test_hs_intropoint.c tor-0.4.9.6/src/test/test_hs_intropoint.c --- tor-0.4.7.16/src/test/test_hs_intropoint.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/test/test_hs_intropoint.c 2026-03-25 14:30:34.000000000 +0000 @@ -14,6 +14,7 @@ #include "test/test.h" #include "test/log_test_helpers.h" #include "lib/crypt_ops/crypto_rand.h" +#include "lib/time/compat_time.h" #include "core/or/or.h" #include "core/or/channel.h" @@ -127,7 +128,7 @@ tt_assert(circ); circuit_change_purpose(TO_CIRCUIT(circ), CIRCUIT_PURPOSE_OR); token_bucket_ctr_init(&circ->introduce2_bucket, 100, 100, - (uint32_t) approx_time()); + (uint32_t) monotime_coarse_absolute_sec()); done: return circ; } @@ -543,7 +544,7 @@ or_circuit_t *intro_circ = NULL; trn_cell_establish_intro_t *establish_intro_cell = NULL; - ed25519_public_key_t auth_key; + ed25519_public_key_t auth_key = {0}; or_circuit_t *returned_intro_circ = NULL; diff -Nru tor-0.4.7.16/src/test/test_hs_metrics.c tor-0.4.9.6/src/test/test_hs_metrics.c --- tor-0.4.7.16/src/test/test_hs_metrics.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/test/test_hs_metrics.c 2026-03-25 14:30:34.000000000 +0000 @@ -40,7 +40,8 @@ /* Update entry by identifier. */ hs_metrics_update_by_ident(HS_METRICS_NUM_INTRODUCTIONS, - &service->keys.identity_pk, 0, 42); + &service->keys.identity_pk, 0, NULL, 42, + 0, false); /* Confirm the entry value. */ const smartlist_t *entries = metrics_store_get_all(service->metrics.store, @@ -53,9 +54,42 @@ /* Update entry by service now. */ hs_metrics_update_by_service(HS_METRICS_NUM_INTRODUCTIONS, - service, 0, 42); + service, 0, NULL, 42, 0, false); tt_int_op(metrics_store_entry_get_value(entry), OP_EQ, 84); + const char *reason = HS_METRICS_ERR_INTRO_REQ_BAD_AUTH_KEY; + + /* Update tor_hs_intro_rejected_intro_req_count */ + hs_metrics_update_by_ident(HS_METRICS_NUM_REJECTED_INTRO_REQ, + &service->keys.identity_pk, 0, + reason, 112, 0, false); + + entries = metrics_store_get_all(service->metrics.store, + "tor_hs_intro_rejected_intro_req_count"); + tt_assert(entries); + tt_int_op(smartlist_len(entries), OP_EQ, + hs_metrics_intro_req_error_reasons_size); + + entry = metrics_store_find_entry_with_label( + entries, "reason=\"bad_auth_key\""); + tt_assert(entry); + tt_int_op(metrics_store_entry_get_value(entry), OP_EQ, 112); + + /* Update tor_hs_intro_rejected_intro_req_count entry by service now. */ + hs_metrics_update_by_service(HS_METRICS_NUM_REJECTED_INTRO_REQ, service, 0, + reason, 10, 0, false); + tt_int_op(metrics_store_entry_get_value(entry), OP_EQ, 122); + + /* So far these have been relative updates. Test updates with reset */ + hs_metrics_update_by_service(HS_METRICS_NUM_REJECTED_INTRO_REQ, + service, 0, reason, 10, 0, true); + tt_int_op(metrics_store_entry_get_value(entry), OP_EQ, 10); + + hs_metrics_update_by_ident(HS_METRICS_NUM_REJECTED_INTRO_REQ, + &service->keys.identity_pk, 0, reason, + 345, 0, true); + tt_int_op(metrics_store_entry_get_value(entry), OP_EQ, 345); + done: hs_free_all(); } diff -Nru tor-0.4.7.16/src/test/test_hs_pow.c tor-0.4.9.6/src/test/test_hs_pow.c --- tor-0.4.7.16/src/test/test_hs_pow.c 1970-01-01 00:00:00.000000000 +0000 +++ tor-0.4.9.6/src/test/test_hs_pow.c 2026-03-25 14:30:34.000000000 +0000 @@ -0,0 +1,500 @@ +/* Copyright (c) 2020-2023, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file test_hs_pow.c + * \brief Tests for service proof-of-work verification and wire protocol. + */ + +#define HS_SERVICE_PRIVATE +#define HS_CIRCUIT_PRIVATE + +#include "lib/cc/compat_compiler.h" +#include "lib/cc/torint.h" + +#include "test/hs_test_helpers.h" +#include "test/log_test_helpers.h" +#include "test/test_helpers.h" +#include "test/test.h" + +#include "app/config/config.h" +#include "core/or/circuitbuild.h" +#include "core/or/circuitlist.h" +#include "core/or/relay.h" +#include "feature/hs/hs_cell.h" +#include "feature/hs/hs_circuit.h" +#include "feature/hs/hs_metrics.h" +#include "feature/hs/hs_pow.h" +#include "feature/hs/hs_service.h" +#include "feature/nodelist/nodelist.h" + +#include "core/or/crypt_path_st.h" +#include "core/or/origin_circuit_st.h" +#include "feature/nodelist/node_st.h" +#include "feature/nodelist/routerinfo_st.h" + +#include "trunnel/hs/cell_introduce1.h" + +static int test_rend_launch_count; +static uint32_t test_rend_launch_expect_effort; + +static void +mock_launch_rendezvous_point_circuit(const hs_service_t *service, + const ed25519_public_key_t *ip_auth_pubkey, + const curve25519_keypair_t *ip_enc_key_kp, + const hs_cell_intro_rdv_data_t *rdv_data, + time_t now) +{ + (void) service; + (void) ip_auth_pubkey; + (void) ip_enc_key_kp; + (void) rdv_data; + (void) now; + + tt_int_op(test_rend_launch_expect_effort, OP_EQ, rdv_data->pow_effort); + test_rend_launch_count++; + +done: + ; +} + +static node_t *fake_node = NULL; + +static const node_t * +mock_build_state_get_exit_node(cpath_build_state_t *state) +{ + (void) state; + + if (!fake_node) { + curve25519_secret_key_t seckey; + curve25519_secret_key_generate(&seckey, 0); + + fake_node = tor_malloc_zero(sizeof(node_t)); + fake_node->ri = tor_malloc_zero(sizeof(routerinfo_t)); + fake_node->ri->onion_curve25519_pkey = + tor_malloc_zero(sizeof(curve25519_public_key_t)); + curve25519_public_key_generate(fake_node->ri->onion_curve25519_pkey, + &seckey); + } + + return fake_node; +} + +static smartlist_t * +mock_node_get_link_specifier_smartlist(const node_t *node, bool direct_conn) +{ + (void) node; + (void) direct_conn; + + smartlist_t *lspecs = smartlist_new(); + link_specifier_t *ls_legacy = link_specifier_new(); + smartlist_add(lspecs, ls_legacy); + + return lspecs; +} + +static size_t relay_payload_len; +static uint8_t relay_payload[RELAY_PAYLOAD_SIZE]; + +static int +mock_relay_send_command_from_edge(streamid_t stream_id, circuit_t *circ, + uint8_t relay_command, const char *payload, + size_t payload_len, + crypt_path_t *cpath_layer, + const char *filename, int lineno) +{ + (void) stream_id; + (void) circ; + (void) relay_command; + (void) payload; + (void) payload_len; + (void) cpath_layer; + (void) filename; + (void) lineno; + + memcpy(relay_payload, payload, payload_len); + relay_payload_len = payload_len; + + return 0; +} + +typedef struct testing_hs_pow_service_t { + hs_service_t service; + hs_subcredential_t subcred; + hs_service_intro_point_t *service_ip; + hs_desc_intro_point_t *desc_ip; + hs_ntor_intro_cell_keys_t intro_keys; + origin_circuit_t *intro_circ; + origin_circuit_t *rend_circ; +} testing_hs_pow_service_t; + +/* Common test setup */ +static testing_hs_pow_service_t * +testing_hs_pow_service_new(void) +{ + MOCK(build_state_get_exit_node, mock_build_state_get_exit_node); + MOCK(relay_send_command_from_edge_, mock_relay_send_command_from_edge); + MOCK(launch_rendezvous_point_circuit, mock_launch_rendezvous_point_circuit); + MOCK(node_get_link_specifier_smartlist, + mock_node_get_link_specifier_smartlist); + + testing_hs_pow_service_t *tsvc = tor_malloc_zero(sizeof *tsvc); + hs_metrics_service_init(&tsvc->service); + + ed25519_keypair_t identity_keypair; + ed25519_keypair_generate(&identity_keypair, 0); + hs_helper_get_subcred_from_identity_keypair(&identity_keypair, + &tsvc->subcred); + + curve25519_secret_key_t seckey; + curve25519_public_key_t pkey; + curve25519_secret_key_generate(&seckey, 0); + curve25519_public_key_generate(&pkey, &seckey); + + node_t intro_node; + memset(&intro_node, 0, sizeof(intro_node)); + routerinfo_t ri; + memset(&ri, 0, sizeof(routerinfo_t)); + ri.onion_curve25519_pkey = &pkey; + intro_node.ri = &ri; + + hs_service_intro_point_t *svc_ip = service_intro_point_new(&intro_node); + const ed25519_public_key_t *ip_auth_pubkey = &svc_ip->auth_key_kp.pubkey; + const curve25519_public_key_t *ip_enc_pubkey = &svc_ip->enc_key_kp.pubkey; + tsvc->service_ip = svc_ip; + + ed25519_keypair_t signing_kp; + ed25519_keypair_generate(&signing_kp, 0); + tsvc->desc_ip = hs_helper_build_intro_point(&signing_kp, 0, "1.2.3.4", 0, + &svc_ip->auth_key_kp, + &svc_ip->enc_key_kp); + + tsvc->intro_circ = origin_circuit_new(); + tsvc->rend_circ = origin_circuit_new(); + + tsvc->intro_circ->cpath = tor_malloc_zero(sizeof(crypt_path_t)); + + struct hs_ident_circuit_t *hs_ident = tor_malloc_zero(sizeof *hs_ident); + tsvc->rend_circ->hs_ident = hs_ident; + tsvc->intro_circ->hs_ident = hs_ident; + curve25519_keypair_generate(&hs_ident->rendezvous_client_kp, 0); + tt_int_op(0, OP_EQ, + hs_ntor_client_get_introduce1_keys(ip_auth_pubkey, + ip_enc_pubkey, + &hs_ident->rendezvous_client_kp, + &tsvc->subcred, + &tsvc->intro_keys)); + done: + return tsvc; +} + +static void +testing_hs_pow_service_free(testing_hs_pow_service_t *tsvc) +{ + hs_metrics_service_free(&tsvc->service); + service_intro_point_free(tsvc->service_ip); + hs_desc_intro_point_free(tsvc->desc_ip); + hs_pow_free_service_state(tsvc->service.state.pow_state); + tor_free(tsvc); + + if (fake_node) { + tor_free(fake_node->ri->onion_curve25519_pkey); + tor_free(fake_node->ri); + tor_free(fake_node); + } + + UNMOCK(build_state_get_exit_node); + UNMOCK(relay_send_command_from_edge_); + UNMOCK(launch_rendezvous_point_circuit); + UNMOCK(node_get_link_specifier_smartlist); +} + +/* Make sure we can send a PoW extension to a service without PoW enabled */ +static void +test_hs_pow_unsolicited(void *arg) +{ + (void)arg; + + testing_hs_pow_service_t *tsvc = testing_hs_pow_service_new(); + + /* Try this twice, changing only the presence or lack of PoW solution */ + for (int test_variant = 0; test_variant < 2; test_variant++) { + + relay_payload_len = 0; + test_rend_launch_count = 0; + test_rend_launch_expect_effort = 0; + memset(relay_payload, 0, sizeof relay_payload); + + hs_pow_solution_t solution = { 0 }; + int retval; + + retval = hs_circ_send_introduce1(tsvc->intro_circ, tsvc->rend_circ, + tsvc->desc_ip, &tsvc->subcred, + test_variant == 0 ? &solution : NULL); + + tt_int_op(retval, OP_EQ, 0); + tt_assert(!fast_mem_is_zero((const char*)relay_payload, + sizeof relay_payload)); + tt_int_op(relay_payload_len, OP_NE, 0); + + retval = hs_circ_handle_introduce2(&tsvc->service, tsvc->intro_circ, + tsvc->service_ip, &tsvc->subcred, + relay_payload, + relay_payload_len); + + tt_int_op(retval, OP_EQ, test_variant == 0 ? -1 : 0); + tt_int_op(test_rend_launch_count, OP_EQ, test_variant == 0 ? 0 : 1); + } + + done: + testing_hs_pow_service_free(tsvc); +} + +static void +test_hs_pow_vectors(void *arg) +{ + (void)arg; + + /* This covers encoding, wire protocol, and verification for PoW-extended + * introduction cells. The solutions here can be generated using the + * setup in test_hs_pow_slow. + */ + static const struct { + uint32_t claimed_effort; + uint32_t validated_effort; + int expected_retval; + const char *seed_hex; + const char *service_blinded_id_hex; + const char *nonce_hex; + const char *sol_hex; + const char *encoded_hex; + } vectors[] = { + { + /* All zero, expect invalid */ + 1, 0, -1, + "0000000000000000000000000000000000000000000000000000000000000000", + "1111111111111111111111111111111111111111111111111111111111111111", + "00000000000000000000000000000000", "00000000000000000000000000000000", + "01" + "00000000000000000000000000000000" + "00000001" "00000000" + "00000000000000000000000000000000" + }, + { + /* Valid zero-effort solution */ + 0, 0, 0, + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "1111111111111111111111111111111111111111111111111111111111111111", + "55555555555555555555555555555555", "4312f87ceab844c78e1c793a913812d7", + "01" + "55555555555555555555555555555555" + "00000000" "aaaaaaaa" + "4312f87ceab844c78e1c793a913812d7" + }, + { + /* Valid high-effort solution */ + 1000000, 1000000, 0, + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "1111111111111111111111111111111111111111111111111111111111111111", + "59217255555555555555555555555555", "0f3db97b9cac20c1771680a1a34848d3", + "01" + "59217255555555555555555555555555" + "000f4240" "aaaaaaaa" + "0f3db97b9cac20c1771680a1a34848d3" + }, + { + /* Reject replays */ + 1000000, 0, -1, + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "1111111111111111111111111111111111111111111111111111111111111111", + "59217255555555555555555555555555", "0f3db97b9cac20c1771680a1a34848d3", + "01" + "59217255555555555555555555555555" + "000f4240" "aaaaaaaa" + "0f3db97b9cac20c1771680a1a34848d3" + }, + { + /* The claimed effort must exactly match what's in the challenge */ + 99999, 0, -1, + "86fb0acf4932cda44dbb451282f415479462dd10cb97ff5e7e8e2a53c3767a7f", + "bfd298428562e530c52bdb36d81a0e293ef4a0e94d787f0f8c0c611f4f9e78ed", + "2eff9fdbc34326d9d2f18ed277469c63", "400cb091139f86b352119f6e131802d6", + "01" + "2eff9fdbc34326d9d2f18ed277469c63" + "0001869f" "86fb0acf" + "400cb091139f86b352119f6e131802d6" + }, + { + /* Otherwise good solution but with a corrupted nonce */ + 100000, 0, -1, + "86fb0acf4932cda44dbb451282f415479462dd10cb97ff5e7e8e2a53c3767a7f", + "bfd298428562e530c52bdb36d81a0e293ef4a0e94d787f0f8c0c611f4f9e78ed", + "2eff9fdbc34326d9a2f18ed277469c63", "400cb091139f86b352119f6e131802d6", + "01" + "2eff9fdbc34326d9a2f18ed277469c63" + "000186a0" "86fb0acf" + "400cb091139f86b352119f6e131802d6" + }, + { + /* Corrected version of above */ + 100000, 100000, 0, + "86fb0acf4932cda44dbb451282f415479462dd10cb97ff5e7e8e2a53c3767a7f", + "bfd298428562e530c52bdb36d81a0e293ef4a0e94d787f0f8c0c611f4f9e78ed", + "2eff9fdbc34326d9d2f18ed277469c63", "400cb091139f86b352119f6e131802d6", + "01" + "2eff9fdbc34326d9d2f18ed277469c63" + "000186a0" "86fb0acf" + "400cb091139f86b352119f6e131802d6" + } + }; + + testing_hs_pow_service_t *tsvc = testing_hs_pow_service_new(); + hs_pow_service_state_t *pow_state = tor_malloc_zero(sizeof *pow_state); + tsvc->service.state.pow_state = pow_state; + tsvc->service.desc_current = service_descriptor_new(); + pow_state->rend_request_pqueue = smartlist_new(); + + char *mem_op_hex_tmp = NULL; + uint8_t *decrypted = NULL; + trn_cell_introduce_encrypted_t *enc_cell = NULL; + trn_cell_introduce1_t *cell = NULL; + + const unsigned num_vectors = sizeof vectors / sizeof vectors[0]; + for (unsigned vec_i = 0; vec_i < num_vectors; vec_i++) { + const int expected_retval = vectors[vec_i].expected_retval; + const char *service_blinded_id_hex = vectors[vec_i].service_blinded_id_hex; + const char *seed_hex = vectors[vec_i].seed_hex; + const char *nonce_hex = vectors[vec_i].nonce_hex; + const char *sol_hex = vectors[vec_i].sol_hex; + const char *encoded_hex = vectors[vec_i].encoded_hex; + + relay_payload_len = 0; + test_rend_launch_count = 0; + test_rend_launch_expect_effort = vectors[vec_i].validated_effort; + memset(relay_payload, 0, sizeof relay_payload); + + hs_pow_solution_t solution = { + .effort = vectors[vec_i].claimed_effort, + }; + int retval; + + tt_int_op(strlen(service_blinded_id_hex), OP_EQ, 2 * HS_POW_ID_LEN); + tt_int_op(strlen(seed_hex), OP_EQ, 2 * HS_POW_SEED_LEN); + tt_int_op(strlen(nonce_hex), OP_EQ, 2 * sizeof solution.nonce); + tt_int_op(strlen(sol_hex), OP_EQ, 2 * sizeof solution.equix_solution); + + tt_assert(tsvc->service.desc_current); + ed25519_public_key_t *desc_blinded_pubkey = + &tsvc->service.desc_current->desc->plaintext_data.blinded_pubkey; + + tt_int_op(base16_decode((char*)desc_blinded_pubkey->pubkey, + HS_POW_ID_LEN, service_blinded_id_hex, + 2 * HS_POW_ID_LEN), + OP_EQ, HS_POW_ID_LEN); + tt_int_op(base16_decode((char*)pow_state->seed_previous, HS_POW_SEED_LEN, + seed_hex, 2 * HS_POW_SEED_LEN), + OP_EQ, HS_POW_SEED_LEN); + tt_int_op(base16_decode((char*)solution.nonce, HS_POW_NONCE_LEN, + nonce_hex, 2 * HS_POW_NONCE_LEN), + OP_EQ, HS_POW_NONCE_LEN); + tt_int_op(base16_decode((char*)solution.equix_solution, HS_POW_EQX_SOL_LEN, + sol_hex, 2 * HS_POW_EQX_SOL_LEN), + OP_EQ, HS_POW_EQX_SOL_LEN); + + ed25519_pubkey_copy(&tsvc->service_ip->blinded_id, desc_blinded_pubkey); + memcpy(solution.seed_head, pow_state->seed_previous, HS_POW_SEED_HEAD_LEN); + + /* Try to encode 'solution' into a relay cell */ + + retval = hs_circ_send_introduce1(tsvc->intro_circ, tsvc->rend_circ, + tsvc->desc_ip, &tsvc->subcred, + &solution); + + tt_int_op(retval, OP_EQ, 0); + tt_assert(!fast_mem_is_zero((const char*)relay_payload, + sizeof relay_payload)); + tt_int_op(relay_payload_len, OP_NE, 0); + + /* Check the service's response to this introduction */ + + retval = hs_circ_handle_introduce2(&tsvc->service, tsvc->intro_circ, + tsvc->service_ip, &tsvc->subcred, + relay_payload, + relay_payload_len); + tt_int_op(retval, OP_EQ, expected_retval); + tt_int_op(test_rend_launch_count, OP_EQ, expected_retval == 0 ? 1 : 0); + + /* Start unpacking the cell ourselves so we can check the PoW data */ + + trn_cell_introduce1_free(cell); + cell = NULL; + tt_int_op(trn_cell_introduce1_parse(&cell, relay_payload, + relay_payload_len), OP_GT, 0); + + size_t encrypted_section_len; + const uint8_t *encrypted_section; + encrypted_section = trn_cell_introduce1_getconstarray_encrypted(cell); + encrypted_section_len = trn_cell_introduce1_getlen_encrypted(cell); + tt_int_op(encrypted_section_len, OP_GT, + DIGEST256_LEN + CURVE25519_PUBKEY_LEN); + + /* Decrypt the encrypted portion of the INTRODUCE1 */ + + crypto_cipher_t *cipher = NULL; + cipher = crypto_cipher_new_with_bits((char *) tsvc->intro_keys.enc_key, + CURVE25519_PUBKEY_LEN * 8); + tt_ptr_op(cipher, OP_NE, NULL); + + size_t decrypted_len = encrypted_section_len + - DIGEST256_LEN - CURVE25519_PUBKEY_LEN; + tor_free(decrypted); + decrypted = tor_malloc_zero(decrypted_len); + retval = crypto_cipher_decrypt(cipher, (char *) decrypted, + (const char *) encrypted_section + + CURVE25519_PUBKEY_LEN, + decrypted_len); + crypto_cipher_free(cipher); + tt_int_op(retval, OP_EQ, 0); + + /* Parse the outer layer of the encrypted payload */ + + trn_cell_introduce_encrypted_free(enc_cell); + enc_cell = NULL; + tt_int_op(trn_cell_introduce_encrypted_parse(&enc_cell, decrypted, + decrypted_len), OP_GT, 0); + + /* Check for the expected single extension */ + + const trn_extension_t *extensions = + trn_cell_introduce_encrypted_get_extensions(enc_cell); + tt_int_op(trn_extension_get_num(extensions), OP_EQ, 1); + + const trn_extension_field_t *field = + trn_extension_getconst_fields(extensions, 0); + tt_int_op(trn_extension_field_get_field_type(field), + OP_EQ, TRUNNEL_EXT_TYPE_POW); + + const uint8_t *field_data = trn_extension_field_getconstarray_field(field); + size_t field_len = trn_extension_field_getlen_field(field); + + /* Our test vectors cover the packed data in the single extension */ + + tt_int_op(field_len * 2, OP_EQ, strlen(encoded_hex)); + test_memeq_hex(field_data, encoded_hex); + } + + done: + tor_free(mem_op_hex_tmp); + tor_free(decrypted); + trn_cell_introduce1_free(cell); + trn_cell_introduce_encrypted_free(enc_cell); + service_descriptor_free(tsvc->service.desc_current); + testing_hs_pow_service_free(tsvc); + hs_pow_remove_seed_from_cache(NULL); +} + +struct testcase_t hs_pow_tests[] = { + { "unsolicited", test_hs_pow_unsolicited, TT_FORK, NULL, NULL }, + { "vectors", test_hs_pow_vectors, TT_FORK, NULL, NULL }, + END_OF_TESTCASES +}; diff -Nru tor-0.4.7.16/src/test/test_hs_pow_slow.c tor-0.4.9.6/src/test/test_hs_pow_slow.c --- tor-0.4.7.16/src/test/test_hs_pow_slow.c 1970-01-01 00:00:00.000000000 +0000 +++ tor-0.4.9.6/src/test/test_hs_pow_slow.c 2026-03-25 14:30:34.000000000 +0000 @@ -0,0 +1,273 @@ +/* Copyright (c) 2020-2023, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file test_hs_pow_slow.c + * \brief Slower (solve + verify) tests for service proof-of-work defenses. + */ + +#define HS_SERVICE_PRIVATE + +#include "lib/cc/compat_compiler.h" +#include "lib/cc/torint.h" + +#include "test/test.h" +#include "test/test_helpers.h" +#include "test/log_test_helpers.h" +#include "test/rng_test_helpers.h" + +#include "app/config/config.h" +#include "feature/hs/hs_pow.h" + +static int +testing_one_hs_pow_solution(const hs_pow_solution_t *ref_solution, + const ed25519_public_key_t *service_blinded_id, + const uint8_t *seed) +{ + int retval = -1; + hs_pow_solution_t sol_buffer; + hs_pow_service_state_t *s = tor_malloc_zero(sizeof(hs_pow_service_state_t)); + s->rend_request_pqueue = smartlist_new(); + + memcpy(s->seed_previous, seed, HS_POW_SEED_LEN); + + const unsigned num_variants = 10; + const unsigned num_attempts = 3; + + for (unsigned variant = 0; variant < num_variants; variant++) { + hs_pow_remove_seed_from_cache(seed); + + for (unsigned attempt = 0; attempt < num_attempts; attempt++) { + int expected = -1; + memcpy(&sol_buffer, ref_solution, sizeof sol_buffer); + + /* One positive test, and a few negative tests of corrupted solutions */ + if (variant == 0) { + if (attempt == 0) { + /* Only the first attempt should succeed (nonce replay) */ + expected = 0; + } + } else if (variant & 1) { + sol_buffer.nonce[variant / 2 % HS_POW_NONCE_LEN]++; + } else { + sol_buffer.equix_solution[variant / 2 % HS_POW_EQX_SOL_LEN]++; + } + + tt_int_op(expected, OP_EQ, + hs_pow_verify(service_blinded_id, s, &sol_buffer)); + } + } + + retval = 0; +done: + hs_pow_free_service_state(s); + return retval; +} + +static void +test_hs_pow_vectors(void *arg) +{ + (void)arg; + + /* All test vectors include a solve, verify, and fail-verify phase + * as well as a test of the nonce replay cache. The initial nonce for the + * solution search is set via the solver's RNG data. The amount of solve + * time during test execution can be tuned based on how far away from the + * winning nonce our solve_rng value is set. + */ + static const struct { + uint32_t effort; + const char *solve_rng_hex; + const char *seed_hex; + const char *service_blinded_id_hex; + const char *nonce_hex; + const char *sol_hex; + } vectors[] = { + { + 0, "55555555555555555555555555555555", + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "1111111111111111111111111111111111111111111111111111111111111111", + "55555555555555555555555555555555", "4312f87ceab844c78e1c793a913812d7" + }, + { + 1, "55555555555555555555555555555555", + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "1111111111111111111111111111111111111111111111111111111111111111", + "55555555555555555555555555555555", "84355542ab2b3f79532ef055144ac5ab" + }, + { + 1, "55555555555555555555555555555555", + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "1111111111111111111111111111111111111111111111111111111111111110", + "55555555555555555555555555555555", "115e4b70da858792fc205030b8c83af9" + }, + { + 2, "55555555555555555555555555555555", + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "1111111111111111111111111111111111111111111111111111111111111111", + "55555555555555555555555555555555", "4600a93a535ed76dc746c99942ab7de2" + }, + { + 10, "55555555555555555555555555555555", + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "1111111111111111111111111111111111111111111111111111111111111111", + "56555555555555555555555555555555", "128bbda5df2929c3be086de2aad34aed" + }, + { + 10, "ffffffffffffffffffffffffffffffff", + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "1111111111111111111111111111111111111111111111111111111111111111", + "01000000000000000000000000000000", "203af985537fadb23f3ed5873b4c81ce" + }, + { + 1337, "7fffffffffffffffffffffffffffffff", + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "4111111111111111111111111111111111111111111111111111111111111111", + "01000000000000000000000000000000", "31c377cb72796ed80ae77df6ac1d6bfd" + }, + { + 31337, "34a20000000000000000000000000000", + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "1111111111111111111111111111111111111111111111111111111111111111", + "36a20000000000000000000000000000", "ca6899b91113aaf7536f28db42526bff" + }, + { + 100, "55555555555555555555555555555555", + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "1111111111111111111111111111111111111111111111111111111111111111", + "56555555555555555555555555555555", "3a4122a240bd7abfc922ab3cbb9479ed" + }, + { + 1000, "d3555555555555555555555555555555", + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "1111111111111111111111111111111111111111111111111111111111111111", + "d4555555555555555555555555555555", "338cc08f57697ce8ac2e4b453057d6e9" + }, + { + 10000, "c5715555555555555555555555555555", + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "1111111111111111111111111111111111111111111111111111111111111111", + "c8715555555555555555555555555555", "9f2d3d4ed831ac96ad34c25fb59ff3e2" + }, + { + 100000, "418d5655555555555555555555555555", + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "1111111111111111111111111111111111111111111111111111111111111111", + "428d5655555555555555555555555555", "9863f3acd2d15adfd244a7ca61d4c6ff" + }, + { + 1000000, "58217255555555555555555555555555", + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "1111111111111111111111111111111111111111111111111111111111111111", + "59217255555555555555555555555555", "0f3db97b9cac20c1771680a1a34848d3" + }, + { + 1, "d0aec1669384bfe5ed39cd724d6c7954", + "c52be1f8a5e6cc3b8fb71cfdbe272cbc91d4d035400f2f94fb0d0074794e0a07", + "bfd298428562e530c52bdb36d81a0e293ef4a0e94d787f0f8c0c611f4f9e78ed", + "d1aec1669384bfe5ed39cd724d6c7954", "462606e5f8c2f3f844127b8bfdd6b4ff" + }, + { + 1, "b4d0e611e6935750fcf9406aae131f62", + "86fb0acf4932cda44dbb451282f415479462dd10cb97ff5e7e8e2a53c3767a7f", + "bfd298428562e530c52bdb36d81a0e293ef4a0e94d787f0f8c0c611f4f9e78ed", + "b4d0e611e6935750fcf9406aae131f62", "9f3fbd50b1a83fb63284bde44318c0fd" + }, + { + 1, "b4d0e611e6935750fcf9406aae131f62", + "9dfbd06d86fed8e12de3ab214e1a63ea61f46253fe08346a20378da70c4a327d", + "bec632eb76123956f99a06d394fcbee8f135b8ed01f2e90aabe404cb0346744a", + "b4d0e611e6935750fcf9406aae131f62", "161baa7490356292d020065fdbe55ffc" + }, + { + 1, "40559fdbc34326d9d2f18ed277469c63", + "86fb0acf4932cda44dbb451282f415479462dd10cb97ff5e7e8e2a53c3767a7f", + "bfd298428562e530c52bdb36d81a0e293ef4a0e94d787f0f8c0c611f4f9e78ed", + "40559fdbc34326d9d2f18ed277469c63", "fa649c6a2c5c0bb6a3511b9ea4b448d1" + }, + { + 10000, "34569fdbc34326d9d2f18ed277469c63", + "86fb0acf4932cda44dbb451282f415479462dd10cb97ff5e7e8e2a53c3767a7f", + "bfd298428562e530c52bdb36d81a0e293ef4a0e94d787f0f8c0c611f4f9e78ed", + "36569fdbc34326d9d2f18ed277469c63", "2802951e623c74adc443ab93e99633ee" + }, + { + 100000, "2cff9fdbc34326d9d2f18ed277469c63", + "86fb0acf4932cda44dbb451282f415479462dd10cb97ff5e7e8e2a53c3767a7f", + "bfd298428562e530c52bdb36d81a0e293ef4a0e94d787f0f8c0c611f4f9e78ed", + "2eff9fdbc34326d9d2f18ed277469c63", "400cb091139f86b352119f6e131802d6" + }, + { + 1000000, "5243b3dbc34326d9d2f18ed277469c63", + "86fb0acf4932cda44dbb451282f415479462dd10cb97ff5e7e8e2a53c3767a7f", + "bfd298428562e530c52bdb36d81a0e293ef4a0e94d787f0f8c0c611f4f9e78ed", + "5543b3dbc34326d9d2f18ed277469c63", "b47c718b56315e9697173a6bac1feaa4" + }, + }; + + const unsigned num_vectors = sizeof vectors / sizeof vectors[0]; + for (unsigned vec_i = 0; vec_i < num_vectors; vec_i++) { + const char *seed_hex = vectors[vec_i].seed_hex; + const char *service_blinded_id_hex = vectors[vec_i].service_blinded_id_hex; + const char *solve_rng_hex = vectors[vec_i].solve_rng_hex; + const char *nonce_hex = vectors[vec_i].nonce_hex; + const char *sol_hex = vectors[vec_i].sol_hex; + + uint8_t rng_bytes[HS_POW_NONCE_LEN]; + hs_pow_solution_t output; + hs_pow_solution_t solution = { 0 }; + hs_pow_solver_inputs_t input = { + .effort = vectors[vec_i].effort, + .CompiledProofOfWorkHash = -1 + }; + + tt_int_op(strlen(service_blinded_id_hex), OP_EQ, 2 * HS_POW_ID_LEN); + tt_int_op(strlen(seed_hex), OP_EQ, 2 * sizeof input.seed); + tt_int_op(strlen(solve_rng_hex), OP_EQ, 2 * sizeof rng_bytes); + tt_int_op(strlen(nonce_hex), OP_EQ, 2 * sizeof solution.nonce); + tt_int_op(strlen(sol_hex), OP_EQ, 2 * sizeof solution.equix_solution); + + tt_int_op(base16_decode((char*)input.service_blinded_id.pubkey, + HS_POW_ID_LEN, service_blinded_id_hex, + 2 * HS_POW_ID_LEN), + OP_EQ, HS_POW_ID_LEN); + tt_int_op(base16_decode((char*)input.seed, HS_POW_SEED_LEN, + seed_hex, 2 * HS_POW_SEED_LEN), + OP_EQ, HS_POW_SEED_LEN); + tt_int_op(base16_decode((char*)rng_bytes, sizeof rng_bytes, + solve_rng_hex, 2 * sizeof rng_bytes), + OP_EQ, HS_POW_NONCE_LEN); + tt_int_op(base16_decode((char*)&solution.nonce, sizeof solution.nonce, + nonce_hex, 2 * sizeof solution.nonce), + OP_EQ, HS_POW_NONCE_LEN); + tt_int_op(base16_decode((char*)&solution.equix_solution, + sizeof solution.equix_solution, + sol_hex, 2 * sizeof solution.equix_solution), + OP_EQ, HS_POW_EQX_SOL_LEN); + memcpy(solution.seed_head, input.seed, HS_POW_SEED_HEAD_LEN); + + memset(&output, 0xaa, sizeof output); + testing_enable_prefilled_rng(rng_bytes, HS_POW_NONCE_LEN); + tt_int_op(0, OP_EQ, hs_pow_solve(&input, &output)); + testing_disable_prefilled_rng(); + + tt_mem_op(solution.seed_head, OP_EQ, output.seed_head, + sizeof output.seed_head); + tt_mem_op(solution.nonce, OP_EQ, output.nonce, + sizeof output.nonce); + tt_mem_op(&solution.equix_solution, OP_EQ, &output.equix_solution, + sizeof output.equix_solution); + + tt_int_op(testing_one_hs_pow_solution(&output, &input.service_blinded_id, + input.seed), OP_EQ, 0); + } + + done: + testing_disable_prefilled_rng(); + hs_pow_remove_seed_from_cache(NULL); +} + +struct testcase_t slow_hs_pow_tests[] = { + { "vectors", test_hs_pow_vectors, 0, NULL, NULL }, + END_OF_TESTCASES +}; diff -Nru tor-0.4.7.16/src/test/test_hs_service.c tor-0.4.9.6/src/test/test_hs_service.c --- tor-0.4.7.16/src/test/test_hs_service.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/test/test_hs_service.c 2026-03-25 14:30:34.000000000 +0000 @@ -224,12 +224,14 @@ tt_int_op(retval, OP_EQ, 1); /* Check the digest algo */ - tt_int_op(crypto_digest_get_algorithm(or_circ->cpath->pvt_crypto.f_digest), + tt_int_op(crypto_digest_get_algorithm( + or_circ->cpath->pvt_crypto.c.tor1.f_digest), OP_EQ, DIGEST_SHA3_256); - tt_int_op(crypto_digest_get_algorithm(or_circ->cpath->pvt_crypto.b_digest), + tt_int_op(crypto_digest_get_algorithm( + or_circ->cpath->pvt_crypto.c.tor1.b_digest), OP_EQ, DIGEST_SHA3_256); - tt_assert(or_circ->cpath->pvt_crypto.f_crypto); - tt_assert(or_circ->cpath->pvt_crypto.b_crypto); + tt_assert(or_circ->cpath->pvt_crypto.c.tor1.f_crypto); + tt_assert(or_circ->cpath->pvt_crypto.c.tor1.b_crypto); /* Ensure that circ purpose was changed */ tt_int_op(or_circ->base_.purpose, OP_EQ, CIRCUIT_PURPOSE_S_REND_JOINED); @@ -1183,6 +1185,8 @@ origin_circuit_t *circ = NULL; hs_service_t *service = NULL; hs_service_intro_point_t *ip = NULL; + const smartlist_t *entries = NULL; + const metrics_store_entry_t *entry = NULL; (void) arg; @@ -1227,6 +1231,37 @@ "an INTRODUCE2 cell on circuit"); teardown_capture_of_logs(); + entries = metrics_store_get_all(service->metrics.store, + "tor_hs_intro_rejected_intro_req_count"); + + tt_assert(entries); + /* There are `hs_metrics_intro_req_size` entries (one for each + * possible `reason` label value). */ + tt_int_op(smartlist_len(entries), OP_EQ, + hs_metrics_intro_req_error_reasons_size); + + /* Make sure the tor_hs_intro_rejected_intro_req_count metric was + * only incremented for reason HS_METRICS_ERR_INTRO_REQ_BAD_AUTH_KEY. */ + for (size_t i = 0; i < hs_metrics_intro_req_error_reasons_size; ++i) { + const char *reason = hs_metrics_intro_req_error_reasons[i]; + + if (!strcmp(reason, HS_METRICS_ERR_INTRO_REQ_BAD_AUTH_KEY)) { + continue; + } + + entry = metrics_store_find_entry_with_label( + entries, + metrics_format_label("reason", reason)); + tt_assert(entry); + tt_int_op(metrics_store_entry_get_value(entry), OP_EQ, 0); + } + + entry = metrics_store_find_entry_with_label( + entries, + metrics_format_label("reason", HS_METRICS_ERR_INTRO_REQ_BAD_AUTH_KEY)); + tt_assert(entry); + tt_int_op(metrics_store_entry_get_value(entry), OP_EQ, 1); + /* Set an IP object now for this circuit. */ { ip = helper_create_service_ip(); @@ -1243,6 +1278,33 @@ tt_int_op(ret, OP_EQ, -1); tt_u64_op(ip->introduce2_count, OP_EQ, 0); + /* Make sure the tor_hs_intro_rejected_intro_req_count metric was incremented + * a second time, this time, with reason="invalid_introduce2_cell". */ + entry = metrics_store_find_entry_with_label( + entries, + metrics_format_label("reason", HS_METRICS_ERR_INTRO_REQ_INTRODUCE2)); + tt_assert(entry); + tt_int_op(metrics_store_entry_get_value(entry), OP_EQ, 1); + + /* The metric entries with other reason labels are unaffected */ + entry = metrics_store_find_entry_with_label( + entries, + metrics_format_label("reason", HS_METRICS_ERR_INTRO_REQ_SUBCREDENTIAL)); + tt_assert(entry); + tt_int_op(metrics_store_entry_get_value(entry), OP_EQ, 0); + + entry = metrics_store_find_entry_with_label( + entries, metrics_format_label( + "reason", HS_METRICS_ERR_INTRO_REQ_INTRODUCE2_REPLAY)); + tt_assert(entry); + tt_int_op(metrics_store_entry_get_value(entry), OP_EQ, 0); + + entry = metrics_store_find_entry_with_label( + entries, + metrics_format_label("reason", HS_METRICS_ERR_INTRO_REQ_BAD_AUTH_KEY)); + tt_assert(entry); + tt_int_op(metrics_store_entry_get_value(entry), OP_EQ, 1); + done: or_state_free(dummy_state); dummy_state = NULL; @@ -1545,7 +1607,6 @@ tt_int_op(ret, OP_EQ, 0); ri.onion_curve25519_pkey = tor_malloc_zero(sizeof(curve25519_public_key_t)); - ri.onion_pkey = tor_malloc_zero(140); curve25519_public_key_generate(ri.onion_curve25519_pkey, &curve25519_secret_key); memset(ri.cache_info.identity_digest, 'A', DIGEST_LEN); @@ -1571,7 +1632,6 @@ update_all_descriptors_intro_points(now); tor_free(node->ri->onion_curve25519_pkey); /* Avoid memleak. */ tor_free(node->ri->cache_info.signing_key_cert); - tor_free(node->ri->onion_pkey); expect_log_msg_containing("just picked 1 intro points and wanted 3 for next " "descriptor. It currently has 0 intro points. " "Launching ESTABLISH_INTRO circuit shortly."); @@ -2219,12 +2279,16 @@ static void mock_launch_rendezvous_point_circuit(const hs_service_t *service, - const hs_service_intro_point_t *ip, - const hs_cell_introduce2_data_t *data) + const ed25519_public_key_t *ip_auth_pubkey, + const curve25519_keypair_t *ip_enc_key_kp, + const hs_cell_intro_rdv_data_t *rdv_data, + time_t now) { (void) service; - (void) ip; - (void) data; + (void) ip_auth_pubkey; + (void) ip_enc_key_kp; + (void) rdv_data; + (void) now; return; } @@ -2276,6 +2340,8 @@ /* Disable onionbalance */ x_service.config.ob_master_pubkeys = NULL; x_service.state.replay_cache_rend_cookie = replaycache_new(0,0); + /* Initialize the metrics store */ + hs_metrics_service_init(&x_service); /* Create subcredential for x: */ ed25519_keypair_t x_identity_keypair; @@ -2344,7 +2410,7 @@ /* Create INTRODUCE1 */ tt_assert(fast_mem_is_zero(relay_payload, sizeof(relay_payload))); retval = hs_circ_send_introduce1(intro_circ, &rend_circ, - alice_ip, &x_subcred); + alice_ip, &x_subcred, NULL); /* Check that the payload was written successfully */ tt_int_op(retval, OP_EQ, 0); @@ -2385,7 +2451,7 @@ /* Create INTRODUCE1 from Alice to X through Z */ memset(relay_payload, 0, sizeof(relay_payload)); retval = hs_circ_send_introduce1(intro_circ, &rend_circ, - alice_ip, &z_subcred); + alice_ip, &z_subcred, NULL); /* Check that the payload was written successfully */ tt_int_op(retval, OP_EQ, 0); @@ -2422,7 +2488,7 @@ /* Create INTRODUCE1 from Alice to X using X's subcred. */ memset(relay_payload, 0, sizeof(relay_payload)); retval = hs_circ_send_introduce1(intro_circ, &rend_circ, - alice_ip, &x_subcred); + alice_ip, &x_subcred, NULL); /* Check that the payload was written successfully */ tt_int_op(retval, OP_EQ, 0); @@ -2439,6 +2505,20 @@ (uint8_t*)relay_payload, relay_payload_len); tt_int_op(retval, OP_EQ, 0); + /* We haven't encountered any errors yet, so all the introduction request + * error metrics should be 0 */ + const smartlist_t *entries = metrics_store_get_all( + x_service.metrics.store, "tor_hs_intro_rejected_intro_req_count"); + const metrics_store_entry_t *entry = NULL; + + for (size_t i = 0; i < hs_metrics_intro_req_error_reasons_size; ++i) { + entry = metrics_store_find_entry_with_label( + entries, + metrics_format_label("reason", hs_metrics_intro_req_error_reasons[i])); + tt_assert(entry); + tt_int_op(metrics_store_entry_get_value(entry), OP_EQ, 0); + } + /* ************************************************************ */ /* Act IV: @@ -2456,6 +2536,11 @@ tt_int_op(retval, OP_EQ, -1); expect_log_msg_containing("with the same ENCRYPTED section"); teardown_capture_of_logs(); + entry = metrics_store_find_entry_with_label( + entries, + metrics_format_label("reason", HS_METRICS_ERR_INTRO_REQ_INTRODUCE2)); + tt_assert(entry); + tt_int_op(metrics_store_entry_get_value(entry), OP_EQ, 1); /* Now cleanup the intro point replay cache but not the service replay cache and see that this one triggers this time. */ @@ -2470,6 +2555,12 @@ expect_log_msg_containing("with same REND_COOKIE"); teardown_capture_of_logs(); + entry = metrics_store_find_entry_with_label( + entries, metrics_format_label( + "reason", HS_METRICS_ERR_INTRO_REQ_INTRODUCE2_REPLAY)); + tt_assert(entry); + tt_int_op(metrics_store_entry_get_value(entry), OP_EQ, 1); + /* Now just to make sure cleanup both replay caches and make sure that the cell gets through */ replaycache_free(x_ip->replay_cache); @@ -2482,12 +2573,15 @@ (uint8_t*)relay_payload, relay_payload_len); tt_int_op(retval, OP_EQ, 0); + /* This time, the error metric was *not* incremented */ + tt_int_op(metrics_store_entry_get_value(entry), OP_EQ, 1); + /* As a final thing, create an INTRODUCE1 cell from Alice to X using Y's * subcred (should fail since Y is just another instance and not the frontend * service!) */ memset(relay_payload, 0, sizeof(relay_payload)); retval = hs_circ_send_introduce1(intro_circ, &rend_circ, - alice_ip, &y_subcred); + alice_ip, &y_subcred, NULL); tt_int_op(retval, OP_EQ, 0); /* Check that the payload was written successfully */ @@ -2498,7 +2592,13 @@ intro_circ, x_ip, &y_subcred, (uint8_t*)relay_payload, relay_payload_len); + tt_int_op(retval, OP_EQ, -1); + entry = metrics_store_find_entry_with_label( + entries, + metrics_format_label("reason", HS_METRICS_ERR_INTRO_REQ_INTRODUCE2)); + tt_assert(entry); + tt_int_op(metrics_store_entry_get_value(entry), OP_EQ, 2); done: /* Start cleaning up X */ @@ -2507,6 +2607,7 @@ tor_free(x_service.state.ob_subcreds); service_descriptor_free(x_service.desc_current); service_descriptor_free(x_service.desc_next); + hs_metrics_service_free(&x_service); service_intro_point_free(x_ip); /* Clean up Alice */ diff -Nru tor-0.4.7.16/src/test/test_include.sh tor-0.4.9.6/src/test/test_include.sh --- tor-0.4.7.16/src/test/test_include.sh 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/test/test_include.sh 2026-03-25 14:30:34.000000000 +0000 @@ -50,7 +50,7 @@ tmpdir= # For some reasons, shellcheck is not seeing that we can call this # function from the trap below. -# shellcheck disable=SC2317 +# shellcheck disable=SC2317,SC2329 clean () { if [ -n "$tmpdir" ] && [ -d "$tmpdir" ]; then rm -rf "$tmpdir" diff -Nru tor-0.4.7.16/src/test/test_link_handshake.c tor-0.4.9.6/src/test/test_link_handshake.c --- tor-0.4.7.16/src/test/test_link_handshake.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/test/test_link_handshake.c 2026-03-25 14:30:34.000000000 +0000 @@ -943,25 +943,15 @@ cell1 = mock_got_var_cell; tt_int_op(0, OP_EQ, connection_or_send_auth_challenge_cell(c1)); cell2 = mock_got_var_cell; -#ifdef HAVE_WORKING_TOR_TLS_GET_TLSSECRETS - tt_int_op(38, OP_EQ, cell1->payload_len); - tt_int_op(38, OP_EQ, cell2->payload_len); -#else tt_int_op(36, OP_EQ, cell1->payload_len); tt_int_op(36, OP_EQ, cell2->payload_len); -#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); tt_int_op(CELL_AUTH_CHALLENGE, OP_EQ, cell2->command); -#ifdef HAVE_WORKING_TOR_TLS_GET_TLSSECRETS - tt_mem_op("\x00\x02\x00\x01\x00\x03", OP_EQ, cell1->payload + 32, 6); - tt_mem_op("\x00\x02\x00\x01\x00\x03", OP_EQ, cell2->payload + 32, 6); -#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 /* defined(HAVE_WORKING_TOR_TLS_GET_TLSSECRETS) */ tt_mem_op(cell1->payload, OP_NE, cell2->payload, 32); done: @@ -1004,7 +994,6 @@ { (void)test; - testing__connection_or_pretend_TLSSECRET_is_supported = 1; authchallenge_data_t *d = tor_malloc_zero(sizeof(*d)); d->c = or_connection_new(CONN_TYPE_OR, AF_INET); d->chan = tor_malloc_zero(sizeof(*d->chan)); @@ -1019,7 +1008,7 @@ d->cell->payload_len = 38; d->cell->payload[33] = 2; /* 2 methods */ d->cell->payload[35] = 7; /* This one isn't real */ - d->cell->payload[37] = 1; /* This is the old RSA one. */ + d->cell->payload[37] = 3; /* This is the currently supported Ed25519 one. */ d->cell->command = CELL_AUTH_CHALLENGE; get_options_mutable()->ORPort_set = 1; @@ -1043,18 +1032,19 @@ }; static void -test_link_handshake_recv_authchallenge_ok(void *arg) +test_link_handshake_recv_authchallenge_no_ed25519(void *arg) { authchallenge_data_t *d = arg; + d->cell->payload[33] = 1; /* only 1 type supported. */ + d->cell->payload_len -= 2; + + setup_capture_of_logs(LOG_INFO); channel_tls_process_auth_challenge_cell(d->cell, d->chan); - tt_int_op(0, OP_EQ, mock_close_called); - tt_int_op(1, OP_EQ, d->c->handshake_state->received_auth_challenge); - tt_int_op(1, OP_EQ, mock_send_authenticate_called); - tt_int_op(1, OP_EQ, mock_send_netinfo_called); - tt_int_op(1, OP_EQ, mock_send_authenticate_called_with_type); /* RSA */ + expect_log_msg_containing("we don't know any of its authentication types"); + done: - ; + teardown_capture_of_logs(); } static void @@ -1154,14 +1144,6 @@ require_failure_message = "It had a nonzero circuit ID"; d->cell->circ_id = 1337) -static int -mock_get_tlssecrets(tor_tls_t *tls, uint8_t *secrets_out) -{ - (void)tls; - memcpy(secrets_out, "int getRandomNumber(){return 4;}", 32); - return 0; -} - static void mock_set_circid_type(channel_t *chan, crypto_pk_t *identity_rcvd, @@ -1173,7 +1155,6 @@ } typedef struct authenticate_data_t { - int is_ed; or_connection_t *c1, *c2; channel_tls_t *chan2; var_cell_t *cell; @@ -1187,7 +1168,6 @@ UNMOCK(connection_or_write_var_cell_to_buf); UNMOCK(tor_tls_get_peer_cert); UNMOCK(tor_tls_get_own_cert); - UNMOCK(tor_tls_get_tlssecrets); UNMOCK(connection_or_close_for_error); UNMOCK(channel_set_circid_type); UNMOCK(tor_tls_export_key_material); @@ -1216,16 +1196,12 @@ authenticate_data_setup(const struct testcase_t *test) { authenticate_data_t *d = tor_malloc_zero(sizeof(*d)); - int is_ed = d->is_ed = (test->setup_data == (void*)3); - - testing__connection_or_pretend_TLSSECRET_is_supported = 1; scheduler_init(); MOCK(connection_or_write_var_cell_to_buf, mock_write_var_cell); MOCK(tor_tls_get_peer_cert, mock_get_peer_cert); MOCK(tor_tls_get_own_cert, mock_get_own_cert); - MOCK(tor_tls_get_tlssecrets, mock_get_tlssecrets); MOCK(connection_or_close_for_error, mock_close_for_err); MOCK(channel_set_circid_type, mock_set_circid_type); MOCK(tor_tls_export_key_material, mock_export_key_material); @@ -1265,7 +1241,7 @@ d->c2->tls = tor_tls_new(-1, 1); d->c2->handshake_state->received_certs_cell = 1; - const tor_x509_cert_t *id_cert=NULL, *link_cert=NULL, *auth_cert=NULL; + const tor_x509_cert_t *id_cert=NULL, *link_cert=NULL; tt_assert(! tor_tls_get_my_certs(1, &link_cert, &id_cert)); const uint8_t *der; @@ -1274,17 +1250,13 @@ d->c1->handshake_state->certs->id_cert = tor_x509_cert_decode(der, sz); d->c2->handshake_state->certs->id_cert = tor_x509_cert_decode(der, sz); - if (is_ed) { + { d->c1->handshake_state->certs->ed_id_sign = tor_cert_dup(get_master_signing_key_cert()); d->c2->handshake_state->certs->ed_id_sign = tor_cert_dup(get_master_signing_key_cert()); d->c2->handshake_state->certs->ed_sign_auth = tor_cert_dup(get_current_auth_key_cert()); - } else { - tt_assert(! tor_tls_get_my_certs(0, &auth_cert, &id_cert)); - tor_x509_cert_get_der(auth_cert, &der, &sz); - d->c2->handshake_state->certs->auth_cert = tor_x509_cert_decode(der, sz); } tor_x509_cert_get_der(link_cert, &der, &sz); @@ -1295,11 +1267,8 @@ tt_assert(mock_own_cert); /* Make an authenticate cell ... */ - int authtype; - if (is_ed) - authtype = AUTHTYPE_ED25519_SHA256_RFC5705; - else - authtype = AUTHTYPE_RSA_SHA256_TLSSECRET; + int authtype = AUTHTYPE_ED25519_SHA256_RFC5705; + tt_int_op(0, OP_EQ, connection_or_send_authenticate_cell(d->c1, authtype)); tt_assert(mock_got_var_cell); @@ -1327,50 +1296,27 @@ /* Is the cell well-formed on the outer layer? */ tt_int_op(d->cell->command, OP_EQ, CELL_AUTHENTICATE); tt_int_op(d->cell->payload[0], OP_EQ, 0); - if (d->is_ed) - tt_int_op(d->cell->payload[1], OP_EQ, 3); - else - tt_int_op(d->cell->payload[1], OP_EQ, 1); + tt_int_op(d->cell->payload[1], OP_EQ, 3); tt_int_op(ntohs(get_uint16(d->cell->payload + 2)), OP_EQ, d->cell->payload_len - 4); /* Check it out for plausibility... */ - auth_ctx_t ctx; - ctx.is_ed = d->is_ed; tt_int_op(d->cell->payload_len-4, OP_EQ, auth1_parse(&auth1, d->cell->payload+4, - d->cell->payload_len - 4, &ctx)); + d->cell->payload_len - 4)); tt_assert(auth1); - if (d->is_ed) { - tt_mem_op(auth1->type, OP_EQ, "AUTH0003", 8); - } else { - tt_mem_op(auth1->type, OP_EQ, "AUTH0001", 8); - } + tt_mem_op(auth1->type, OP_EQ, "AUTH0003", 8); tt_mem_op(auth1->tlssecrets, OP_EQ, "int getRandomNumber(){return 4;}", 32); /* Is the signature okay? */ const uint8_t *start = d->cell->payload+4, *end = auth1->end_of_signed; - if (d->is_ed) { + { ed25519_signature_t sig; tt_int_op(auth1_getlen_sig(auth1), OP_EQ, ED25519_SIG_LEN); memcpy(&sig.sig, auth1_getarray_sig(auth1), ED25519_SIG_LEN); tt_assert(!ed25519_checksig(&sig, start, end-start, &get_current_auth_keypair()->pubkey)); - } else { - uint8_t sig[128]; - uint8_t digest[32]; - tt_int_op(auth1_getlen_sig(auth1), OP_GT, 120); - auth_pubkey = tor_tls_cert_get_key( - d->c2->handshake_state->certs->auth_cert); - int n = crypto_pk_public_checksig( - auth_pubkey, - (char*)sig, sizeof(sig), (char*)auth1_getarray_sig(auth1), - auth1_getlen_sig(auth1)); - tt_int_op(n, OP_EQ, 32); - crypto_digest256((char*)digest, - (const char*)start, end-start, DIGEST_SHA256); - tt_mem_op(sig, OP_EQ, digest, 32); } /* Then feed it to c2. */ @@ -1378,12 +1324,9 @@ channel_tls_process_authenticate_cell(d->cell, d->chan2); tt_int_op(mock_close_called, OP_EQ, 0); tt_int_op(d->c2->handshake_state->authenticated, OP_EQ, 1); - if (d->is_ed) { + { tt_int_op(d->c2->handshake_state->authenticated_ed25519, OP_EQ, 1); tt_int_op(d->c2->handshake_state->authenticated_rsa, OP_EQ, 1); - } else { - tt_int_op(d->c2->handshake_state->authenticated_ed25519, OP_EQ, 0); - tt_int_op(d->c2->handshake_state->authenticated_rsa, OP_EQ, 1); } done: @@ -1445,11 +1388,6 @@ "certificate"; tor_x509_cert_free(d->c2->handshake_state->certs->id_cert); d->c2->handshake_state->certs->id_cert = NULL) -AUTHENTICATE_FAIL(noauthcert, - require_failure_message = "We never got an RSA " - "authentication certificate"; - tor_x509_cert_free(d->c2->handshake_state->certs->auth_cert); - d->c2->handshake_state->certs->auth_cert = NULL) AUTHENTICATE_FAIL(tooshort, require_failure_message = "Cell was way too short"; d->cell->payload_len = 3) @@ -1473,10 +1411,7 @@ "cell body was not as expected"; d->cell->payload[10] ^= 0xff) AUTHENTICATE_FAIL(badsig_1, - if (d->is_ed) - require_failure_message = "Ed25519 signature wasn't valid"; - else - require_failure_message = "RSA signature wasn't valid"; + require_failure_message = "Ed25519 signature wasn't valid"; d->cell->payload[d->cell->payload_len - 5] ^= 0xff) AUTHENTICATE_FAIL(missing_ed_id, { @@ -1522,10 +1457,13 @@ test_link_handshake_recv_certs_ ## name, TT_FORK, \ &setup_recv_certs, (void*)type } +/* These two used to have different behavior, but since we've + disabled RSA-SHAS256-TLSSecret authentication, we no longer + have any need to distinguish. +*/ #define TEST_AUTHENTICATE(name) \ { "authenticate/" #name , test_link_handshake_auth_ ## name, TT_FORK, \ &setup_authenticate, NULL } - #define TEST_AUTHENTICATE_ED(name) \ { "authenticate/" #name "_ed25519" , test_link_handshake_auth_ ## name, \ TT_FORK, &setup_authenticate, (void*)3 } @@ -1581,7 +1519,7 @@ TEST_RCV_CERTS(server_wrong_labels_1), TEST_RSA(send_authchallenge, TT_FORK), - TEST_RCV_AUTHCHALLENGE(ok), + TEST_RCV_AUTHCHALLENGE(no_ed25519), TEST_RCV_AUTHCHALLENGE(ok_ed25519), TEST_RCV_AUTHCHALLENGE(ok_noserver), TEST_RCV_AUTHCHALLENGE(ok_unrecognized), @@ -1603,7 +1541,6 @@ TEST_AUTHENTICATE(already_authenticated), TEST_AUTHENTICATE(nocerts), TEST_AUTHENTICATE(noidcert), - TEST_AUTHENTICATE(noauthcert), TEST_AUTHENTICATE(tooshort), TEST_AUTHENTICATE(badtype), TEST_AUTHENTICATE(truncated_1), diff -Nru tor-0.4.7.16/src/test/test_metrics.c tor-0.4.9.6/src/test/test_metrics.c --- tor-0.4.7.16/src/test/test_metrics.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/test/test_metrics.c 2026-03-25 14:30:34.000000000 +0000 @@ -28,11 +28,16 @@ #include "lib/encoding/confline.h" #include "lib/metrics/metrics_store.h" +#include + #define TEST_METRICS_ENTRY_NAME "entryA" #define TEST_METRICS_ENTRY_HELP "Description of entryA" #define TEST_METRICS_ENTRY_LABEL_1 "label=\"farfadet\"" #define TEST_METRICS_ENTRY_LABEL_2 "label=\"ponki\"" +#define TEST_METRICS_HIST_ENTRY_NAME "test_hist_entry" +#define TEST_METRICS_HIST_ENTRY_HELP "Description of test_hist_entry" + static void set_metrics_port(or_options_t *options) { @@ -189,7 +194,8 @@ /* Add entry and validate its content. */ entry = metrics_store_add(store, METRICS_TYPE_COUNTER, TEST_METRICS_ENTRY_NAME, - TEST_METRICS_ENTRY_HELP); + TEST_METRICS_ENTRY_HELP, + 0, NULL); tt_assert(entry); metrics_store_entry_add_label(entry, TEST_METRICS_ENTRY_LABEL_1); @@ -209,10 +215,60 @@ } static void +test_prometheus_histogram(void *arg) +{ + metrics_store_t *store = NULL; + metrics_store_entry_t *entry = NULL; + buf_t *buf = buf_new(); + char *output = NULL; + const int64_t buckets[] = { 10, 20, 3000 }; + + (void) arg; + + /* Fresh new store. No entries. */ + store = metrics_store_new(); + tt_assert(store); + + /* Add a histogram entry and validate its content. */ + entry = metrics_store_add(store, METRICS_TYPE_HISTOGRAM, + TEST_METRICS_HIST_ENTRY_NAME, + TEST_METRICS_HIST_ENTRY_HELP, + ARRAY_LENGTH(buckets), buckets); + tt_assert(entry); + metrics_store_entry_add_label(entry, TEST_METRICS_ENTRY_LABEL_1); + + static const char *expected = + "# HELP " TEST_METRICS_HIST_ENTRY_NAME " " + TEST_METRICS_HIST_ENTRY_HELP "\n" + "# TYPE " TEST_METRICS_HIST_ENTRY_NAME " histogram\n" + TEST_METRICS_HIST_ENTRY_NAME "_bucket{" + TEST_METRICS_ENTRY_LABEL_1 ",le=\"10.00\"} 0\n" + TEST_METRICS_HIST_ENTRY_NAME "_bucket{" + TEST_METRICS_ENTRY_LABEL_1 ",le=\"20.00\"} 0\n" + TEST_METRICS_HIST_ENTRY_NAME "_bucket{" + TEST_METRICS_ENTRY_LABEL_1 ",le=\"3000.00\"} 0\n" + TEST_METRICS_HIST_ENTRY_NAME "_bucket{" + TEST_METRICS_ENTRY_LABEL_1 ",le=\"+Inf\"} 0\n" + TEST_METRICS_HIST_ENTRY_NAME "_sum{" TEST_METRICS_ENTRY_LABEL_1 "} 0\n" + TEST_METRICS_HIST_ENTRY_NAME "_count{" TEST_METRICS_ENTRY_LABEL_1 "} 0\n"; + + metrics_store_get_output(METRICS_FORMAT_PROMETHEUS, store, buf); + output = buf_extract(buf, NULL); + tt_str_op(expected, OP_EQ, output); + + done: + buf_free(buf); + tor_free(output); + metrics_store_free(store); +} + +static void test_store(void *arg) { metrics_store_t *store = NULL; metrics_store_entry_t *entry = NULL; + const int64_t buckets[] = { 10, 20, 3000 }; + const size_t bucket_count = ARRAY_LENGTH(buckets); (void) arg; @@ -224,7 +280,7 @@ /* Add entry and validate its content. */ entry = metrics_store_add(store, METRICS_TYPE_COUNTER, TEST_METRICS_ENTRY_NAME, - TEST_METRICS_ENTRY_HELP); + TEST_METRICS_ENTRY_HELP, 0, NULL); tt_assert(entry); tt_int_op(entry->type, OP_EQ, METRICS_TYPE_COUNTER); tt_str_op(entry->name, OP_EQ, TEST_METRICS_ENTRY_NAME); @@ -251,7 +307,7 @@ /* Add entry and validate its content. */ entry = metrics_store_add(store, METRICS_TYPE_COUNTER, TEST_METRICS_ENTRY_NAME, - TEST_METRICS_ENTRY_HELP); + TEST_METRICS_ENTRY_HELP, 0, NULL); tt_assert(entry); metrics_store_entry_add_label(entry, TEST_METRICS_ENTRY_LABEL_2); @@ -261,6 +317,89 @@ tt_assert(entries); tt_int_op(smartlist_len(entries), OP_EQ, 2); + /* Add a histogram entry and validate its content. */ + entry = metrics_store_add(store, METRICS_TYPE_HISTOGRAM, + TEST_METRICS_HIST_ENTRY_NAME, + TEST_METRICS_HIST_ENTRY_HELP, + bucket_count, buckets); + + tt_assert(entry); + tt_int_op(entry->type, OP_EQ, METRICS_TYPE_HISTOGRAM); + tt_str_op(entry->name, OP_EQ, TEST_METRICS_HIST_ENTRY_NAME); + tt_str_op(entry->help, OP_EQ, TEST_METRICS_HIST_ENTRY_HELP); + tt_uint_op(entry->u.histogram.bucket_count, OP_EQ, bucket_count); + + for (size_t i = 0; i < bucket_count; ++i) { + tt_uint_op(entry->u.histogram.buckets[i].bucket, OP_EQ, buckets[i]); + tt_uint_op(entry->u.histogram.buckets[i].value, OP_EQ, 0); + } + + /* Access the entry. */ + tt_assert(metrics_store_get_all(store, TEST_METRICS_HIST_ENTRY_NAME)); + + /* Record various observations. */ + metrics_store_hist_entry_update(entry, 3, 11); + tt_int_op(metrics_store_hist_entry_get_value(entry, 10), OP_EQ, 0); + tt_int_op(metrics_store_hist_entry_get_value(entry, 20), OP_EQ, 3); + tt_int_op(metrics_store_hist_entry_get_value(entry, 3000), OP_EQ, 3); + tt_int_op(metrics_store_hist_entry_get_value(entry, 3000), OP_EQ, 3); + tt_int_op(metrics_store_hist_entry_get_count(entry), OP_EQ, 3); + tt_int_op(metrics_store_hist_entry_get_sum(entry), OP_EQ, 11); + + metrics_store_hist_entry_update(entry, 1, 42); + tt_int_op(metrics_store_hist_entry_get_value(entry, 10), OP_EQ, 0); + tt_int_op(metrics_store_hist_entry_get_value(entry, 20), OP_EQ, 3); + tt_int_op(metrics_store_hist_entry_get_value(entry, 3000), OP_EQ, 4); + tt_int_op(metrics_store_hist_entry_get_value(entry, 3000), OP_EQ, 4); + tt_int_op(metrics_store_hist_entry_get_count(entry), OP_EQ, 4); + tt_int_op(metrics_store_hist_entry_get_sum(entry), OP_EQ, 53); + + /* Ensure this resets all buckets back to 0. */ + metrics_store_entry_reset(entry); + for (size_t i = 0; i < bucket_count; ++i) { + tt_uint_op(entry->u.histogram.buckets[i].bucket, OP_EQ, buckets[i]); + tt_uint_op(entry->u.histogram.buckets[i].value, OP_EQ, 0); + } + + /* tt_int_op assigns the third argument to a variable of type long, which + * overflows on some platforms (e.g. on some 32-bit systems). We disable + * these checks for those platforms. */ +#if LONG_MAX >= INT64_MAX + metrics_store_hist_entry_update(entry, 1, INT64_MAX - 13); + tt_int_op(metrics_store_hist_entry_get_sum(entry), OP_EQ, INT64_MAX - 13); + metrics_store_hist_entry_update(entry, 1, 13); + tt_int_op(metrics_store_hist_entry_get_sum(entry), OP_EQ, INT64_MAX); + /* Uh-oh, the sum of all observations is now greater than INT64_MAX. Make + * sure we reset the entry instead of overflowing the sum. */ + metrics_store_hist_entry_update(entry, 1, 1); + tt_int_op(metrics_store_hist_entry_get_value(entry, 10), OP_EQ, 1); + tt_int_op(metrics_store_hist_entry_get_value(entry, 20), OP_EQ, 1); + tt_int_op(metrics_store_hist_entry_get_value(entry, 3000), OP_EQ, 1); + tt_int_op(metrics_store_hist_entry_get_value(entry, 3000), OP_EQ, 1); + tt_int_op(metrics_store_hist_entry_get_count(entry), OP_EQ, 1); + tt_int_op(metrics_store_hist_entry_get_sum(entry), OP_EQ, 1); +#endif + +#if LONG_MIN <= INT64_MIN + metrics_store_entry_reset(entry); + /* In practice, we're not going to have negative observations (as we only use + * histograms for timings, which are always positive), but technically + * prometheus _does_ support negative observations. */ + metrics_store_hist_entry_update(entry, 1, INT64_MIN + 13); + tt_int_op(metrics_store_hist_entry_get_sum(entry), OP_EQ, INT64_MIN + 13); + metrics_store_hist_entry_update(entry, 1, -13); + tt_int_op(metrics_store_hist_entry_get_sum(entry), OP_EQ, INT64_MIN); + /* Uh-oh, the sum of all observations is now less than INT64_MIN. Make + * sure we reset the entry instead of underflowing the sum. */ + metrics_store_hist_entry_update(entry, 1, -1); + tt_int_op(metrics_store_hist_entry_get_value(entry, 10), OP_EQ, 1); + tt_int_op(metrics_store_hist_entry_get_value(entry, 20), OP_EQ, 1); + tt_int_op(metrics_store_hist_entry_get_value(entry, 3000), OP_EQ, 1); + tt_int_op(metrics_store_hist_entry_get_value(entry, 3000), OP_EQ, 1); + tt_int_op(metrics_store_hist_entry_get_count(entry), OP_EQ, 1); + tt_int_op(metrics_store_hist_entry_get_sum(entry), OP_EQ, -1); +#endif + done: metrics_store_free(store); } @@ -270,6 +409,7 @@ { "config", test_config, TT_FORK, NULL, NULL }, { "connection", test_connection, TT_FORK, NULL, NULL }, { "prometheus", test_prometheus, TT_FORK, NULL, NULL }, + { "prometheus_histogram", test_prometheus_histogram, TT_FORK, NULL, NULL }, { "store", test_store, TT_FORK, NULL, NULL }, END_OF_TESTCASES diff -Nru tor-0.4.7.16/src/test/test_microdesc.c tor-0.4.9.6/src/test/test_microdesc.c --- tor-0.4.7.16/src/test/test_microdesc.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/test/test_microdesc.c 2026-03-25 14:30:34.000000000 +0000 @@ -366,38 +366,30 @@ "iFJkKxxDx7ksxX0zdl7aPT4ORFEuRhCYS6el7YJmoyg=\n" "-----END SIGNATURE-----\n"; -static const char test_md2_25[] = +static const char test_md2_withfamily_33[] = "onion-key\n" "-----BEGIN RSA PUBLIC KEY-----\n" "MIGJAoGBAMvEJ/JVNK7I38PPWhQMuCgkET/ki4WIas4tj5Kmqfb9kHqxMR+EunRD\n" "83k4pel1yB7QdV+iTd/4SZOI8RpZP+BO1KnOTWfpztAU1lDGr19/PwdwcHaILpBD\n" "nNzm6otk4/bKUQ0vqpOfJljtg0DfAm4uMAQ6BMFy6uEAF7+JupuPAgMBAAE=\n" "-----END RSA PUBLIC KEY-----\n" - "ntor-onion-key FChIfm77vrWB7JsxQ+jMbN6VSSp1P0DYbw/2aqey4iA=\n" - "p accept 1-65535\n" - "id ed25519 J5lkRqyL6qW+CpN3E4RIlgJZeLgwjtmOOrjZvVhuwLQ\n"; - -static const char test_md2_withfamily_28[] = - "onion-key\n" - "-----BEGIN RSA PUBLIC KEY-----\n" - "MIGJAoGBAMvEJ/JVNK7I38PPWhQMuCgkET/ki4WIas4tj5Kmqfb9kHqxMR+EunRD\n" - "83k4pel1yB7QdV+iTd/4SZOI8RpZP+BO1KnOTWfpztAU1lDGr19/PwdwcHaILpBD\n" - "nNzm6otk4/bKUQ0vqpOfJljtg0DfAm4uMAQ6BMFy6uEAF7+JupuPAgMBAAE=\n" - "-----END RSA PUBLIC KEY-----\n" - "ntor-onion-key FChIfm77vrWB7JsxQ+jMbN6VSSp1P0DYbw/2aqey4iA=\n" - "family OtherNode !Strange\n" + "ntor-onion-key FChIfm77vrWB7JsxQ+jMbN6VSSp1P0DYbw/2aqey4iA\n" + "family !Strange $D219590AC9513BCDEBBA9AB721007A4CC01BBAE3 othernode\n" "p accept 1-65535\n" "id ed25519 J5lkRqyL6qW+CpN3E4RIlgJZeLgwjtmOOrjZvVhuwLQ\n"; -static const char test_md2_withfamily_29[] = +static const char test_md2_withfamilyids_35[] = "onion-key\n" "-----BEGIN RSA PUBLIC KEY-----\n" "MIGJAoGBAMvEJ/JVNK7I38PPWhQMuCgkET/ki4WIas4tj5Kmqfb9kHqxMR+EunRD\n" "83k4pel1yB7QdV+iTd/4SZOI8RpZP+BO1KnOTWfpztAU1lDGr19/PwdwcHaILpBD\n" "nNzm6otk4/bKUQ0vqpOfJljtg0DfAm4uMAQ6BMFy6uEAF7+JupuPAgMBAAE=\n" "-----END RSA PUBLIC KEY-----\n" - "ntor-onion-key FChIfm77vrWB7JsxQ+jMbN6VSSp1P0DYbw/2aqey4iA=\n" + "ntor-onion-key FChIfm77vrWB7JsxQ+jMbN6VSSp1P0DYbw/2aqey4iA\n" "family !Strange $D219590AC9513BCDEBBA9AB721007A4CC01BBAE3 othernode\n" + "family-ids " + "ed25519:YWxsIGhhcHB5IGZhbWlsaWVzIGFyZSBhbGlrZSAtTFQ " + "rlwe:0YHRh9Cw0YHRgtC70LjQstGL0LUg0YHQtdC80YzQuC0\n" "p accept 1-65535\n" "id ed25519 J5lkRqyL6qW+CpN3E4RIlgJZeLgwjtmOOrjZvVhuwLQ\n"; @@ -411,21 +403,22 @@ ri = router_parse_entry_from_string(test_ri, NULL, 0, 0, NULL, NULL); tt_assert(ri); - md = dirvote_create_microdescriptor(ri, 25); - tt_str_op(md->body, OP_EQ, test_md2_25); - 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); + md = dirvote_create_microdescriptor(ri, 33); + tt_str_op(md->body, OP_EQ, test_md2_withfamily_33); + // Try family-ids. microdesc_free(md); - md = dirvote_create_microdescriptor(ri, 29); - tt_str_op(md->body, OP_EQ, test_md2_withfamily_29); + ri->family_ids = smartlist_new(); + smartlist_add_strdup(ri->family_ids, + "ed25519:YWxsIGhhcHB5IGZhbWlsaWVzIGFyZSBhbGlrZSAtTFQ"); + smartlist_add_strdup(ri->family_ids, + "rlwe:0YHRh9Cw0YHRgtC70LjQstGL0LUg0YHQtdC80YzQuC0"); + md = dirvote_create_microdescriptor(ri, 35); + tt_str_op(md->body, OP_EQ, test_md2_withfamilyids_35); done: microdesc_free(md); @@ -792,6 +785,73 @@ teardown_capture_of_logs(); } +static void +test_md_parse_no_onion_key(void *arg) +{ + (void)arg; + + /* A correct MD with no onion key. */ + const char GOOD_MD[] = + "onion-key\n" + "ntor-onion-key AppBt6CSeb1kKid/36ototmFA24ddfW5JpjWPLuoJgs=\n" + "id ed25519 VGhpcyBpc24ndCBhY3R1YWxseSBhIHB1YmxpYyBrZXk\n"; + + smartlist_t *mds = NULL; + + mds = microdescs_parse_from_string(GOOD_MD, + NULL, 1, SAVED_NOWHERE, NULL); + tt_assert(mds); + tt_int_op(smartlist_len(mds), OP_EQ, 1); + const microdesc_t *md = smartlist_get(mds, 0); + tt_mem_op(md->ed25519_identity_pkey, OP_EQ, + "This isn't actually a public key", ED25519_PUBKEY_LEN); + + done: + if (mds) { + SMARTLIST_FOREACH(mds, microdesc_t *, m, microdesc_free(m)); + smartlist_free(mds); + } + teardown_capture_of_logs(); +} + +static void +test_md_parse_family_ids(void *arg) +{ + (void)arg; + + const char GOOD_MDS[] = + "onion-key\n" + "ntor-onion-key VHlycmFueSwgbGlrZSBoZWxsLCBpcyBub3QgZWFzaWw\n" + "id ed25519 eSBjb25xdWVyZWQ7IHlldCB3ZSBoYXZlIHRoaXMgY28\n" + "family-ids\n" + "onion-key\n" + "ntor-onion-key bnNvbGF0aW9uIHdpdGggdXMsIHRoYXQgdGhlIGhhcmQ\n" + "id ed25519 ZXIgdGhlIGNvbmZsaWN0LCB0aGUgbW9yZSBnbG9yaW8\n" + "family-ids ed25519:dXMgdGhlIHRyaXVtcGguICAgIC1UaG9tYXMgUGFpbmU " + "other:Example\n"; + smartlist_t *mds = NULL; + mds = microdescs_parse_from_string(GOOD_MDS, NULL, 1, SAVED_NOWHERE, NULL); + tt_assert(mds); + tt_int_op(smartlist_len(mds), OP_EQ, 2); + + const microdesc_t *md1 = smartlist_get(mds, 0); + tt_ptr_op(md1->family_ids, OP_EQ, NULL); + + const microdesc_t *md2 = smartlist_get(mds, 1); + tt_ptr_op(md2->family_ids, OP_NE, NULL); + tt_int_op(smartlist_len(md2->family_ids), OP_EQ, 2); + tt_str_op(smartlist_get(md2->family_ids, 0), OP_EQ, + "ed25519:dXMgdGhlIHRyaXVtcGguICAgIC1UaG9tYXMgUGFpbmU"); + tt_str_op(smartlist_get(md2->family_ids, 1), OP_EQ, + "other:Example"); + + done: + if (mds) { + SMARTLIST_FOREACH(mds, microdesc_t *, m, microdesc_free(m)); + smartlist_free(mds); + } +} + static int mock_rgsbd_called = 0; static routerstatus_t *mock_rgsbd_val_a = NULL; static routerstatus_t *mock_rgsbd_val_b = NULL; @@ -926,6 +986,8 @@ { "generate", test_md_generate, 0, NULL, NULL }, { "parse", test_md_parse, 0, NULL, NULL }, { "parse_id_ed25519", test_md_parse_id_ed25519, 0, NULL, NULL }, + { "parse_no_onion_key", test_md_parse_no_onion_key, 0, NULL, NULL }, + { "parse_family_ids", test_md_parse_family_ids, 0, NULL, NULL }, { "reject_cache", test_md_reject_cache, TT_FORK, NULL, NULL }, { "corrupt_desc", test_md_corrupt_desc, TT_FORK, NULL, NULL }, END_OF_TESTCASES diff -Nru tor-0.4.7.16/src/test/test_nodelist.c tor-0.4.9.6/src/test/test_nodelist.c --- tor-0.4.7.16/src/test/test_nodelist.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/test/test_nodelist.c 2026-03-25 14:30:34.000000000 +0000 @@ -559,34 +559,34 @@ memcpy(mock_node2.identity, "SecondNodeWe'reTestn", DIGEST_LEN); // empty families. - tt_assert(! node_family_contains(&mock_node1, &mock_node2)); - tt_assert(! node_family_contains(&mock_node2, &mock_node1)); + tt_assert(! node_family_list_contains(&mock_node1, &mock_node2)); + tt_assert(! node_family_list_contains(&mock_node2, &mock_node1)); // Families contain nodes, but not these nodes mock_ri.declared_family = smartlist_new(); smartlist_add(mock_ri.declared_family, (char*)"NodeThree"); mock_md.family = nodefamily_parse("NodeFour", NULL, 0); - tt_assert(! node_family_contains(&mock_node1, &mock_node2)); - tt_assert(! node_family_contains(&mock_node2, &mock_node1)); + tt_assert(! node_family_list_contains(&mock_node1, &mock_node2)); + tt_assert(! node_family_list_contains(&mock_node2, &mock_node1)); // Families contain one another. smartlist_add(mock_ri.declared_family, (char*) "4e6f64654f6e654e6f6465314e6f64654f6e6531"); - tt_assert(! node_family_contains(&mock_node1, &mock_node2)); - tt_assert(node_family_contains(&mock_node2, &mock_node1)); + tt_assert(! node_family_list_contains(&mock_node1, &mock_node2)); + tt_assert(node_family_list_contains(&mock_node2, &mock_node1)); nodefamily_free(mock_md.family); mock_md.family = nodefamily_parse( "NodeFour " "5365636f6e644e6f64655765277265546573746e", NULL, 0); - tt_assert(node_family_contains(&mock_node1, &mock_node2)); - tt_assert(node_family_contains(&mock_node2, &mock_node1)); + tt_assert(node_family_list_contains(&mock_node1, &mock_node2)); + tt_assert(node_family_list_contains(&mock_node2, &mock_node1)); // Try looking up families now. MOCK(node_get_by_nickname, mock_node_get_by_nickname); MOCK(node_get_by_id, mock_node_get_by_id); - node_lookup_declared_family(nodes, &mock_node1); + node_lookup_declared_family_list(nodes, &mock_node1); tt_int_op(smartlist_len(nodes), OP_EQ, 2); const node_t *n = smartlist_get(nodes, 0); tt_mem_op(n->identity, OP_EQ, "SecondNodeWe'reTestn", DIGEST_LEN); @@ -597,7 +597,7 @@ SMARTLIST_FOREACH(nodes, node_t *, x, tor_free(x)); smartlist_clear(nodes); - node_lookup_declared_family(nodes, &mock_node2); + node_lookup_declared_family_list(nodes, &mock_node2); tt_int_op(smartlist_len(nodes), OP_EQ, 2); n = smartlist_get(nodes, 0); // This gets a truncated hex hex ID since it was looked up by name @@ -1273,7 +1273,6 @@ memcpy(rs_orig.descriptor_digest, "abcdefghijklmnopqrst", 20); tor_addr_from_ipv4h(&rs_orig.ipv4_addr, 0x7f000001); rs_orig.ipv4_orport = 3; - rs_orig.published_on = time(NULL); rs_orig.has_bandwidth = 1; rs_orig.bandwidth_kb = 20; @@ -1284,9 +1283,9 @@ tor_free(fmt); \ fmt_orig = routerstatus_format_entry(&rs_orig, NULL, NULL, \ NS_CONTROL_PORT, \ - NULL); \ + NULL, -1); \ fmt = routerstatus_format_entry(&rs, NULL, NULL, NS_CONTROL_PORT, \ - NULL); \ + NULL, -1); \ tt_assert(fmt_orig); \ tt_assert(fmt); \ STMT_END @@ -1322,9 +1321,6 @@ strlcpy(rs.nickname, "fr1end1y", sizeof(rs.nickname)); ASSERT_CHANGED(); - rs.published_on += 3600; - ASSERT_CHANGED(); - rs.ipv4_orport = 55; ASSERT_CHANGED(); diff -Nru tor-0.4.7.16/src/test/test_ntor_v3.c tor-0.4.9.6/src/test/test_ntor_v3.c --- tor-0.4.7.16/src/test/test_ntor_v3.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/test/test_ntor_v3.c 2026-03-25 14:30:34.000000000 +0000 @@ -14,6 +14,8 @@ #include "core/or/extend_info_st.h" #include "core/or/crypt_path_st.h" #define TOR_CONGESTION_CONTROL_PRIVATE +#define TOR_CONGESTION_CONTROL_COMMON_PRIVATE +#include "core/or/congestion_control_st.h" #include "core/or/congestion_control_common.h" #include "app/config/config.h" @@ -190,6 +192,7 @@ uint8_t client_keys[CELL_PAYLOAD_SIZE]; uint8_t rend_auth[DIGEST_LEN]; + info.supports_ntor_v3 = true; info.exit_supports_congestion_control = 1; unhex(relay_onion_key.seckey.secret_key, @@ -216,18 +219,20 @@ server_keys.junk_keypair = &handshake_state.u.ntor3->client_keypair; + size_t serv_keylen = sizeof(serv_keys); + size_t client_keylen = sizeof(serv_keys); reply_len = onion_skin_server_handshake(ONION_HANDSHAKE_TYPE_NTOR_V3, onionskin, onionskin_len, &server_keys, serv_params_in, serv_reply, sizeof(serv_reply), - serv_keys, sizeof(serv_keys), + serv_keys, &serv_keylen, rend_nonce, serv_params_out); tt_int_op(reply_len, OP_NE, -1); tt_int_op(onion_skin_client_handshake(ONION_HANDSHAKE_TYPE_NTOR_V3, &handshake_state, serv_reply, reply_len, - client_keys, sizeof(client_keys), + client_keys, &client_keylen, rend_auth, client_params_out, NULL), OP_EQ, 0); @@ -262,6 +267,7 @@ tt_int_op(serv_params.cc_enabled, OP_EQ, 0); /* client off, serv on -> off */ + congestion_control_set_cc_disabled(); serv_ns_params.cc_enabled = 1; run_full_handshake(&serv_ns_params, &client_params, &serv_params); tt_int_op(client_params.cc_enabled, OP_EQ, 0); diff -Nru tor-0.4.7.16/src/test/test_options.c tor-0.4.9.6/src/test/test_options.c --- tor-0.4.7.16/src/test/test_options.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/test/test_options.c 2026-03-25 14:30:34.000000000 +0000 @@ -2006,43 +2006,6 @@ } static void -test_options_validate__hidserv(void *ignored) -{ - (void)ignored; - int ret; - char *msg; - setup_capture_of_logs(LOG_WARN); - - options_test_data_t *tdata = NULL; - - free_options_test_data(tdata); - tdata = get_options_test_data("RendPostPeriod 1\n" ); - mock_clean_saved_logs(); - ret = options_validate(NULL, tdata->opt, &msg); - tt_int_op(ret, OP_EQ, 0); - expect_log_msg("RendPostPeriod option is too short;" - " raising to 600 seconds.\n"); - tt_int_op(tdata->opt->RendPostPeriod, OP_EQ, 600); - tor_free(msg); - - free_options_test_data(tdata); - tdata = get_options_test_data("RendPostPeriod 302401\n" ); - mock_clean_saved_logs(); - ret = options_validate(NULL, tdata->opt, &msg); - tt_int_op(ret, OP_EQ, 0); - expect_log_msg("RendPostPeriod is too large; " - "clipping to 302400s.\n"); - tt_int_op(tdata->opt->RendPostPeriod, OP_EQ, 302400); - tor_free(msg); - - done: - teardown_capture_of_logs(); - policies_free_all(); - free_options_test_data(tdata); - tor_free(msg); -} - -static void test_options_validate__path_bias(void *ignored) { (void)ignored; @@ -4270,7 +4233,6 @@ LOCAL_VALIDATE_TEST(safe_logging), LOCAL_VALIDATE_TEST(publish_server_descriptor), LOCAL_VALIDATE_TEST(testing), - LOCAL_VALIDATE_TEST(hidserv), LOCAL_VALIDATE_TEST(path_bias), LOCAL_VALIDATE_TEST(bandwidth), LOCAL_VALIDATE_TEST(circuits), diff -Nru tor-0.4.7.16/src/test/test_parsecommon.c tor-0.4.9.6/src/test/test_parsecommon.c --- tor-0.4.7.16/src/test/test_parsecommon.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/test/test_parsecommon.c 2026-03-25 14:30:34.000000000 +0000 @@ -254,6 +254,50 @@ } static void +test_parsecommon_get_next_token_carriage_return(void *arg) +{ + memarea_t *area = memarea_new(); + smartlist_t *tokens = smartlist_new(); + + (void)arg; + + token_rule_t table[] = { + T01("uptime", K_UPTIME, GE(1), NO_OBJ), + T01("hibernating", K_HIBERNATING, GE(1), NO_OBJ), + END_OF_TABLE, + }; + + char *str = tor_strdup( + "hibernating 0\r\nuptime 1024\n" + "hibernating 0\ruptime 1024\n"); + + int retval = + tokenize_string(area, str, NULL, + tokens, table, 0); + + tt_int_op(smartlist_len(tokens), OP_EQ, 3); + directory_token_t *token = smartlist_get(tokens, 0); + + tt_int_op(token->tp, OP_EQ, K_HIBERNATING); + + token = smartlist_get(tokens, 1); + + tt_int_op(token->tp, OP_EQ, K_UPTIME); + + token = smartlist_get(tokens, 2); + + tt_int_op(token->tp, OP_EQ, K_HIBERNATING); + + tt_int_op(retval, OP_EQ, -1); + + done: + tor_free(str); + memarea_drop_all(area); + smartlist_free(tokens); + return; +} + +static void test_parsecommon_get_next_token_concat_args(void *arg) { memarea_t *area = memarea_new(); @@ -571,6 +615,7 @@ struct testcase_t parsecommon_tests[] = { PARSECOMMON_TEST(tokenize_string_null), + PARSECOMMON_TEST(get_next_token_carriage_return), PARSECOMMON_TEST(tokenize_string_multiple_lines), PARSECOMMON_TEST(tokenize_string_min_cnt), PARSECOMMON_TEST(tokenize_string_max_cnt), diff -Nru tor-0.4.7.16/src/test/test_parseconf.sh tor-0.4.9.6/src/test/test_parseconf.sh --- tor-0.4.7.16/src/test/test_parseconf.sh 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/test/test_parseconf.sh 2026-03-25 14:30:34.000000000 +0000 @@ -98,6 +98,9 @@ # want to encode that knowledge in this test script, so we supply a # separate result file for every combination of disabled modules that # has a different result.) +# +# This logic ignores modules that are not listed by --list-modules +# (dircache) and some that do not currently affect config parsing (pow). umask 077 set -e @@ -197,6 +200,8 @@ "$NON_EMPTY" STANDARD_LIBS="libevent\\|openssl\\|zlib" +MODULES_WITHOUT_CONFIG_TESTS="dircache\\|pow" + # Lib names are restricted to [a-z0-9]* at the moment # We don't actually want to support foreign accents here # shellcheck disable=SC2018,SC2019 @@ -229,6 +234,7 @@ | grep -v '^_*$' | tr '\n' ' ')" TOR_MODULES_DISABLED="$("$TOR_BINARY" --list-modules | grep ': no' \ + | grep -v "$MODULES_WITHOUT_CONFIG_TESTS" \ | cut -d ':' -f1 | sort | tr '\n' '_')" # Remove the last underscore, if there is one TOR_MODULES_DISABLED=${TOR_MODULES_DISABLED%_} diff -Nru tor-0.4.7.16/src/test/test_periodic_event.c tor-0.4.9.6/src/test/test_periodic_event.c --- tor-0.4.7.16/src/test/test_periodic_event.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/test/test_periodic_event.c 2026-03-25 14:30:34.000000000 +0000 @@ -50,7 +50,7 @@ /* Initialize the events but the callback won't get called since we would * 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. */ + * tests. Instead, we'll test the callback work independently elsewhere. */ initialize_periodic_events(); periodic_events_connect_all(); set_network_participation(false); diff -Nru tor-0.4.7.16/src/test/test_process_descs.c tor-0.4.9.6/src/test/test_process_descs.c --- tor-0.4.7.16/src/test/test_process_descs.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/test/test_process_descs.c 2026-03-25 14:30:34.000000000 +0000 @@ -47,20 +47,22 @@ { "Tor 0.4.3.0-alpha-dev", true }, { "Tor 0.4.3.8", true }, { "Tor 0.4.4.9", true }, - - /* The 0.4.5.x series stable is supported. */ { "Tor 0.4.5.5-rc", true }, - { "Tor 0.4.5.6", false }, - { "Tor 0.4.5.15", false }, - + { "Tor 0.4.5.6", true }, + { "Tor 0.4.5.15", true }, { "Tor 0.4.6.0-alpha-dev", true }, { "Tor 0.4.6.1-alpha", true }, { "Tor 0.4.6.5", true }, { "Tor 0.4.6.50", true }, /* Non existing one in the 0.4.6 series */ + { "Tor 0.4.7.0-alpha-dev", true }, + { "Tor 0.4.7.3-alpha", true }, + { "Tor 0.4.7.12", true }, - { "Tor 0.4.7.0-alpha-dev", false }, - { "Tor 0.4.7.3-alpha", false }, - { "Tor 0.4.7.12", false }, + /* The 0.4.8.x series is supported. */ + { "Tor 0.4.8.0-alpha-dev", false }, + { "Tor 0.4.8.2-alpha", false }, + { "Tor 0.4.8.3-rc", false }, + { "Tor 0.4.8.12", false }, // Very far in the future { "Tor 100.100.1.5", false }, diff -Nru tor-0.4.7.16/src/test/test_proto_http.c tor-0.4.9.6/src/test/test_proto_http.c --- tor-0.4.7.16/src/test/test_proto_http.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/test/test_proto_http.c 2026-03-25 14:30:34.000000000 +0000 @@ -6,11 +6,14 @@ * \brief Tests for our HTTP protocol parser code */ +#define CONNECTION_EDGE_PRIVATE + #include "core/or/or.h" #include "test/test.h" #include "lib/buf/buffers.h" #include "core/proto/proto_http.h" #include "test/log_test_helpers.h" +#include "core/or/connection_edge.h" #define S(str) str, sizeof(str)-1 @@ -203,11 +206,33 @@ teardown_capture_of_logs(); } +static void +test_proto_http_proxy_auth(void *arg) +{ + (void)arg; + + tt_assert(using_old_proxy_auth("")); + tt_assert(using_old_proxy_auth("Foo Bar")); + tt_assert(using_old_proxy_auth("Basicish Bar")); + tt_assert(using_old_proxy_auth("Basic")); + tt_assert(using_old_proxy_auth("Basic x")); + // encodes foo:bar + tt_assert(using_old_proxy_auth("Basic Zm9vOmJhcg==")); + // encodes torx:bar + tt_assert(using_old_proxy_auth("Basic dG9yeDpiYXI=")); + + // encodes tor:random + tt_assert(! using_old_proxy_auth("Basic dG9yOnJhbmRvbQ==")); + + done: + ; +} + struct testcase_t proto_http_tests[] = { { "peek", test_proto_http_peek, 0, NULL, NULL }, { "valid", test_proto_http_valid, 0, NULL, NULL }, { "invalid", test_proto_http_invalid, 0, NULL, NULL }, + { "proxyauth", test_proto_http_proxy_auth, 0, NULL, NULL }, END_OF_TESTCASES }; - diff -Nru tor-0.4.7.16/src/test/test_protover.c tor-0.4.9.6/src/test/test_protover.c --- tor-0.4.7.16/src/test/test_protover.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/test/test_protover.c 2026-03-25 14:30:34.000000000 +0000 @@ -219,15 +219,15 @@ tt_str_op(msg, OP_EQ, "Link=6-60"); tor_free(msg); tt_assert(! protover_all_supported("Link=1-3,50-63", &msg)); - tt_str_op(msg, OP_EQ, "Link=50-63"); + tt_str_op(msg, OP_EQ, "Link=1-2,50-63"); tor_free(msg); tt_assert(! protover_all_supported("Link=1-3,5-12", &msg)); - tt_str_op(msg, OP_EQ, "Link=6-12"); + tt_str_op(msg, OP_EQ, "Link=1-2,6-12"); tor_free(msg); /* Mix of protocols we do support and some we don't, where the protocols * we do support have some versions we don't support. */ - tt_assert(! protover_all_supported("Link=1-3,5-12 Quokka=40-41", &msg)); + tt_assert(! protover_all_supported("Link=3,5-12 Quokka=40-41", &msg)); tt_str_op(msg, OP_EQ, "Link=6-12 Quokka=40-41"); tor_free(msg); @@ -329,7 +329,7 @@ * headers. */ #define PROTOVER_LINKAUTH_V1 1 #define PROTOVER_LINKAUTH_V2 2 -#define PROTOVER_RELAY_V1 1 +#define PROTOVER_RELAY_V2 2 /* Deprecated HSIntro versions */ #define PROTOVER_HS_INTRO_DEPRECATED_1 1 @@ -397,7 +397,7 @@ /* Relay protovers do not appear anywhere in the code. */ tt_assert(protocol_list_supports_protocol(supported_protocols, PRT_RELAY, - PROTOVER_RELAY_V1)); + PROTOVER_RELAY_V2)); tt_assert(protocol_list_supports_protocol(supported_protocols, PRT_RELAY, PROTOVER_RELAY_EXTEND2)); diff -Nru tor-0.4.7.16/src/test/test_pt.c tor-0.4.9.6/src/test/test_pt.c --- tor-0.4.7.16/src/test/test_pt.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/test/test_pt.c 2026-03-25 14:30:34.000000000 +0000 @@ -31,6 +31,9 @@ mp->conf_state = PT_PROTO_LAUNCHED; SMARTLIST_FOREACH(mp->transports, transport_t *, t, transport_free(t)); smartlist_clear(mp->transports); + + tor_free(mp->version); + tor_free(mp->implementation); } static void @@ -143,6 +146,131 @@ } static void +test_pt_status_parsing(void *arg) +{ + char line[200]; + char *test_binary = tor_strdup("test-pt"); + char *argv[] = { + test_binary, + NULL, + }; + + managed_proxy_t *mp = tor_malloc_zero(sizeof(managed_proxy_t)); + (void)arg; + mp->conf_state = PT_PROTO_INFANT; + mp->transports = smartlist_new(); + mp->argv = argv; + + /* STATUS TYPE=version messages. */ + tt_ptr_op(mp->version, OP_EQ, NULL); + tt_ptr_op(mp->implementation, OP_EQ, NULL); + + /* Normal case. */ + strlcpy(line, "STATUS " + "IMPLEMENTATION=xyz " + "TYPE=version " + "VERSION=\"1.33.7-hax beta\"", + sizeof(line)); + handle_proxy_line(line, mp); + + tt_str_op(mp->version, OP_EQ, "1.33.7-hax beta"); + tt_str_op(mp->implementation, OP_EQ, "xyz"); + reset_mp(mp); + + /* Normal case but different case for TYPE value. */ + strlcpy(line, "STATUS " + "IMPLEMENTATION=xyz " + "TYPE=vErSiON " + "VERSION=\"1.33.7-hax beta\"", + sizeof(line)); + handle_proxy_line(line, mp); + + tt_str_op(mp->version, OP_EQ, "1.33.7-hax beta"); + tt_str_op(mp->implementation, OP_EQ, "xyz"); + reset_mp(mp); + + /* IMPLEMENTATION and VERSION set but no TYPE. */ + strlcpy(line, "STATUS " + "IMPLEMENTATION=xyz " + "VERSION=\"1.33.7-hax beta\"", + sizeof(line)); + handle_proxy_line(line, mp); + + tt_assert(mp->version == NULL); + tt_assert(mp->implementation == NULL); + reset_mp(mp); + + /* Multiple TYPE= is not allowed. */ + strlcpy(line, "STATUS " + "IMPLEMENTATION=xyz " + "TYPE=version " + "VERSION=\"1.33.7-hax beta\" " + "TYPE=nothing", + sizeof(line)); + handle_proxy_line(line, mp); + + tt_assert(mp->version == NULL); + tt_assert(mp->implementation == NULL); + reset_mp(mp); + + /* Multiple TYPE= is not allowed. */ + strlcpy(line, "STATUS " + "IMPLEMENTATION=xyz " + "TYPE=version " + "VERSION=\"1.33.7-hax beta\" " + "TYPE=version", + sizeof(line)); + handle_proxy_line(line, mp); + + tt_assert(mp->version == NULL); + tt_assert(mp->implementation == NULL); + reset_mp(mp); + + /* Missing VERSION. */ + strlcpy(line, "STATUS " + "TYPE=version " + "IMPLEMENTATION=xyz ", + sizeof(line)); + handle_proxy_line(line, mp); + + tt_assert(mp->version == NULL); + tt_assert(mp->implementation == NULL); + reset_mp(mp); + + /* Many IMPLEMENTATION and VERSION. First found are used. */ + strlcpy(line, "STATUS " + "TYPE=version " + "IMPLEMENTATION=xyz " + "VERSION=\"1.33.7-hax beta\" " + "IMPLEMENTATION=abc " + "VERSION=\"2.33.7-hax beta\" ", + sizeof(line)); + handle_proxy_line(line, mp); + + tt_str_op(mp->version, OP_EQ, "1.33.7-hax beta"); + tt_str_op(mp->implementation, OP_EQ, "xyz"); + reset_mp(mp); + + /* Control characters. Invalid input. */ + strlcpy(line, "STATUS " + "TYPE=version " + "IMPLEMENTATION=xyz\0abc " + "VERSION=\"1.33.7-hax beta\"\0.3 ", + sizeof(line)); + handle_proxy_line(line, mp); + + tt_assert(mp->version == NULL); + tt_assert(mp->implementation == NULL); + reset_mp(mp); + + done: + reset_mp(mp); + smartlist_free(mp->transports); + tor_free(mp); + tor_free(test_binary); +} + +static void test_pt_get_transport_options(void *arg) { char **execve_args; @@ -285,7 +413,9 @@ tt_assert(s); tt_str_op(s, OP_EQ, "transport hagbard 127.0.0.1:5555\n" - "transport celine 127.0.0.1:1723 card=no-enemy\n"); + "transport-info\n" + "transport celine 127.0.0.1:1723 card=no-enemy\n" + "transport-info\n"); done: /* XXXX clean up better */ @@ -590,6 +720,7 @@ struct testcase_t pt_tests[] = { PT_LEGACY(parsing), + PT_LEGACY(status_parsing), PT_LEGACY(protocol), { "get_transport_options", test_pt_get_transport_options, TT_FORK, NULL, NULL }, diff -Nru tor-0.4.7.16/src/test/test_rebind.sh tor-0.4.9.6/src/test/test_rebind.sh --- tor-0.4.7.16/src/test/test_rebind.sh 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/test/test_rebind.sh 2026-03-25 14:30:34.000000000 +0000 @@ -48,9 +48,10 @@ tmpdir= # For some reasons, shellcheck is not seeing that we can call this # function from the trap below. -# shellcheck disable=SC2317 +# shellcheck disable=SC2317,SC2329 clean () { if [ -n "$tmpdir" ] && [ -d "$tmpdir" ]; then + ls -l "$tmpdir" rm -rf "$tmpdir" fi } diff -Nru tor-0.4.7.16/src/test/test_relaycell.c tor-0.4.9.6/src/test/test_relaycell.c --- tor-0.4.7.16/src/test/test_relaycell.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/test/test_relaycell.c 2026-03-25 14:30:34.000000000 +0000 @@ -19,6 +19,7 @@ #include "core/or/connection_edge.h" #include "core/or/sendme.h" #include "core/or/relay.h" +#include "core/or/relay_msg.h" #include "test/test.h" #include "test/log_test_helpers.h" @@ -172,19 +173,20 @@ return entryconn; } -#define PACK_CELL(id, cmd, body_s) do { \ - memset(&cell, 0, sizeof(cell)); \ - memset(&rh, 0, sizeof(rh)); \ - memcpy(cell.payload+RELAY_HEADER_SIZE, (body_s), sizeof((body_s))-1); \ - rh.length = sizeof((body_s))-1; \ - rh.command = (cmd); \ - rh.stream_id = (id); \ - relay_header_pack((uint8_t*)&cell.payload, &rh); \ +#define PACK_CELL(id, cmd, body_s) do { \ + len_tmp = sizeof(body_s)-1; \ + relay_msg_free(msg); \ + msg = tor_malloc_zero(sizeof(relay_msg_t)); \ + msg->command = (cmd); \ + msg->stream_id = (id); \ + msg->body = cell_buf; \ + msg->length = len_tmp; \ + memcpy(cell_buf, (body_s), len_tmp); \ } while (0) #define ASSERT_COUNTED_BW() do { \ - tt_int_op(circ->n_delivered_read_circ_bw, OP_EQ, delivered+rh.length); \ + tt_int_op(circ->n_delivered_read_circ_bw, OP_EQ, delivered+msg->length); \ tt_int_op(circ->n_overhead_read_circ_bw, OP_EQ, \ - overhead+RELAY_PAYLOAD_SIZE-rh.length); \ + overhead+RELAY_PAYLOAD_SIZE-msg->length); \ delivered = circ->n_delivered_read_circ_bw; \ overhead = circ->n_overhead_read_circ_bw; \ } while (0) @@ -196,14 +198,15 @@ static int subtest_circbw_halfclosed(origin_circuit_t *circ, streamid_t init_id) { - cell_t cell; - relay_header_t rh; + relay_msg_t *msg = NULL; + size_t len_tmp; edge_connection_t *edgeconn; entry_connection_t *entryconn2=NULL; entry_connection_t *entryconn3=NULL; entry_connection_t *entryconn4=NULL; int delivered = circ->n_delivered_read_circ_bw; int overhead = circ->n_overhead_read_circ_bw; + uint8_t cell_buf[RELAY_PAYLOAD_SIZE_MAX]; /* Make new entryconns */ entryconn2 = fake_entry_conn(circ, init_id); @@ -225,36 +228,36 @@ /* Data cell not in the half-opened list */ PACK_CELL(4000, RELAY_COMMAND_DATA, "Data1234"); if (circ->base_.purpose == CIRCUIT_PURPOSE_PATH_BIAS_TESTING) - pathbias_count_valid_cells(TO_CIRCUIT(circ), &cell); + pathbias_count_valid_cells(TO_CIRCUIT(circ), msg); else - connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), NULL, + connection_edge_process_relay_cell(msg, TO_CIRCUIT(circ), NULL, circ->cpath); ASSERT_UNCOUNTED_BW(); /* Sendme cell not in the half-opened list */ PACK_CELL(4000, RELAY_COMMAND_SENDME, "Data1234"); if (circ->base_.purpose == CIRCUIT_PURPOSE_PATH_BIAS_TESTING) - pathbias_count_valid_cells(TO_CIRCUIT(circ), &cell); + pathbias_count_valid_cells(TO_CIRCUIT(circ), msg); else - connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), NULL, + connection_edge_process_relay_cell(msg, TO_CIRCUIT(circ), NULL, circ->cpath); ASSERT_UNCOUNTED_BW(); /* Connected cell not in the half-opened list */ PACK_CELL(4000, RELAY_COMMAND_CONNECTED, "Data1234"); if (circ->base_.purpose == CIRCUIT_PURPOSE_PATH_BIAS_TESTING) - pathbias_count_valid_cells(TO_CIRCUIT(circ), &cell); + pathbias_count_valid_cells(TO_CIRCUIT(circ), msg); else - connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), NULL, + connection_edge_process_relay_cell(msg, TO_CIRCUIT(circ), NULL, circ->cpath); ASSERT_UNCOUNTED_BW(); /* Resolved cell not in the half-opened list */ PACK_CELL(4000, RELAY_COMMAND_RESOLVED, "Data1234"); if (circ->base_.purpose == CIRCUIT_PURPOSE_PATH_BIAS_TESTING) - pathbias_count_valid_cells(TO_CIRCUIT(circ), &cell); + pathbias_count_valid_cells(TO_CIRCUIT(circ), msg); else - connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), NULL, + connection_edge_process_relay_cell(msg, TO_CIRCUIT(circ), NULL, circ->cpath); ASSERT_UNCOUNTED_BW(); @@ -262,9 +265,9 @@ edgeconn = ENTRY_TO_EDGE_CONN(entryconn2); PACK_CELL(edgeconn->stream_id, RELAY_COMMAND_CONNECTED, "Data1234"); if (circ->base_.purpose == CIRCUIT_PURPOSE_PATH_BIAS_TESTING) - pathbias_count_valid_cells(TO_CIRCUIT(circ), &cell); + pathbias_count_valid_cells(TO_CIRCUIT(circ), msg); else - connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), NULL, + connection_edge_process_relay_cell(msg, TO_CIRCUIT(circ), NULL, circ->cpath); ASSERT_UNCOUNTED_BW(); @@ -273,9 +276,9 @@ ENTRY_TO_CONN(entryconn2)->marked_for_close = 0; PACK_CELL(edgeconn->stream_id, RELAY_COMMAND_DATA, "Data1234"); if (circ->base_.purpose == CIRCUIT_PURPOSE_PATH_BIAS_TESTING) - pathbias_count_valid_cells(TO_CIRCUIT(circ), &cell); + pathbias_count_valid_cells(TO_CIRCUIT(circ), msg); else - connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), NULL, + connection_edge_process_relay_cell(msg, TO_CIRCUIT(circ), NULL, circ->cpath); ASSERT_COUNTED_BW(); data_cells--; @@ -283,9 +286,9 @@ ENTRY_TO_CONN(entryconn2)->marked_for_close = 0; PACK_CELL(edgeconn->stream_id, RELAY_COMMAND_DATA, "Data1234"); if (circ->base_.purpose == CIRCUIT_PURPOSE_PATH_BIAS_TESTING) - pathbias_count_valid_cells(TO_CIRCUIT(circ), &cell); + pathbias_count_valid_cells(TO_CIRCUIT(circ), msg); else - connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), NULL, + connection_edge_process_relay_cell(msg, TO_CIRCUIT(circ), NULL, circ->cpath); ASSERT_UNCOUNTED_BW(); @@ -294,9 +297,9 @@ ENTRY_TO_CONN(entryconn2)->marked_for_close = 0; PACK_CELL(edgeconn->stream_id, RELAY_COMMAND_SENDME, "Data1234"); if (circ->base_.purpose == CIRCUIT_PURPOSE_PATH_BIAS_TESTING) - pathbias_count_valid_cells(TO_CIRCUIT(circ), &cell); + pathbias_count_valid_cells(TO_CIRCUIT(circ), msg); else - connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), NULL, + connection_edge_process_relay_cell(msg, TO_CIRCUIT(circ), NULL, circ->cpath); ASSERT_COUNTED_BW(); sendme_cells--; @@ -304,9 +307,9 @@ ENTRY_TO_CONN(entryconn2)->marked_for_close = 0; PACK_CELL(edgeconn->stream_id, RELAY_COMMAND_SENDME, "Data1234"); if (circ->base_.purpose == CIRCUIT_PURPOSE_PATH_BIAS_TESTING) - pathbias_count_valid_cells(TO_CIRCUIT(circ), &cell); + pathbias_count_valid_cells(TO_CIRCUIT(circ), msg); else - connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), NULL, + connection_edge_process_relay_cell(msg, TO_CIRCUIT(circ), NULL, circ->cpath); ASSERT_UNCOUNTED_BW(); @@ -314,18 +317,18 @@ ENTRY_TO_CONN(entryconn2)->marked_for_close = 0; PACK_CELL(edgeconn->stream_id, RELAY_COMMAND_END, "Data1234"); if (circ->base_.purpose == CIRCUIT_PURPOSE_PATH_BIAS_TESTING) - pathbias_count_valid_cells(TO_CIRCUIT(circ), &cell); + pathbias_count_valid_cells(TO_CIRCUIT(circ), msg); else - connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), NULL, + connection_edge_process_relay_cell(msg, TO_CIRCUIT(circ), NULL, circ->cpath); ASSERT_COUNTED_BW(); ENTRY_TO_CONN(entryconn2)->marked_for_close = 0; PACK_CELL(edgeconn->stream_id, RELAY_COMMAND_END, "Data1234"); if (circ->base_.purpose == CIRCUIT_PURPOSE_PATH_BIAS_TESTING) - pathbias_count_valid_cells(TO_CIRCUIT(circ), &cell); + pathbias_count_valid_cells(TO_CIRCUIT(circ), msg); else - connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), NULL, + connection_edge_process_relay_cell(msg, TO_CIRCUIT(circ), NULL, circ->cpath); ASSERT_UNCOUNTED_BW(); @@ -335,7 +338,7 @@ /* sendme cell on open entryconn with full window */ PACK_CELL(edgeconn->stream_id, RELAY_COMMAND_SENDME, "Data1234"); int ret = - connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), edgeconn, + connection_edge_process_relay_cell(msg, TO_CIRCUIT(circ), edgeconn, circ->cpath); tt_int_op(ret, OP_EQ, -END_CIRC_REASON_TORPROTOCOL); ASSERT_UNCOUNTED_BW(); @@ -346,18 +349,18 @@ connection_edge_reached_eof(edgeconn); PACK_CELL(edgeconn->stream_id, RELAY_COMMAND_CONNECTED, "Data1234"); if (circ->base_.purpose == CIRCUIT_PURPOSE_PATH_BIAS_TESTING) - pathbias_count_valid_cells(TO_CIRCUIT(circ), &cell); + pathbias_count_valid_cells(TO_CIRCUIT(circ), msg); else - connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), NULL, + connection_edge_process_relay_cell(msg, TO_CIRCUIT(circ), NULL, circ->cpath); ASSERT_COUNTED_BW(); ENTRY_TO_CONN(entryconn3)->marked_for_close = 0; PACK_CELL(edgeconn->stream_id, RELAY_COMMAND_CONNECTED, "Data1234"); if (circ->base_.purpose == CIRCUIT_PURPOSE_PATH_BIAS_TESTING) - pathbias_count_valid_cells(TO_CIRCUIT(circ), &cell); + pathbias_count_valid_cells(TO_CIRCUIT(circ), msg); else - connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), NULL, + connection_edge_process_relay_cell(msg, TO_CIRCUIT(circ), NULL, circ->cpath); ASSERT_UNCOUNTED_BW(); @@ -365,16 +368,16 @@ ENTRY_TO_CONN(entryconn3)->marked_for_close = 0; PACK_CELL(edgeconn->stream_id, RELAY_COMMAND_END, "Data1234"); if (circ->base_.purpose == CIRCUIT_PURPOSE_PATH_BIAS_TESTING) - pathbias_count_valid_cells(TO_CIRCUIT(circ), &cell); + pathbias_count_valid_cells(TO_CIRCUIT(circ), msg); else - connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), NULL, + connection_edge_process_relay_cell(msg, TO_CIRCUIT(circ), NULL, circ->cpath); ASSERT_COUNTED_BW(); ENTRY_TO_CONN(entryconn3)->marked_for_close = 0; PACK_CELL(edgeconn->stream_id, RELAY_COMMAND_SENDME, "Data1234"); ret = - connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), NULL, + connection_edge_process_relay_cell(msg, TO_CIRCUIT(circ), NULL, circ->cpath); tt_int_op(ret, OP_NE, -END_CIRC_REASON_TORPROTOCOL); ASSERT_UNCOUNTED_BW(); @@ -382,9 +385,9 @@ ENTRY_TO_CONN(entryconn3)->marked_for_close = 0; PACK_CELL(edgeconn->stream_id, RELAY_COMMAND_DATA, "Data1234"); if (circ->base_.purpose == CIRCUIT_PURPOSE_PATH_BIAS_TESTING) - pathbias_count_valid_cells(TO_CIRCUIT(circ), &cell); + pathbias_count_valid_cells(TO_CIRCUIT(circ), msg); else - connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), NULL, + connection_edge_process_relay_cell(msg, TO_CIRCUIT(circ), NULL, circ->cpath); ASSERT_UNCOUNTED_BW(); @@ -400,16 +403,16 @@ PACK_CELL(edgeconn->stream_id, RELAY_COMMAND_RESOLVED, "\x04\x04\x12\x00\x00\x01\x00\x00\x02\x00"); if (circ->base_.purpose == CIRCUIT_PURPOSE_PATH_BIAS_TESTING) - pathbias_count_valid_cells(TO_CIRCUIT(circ), &cell); + pathbias_count_valid_cells(TO_CIRCUIT(circ), msg); else - connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), NULL, + connection_edge_process_relay_cell(msg, TO_CIRCUIT(circ), NULL, circ->cpath); ASSERT_COUNTED_BW(); ENTRY_TO_CONN(entryconn4)->marked_for_close = 0; PACK_CELL(edgeconn->stream_id, RELAY_COMMAND_RESOLVED, "\x04\x04\x12\x00\x00\x01\x00\x00\x02\x00"); - connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), NULL, + connection_edge_process_relay_cell(msg, TO_CIRCUIT(circ), NULL, circ->cpath); ASSERT_UNCOUNTED_BW(); @@ -417,9 +420,9 @@ ENTRY_TO_CONN(entryconn4)->marked_for_close = 0; PACK_CELL(edgeconn->stream_id, RELAY_COMMAND_DATA, "Data1234"); if (circ->base_.purpose == CIRCUIT_PURPOSE_PATH_BIAS_TESTING) - pathbias_count_valid_cells(TO_CIRCUIT(circ), &cell); + pathbias_count_valid_cells(TO_CIRCUIT(circ), msg); else - connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), NULL, + connection_edge_process_relay_cell(msg, TO_CIRCUIT(circ), NULL, circ->cpath); ASSERT_UNCOUNTED_BW(); @@ -427,17 +430,19 @@ ENTRY_TO_CONN(entryconn4)->marked_for_close = 0; PACK_CELL(edgeconn->stream_id, RELAY_COMMAND_END, "Data1234"); if (circ->base_.purpose == CIRCUIT_PURPOSE_PATH_BIAS_TESTING) - pathbias_count_valid_cells(TO_CIRCUIT(circ), &cell); + pathbias_count_valid_cells(TO_CIRCUIT(circ), msg); else - connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), NULL, + connection_edge_process_relay_cell(msg, TO_CIRCUIT(circ), NULL, circ->cpath); ASSERT_UNCOUNTED_BW(); + relay_msg_free(msg); connection_free_minimal(ENTRY_TO_CONN(entryconn2)); connection_free_minimal(ENTRY_TO_CONN(entryconn3)); connection_free_minimal(ENTRY_TO_CONN(entryconn4)); return 1; done: + relay_msg_free(msg); connection_free_minimal(ENTRY_TO_CONN(entryconn2)); connection_free_minimal(ENTRY_TO_CONN(entryconn3)); connection_free_minimal(ENTRY_TO_CONN(entryconn4)); @@ -666,14 +671,15 @@ static void test_circbw_relay(void *arg) { - cell_t cell; - relay_header_t rh; + relay_msg_t *msg = NULL; + size_t len_tmp; tor_addr_t addr; edge_connection_t *edgeconn; entry_connection_t *entryconn1=NULL; origin_circuit_t *circ; int delivered = 0; int overhead = 0; + uint8_t cell_buf[RELAY_PAYLOAD_SIZE_MAX]; (void)arg; @@ -692,23 +698,22 @@ /* Stream id 0: Not counted */ PACK_CELL(0, RELAY_COMMAND_END, "Data1234"); - connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), edgeconn, + connection_edge_process_relay_cell(msg, TO_CIRCUIT(circ), edgeconn, circ->cpath); ASSERT_UNCOUNTED_BW(); /* Stream id 1: Counted */ PACK_CELL(1, RELAY_COMMAND_END, "Data1234"); - connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), edgeconn, + connection_edge_process_relay_cell(msg, TO_CIRCUIT(circ), edgeconn, circ->cpath); ASSERT_COUNTED_BW(); /* Properly formatted connect cell: counted */ PACK_CELL(1, RELAY_COMMAND_CONNECTED, "Data1234"); tor_addr_parse(&addr, "30.40.50.60"); - rh.length = connected_cell_format_payload(cell.payload+RELAY_HEADER_SIZE, - &addr, 1024); - relay_header_pack((uint8_t*)&cell.payload, &rh); \ - connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), edgeconn, + msg->length = connected_cell_format_payload(cell_buf, + &addr, 1024); + connection_edge_process_relay_cell(msg, TO_CIRCUIT(circ), edgeconn, circ->cpath); ASSERT_COUNTED_BW(); @@ -718,7 +723,7 @@ edgeconn->on_circuit = TO_CIRCUIT(circ); PACK_CELL(1, RELAY_COMMAND_RESOLVED, "\x04\x04\x12\x00\x00\x01\x00\x00\x02\x00"); - connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), edgeconn, + connection_edge_process_relay_cell(msg, TO_CIRCUIT(circ), edgeconn, circ->cpath); ASSERT_COUNTED_BW(); @@ -727,65 +732,65 @@ /* Connected cell after open: not counted */ PACK_CELL(1, RELAY_COMMAND_CONNECTED, "Data1234"); - connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), edgeconn, + connection_edge_process_relay_cell(msg, TO_CIRCUIT(circ), edgeconn, circ->cpath); ASSERT_UNCOUNTED_BW(); /* Resolved cell after open: not counted */ PACK_CELL(1, RELAY_COMMAND_RESOLVED, "Data1234"); - connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), edgeconn, + connection_edge_process_relay_cell(msg, TO_CIRCUIT(circ), edgeconn, circ->cpath); ASSERT_UNCOUNTED_BW(); /* Drop cell: not counted */ PACK_CELL(1, RELAY_COMMAND_DROP, "Data1234"); - connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), edgeconn, + connection_edge_process_relay_cell(msg, TO_CIRCUIT(circ), edgeconn, circ->cpath); ASSERT_UNCOUNTED_BW(); /* Data cell on stream 0: not counted */ PACK_CELL(0, RELAY_COMMAND_DATA, "Data1234"); - connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), edgeconn, + connection_edge_process_relay_cell(msg, TO_CIRCUIT(circ), edgeconn, circ->cpath); ASSERT_UNCOUNTED_BW(); /* Data cell on open connection: counted */ ENTRY_TO_CONN(entryconn1)->marked_for_close = 0; PACK_CELL(1, RELAY_COMMAND_DATA, "Data1234"); - connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), edgeconn, + connection_edge_process_relay_cell(msg, TO_CIRCUIT(circ), edgeconn, circ->cpath); ASSERT_COUNTED_BW(); /* Empty Data cell on open connection: not counted */ ENTRY_TO_CONN(entryconn1)->marked_for_close = 0; PACK_CELL(1, RELAY_COMMAND_DATA, ""); - connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), edgeconn, + connection_edge_process_relay_cell(msg, TO_CIRCUIT(circ), edgeconn, circ->cpath); ASSERT_UNCOUNTED_BW(); /* Sendme on valid stream: counted */ edgeconn->package_window -= STREAMWINDOW_INCREMENT; PACK_CELL(1, RELAY_COMMAND_SENDME, "Data1234"); - connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), edgeconn, + connection_edge_process_relay_cell(msg, TO_CIRCUIT(circ), edgeconn, circ->cpath); ASSERT_COUNTED_BW(); /* Sendme on valid stream with full window: not counted */ PACK_CELL(1, RELAY_COMMAND_SENDME, "Data1234"); edgeconn->package_window = STREAMWINDOW_START; - connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), edgeconn, + connection_edge_process_relay_cell(msg, TO_CIRCUIT(circ), edgeconn, circ->cpath); ASSERT_UNCOUNTED_BW(); /* Sendme on unknown stream: not counted */ PACK_CELL(1, RELAY_COMMAND_SENDME, "Data1234"); - connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), NULL, + connection_edge_process_relay_cell(msg, TO_CIRCUIT(circ), NULL, circ->cpath); ASSERT_UNCOUNTED_BW(); /* Sendme on circuit with full window: not counted */ PACK_CELL(0, RELAY_COMMAND_SENDME, "Data1234"); - connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), edgeconn, + connection_edge_process_relay_cell(msg, TO_CIRCUIT(circ), edgeconn, circ->cpath); ASSERT_UNCOUNTED_BW(); @@ -796,44 +801,44 @@ 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, + connection_edge_process_relay_cell(msg, TO_CIRCUIT(circ), edgeconn, circ->cpath); ASSERT_COUNTED_BW(); /* Invalid extended cell: not counted */ PACK_CELL(1, RELAY_COMMAND_EXTENDED2, "Data1234"); - connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), NULL, + connection_edge_process_relay_cell(msg, TO_CIRCUIT(circ), NULL, circ->cpath); ASSERT_UNCOUNTED_BW(); /* Invalid extended cell: not counted */ PACK_CELL(1, RELAY_COMMAND_EXTENDED, "Data1234"); - connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), NULL, + connection_edge_process_relay_cell(msg, TO_CIRCUIT(circ), NULL, circ->cpath); ASSERT_UNCOUNTED_BW(); /* Invalid HS cell: not counted */ PACK_CELL(1, RELAY_COMMAND_ESTABLISH_INTRO, "Data1234"); - connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), NULL, + connection_edge_process_relay_cell(msg, TO_CIRCUIT(circ), NULL, circ->cpath); ASSERT_UNCOUNTED_BW(); /* "Valid" HS cell in expected state: counted */ TO_CIRCUIT(circ)->purpose = CIRCUIT_PURPOSE_C_ESTABLISH_REND; PACK_CELL(1, RELAY_COMMAND_RENDEZVOUS_ESTABLISHED, "Data1234"); - connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), NULL, + connection_edge_process_relay_cell(msg, TO_CIRCUIT(circ), NULL, circ->cpath); ASSERT_COUNTED_BW(); /* End cell on non-closed connection: counted */ PACK_CELL(1, RELAY_COMMAND_END, "Data1234"); - connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), edgeconn, + connection_edge_process_relay_cell(msg, TO_CIRCUIT(circ), edgeconn, circ->cpath); ASSERT_COUNTED_BW(); /* End cell on connection that already got one: not counted */ PACK_CELL(1, RELAY_COMMAND_END, "Data1234"); - connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), NULL, + connection_edge_process_relay_cell(msg, TO_CIRCUIT(circ), NULL, circ->cpath); ASSERT_UNCOUNTED_BW(); @@ -848,10 +853,11 @@ /* Path bias: truncated */ tt_int_op(circ->base_.marked_for_close, OP_EQ, 0); PACK_CELL(0, RELAY_COMMAND_TRUNCATED, "Data1234"); - pathbias_count_valid_cells(TO_CIRCUIT(circ), &cell); + pathbias_count_valid_cells(TO_CIRCUIT(circ), msg); tt_int_op(circ->base_.marked_for_close, OP_EQ, 1); done: + relay_msg_free(msg); UNMOCK(connection_start_reading); UNMOCK(connection_mark_unattached_ap_); UNMOCK(connection_mark_for_close_internal_); @@ -872,17 +878,19 @@ { entry_connection_t *entryconn; edge_connection_t *edgeconn; - cell_t cell; - relay_header_t rh; + relay_msg_t *msg = NULL; int r; or_options_t *options = get_options_mutable(); + size_t len_tmp; + uint8_t cell_buf[RELAY_PAYLOAD_SIZE_MAX]; #define SET_CELL(s) do { \ - memset(&cell, 0, sizeof(cell)); \ - memset(&rh, 0, sizeof(rh)); \ - memcpy(cell.payload + RELAY_HEADER_SIZE, (s), sizeof((s))-1); \ - rh.length = sizeof((s))-1; \ - rh.command = RELAY_COMMAND_RESOLVED; \ + relay_msg_free(msg); \ + msg = tor_malloc_zero(sizeof(relay_msg_t)); \ + len_tmp = sizeof(s) - 1; \ + msg->body = cell_buf; \ + msg->length = len_tmp; \ + memcpy(cell_buf, s, len_tmp); \ } while (0) #define MOCK_RESET() do { \ srm_ncalls = mum_ncalls = 0; \ @@ -892,20 +900,20 @@ tt_ptr_op(mum_conn, OP_EQ, entryconn); \ tt_int_op(mum_endreason, OP_EQ, (reason)); \ } while (0) -#define ASSERT_RESOLVED_CALLED(atype, answer, ttl, expires) do { \ - tt_int_op(srm_ncalls, OP_EQ, 1); \ - tt_ptr_op(srm_conn, OP_EQ, entryconn); \ - tt_int_op(srm_atype, OP_EQ, (atype)); \ - if ((answer) != NULL) { \ - tt_int_op(srm_alen, OP_EQ, sizeof(answer)-1); \ - tt_int_op(srm_alen, OP_LT, 512); \ - tt_int_op(srm_answer_is_set, OP_EQ, 1); \ - tt_mem_op(srm_answer, OP_EQ, answer, sizeof(answer)-1); \ - } else { \ - tt_int_op(srm_answer_is_set, OP_EQ, 0); \ - } \ - tt_int_op(srm_ttl, OP_EQ, ttl); \ - tt_i64_op(srm_expires, OP_EQ, expires); \ +#define ASSERT_RESOLVED_CALLED(atype, answer, ttl, expires) do { \ + tt_int_op(srm_ncalls, OP_EQ, 1); \ + tt_ptr_op(srm_conn, OP_EQ, entryconn); \ + tt_int_op(srm_atype, OP_EQ, (atype)); \ + if ((answer) != NULL) { \ + tt_int_op(srm_alen, OP_EQ, sizeof(answer)-1); \ + tt_int_op(srm_alen, OP_LT, 512); \ + tt_int_op(srm_answer_is_set, OP_EQ, 1); \ + tt_mem_op(srm_answer, OP_EQ, answer, sizeof(answer)-1); \ + } else { \ + tt_int_op(srm_answer_is_set, OP_EQ, 0); \ + } \ + tt_int_op(srm_ttl, OP_EQ, ttl); \ + tt_i64_op(srm_expires, OP_EQ, expires); \ } while (0) (void)arg; @@ -930,7 +938,7 @@ /* Try with connection in non-RESOLVE_WAIT state: cell gets ignored */ MOCK_RESET(); - r = connection_edge_process_resolved_cell(edgeconn, &cell, &rh); + r = connection_edge_process_resolved_cell(edgeconn, msg); tt_int_op(r, OP_EQ, 0); tt_int_op(srm_ncalls, OP_EQ, 0); tt_int_op(mum_ncalls, OP_EQ, 0); @@ -944,7 +952,7 @@ /* We prefer ipv4, so we should get the first ipv4 answer */ MOCK_RESET(); - r = connection_edge_process_resolved_cell(edgeconn, &cell, &rh); + r = connection_edge_process_resolved_cell(edgeconn, msg); tt_int_op(r, OP_EQ, 0); ASSERT_MARK_CALLED(END_STREAM_REASON_DONE| END_STREAM_REASON_FLAG_ALREADY_SOCKS_REPLIED); @@ -953,7 +961,7 @@ /* But we may be discarding private answers. */ MOCK_RESET(); options->ClientDNSRejectInternalAddresses = 1; - r = connection_edge_process_resolved_cell(edgeconn, &cell, &rh); + r = connection_edge_process_resolved_cell(edgeconn, msg); tt_int_op(r, OP_EQ, 0); ASSERT_MARK_CALLED(END_STREAM_REASON_DONE| END_STREAM_REASON_FLAG_ALREADY_SOCKS_REPLIED); @@ -962,7 +970,7 @@ /* now prefer ipv6, and get the first ipv6 answer */ entryconn->entry_cfg.prefer_ipv6 = 1; MOCK_RESET(); - r = connection_edge_process_resolved_cell(edgeconn, &cell, &rh); + r = connection_edge_process_resolved_cell(edgeconn, msg); tt_int_op(r, OP_EQ, 0); ASSERT_MARK_CALLED(END_STREAM_REASON_DONE| END_STREAM_REASON_FLAG_ALREADY_SOCKS_REPLIED); @@ -974,7 +982,7 @@ /* With a cell that only has IPv4, we report IPv4 even if we prefer IPv6 */ MOCK_RESET(); SET_CELL("\x04\x04\x12\x00\x00\x01\x00\x00\x02\x00"); - r = connection_edge_process_resolved_cell(edgeconn, &cell, &rh); + r = connection_edge_process_resolved_cell(edgeconn, msg); tt_int_op(r, OP_EQ, 0); ASSERT_MARK_CALLED(END_STREAM_REASON_DONE| END_STREAM_REASON_FLAG_ALREADY_SOCKS_REPLIED); @@ -984,17 +992,17 @@ * ipv4 */ MOCK_RESET(); entryconn->entry_cfg.ipv4_traffic = 0; - r = connection_edge_process_resolved_cell(edgeconn, &cell, &rh); + r = connection_edge_process_resolved_cell(edgeconn, msg); tt_int_op(r, OP_EQ, 0); ASSERT_MARK_CALLED(END_STREAM_REASON_DONE| END_STREAM_REASON_FLAG_ALREADY_SOCKS_REPLIED); - ASSERT_RESOLVED_CALLED(RESOLVED_TYPE_ERROR, NULL, -1, -1); + ASSERT_RESOLVED_CALLED(RESOLVED_TYPE_NOERROR, NULL, -1, -1); /* If we wanted hostnames, we report nothing, since we only had IPs. */ MOCK_RESET(); entryconn->entry_cfg.ipv4_traffic = 1; entryconn->socks_request->command = SOCKS_COMMAND_RESOLVE_PTR; - r = connection_edge_process_resolved_cell(edgeconn, &cell, &rh); + r = connection_edge_process_resolved_cell(edgeconn, msg); tt_int_op(r, OP_EQ, 0); ASSERT_MARK_CALLED(END_STREAM_REASON_DONE| END_STREAM_REASON_FLAG_ALREADY_SOCKS_REPLIED); @@ -1003,7 +1011,7 @@ /* A hostname cell is fine though. */ MOCK_RESET(); SET_CELL("\x00\x0fwww.example.com\x00\x01\x00\x00"); - r = connection_edge_process_resolved_cell(edgeconn, &cell, &rh); + r = connection_edge_process_resolved_cell(edgeconn, msg); tt_int_op(r, OP_EQ, 0); ASSERT_MARK_CALLED(END_STREAM_REASON_DONE| END_STREAM_REASON_FLAG_ALREADY_SOCKS_REPLIED); @@ -1013,7 +1021,7 @@ MOCK_RESET(); entryconn->socks_request->command = SOCKS_COMMAND_RESOLVE; SET_CELL("\x04\x04\x01\x02\x03\x04"); /* no ttl */ - r = connection_edge_process_resolved_cell(edgeconn, &cell, &rh); + r = connection_edge_process_resolved_cell(edgeconn, msg); tt_int_op(r, OP_EQ, 0); ASSERT_MARK_CALLED(END_STREAM_REASON_TORPROTOCOL); tt_int_op(srm_ncalls, OP_EQ, 0); @@ -1024,7 +1032,7 @@ "\x04\x04\x7f\x00\x01\x02\x00\x00\x01\x00" /* IPv4: 192.168.1.1, ttl 256 */ "\x04\x04\xc0\xa8\x01\x01\x00\x00\x01\x00"); - r = connection_edge_process_resolved_cell(edgeconn, &cell, &rh); + r = connection_edge_process_resolved_cell(edgeconn, msg); tt_int_op(r, OP_EQ, 0); ASSERT_MARK_CALLED(END_STREAM_REASON_TORPROTOCOL); ASSERT_RESOLVED_CALLED(RESOLVED_TYPE_ERROR_TRANSIENT, NULL, 0, TIME_MAX); @@ -1032,13 +1040,14 @@ /* Legit error code */ MOCK_RESET(); SET_CELL("\xf0\x15" "quiet and meaningless" "\x00\x00\x0f\xff"); - r = connection_edge_process_resolved_cell(edgeconn, &cell, &rh); + r = connection_edge_process_resolved_cell(edgeconn, msg); tt_int_op(r, OP_EQ, 0); ASSERT_MARK_CALLED(END_STREAM_REASON_DONE| END_STREAM_REASON_FLAG_ALREADY_SOCKS_REPLIED); ASSERT_RESOLVED_CALLED(RESOLVED_TYPE_ERROR_TRANSIENT, NULL, -1, -1); done: + relay_msg_free(msg); UNMOCK(connection_mark_unattached_ap_); UNMOCK(connection_ap_handshake_socks_resolved); } diff -Nru tor-0.4.7.16/src/test/test_relaycrypt.c tor-0.4.9.6/src/test/test_relaycrypt.c --- tor-0.4.7.16/src/test/test_relaycrypt.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/test/test_relaycrypt.c 2026-03-25 14:30:34.000000000 +0000 @@ -19,11 +19,18 @@ #include "test/test.h" -static const char KEY_MATERIAL[3][CPATH_KEY_MATERIAL_LEN] = { +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wattributes" +#endif +NONSTRING static const char KEY_MATERIAL[3][CPATH_KEY_MATERIAL_LEN] = { " 'My public key is in this signed x509 object', said Tom assertively.", "'Let's chart the pedal phlanges in the tomb', said Tom cryptographically", " 'Segmentation fault bugs don't _just happen_', said Tom seethingly.", }; +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif typedef struct testing_circuitset_t { or_circuit_t *or_circ[3]; @@ -42,17 +49,18 @@ for (i=0; i<3; ++i) { cs->or_circ[i] = or_circuit_new(0, NULL); tt_int_op(0, OP_EQ, - relay_crypto_init(&cs->or_circ[i]->crypto, - KEY_MATERIAL[i], sizeof(KEY_MATERIAL[i]), - 0, 0)); + relay_crypto_init(RELAY_CRYPTO_ALG_TOR1, + &cs->or_circ[i]->crypto, + KEY_MATERIAL[i], sizeof(KEY_MATERIAL[i]))); } cs->origin_circ = origin_circuit_new(); 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->pvt_crypto, KEY_MATERIAL[i], - sizeof(KEY_MATERIAL[i]), 0, 0); + relay_crypto_init(RELAY_CRYPTO_ALG_TOR1, + &hop->pvt_crypto, KEY_MATERIAL[i], + sizeof(KEY_MATERIAL[i])); hop->state = CPATH_STATE_OPEN; cpath_extend_linked_list(&cs->origin_circ->cpath, hop); tt_ptr_op(hop, OP_EQ, cs->origin_circ->cpath->prev); @@ -189,4 +197,3 @@ TEST(inbound), END_OF_TESTCASES }; - diff -Nru tor-0.4.7.16/src/test/test_router.c tor-0.4.9.6/src/test/test_router.c --- tor-0.4.7.16/src/test/test_router.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/test/test_router.c 2026-03-25 14:30:34.000000000 +0000 @@ -60,8 +60,8 @@ mock_routerinfo->identity_pkey = crypto_pk_dup_key(ident_key); mock_routerinfo->protocol_list = tor_strdup("Cons=1-2 Desc=1-2 DirCache=1-2"); - router_set_rsa_onion_pkey(tap_key, &mock_routerinfo->onion_pkey, - &mock_routerinfo->onion_pkey_len); + router_set_rsa_onion_pkey(tap_key, &mock_routerinfo->tap_onion_pkey, + &mock_routerinfo->tap_onion_pkey_len); mock_routerinfo->bandwidthrate = 9001; mock_routerinfo->bandwidthburst = 9002; @@ -282,7 +282,6 @@ mock_ns = &ns; mock_ns->valid_after = now-3600; mock_rs = &rs; - mock_rs->published_on = now - 10; // no reason to mark this time. desc_clean_since = now-10; @@ -302,25 +301,14 @@ tt_i64_op(desc_clean_since, OP_EQ, 0); tt_str_op(desc_dirty_reason, OP_EQ, "time for new descriptor"); - // Version in consensus published a long time ago? We won't mark it - // if it's been clean for only a short time. desc_clean_since = now - 10; desc_dirty_reason = NULL; - mock_rs->published_on = now - 3600 * 96; mark_my_descriptor_dirty_if_too_old(now); tt_i64_op(desc_clean_since, OP_EQ, now - 10); - // ... but if it's been clean a while, we mark. - desc_clean_since = now - 2 * 3600; - mark_my_descriptor_dirty_if_too_old(now); - tt_i64_op(desc_clean_since, OP_EQ, 0); - tt_str_op(desc_dirty_reason, OP_EQ, - "version listed in consensus is quite old"); - - // same deal if we're marked stale. + // Version in consensus marked as stale? We'll mark it. desc_clean_since = now - 2 * 3600; desc_dirty_reason = NULL; - mock_rs->published_on = now - 10; mock_rs->is_staledesc = 1; mark_my_descriptor_dirty_if_too_old(now); tt_i64_op(desc_clean_since, OP_EQ, 0); diff -Nru tor-0.4.7.16/src/test/test_routerkeys.c tor-0.4.9.6/src/test/test_routerkeys.c --- tor-0.4.7.16/src/test/test_routerkeys.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/test/test_routerkeys.c 2026-03-25 14:30:34.000000000 +0000 @@ -5,6 +5,7 @@ #include "orconfig.h" #define ROUTER_PRIVATE +#define ROUTERKEYS_PRIVATE #include "core/or/or.h" #include "app/config/config.h" #include "feature/relay/router.h" @@ -735,6 +736,87 @@ tor_free(cc); } +static void +test_routerkeys_family_key_fname(void *arg) +{ + (void)arg; + + tt_assert(is_family_key_fname("hello.secret_family_key")); + tt_assert(is_family_key_fname("xyzzy.secret_family_key")); + tt_assert(is_family_key_fname("909.secret_family_key")); + tt_assert(! is_family_key_fname("zzz.secret_family_key~")); + tt_assert(! is_family_key_fname("secret_family_key")); + + done: + ; +} + +static void +test_routerkeys_load_family_keys(void *arg) +{ + (void) arg; + char *dname = tor_strdup(get_fname_rnd("fkeys")); + char *fname = NULL; + or_options_t *options = get_options_mutable(); + ed25519_public_key_t pubkey; + +#ifdef _WIN32 + tt_assert(0==mkdir(dname)); +#else + tt_assert(0==mkdir(dname,0700)); +#endif + + options->FamilyIds = smartlist_new(); + + // Not a family key, will be ignored + tor_asprintf(&fname, "%s"PATH_SEPARATOR"junk.1", dname); + write_str_to_file(fname, "hello world", 0); + tor_free(fname); + + tt_int_op(0, OP_EQ, load_family_id_keys_impl(options, dname)); + tt_int_op(0, OP_EQ, smartlist_len(get_current_family_id_keys())); + + // Create a family key; make sure we can load it. + tor_asprintf(&fname, "%s"PATH_SEPARATOR"cg.secret_family_key", dname); + tt_int_op(0, OP_EQ, create_family_id_key(fname, &pubkey)); + tor_free(fname); + smartlist_add(options->FamilyIds, tor_memdup(&pubkey, sizeof(pubkey))); + + tt_int_op(0, OP_EQ, load_family_id_keys_impl(options, dname)); + tt_int_op(1, OP_EQ, smartlist_len(get_current_family_id_keys())); + + //Try a second key. + tor_asprintf(&fname, "%s"PATH_SEPARATOR"eb.secret_family_key", dname); + tt_int_op(0, OP_EQ, create_family_id_key(fname, &pubkey)); + smartlist_add(options->FamilyIds, tor_memdup(&pubkey, sizeof(pubkey))); + tor_free(fname); + + tt_int_op(0, OP_EQ, load_family_id_keys_impl(options, dname)); + tt_int_op(2, OP_EQ, smartlist_len(get_current_family_id_keys())); + + // Try an unlisted key, make sure it isn't loaded. + tor_asprintf(&fname, "%s"PATH_SEPARATOR"gt.secret_family_key", dname); + tt_int_op(0, OP_EQ, create_family_id_key(fname, &pubkey)); + // Do not add to FamilyIDs here; we're leaving it unlisted. + tor_free(fname); + + tt_int_op(0, OP_EQ, load_family_id_keys_impl(options, dname)); + tt_int_op(2, OP_EQ, smartlist_len(get_current_family_id_keys())); + + // Make a junk key, make sure it causes an error. + tor_asprintf(&fname, "%s"PATH_SEPARATOR"xyz.secret_family_key", dname); + write_str_to_file(fname, "hello world", 0); + tor_free(fname); + + tt_int_op(-1, OP_EQ, load_family_id_keys_impl(options, dname)); + // keys unchanged + tt_int_op(2, OP_EQ, smartlist_len(get_current_family_id_keys())); + + done: + tor_free(dname); + tor_free(fname); +} + #define TEST(name, flags) \ { #name , test_routerkeys_ ## name, (flags), NULL, NULL } @@ -749,5 +831,7 @@ TEST(cross_certify_ntor, 0), TEST(cross_certify_tap, 0), TEST(rsa_ed_crosscert, 0), + TEST(family_key_fname, 0), + TEST(load_family_keys, TT_FORK), END_OF_TESTCASES }; diff -Nru tor-0.4.7.16/src/test/test_sandbox.c tor-0.4.9.6/src/test/test_sandbox.c --- tor-0.4.7.16/src/test/test_sandbox.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/test/test_sandbox.c 2026-03-25 14:30:34.000000000 +0000 @@ -12,6 +12,8 @@ #include "orconfig.h" #include "lib/sandbox/sandbox.h" +#include "lib/crypt_ops/crypto_rand.h" +#include "ext/equix/include/equix.h" #ifdef USE_LIBSECCOMP @@ -292,6 +294,58 @@ (void)0; } +/** This is a simplified subset of test_crypto_equix(), running one solve + * and one verify from inside the sandbox. The sandbox restricts mprotect, and + * hashx will experience a failure at runtime which this test case exercises. + * The result of the solve and verify should both still be correct, since we + * expect it to cleanly fall back on an interpreted implementation which has + * no operating system dependencies. */ +static void +test_sandbox_crypto_equix(void *arg) +{ + (void)arg; + + const char *challenge_literal = "abce"; + const size_t challenge_len = strlen(challenge_literal); + const size_t num_sols = 4; + static const equix_solution sols_expected[EQUIX_MAX_SOLS] = { + {{ 0x4fca, 0x72eb, 0x101f, 0xafab, 0x1add, 0x2d71, 0x75a3, 0xc978 }}, + {{ 0x17f1, 0x7aa6, 0x23e3, 0xab00, 0x7e2f, 0x917e, 0x16da, 0xda9e }}, + {{ 0x70ee, 0x7757, 0x8a54, 0xbd2b, 0x90e4, 0xe31e, 0x2085, 0xe47e }}, + {{ 0x62c5, 0x86d1, 0x5752, 0xe1f0, 0x12da, 0x8f33, 0x7336, 0xf161 }}, + }; + + equix_solutions_buffer output; + equix_ctx *solve_ctx = NULL, *verify_ctx = NULL; + + solve_ctx = equix_alloc(EQUIX_CTX_SOLVE | EQUIX_CTX_TRY_COMPILE); + tt_ptr_op(solve_ctx, OP_NE, NULL); + + equix_result result; + memset(&output, 0xEE, sizeof output); + result = equix_solve(solve_ctx, challenge_literal, challenge_len, &output); + tt_int_op(result, OP_EQ, EQUIX_OK); + tt_int_op(output.count, OP_EQ, num_sols); + tt_int_op(output.flags, OP_EQ, 0); /* EQUIX_SOLVER_DID_USE_COMPILER unset */ + tt_mem_op(output.sols, OP_EQ, sols_expected, + num_sols * sizeof(equix_solution)); + + verify_ctx = equix_alloc(EQUIX_CTX_VERIFY | EQUIX_CTX_TRY_COMPILE); + tt_ptr_op(verify_ctx, OP_NE, NULL); + + /* Test one of the solutions randomly */ + const unsigned sol_i = crypto_rand_int(num_sols); + equix_solution *sol = &output.sols[sol_i]; + + result = equix_verify(verify_ctx, challenge_literal, + challenge_len, sol); + tt_int_op(EQUIX_OK, OP_EQ, result); + + done: + equix_free(solve_ctx); + equix_free(verify_ctx); +} + #define SANDBOX_TEST_SKIPPED(name) \ { #name, test_sandbox_ ## name, TT_SKIP, NULL, NULL } @@ -310,22 +364,32 @@ struct testcase_t sandbox_tests[] = { SANDBOX_TEST(is_active, TT_FORK), -/* When Tor is built with fragile compiler-hardening the sandbox is unable to - * filter requests to open files or directories (on systems where glibc uses - * the "open" system call to provide this functionality), as doing so would +/* When Tor is built with fragile compiler-hardening the sandbox is usually + * unable to filter requests to open files or directories, as doing so would * interfere with the address sanitizer as it retrieves information about the * running process via the filesystem. Skip these tests in that case as the * corresponding functions are likely to have no effect and this will cause the * tests to fail. */ #ifdef ENABLE_FRAGILE_HARDENING SANDBOX_TEST_SKIPPED(open_filename), + SANDBOX_TEST_SKIPPED(openat_filename), SANDBOX_TEST_SKIPPED(opendir_dirname), #else SANDBOX_TEST_IN_SANDBOX(open_filename), - SANDBOX_TEST_IN_SANDBOX(opendir_dirname), + SANDBOX_TEST_IN_SANDBOX(openat_filename), #endif /* defined(ENABLE_FRAGILE_HARDENING) */ - SANDBOX_TEST_IN_SANDBOX(openat_filename), + /* Ok why... Quick answer is #40918. This has been failing on Debian SID + * making us unable to have nightly packages which is a problem as we have + * several relay operators using them and actively reporting us issues with + * them. This test fails due to the sandbox denying it. + * + * We are deprecating C-tor slowly and honestly, the Sandbox feature has + * always been a source of pain and unhappiness. Disable this as finding why, + * fixing it and hoping it doesn't come back will mostly be a waste of our + * time at this point. */ + SANDBOX_TEST_SKIPPED(opendir_dirname), + SANDBOX_TEST_IN_SANDBOX(chmod_filename), SANDBOX_TEST_IN_SANDBOX(chown_filename), SANDBOX_TEST_IN_SANDBOX(rename_filename), @@ -343,6 +407,8 @@ #else SANDBOX_TEST_SKIPPED(stat_filename), #endif + + SANDBOX_TEST_IN_SANDBOX(crypto_equix), END_OF_TESTCASES }; diff -Nru tor-0.4.7.16/src/test/test_scheduler.c tor-0.4.9.6/src/test/test_scheduler.c --- tor-0.4.7.16/src/test/test_scheduler.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/test/test_scheduler.c 2026-03-25 14:30:34.000000000 +0000 @@ -81,8 +81,7 @@ (void)default_val; (void)min_val; (void)max_val; - // only support KISTSchedRunInterval right now - tor_assert(strcmp(param_name, "KISTSchedRunInterval")==0); + (void)param_name; return 0; } @@ -95,8 +94,7 @@ (void)default_val; (void)min_val; (void)max_val; - // only support KISTSchedRunInterval right now - tor_assert(strcmp(param_name, "KISTSchedRunInterval")==0); + (void)param_name; return 12; } @@ -863,7 +861,7 @@ /* We have specified nothing in the torrc and there's no consensus so the * KIST scheduler is what should be in use */ tt_ptr_op(the_scheduler, OP_EQ, get_kist_scheduler()); - tt_int_op(sched_run_interval, OP_EQ, 10); + tt_int_op(sched_run_interval, OP_EQ, KIST_SCHED_RUN_INTERVAL_DEFAULT); scheduler_free_all(); @@ -906,7 +904,7 @@ #else /* HAVE_KIST_SUPPORT */ tt_int_op(res_should, OP_EQ, 0); #endif /* HAVE_KIST_SUPPORT */ - tt_int_op(res_freq, OP_EQ, 10); + tt_int_op(res_freq, OP_EQ, KIST_SCHED_RUN_INTERVAL_DEFAULT); /* Test defer to consensus, and kist consensus available */ MOCK(networkstatus_get_param, mock_kist_networkstatus_get_param); diff -Nru tor-0.4.7.16/src/test/test_sendme.c tor-0.4.9.6/src/test/test_sendme.c --- tor-0.4.7.16/src/test/test_sendme.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/test/test_sendme.c 2026-03-25 14:30:34.000000000 +0000 @@ -7,6 +7,7 @@ #define NETWORKSTATUS_PRIVATE #define SENDME_PRIVATE #define RELAY_PRIVATE +#define RELAY_CELL_PRIVATE #include "core/or/circuit_st.h" #include "core/or/or_circuit_st.h" @@ -152,26 +153,28 @@ 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); + ret = build_cell_payload_v1(digest, 20, 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); + tt_int_op(sendme_is_valid(circ, NULL, 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); + tt_int_op(sendme_is_valid(circ, NULL, (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); + tt_int_op(sendme_is_valid(circ, NULL, 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(); @@ -181,18 +184,20 @@ 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); + tt_int_op(sendme_is_valid(circ, NULL, 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)); + memcpy(or_circ->crypto.c.tor1.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); + tt_int_op(sendme_is_valid(circ, NULL, 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); @@ -202,48 +207,6 @@ } 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; @@ -275,9 +238,11 @@ 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)); + or_circuit_t *or_circ = or_circuit_new(0, NULL); + crypt_path_t *cpath = NULL; + circuit_t *c = TO_CIRCUIT(or_circ); + + or_circ->relay_cell_format = RELAY_CELL_FORMAT_V0; /* check initial conditions. */ circuit_reset_sendme_randomness(c); @@ -288,15 +253,16 @@ /* 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); + size_t n = connection_edge_get_inbuf_bytes_to_package(10000, 0, c, cpath); tt_uint_op(RELAY_PAYLOAD_SIZE, OP_EQ, n); - n = connection_edge_get_inbuf_bytes_to_package(95000, 1, c); + n = connection_edge_get_inbuf_bytes_to_package(95000, 1, c, cpath); 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); + n = connection_edge_get_inbuf_bytes_to_package(RELAY_PAYLOAD_SIZE-1, 0, + c, cpath); tt_int_op(n, OP_EQ, 0); /* no change in our state, since nothing was sent. */ tt_assert(! c->have_sent_sufficiently_random_cell); @@ -305,13 +271,15 @@ /* 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); + n = connection_edge_get_inbuf_bytes_to_package(RELAY_PAYLOAD_SIZE-1, 1, + c, cpath); 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); + n = connection_edge_get_inbuf_bytes_to_package(RELAY_PAYLOAD_SIZE-64, 1, + c, cpath); 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); @@ -320,7 +288,7 @@ * 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); + n = connection_edge_get_inbuf_bytes_to_package(10000, 1, c, cpath); tt_int_op(n, OP_EQ, RELAY_PAYLOAD_SIZE); /* Now these will be reset. */ tt_assert(! c->have_sent_sufficiently_random_cell); @@ -329,7 +297,7 @@ /* 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); + n = connection_edge_get_inbuf_bytes_to_package(10000, 1, c, cpath); 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. */ @@ -341,55 +309,12 @@ * 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); + n = connection_edge_get_inbuf_bytes_to_package(reduced_payload_size, 0, + c, cpath); tt_int_op(n, OP_EQ, reduced_payload_size); done: - tor_free(c); -} - -/* Check that circuit_sendme_is_next works with a window of 1000, - * and a sendme_inc of 100 (old school tor compat) */ -static void -test_sendme_is_next1000(void *arg) -{ - (void)arg; - tt_int_op(circuit_sendme_cell_is_next(1000, 100), OP_EQ, 0); - tt_int_op(circuit_sendme_cell_is_next(999, 100), OP_EQ, 0); - tt_int_op(circuit_sendme_cell_is_next(901, 100), OP_EQ, 1); - - tt_int_op(circuit_sendme_cell_is_next(900, 100), OP_EQ, 0); - tt_int_op(circuit_sendme_cell_is_next(899, 100), OP_EQ, 0); - tt_int_op(circuit_sendme_cell_is_next(801, 100), OP_EQ, 1); - - tt_int_op(circuit_sendme_cell_is_next(101, 100), OP_EQ, 1); - tt_int_op(circuit_sendme_cell_is_next(100, 100), OP_EQ, 0); - tt_int_op(circuit_sendme_cell_is_next(99, 100), OP_EQ, 0); - tt_int_op(circuit_sendme_cell_is_next(1, 100), OP_EQ, 1); - tt_int_op(circuit_sendme_cell_is_next(0, 100), OP_EQ, 0); - -done: - ; -} - -/* Check that circuit_sendme_is_next works with a window of 31 */ -static void -test_sendme_is_next(void *arg) -{ - (void)arg; - tt_int_op(circuit_sendme_cell_is_next(1000, 31), OP_EQ, 0); - tt_int_op(circuit_sendme_cell_is_next(970, 31), OP_EQ, 1); - tt_int_op(circuit_sendme_cell_is_next(969, 31), OP_EQ, 0); - - /* deliver_window should never get this low, but test anyway */ - tt_int_op(circuit_sendme_cell_is_next(9, 31), OP_EQ, 1); - tt_int_op(circuit_sendme_cell_is_next(8, 31), OP_EQ, 0); - tt_int_op(circuit_sendme_cell_is_next(7, 31), OP_EQ, 0); - tt_int_op(circuit_sendme_cell_is_next(1, 31), OP_EQ, 0); - tt_int_op(circuit_sendme_cell_is_next(0, 31), OP_EQ, 0); - - done: - ; + circuit_free(c); } struct testcase_t sendme_tests[] = { @@ -399,13 +324,9 @@ 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 }, - { "sendme_is_next1000", test_sendme_is_next1000, 0, NULL, NULL }, - { "sendme_is_next", test_sendme_is_next, 0, NULL, NULL }, END_OF_TESTCASES }; diff -Nru tor-0.4.7.16/src/test/test_slow.c tor-0.4.9.6/src/test/test_slow.c --- tor-0.4.7.16/src/test/test_slow.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/test/test_slow.c 2026-03-25 14:30:34.000000000 +0000 @@ -21,6 +21,7 @@ struct testgroup_t testgroups[] = { { "slow/crypto/", slow_crypto_tests }, { "slow/process/", slow_process_tests }, + { "slow/hs_pow/", slow_hs_pow_tests }, { "slow/prob_distr/", slow_stochastic_prob_distr_tests }, { "slow/ptr/", slow_ptr_tests }, END_OF_GROUPS diff -Nru tor-0.4.7.16/src/test/test_socks.c tor-0.4.9.6/src/test/test_socks.c --- tor-0.4.7.16/src/test/test_socks.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/test/test_socks.c 2026-03-25 14:30:34.000000000 +0000 @@ -596,6 +596,70 @@ ; } +/** Perform SOCKS 5 authentication and send data all in one go */ +static void +test_socks_5_authenticate_with_rpc_objectid(void *ptr) +{ + SOCKS_TEST_INIT(); + + /* SOCKS 5 Negotiate username/password authentication */ + ADD_DATA(buf, "\x05\x01\x02"); + tt_assert(!fetch_from_buf_socks(buf, socks, + get_options()->TestSocks, + get_options()->SafeSocks)); + /* SOCKS 5 Send username/password as a RPC ObjectID (see prop351). This + * should be invalid as in only the objectID prefix without a version. */ + ADD_DATA(buf, "\x01\x08\x08password"); + tt_int_op(fetch_from_buf_socks(buf, socks, get_options()->TestSocks, + get_options()->SafeSocks), OP_EQ, -1); + + buf_clear(buf); + socks_request_clear(socks); + + /* SOCKS 5 Negotiate username/password authentication */ + ADD_DATA(buf, "\x05\x01\x02"); + tt_assert(!fetch_from_buf_socks(buf, socks, + get_options()->TestSocks, + get_options()->SafeSocks)); + /* SOCKS 5 Send username/password as a RPC ObjectID (see prop351). This + * should be valid because it is exactly the prefix and version without an + * object ID. */ + ADD_DATA(buf, "\x01\x090\x08password"); + tt_int_op(fetch_from_buf_socks(buf, socks, get_options()->TestSocks, + get_options()->SafeSocks), OP_EQ, 0); + + buf_clear(buf); + socks_request_clear(socks); + + /* SOCKS 5 Negotiate username/password authentication */ + ADD_DATA(buf, "\x05\x01\x02"); + tt_assert(!fetch_from_buf_socks(buf, socks, + get_options()->TestSocks, + get_options()->SafeSocks)); + /* SOCKS 5 Send username/password as a RPC ObjectID (see prop351). This + * should be invalid as an unknown version per prop351. */ + ADD_DATA(buf, "\x01\x091\x08password"); + tt_int_op(fetch_from_buf_socks(buf, socks, get_options()->TestSocks, + get_options()->SafeSocks), OP_EQ, -1); + + buf_clear(buf); + socks_request_clear(socks); + + /* SOCKS 5 Negotiate username/password authentication */ + ADD_DATA(buf, "\x05\x01\x02"); + tt_assert(!fetch_from_buf_socks(buf, socks, + get_options()->TestSocks, + get_options()->SafeSocks)); + /* SOCKS 5 Send username/password as a RPC ObjectID (see prop351). This + * should be invalid because there is an objectID after the prefix. */ + ADD_DATA(buf, "\x01\x0C0abc\x08password"); + tt_int_op(fetch_from_buf_socks(buf, socks, get_options()->TestSocks, + get_options()->SafeSocks), OP_EQ, -1); + + done: + ; +} + /** Try to negotiate an unsupported authentication type */ static void test_socks_5_auth_unsupported_type(void *ptr) @@ -1112,6 +1176,7 @@ SOCKSENT(5_authenticate), SOCKSENT(5_authenticate_empty_user_pass), SOCKSENT(5_authenticate_with_data), + SOCKSENT(5_authenticate_with_rpc_objectid), SOCKSENT(5_malformed_commands), SOCKSENT(5_bad_arguments), diff -Nru tor-0.4.7.16/src/test/test_status.c tor-0.4.9.6/src/test/test_status.c --- tor-0.4.7.16/src/test/test_status.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/test/test_status.c 2026-03-25 14:30:34.000000000 +0000 @@ -333,10 +333,12 @@ status_hb_not_in_consensus_server_mode); log_global_min_severity_ = LOG_DEBUG; - onion_handshakes_requested[ONION_HANDSHAKE_TYPE_TAP] = 1; onion_handshakes_assigned[ONION_HANDSHAKE_TYPE_TAP] = 1; - onion_handshakes_requested[ONION_HANDSHAKE_TYPE_NTOR] = 1; - onion_handshakes_assigned[ONION_HANDSHAKE_TYPE_NTOR] = 1; + onion_handshakes_requested[ONION_HANDSHAKE_TYPE_TAP] = 2; + onion_handshakes_assigned[ONION_HANDSHAKE_TYPE_NTOR] = 3; + onion_handshakes_requested[ONION_HANDSHAKE_TYPE_NTOR] = 4; + onion_handshakes_assigned[ONION_HANDSHAKE_TYPE_NTOR_V3] = 5; + onion_handshakes_requested[ONION_HANDSHAKE_TYPE_NTOR_V3] = 6; expected = 0; setup_capture_of_logs(LOG_INFO); @@ -352,8 +354,8 @@ "I've made 0 connections with IPv4 and 0 with IPv6.\n"); expect_log_msg("Average packaged cell fullness: 100.000%. " "TLS write overhead: 0%\n"); - expect_log_msg("Circuit handshake stats since last time: 1/1 TAP, " - "1/1 NTor.\n"); + expect_log_msg("Circuit handshake stats since last time: 1/2 TAP, " + "3/4 NTor, 5/6 NTor (v3).\n"); expect_log_msg("Since startup we initiated 0 and received 0 v1 " "connections; initiated 0 and received 0 v2 connections; " "initiated 0 and received 0 v3 connections; " @@ -363,6 +365,7 @@ "with too many cells, [DoSCircuitCreationEnabled disabled], " "[DoSConnectionEnabled disabled], " "[DoSRefuseSingleHopClientRendezvous disabled], " + "[DoSStreamCreationEnabled disabled], " "0 INTRODUCE2 rejected.\n"); tt_int_op(mock_saved_log_n_entries(), OP_EQ, 6); diff -Nru tor-0.4.7.16/src/test/test_tortls.c tor-0.4.9.6/src/test/test_tortls.c --- tor-0.4.7.16/src/test/test_tortls.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/test/test_tortls.c 2026-03-25 14:30:34.000000000 +0000 @@ -49,62 +49,80 @@ "evnAhf0cwULaebn+lMs8Pdl7y37+sfluVok=\n" "-----END CERTIFICATE-----\n"; -const char* validCertString = "-----BEGIN CERTIFICATE-----\n" - "MIIDpTCCAY0CAg3+MA0GCSqGSIb3DQEBBQUAMF4xCzAJBgNVBAYTAlVTMREwDwYD\n" - "VQQIDAhJbGxpbm9pczEQMA4GA1UEBwwHQ2hpY2FnbzEUMBIGA1UECgwLVG9yIFRl\n" - "c3RpbmcxFDASBgNVBAMMC1RvciBUZXN0aW5nMB4XDTE1MDkwNjEzMzk1OVoXDTQz\n" - "MDEyMjEzMzk1OVowVjELMAkGA1UEBhMCVVMxEDAOBgNVBAcMB0NoaWNhZ28xFDAS\n" - "BgNVBAoMC1RvciBUZXN0aW5nMR8wHQYDVQQDDBZ0ZXN0aW5nLnRvcnByb2plY3Qu\n" - "b3JnMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDoT6uyVVhWyOF3wkHjjYbd\n" - "nKaykyRv4JVtKQdZ4OpEErmX1zw4MmyzpQNV6iR4bQnWiyLfzyVJMZDIC/WILBfX\n" - "w2Pza/yuLgUvDc3twMuhOACzOQVO8PrEF/aVv2+hbCCy2udXvKhnYn+CCXl3ozc8\n" - "XcKYvujTXDyvGWY3xwAjlQIDAQABMA0GCSqGSIb3DQEBBQUAA4ICAQCUvnhzQWuQ\n" - "MrN+pERkE+zcTI/9dGS90rUMMLgu8VDNqTa0TUQh8uO0EQ6uDvI8Js6e8tgwS0BR\n" - "UBahqb7ZHv+rejGCBr5OudqD+x4STiiuPNJVs86JTLN8SpM9CHjIBH5WCCN2KOy3\n" - "mevNoRcRRyYJzSFULCunIK6FGulszigMYGscrO4oiTkZiHPh9KvWT40IMiHfL+Lw\n" - "EtEWiLex6064LcA2YQ1AMuSZyCexks63lcfaFmQbkYOKqXa1oLkIRuDsOaSVjTfe\n" - "vec+X6jvf12cFTKS5WIeqkKF2Irt+dJoiHEGTe5RscUMN/f+gqHPzfFz5dR23sxo\n" - "g+HC6MZHlFkLAOx3wW6epPS8A/m1mw3zMPoTnb2U2YYt8T0dJMMlUn/7Y1sEAa+a\n" - "dSTMaeUf6VnJ//11m454EZl1to9Z7oJOgqmFffSrdD4BGIWe8f7hhW6L1Enmqe/J\n" - "BKL3wbzZh80O1W0bndAwhnEEhlzneFY84cbBo9pmVxpODHkUcStpr5Z7pBDrcL21\n" - "Ss/aB/1YrsVXhdvJdOGxl3Mnl9dUY57CympLGlT8f0pPS6GAKOelECOhFMHmJd8L\n" - "dj3XQSmKtYHevZ6IvuMXSlB/fJvSjSlkCuLo5+kJoaqPuRu+i/S1qxeRy3CBwmnE\n" - "LdSNdcX4N79GQJ996PA8+mUCQG7YRtK+WA==\n" +// Tor www.torproject.org certificate. +// Fetched March 6 2025, ~1320 UTC. +const char* validCertString = + "-----BEGIN CERTIFICATE-----\n" + "MIIF8zCCBNugAwIBAgISBMmLkAm3fEUb8UQC5EdseU8ZMA0GCSqGSIb3DQEBCwUA\n" + "MDMxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MQwwCgYDVQQD\n" + "EwNSMTAwHhcNMjUwMTMwMDA1MTU0WhcNMjUwNDMwMDA1MTUzWjAdMRswGQYDVQQD\n" + "ExJ3d3cudG9ycHJvamVjdC5vcmcwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK\n" + "AoICAQDGG3XaG3ZB5QbJisjUbyBW+dgoZy2E3dJ0qMaWyO3/dB8yz4gKKMFCr1Gj\n" + "xjcfWYiayN1mcL8/QWOiD8x1s25FHeWBoDpyHX70TlRK6ZL1u2imsgoIiNaOh7f6\n" + "zfY7EQHu5UTuwSF9xBVf6FGuJ1b+ZGfXE5dBg3JJ78E8unT+xz6TUzEBUHRF7mgR\n" + "nGSgy2vqTT2EpoGq2ZioV8v8JrjkLFUx40XimUPphBs0vdY+gzVCp2wKHRgxglAD\n" + "ut3UzLLs7dW/JV9OSSj5L46CQwuaC5xjGEBcarS202oyBdC7DZpolHVKmwJd6IOj\n" + "DcachL3VFDGPXQe3/TVcale8y6mfhYbGYn8v9SpeHOdsWv5kCNCpHaHYmdSCiCFG\n" + "lmFxnuisu74WghiLrHeHB3oydjACQOyJ4d3u1P9oFKqxPX4ui3ACVWcvksNVQSmR\n" + "LlLE2SrK9wIwn2oNs5jJuR68yMV57i20TGvqBSsCZ3m99glpXwG50tzgqfBwFFDX\n" + "QElJWI8GQvKQIh43TYBvpZXYIG9srvGdl9eUCNXTFhGosc0+sfKoPpUf7f0R58pj\n" + "fjdyDyXb+M6Z60mflOeUM+UR9Q5VeTJ69IfpLypC2JaHy2HCuNekvkbB7TuPuvC9\n" + "vANjovgo5zI3MAcp2v9Y6EDgeScKMbZBQM6nuljvw9npaqkHXQIDAQABo4ICFTCC\n" + "AhEwDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcD\n" + "AjAMBgNVHRMBAf8EAjAAMB0GA1UdDgQWBBRWG7Q4+uqENJPVGkL74DH+LCrhjzAf\n" + "BgNVHSMEGDAWgBS7vMNHpeS8qcbDpHIMEI2iNeHI6DBXBggrBgEFBQcBAQRLMEkw\n" + "IgYIKwYBBQUHMAGGFmh0dHA6Ly9yMTAuby5sZW5jci5vcmcwIwYIKwYBBQUHMAKG\n" + "F2h0dHA6Ly9yMTAuaS5sZW5jci5vcmcvMB0GA1UdEQQWMBSCEnd3dy50b3Jwcm9q\n" + "ZWN0Lm9yZzATBgNVHSAEDDAKMAgGBmeBDAECATCCAQMGCisGAQQB1nkCBAIEgfQE\n" + "gfEA7wB1AMz7D2qFcQll/pWbU87psnwi6YVcDZeNtql+VMD+TA2wAAABlLTm/wYA\n" + "AAQDAEYwRAIgHWbnkMLOUDDJg7vog3J66Aa2wuRYg4DFS21uUtPVUQgCIFZhio8Z\n" + "CQcZsdFpeGzAUjXcyboVrvdMg3/3jwWgdQ82AHYA5tIxY0B3jMEQQQbXcbnOwdJA\n" + "9paEhvu6hzId/R43jlAAAAGUtOb/DQAABAMARzBFAiBHNO8CjQdQcMENnXyH5oBL\n" + "kfdZghUHzMEfFKlg5p+QDAIhAP0dEqz+Q2A2XCvN09vZJ1gsG8IzQELHpBM8QDyM\n" + "KSavMA0GCSqGSIb3DQEBCwUAA4IBAQDNh8KjUWJKio63zn2JrFlpIsnrVchPP+ee\n" + "1XUrHQt/BA1pUdlTFPQrHOCf6KOGpiyjXxKkBdtJvc/5ZJZYJ26E6Ytd0nGOCirE\n" + "v0W45Vh22rH1w0Q1fH1xOqZx1qeh4QYr1/QJ3gWWMTOH5uV5dTzK9RWfp0C1pjQ6\n" + "Rct/0ZqyZHYqMD9VoAiVap7lwnWNWOj+UEioH2cMqjCkD5g8QGNHEfereB3DtoV3\n" + "Qw1Z3KoUEr2zEDfq+Uv6RLKCw3HjzDYKbHWSYkrUO7YyIQ3nlZAT861478k5WSKv\n" + "hpy8XisMLpQLAhSByV965gINlmHXbe61anJUh3JJpnOu/JyMfaf/\n" "-----END CERTIFICATE-----\n"; -const char* caCertString = "-----BEGIN CERTIFICATE-----\n" - "MIIFjzCCA3egAwIBAgIJAKd5WgyfPMYRMA0GCSqGSIb3DQEBCwUAMF4xCzAJBgNV\n" - "BAYTAlVTMREwDwYDVQQIDAhJbGxpbm9pczEQMA4GA1UEBwwHQ2hpY2FnbzEUMBIG\n" - "A1UECgwLVG9yIFRlc3RpbmcxFDASBgNVBAMMC1RvciBUZXN0aW5nMB4XDTE1MDkw\n" - "NjEzMzc0MVoXDTQzMDEyMjEzMzc0MVowXjELMAkGA1UEBhMCVVMxETAPBgNVBAgM\n" - "CElsbGlub2lzMRAwDgYDVQQHDAdDaGljYWdvMRQwEgYDVQQKDAtUb3IgVGVzdGlu\n" - "ZzEUMBIGA1UEAwwLVG9yIFRlc3RpbmcwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAw\n" - "ggIKAoICAQCpLMUEiLW5leUgBZoEJms2V7lZRhIAjnJBhVMHD0e3UubNknmaQoxf\n" - "ARz3rvqOaRd0JlV+qM9qE0DjiYcCVP1cAfqAo9d83uS1vwY3YMVJzADlaIiHfyVW\n" - "uEgBy0vvkeUBqaua24dYlcwsemOiXYLu41yM1wkcGHW1AhBNHppY6cznb8TyLgNM\n" - "2x3SGUdzc5XMyAFx51faKGBA3wjs+Hg1PLY7d30nmCgEOBavpm5I1disM/0k+Mcy\n" - "YmAKEo/iHJX/rQzO4b9znP69juLlR8PDBUJEVIG/CYb6+uw8MjjUyiWXYoqfVmN2\n" - "hm/lH8b6rXw1a2Aa3VTeD0DxaWeacMYHY/i01fd5n7hCoDTRNdSw5KJ0L3Z0SKTu\n" - "0lzffKzDaIfyZGlpW5qdouACkWYzsaitQOePVE01PIdO30vUfzNTFDfy42ccx3Di\n" - "59UCu+IXB+eMtrBfsok0Qc63vtF1linJgjHW1z/8ujk8F7/qkOfODhk4l7wngc2A\n" - "EmwWFIFoGaiTEZHB9qteXr4unbXZ0AHpM02uGGwZEGohjFyebEb73M+J57WKKAFb\n" - "PqbLcGUksL1SHNBNAJcVLttX55sO4nbidOS/kA3m+F1R04MBTyQF9qA6YDDHqdI3\n" - "h/3pw0Z4fxVouTYT4/NfRnX4JTP4u+7Mpcoof28VME0qWqD1LnRhFQIDAQABo1Aw\n" - "TjAdBgNVHQ4EFgQUMoAgIXH7pZ3QMRwTjT+DM9Yo/v0wHwYDVR0jBBgwFoAUMoAg\n" - "IXH7pZ3QMRwTjT+DM9Yo/v0wDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOC\n" - "AgEAUJxacjXR9sT+Xs6ISFiUsyd0T6WVKMnV46xrYJHirGfx+krWHrjxMY+ZtxYD\n" - "DBDGlo11Qc4v6QrclNf5QUBfIiGQsP9Cm6hHcQ+Tpg9HHCgSqG1YNPwCPReCR4br\n" - "BLvLfrfkcBL2IWM0PdQdCze+59DBfipsULD2mEn9fjYRXQEwb2QWtQ9qRc20Yb/x\n" - "Q4b/+CvUodLkaq7B8MHz0BV8HHcBoph6DYaRmO/N+hPauIuSp6XyaGYcEefGKVKj\n" - "G2+fcsdyXsoijNdL8vNKwm4j2gVwCBnw16J00yfFoV46YcbfqEdJB2je0XSvwXqt\n" - "14AOTngxso2h9k9HLtrfpO1ZG/B5AcCMs1lzbZ2fp5DPHtjvvmvA2RJqgo3yjw4W\n" - "4DHAuTglYFlC3mDHNfNtcGP20JvepcQNzNP2UzwcpOc94hfKikOFw+gf9Vf1qd0y\n" - "h/Sk6OZHn2+JVUPiWHIQV98Vtoh4RmUZDJD+b55ia3fQGTGzt4z1XFzQYSva5sfs\n" - "wocS/papthqWldQU7x+3wofNd5CNU1x6WKXG/yw30IT/4F8ADJD6GeygNT8QJYvt\n" - "u/8lAkbOy6B9xGmSvr0Kk1oq9P2NshA6kalxp1Oz/DTNDdL4AeBXV3JmM6WWCjGn\n" - "Yy1RT69d0rwYc5u/vnqODz1IjvT90smsrkBumGt791FAFeg=\n" +// Let's encrypt certificate, used to sign validCertString. +// Also fetched March 6 2025, ~1320 UTC. +const char* caCertString = + "-----BEGIN CERTIFICATE-----\n" + "MIIFBTCCAu2gAwIBAgIQS6hSk/eaL6JzBkuoBI110DANBgkqhkiG9w0BAQsFADBP\n" + "MQswCQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJuZXQgU2VjdXJpdHkgUmVzZWFy\n" + "Y2ggR3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBYMTAeFw0yNDAzMTMwMDAwMDBa\n" + "Fw0yNzAzMTIyMzU5NTlaMDMxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBF\n" + "bmNyeXB0MQwwCgYDVQQDEwNSMTAwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK\n" + "AoIBAQDPV+XmxFQS7bRH/sknWHZGUCiMHT6I3wWd1bUYKb3dtVq/+vbOo76vACFL\n" + "YlpaPAEvxVgD9on/jhFD68G14BQHlo9vH9fnuoE5CXVlt8KvGFs3Jijno/QHK20a\n" + "/6tYvJWuQP/py1fEtVt/eA0YYbwX51TGu0mRzW4Y0YCF7qZlNrx06rxQTOr8IfM4\n" + "FpOUurDTazgGzRYSespSdcitdrLCnF2YRVxvYXvGLe48E1KGAdlX5jgc3421H5KR\n" + "mudKHMxFqHJV8LDmowfs/acbZp4/SItxhHFYyTr6717yW0QrPHTnj7JHwQdqzZq3\n" + "DZb3EoEmUVQK7GH29/Xi8orIlQ2NAgMBAAGjgfgwgfUwDgYDVR0PAQH/BAQDAgGG\n" + "MB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcDATASBgNVHRMBAf8ECDAGAQH/\n" + "AgEAMB0GA1UdDgQWBBS7vMNHpeS8qcbDpHIMEI2iNeHI6DAfBgNVHSMEGDAWgBR5\n" + "tFnme7bl5AFzgAiIyBpY9umbbjAyBggrBgEFBQcBAQQmMCQwIgYIKwYBBQUHMAKG\n" + "Fmh0dHA6Ly94MS5pLmxlbmNyLm9yZy8wEwYDVR0gBAwwCjAIBgZngQwBAgEwJwYD\n" + "VR0fBCAwHjAcoBqgGIYWaHR0cDovL3gxLmMubGVuY3Iub3JnLzANBgkqhkiG9w0B\n" + "AQsFAAOCAgEAkrHnQTfreZ2B5s3iJeE6IOmQRJWjgVzPw139vaBw1bGWKCIL0vIo\n" + "zwzn1OZDjCQiHcFCktEJr59L9MhwTyAWsVrdAfYf+B9haxQnsHKNY67u4s5Lzzfd\n" + "u6PUzeetUK29v+PsPmI2cJkxp+iN3epi4hKu9ZzUPSwMqtCceb7qPVxEbpYxY1p9\n" + "1n5PJKBLBX9eb9LU6l8zSxPWV7bK3lG4XaMJgnT9x3ies7msFtpKK5bDtotij/l0\n" + "GaKeA97pb5uwD9KgWvaFXMIEt8jVTjLEvwRdvCn294GPDF08U8lAkIv7tghluaQh\n" + "1QnlE4SEN4LOECj8dsIGJXpGUk3aU3KkJz9icKy+aUgA+2cP21uh6NcDIS3XyfaZ\n" + "QjmDQ993ChII8SXWupQZVBiIpcWO4RqZk3lr7Bz5MUCwzDIA359e57SSq5CCkY0N\n" + "4B6Vulk7LktfwrdGNVI5BsC9qqxSwSKgRJeZ9wygIaehbHFHFhcBaMDKpiZlBHyz\n" + "rsnnlFXCb5s8HKn5LsUgGvB24L7sGNZP2CX7dhHov+YhD+jozLW2p9W4959Bz2Ei\n" + "RmqDtmiXLnzqTpXbI+suyCsohKRg6Un0RC47+cpiVwHiXZAW+cn8eiNIjqbVgXLx\n" + "KPpdzvvtTnOPlC7SQZSYmdunr3Bf9b77AiC/ZidstK36dRILKz7OA54=\n" "-----END CERTIFICATE-----\n"; +// A time at which the certs above are valid. +const time_t cert_strings_valid_at = 1741267580; + static tor_x509_cert_t *fixed_x509_cert = NULL; static tor_x509_cert_t * get_peer_cert_mock_return_fixed(tor_tls_t *tls) @@ -136,24 +154,6 @@ return res; } -static tor_x509_cert_impl_t * - fixed_try_to_extract_certs_from_tls_cert_out_result = NULL; -static tor_x509_cert_impl_t * - fixed_try_to_extract_certs_from_tls_id_cert_out_result = NULL; - -static void -fixed_try_to_extract_certs_from_tls(int severity, tor_tls_t *tls, - tor_x509_cert_impl_t **cert_out, - tor_x509_cert_impl_t **id_cert_out) -{ - (void) severity; - (void) tls; - *cert_out = tor_x509_cert_impl_dup_( - fixed_try_to_extract_certs_from_tls_cert_out_result); - *id_cert_out = tor_x509_cert_impl_dup_( - fixed_try_to_extract_certs_from_tls_id_cert_out_result); -} - static void test_tortls_errno_to_tls_error(void *data) { @@ -309,44 +309,6 @@ done: tor_free(tls); } - -static void -test_tortls_used_v1_handshake(void *ignored) -{ - (void)ignored; - int ret; - tor_tls_t *tls; - tls = tor_malloc_zero(sizeof(tor_tls_t)); - - // These tests assume both V2 handshake server and client are enabled - tls->wasV2Handshake = 0; - ret = tor_tls_used_v1_handshake(tls); - tt_int_op(ret, OP_EQ, 1); - - tls->wasV2Handshake = 1; - ret = tor_tls_used_v1_handshake(tls); - tt_int_op(ret, OP_EQ, 0); - - done: - tor_free(tls); -} - -static void -test_tortls_server_got_renegotiate(void *ignored) -{ - (void)ignored; - int ret; - tor_tls_t *tls; - - tls = tor_malloc_zero(sizeof(tor_tls_t)); - - tls->got_renegotiate = 1; - ret = tor_tls_server_got_renegotiate(tls); - tt_int_op(ret, OP_EQ, 1); - - done: - tor_free(tls); -} #endif /* defined(ENABLE_OPENSSL) */ static void @@ -474,57 +436,6 @@ } static void -test_tortls_verify(void *ignored) -{ - (void)ignored; - int ret; - tor_tls_t *tls; - crypto_pk_t *k = NULL; - tor_x509_cert_impl_t *cert1 = NULL, *cert2 = NULL, *invalidCert = NULL, - *validCert = NULL, *caCert = NULL; - - validCert = read_cert_from(validCertString); - caCert = read_cert_from(caCertString); - invalidCert = read_cert_from(notCompletelyValidCertString); - - tls = tor_malloc_zero(sizeof(tor_tls_t)); - - MOCK(try_to_extract_certs_from_tls, fixed_try_to_extract_certs_from_tls); - - fixed_try_to_extract_certs_from_tls_cert_out_result = cert1; - ret = tor_tls_verify(LOG_WARN, tls, &k); - tt_int_op(ret, OP_EQ, -1); - - fixed_try_to_extract_certs_from_tls_id_cert_out_result = cert2; - ret = tor_tls_verify(LOG_WARN, tls, &k); - tt_int_op(ret, OP_EQ, -1); - - fixed_try_to_extract_certs_from_tls_cert_out_result = invalidCert; - fixed_try_to_extract_certs_from_tls_id_cert_out_result = invalidCert; - - ret = tor_tls_verify(LOG_WARN, tls, &k); - tt_int_op(ret, OP_EQ, -1); - - fixed_try_to_extract_certs_from_tls_cert_out_result = validCert; - fixed_try_to_extract_certs_from_tls_id_cert_out_result = caCert; - - ret = tor_tls_verify(LOG_WARN, tls, &k); - tt_int_op(ret, OP_EQ, 0); - tt_assert(k); - - done: - UNMOCK(try_to_extract_certs_from_tls); - tor_x509_cert_impl_free(cert1); - tor_x509_cert_impl_free(cert2); - tor_x509_cert_impl_free(validCert); - tor_x509_cert_impl_free(invalidCert); - tor_x509_cert_impl_free(caCert); - - tor_free(tls); - crypto_pk_free(k); -} - -static void test_tortls_cert_matches_key(void *ignored) { (void)ignored; @@ -596,15 +507,12 @@ #ifdef ENABLE_OPENSSL LOCAL_TEST_CASE(tor_tls_get_error, 0), LOCAL_TEST_CASE(get_forced_write_size, 0), - LOCAL_TEST_CASE(used_v1_handshake, TT_FORK), - LOCAL_TEST_CASE(server_got_renegotiate, 0), #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), LOCAL_TEST_CASE(is_server, 0), LOCAL_TEST_CASE(bridge_init, TT_FORK), - LOCAL_TEST_CASE(verify, TT_FORK), LOCAL_TEST_CASE(cert_matches_key, 0), END_OF_TESTCASES }; diff -Nru tor-0.4.7.16/src/test/test_tortls.h tor-0.4.9.6/src/test/test_tortls.h --- tor-0.4.7.16/src/test/test_tortls.h 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/test/test_tortls.h 2026-03-25 14:30:34.000000000 +0000 @@ -9,5 +9,6 @@ extern const char *notCompletelyValidCertString; extern const char *validCertString; extern const char *caCertString; +extern const time_t cert_strings_valid_at; #endif /* !defined(TEST_TORTLS_H) */ diff -Nru tor-0.4.7.16/src/test/test_tortls_openssl.c tor-0.4.9.6/src/test/test_tortls_openssl.c --- tor-0.4.7.16/src/test/test_tortls_openssl.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/test/test_tortls_openssl.c 2026-03-25 14:30:34.000000000 +0000 @@ -46,15 +46,19 @@ #include "test/log_test_helpers.h" #include "test/test_tortls.h" -#ifndef HAVE_SSL_STATE -#define OPENSSL_OPAQUE -#endif - -#if defined(OPENSSL_OPAQUE) && !defined(LIBRESSL_VERSION_NUMBER) #define SSL_STATE_STR "before SSL initialization" -#else -#define SSL_STATE_STR "before/accept initialization" -#endif + +/* Every version and fork of OpenSSL we support now qualifies as "opaque", + * in that it hides the members of important structures. + * + * That's a good thing, but it means we can't run a number of older tests + * that require the ability to poke at OpenSSL's internals. + * + * We're retaining these tests here, rather than removing them, + * in case anybody wants to port them to modern OpenSSL. + * (Some of them are probably not worth saving, though.) + */ +#define OPENSSL_OPAQUE #ifndef OPENSSL_OPAQUE static SSL_METHOD * @@ -124,12 +128,7 @@ static void library_init(void) { -#ifdef OPENSSL_1_1_API OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS, NULL); -#else - SSL_library_init(); - SSL_load_error_strings(); -#endif /* defined(OPENSSL_1_1_API) */ } static void @@ -296,13 +295,6 @@ LOG_WARN, 0, NULL); expect_log_severity(LOG_INFO); -#ifndef OPENSSL_1_1_API - mock_clean_saved_logs(); - tor_tls_log_one_error(tls, ERR_PACK(1, 2, SSL_R_RECORD_TOO_LARGE), - LOG_WARN, 0, NULL); - expect_log_severity(LOG_INFO); -#endif /* !defined(OPENSSL_1_1_API) */ - mock_clean_saved_logs(); tor_tls_log_one_error(tls, ERR_PACK(1, 2, SSL_R_UNKNOWN_PROTOCOL), LOG_WARN, 0, NULL); @@ -505,232 +497,6 @@ } #endif /* !defined(OPENSSL_OPAQUE) */ -static void -test_tortls_get_my_client_auth_key(void *ignored) -{ - (void)ignored; - crypto_pk_t *ret; - crypto_pk_t *expected; - tor_tls_context_t *ctx; - RSA *k = RSA_new(); - - ctx = tor_malloc_zero(sizeof(tor_tls_context_t)); - expected = crypto_new_pk_from_openssl_rsa_(k); - ctx->auth_key = expected; - - client_tls_context = NULL; - ret = tor_tls_get_my_client_auth_key(); - tt_assert(!ret); - - client_tls_context = ctx; - ret = tor_tls_get_my_client_auth_key(); - tt_assert(ret == expected); - - done: - crypto_pk_free(expected); - tor_free(ctx); -} - -#ifndef HAVE_SSL_GET_CLIENT_CIPHERS -static SSL_CIPHER * -get_cipher_by_name(const char *name) -{ - int i; - const SSL_METHOD *method = SSLv23_method(); - int num = method->num_ciphers(); - - for (i = 0; i < num; ++i) { - const SSL_CIPHER *cipher = method->get_cipher(i); - const char *ciphername = SSL_CIPHER_get_name(cipher); - if (!strcmp(ciphername, name)) { - return (SSL_CIPHER *)cipher; - } - } - - return NULL; -} -#endif /* !defined(HAVE_SSL_GET_CLIENT_CIPHERS) */ - -#ifndef OPENSSL_OPAQUE -static void -test_tortls_get_ciphersuite_name(void *ignored) -{ - (void)ignored; - const char *ret; - tor_tls_t *ctx; - ctx = tor_malloc_zero(sizeof(tor_tls_t)); - ctx->ssl = tor_malloc_zero(sizeof(SSL)); - - ret = tor_tls_get_ciphersuite_name(ctx); - tt_str_op(ret, OP_EQ, "(NONE)"); - - done: - tor_free(ctx->ssl); - tor_free(ctx); -} - -static SSL_CIPHER * -get_cipher_by_id(uint16_t id) -{ - int i; - const SSL_METHOD *method = SSLv23_method(); - int num = method->num_ciphers(); - for (i = 0; i < num; ++i) { - const SSL_CIPHER *cipher = method->get_cipher(i); - if (id == (SSL_CIPHER_get_id(cipher) & 0xffff)) { - return (SSL_CIPHER *)cipher; - } - } - - return NULL; -} - -static void -test_tortls_classify_client_ciphers(void *ignored) -{ - (void)ignored; - int i; - int ret; - SSL_CTX *ctx; - SSL *ssl; - tor_tls_t *tls; - STACK_OF(SSL_CIPHER) *ciphers; - SSL_CIPHER *tmp_cipher; - - library_init(); - - tor_tls_allocate_tor_tls_object_ex_data_index(); - - tls = tor_malloc_zero(sizeof(tor_tls_t)); - tls->magic = TOR_TLS_MAGIC; - - ctx = SSL_CTX_new(TLSv1_method()); - ssl = SSL_new(ctx); - tls->ssl = ssl; - - ciphers = sk_SSL_CIPHER_new_null(); - - ret = tor_tls_classify_client_ciphers(ssl, NULL); - tt_int_op(ret, OP_EQ, -1); - - SSL_set_ex_data(ssl, tor_tls_object_ex_data_index, tls); - tls->client_cipher_list_type = 42; - - ret = tor_tls_classify_client_ciphers(ssl, NULL); - tt_int_op(ret, OP_EQ, 42); - - tls->client_cipher_list_type = 0; - ret = tor_tls_classify_client_ciphers(ssl, ciphers); - tt_int_op(ret, OP_EQ, 1); - tt_int_op(tls->client_cipher_list_type, OP_EQ, 1); - - tls->client_cipher_list_type = 0; - ret = tor_tls_classify_client_ciphers(ssl, SSL_get_ciphers(ssl)); - tt_int_op(ret, OP_EQ, 3); - tt_int_op(tls->client_cipher_list_type, OP_EQ, 3); - - SSL_CIPHER *one = get_cipher_by_name(TLS1_TXT_DHE_RSA_WITH_AES_128_SHA), - *two = get_cipher_by_name(TLS1_TXT_DHE_RSA_WITH_AES_256_SHA), - *three = get_cipher_by_name(SSL3_TXT_EDH_RSA_DES_192_CBC3_SHA), - *four = NULL; - sk_SSL_CIPHER_push(ciphers, one); - sk_SSL_CIPHER_push(ciphers, two); - sk_SSL_CIPHER_push(ciphers, three); - sk_SSL_CIPHER_push(ciphers, four); - - tls->client_cipher_list_type = 0; - ret = tor_tls_classify_client_ciphers(ssl, ciphers); - tt_int_op(ret, OP_EQ, 1); - tt_int_op(tls->client_cipher_list_type, OP_EQ, 1); - - sk_SSL_CIPHER_zero(ciphers); - - one = get_cipher_by_name("ECDHE-RSA-AES256-GCM-SHA384"); - tt_assert(one); - one->id = 0x00ff; - two = get_cipher_by_name("ECDHE-RSA-AES128-GCM-SHA256"); - tt_assert(two); - two->id = 0x0000; - sk_SSL_CIPHER_push(ciphers, one); - tls->client_cipher_list_type = 0; - ret = tor_tls_classify_client_ciphers(ssl, ciphers); - tt_int_op(ret, OP_EQ, 3); - tt_int_op(tls->client_cipher_list_type, OP_EQ, 3); - - sk_SSL_CIPHER_push(ciphers, two); - tls->client_cipher_list_type = 0; - ret = tor_tls_classify_client_ciphers(ssl, ciphers); - tt_int_op(ret, OP_EQ, 3); - tt_int_op(tls->client_cipher_list_type, OP_EQ, 3); - - one->id = 0xC00A; - tls->client_cipher_list_type = 0; - ret = tor_tls_classify_client_ciphers(ssl, ciphers); - tt_int_op(ret, OP_EQ, 3); - tt_int_op(tls->client_cipher_list_type, OP_EQ, 3); - - sk_SSL_CIPHER_zero(ciphers); - for (i=0; v2_cipher_list[i]; i++) { - tmp_cipher = get_cipher_by_id(v2_cipher_list[i]); - tt_assert(tmp_cipher); - sk_SSL_CIPHER_push(ciphers, tmp_cipher); - } - tls->client_cipher_list_type = 0; - ret = tor_tls_classify_client_ciphers(ssl, ciphers); - tt_int_op(ret, OP_EQ, 2); - tt_int_op(tls->client_cipher_list_type, OP_EQ, 2); - - done: - sk_SSL_CIPHER_free(ciphers); - SSL_free(tls->ssl); - tor_free(tls); - SSL_CTX_free(ctx); -} -#endif /* !defined(OPENSSL_OPAQUE) */ - -static void -test_tortls_client_is_using_v2_ciphers(void *ignored) -{ - (void)ignored; - -#ifdef HAVE_SSL_GET_CLIENT_CIPHERS - tt_skip(); - done: - (void)1; -#else - int ret; - SSL_CTX *ctx; - SSL *ssl; - SSL_SESSION *sess; - STACK_OF(SSL_CIPHER) *ciphers; - - library_init(); - - ctx = SSL_CTX_new(TLSv1_method()); - ssl = SSL_new(ctx); - sess = SSL_SESSION_new(); - - ret = tor_tls_client_is_using_v2_ciphers(ssl); - tt_int_op(ret, OP_EQ, -1); - - ssl->session = sess; - ret = tor_tls_client_is_using_v2_ciphers(ssl); - tt_int_op(ret, OP_EQ, 0); - - ciphers = sk_SSL_CIPHER_new_null(); - SSL_CIPHER *one = get_cipher_by_name("ECDHE-RSA-AES256-GCM-SHA384"); - tt_assert(one); - one->id = 0x00ff; - sk_SSL_CIPHER_push(ciphers, one); - sess->ciphers = ciphers; - ret = tor_tls_client_is_using_v2_ciphers(ssl); - tt_int_op(ret, OP_EQ, 1); - done: - SSL_free(ssl); - SSL_CTX_free(ctx); -#endif /* defined(HAVE_SSL_GET_CLIENT_CIPHERS) */ -} - #ifndef OPENSSL_OPAQUE static int fixed_ssl_pending_result = 0; @@ -768,65 +534,6 @@ #ifndef OPENSSL_OPAQUE static void -test_tortls_SSL_SESSION_get_master_key(void *ignored) -{ - (void)ignored; - size_t ret; - tor_tls_t *tls; - uint8_t *out; - out = tor_malloc_zero(1); - tls = tor_malloc_zero(sizeof(tor_tls_t)); - tls->ssl = tor_malloc_zero(sizeof(SSL)); - tls->ssl->session = tor_malloc_zero(sizeof(SSL_SESSION)); - tls->ssl->session->master_key_length = 1; - -#ifndef HAVE_SSL_SESSION_GET_MASTER_KEY - tls->ssl->session->master_key[0] = 43; - ret = SSL_SESSION_get_master_key(tls->ssl->session, out, 0); - tt_int_op(ret, OP_EQ, 1); - tt_int_op(out[0], OP_EQ, 0); - - ret = SSL_SESSION_get_master_key(tls->ssl->session, out, 1); - tt_int_op(ret, OP_EQ, 1); - tt_int_op(out[0], OP_EQ, 43); - - done: -#endif /* !defined(HAVE_SSL_SESSION_GET_MASTER_KEY) */ - tor_free(tls->ssl->session); - tor_free(tls->ssl); - tor_free(tls); - tor_free(out); -} -#endif /* !defined(OPENSSL_OPAQUE) */ - -#ifndef OPENSSL_OPAQUE -static void -test_tortls_get_tlssecrets(void *ignored) -{ - (void)ignored; - int ret; - uint8_t *secret_out = tor_malloc_zero(DIGEST256_LEN); - tor_tls_t *tls; - tls = tor_malloc_zero(sizeof(tor_tls_t)); - tls->ssl = tor_malloc_zero(sizeof(SSL)); - tls->ssl->session = tor_malloc_zero(sizeof(SSL_SESSION)); - tls->ssl->session->master_key_length = 1; - tls->ssl->s3 = tor_malloc_zero(sizeof(SSL3_STATE)); - - ret = tor_tls_get_tlssecrets(tls, secret_out); - tt_int_op(ret, OP_EQ, 0); - - done: - tor_free(secret_out); - tor_free(tls->ssl->s3); - tor_free(tls->ssl->session); - tor_free(tls->ssl); - tor_free(tls); -} -#endif /* !defined(OPENSSL_OPAQUE) */ - -#ifndef OPENSSL_OPAQUE -static void test_tortls_get_buffer_sizes(void *ignored) { (void)ignored; @@ -849,23 +556,7 @@ tls->ssl->s3->wbuf.left = 43; ret = tor_tls_get_buffer_sizes(tls, &rbuf_c, &rbuf_b, &wbuf_c, &wbuf_b); -#if OPENSSL_VERSION_NUMBER >= OPENSSL_V_SERIES(1,1,0) tt_int_op(ret, OP_EQ, -1); -#else - tt_int_op(ret, OP_EQ, 0); - tt_int_op(rbuf_c, OP_EQ, 0); - tt_int_op(wbuf_c, OP_EQ, 0); - tt_int_op(rbuf_b, OP_EQ, 42); - tt_int_op(wbuf_b, OP_EQ, 43); - - tls->ssl->s3->rbuf.buf = tor_malloc_zero(1); - tls->ssl->s3->wbuf.buf = tor_malloc_zero(1); - ret = tor_tls_get_buffer_sizes(tls, &rbuf_c, &rbuf_b, &wbuf_c, &wbuf_b); - tt_int_op(ret, OP_EQ, 0); - tt_int_op(rbuf_c, OP_EQ, 1); - tt_int_op(wbuf_c, OP_EQ, 2); - -#endif /* OPENSSL_VERSION_NUMBER >= OPENSSL_V_SERIES(1,1,0) */ done: tor_free(tls->ssl->s3->rbuf.buf); @@ -877,76 +568,6 @@ #endif /* !defined(OPENSSL_OPAQUE) */ #ifndef OPENSSL_OPAQUE -typedef struct cert_pkey_st_local -{ - X509 *x509; - EVP_PKEY *privatekey; - const EVP_MD *digest; -} CERT_PKEY_local; - -typedef struct sess_cert_st_local -{ - STACK_OF(X509) *cert_chain; - int peer_cert_type; - CERT_PKEY_local *peer_key; - CERT_PKEY_local peer_pkeys[8]; - int references; -} SESS_CERT_local; - -static void -test_tortls_try_to_extract_certs_from_tls(void *ignored) -{ - (void)ignored; - tor_tls_t *tls; - X509 *cert = NULL, *id_cert = NULL, *c1 = NULL, *c2 = NULL; - SESS_CERT_local *sess = NULL; - - c1 = read_cert_from(validCertString); - c2 = read_cert_from(caCertString); - - tls = tor_malloc_zero(sizeof(tor_tls_t)); - tls->ssl = tor_malloc_zero(sizeof(SSL)); - tls->ssl->session = tor_malloc_zero(sizeof(SSL_SESSION)); - sess = tor_malloc_zero(sizeof(SESS_CERT_local)); - tls->ssl->session->sess_cert = (void *)sess; - - try_to_extract_certs_from_tls(LOG_WARN, tls, &cert, &id_cert); - tt_assert(!cert); - tt_assert(!id_cert); - - tls->ssl->session->peer = c1; - try_to_extract_certs_from_tls(LOG_WARN, tls, &cert, &id_cert); - tt_assert(cert == c1); - tt_assert(!id_cert); - X509_free(cert); /* decrease refcnt */ - - sess->cert_chain = sk_X509_new_null(); - try_to_extract_certs_from_tls(LOG_WARN, tls, &cert, &id_cert); - tt_assert(cert == c1); - tt_assert(!id_cert); - X509_free(cert); /* decrease refcnt */ - - sk_X509_push(sess->cert_chain, c1); - sk_X509_push(sess->cert_chain, c2); - - try_to_extract_certs_from_tls(LOG_WARN, tls, &cert, &id_cert); - tt_assert(cert == c1); - tt_assert(id_cert); - X509_free(cert); /* decrease refcnt */ - X509_free(id_cert); /* decrease refcnt */ - - done: - sk_X509_free(sess->cert_chain); - tor_free(sess); - tor_free(tls->ssl->session); - tor_free(tls->ssl); - tor_free(tls); - X509_free(c1); - X509_free(c2); -} -#endif /* !defined(OPENSSL_OPAQUE) */ - -#ifndef OPENSSL_OPAQUE static void test_tortls_get_peer_cert(void *ignored) { @@ -1112,11 +733,6 @@ tor_tls_block_renegotiation(tls); -#ifndef OPENSSL_1_1_API - tt_assert(!(tls->ssl->s3->flags & - SSL3_FLAGS_ALLOW_UNSAFE_LEGACY_RENEGOTIATION)); -#endif - done: tor_free(tls->ssl->s3); tor_free(tls->ssl); @@ -1199,93 +815,6 @@ #endif /* !defined(OPENSSL_OPAQUE) */ #ifndef OPENSSL_OPAQUE -static SSL_CIPHER *fixed_cipher1 = NULL; -static SSL_CIPHER *fixed_cipher2 = NULL; -static const SSL_CIPHER * -fake_get_cipher(unsigned ncipher) -{ - - switch (ncipher) { - case 1: - return fixed_cipher1; - case 2: - return fixed_cipher2; - default: - return NULL; - } -} -#endif /* !defined(OPENSSL_OPAQUE) */ - -#ifndef OPENSSL_OPAQUE -static void -test_tortls_find_cipher_by_id(void *ignored) -{ - (void)ignored; - int ret; - SSL *ssl; - SSL_CTX *ctx; - const SSL_METHOD *m = TLSv1_method(); - SSL_METHOD *empty_method = tor_malloc_zero(sizeof(SSL_METHOD)); - - fixed_cipher1 = tor_malloc_zero(sizeof(SSL_CIPHER)); - fixed_cipher2 = tor_malloc_zero(sizeof(SSL_CIPHER)); - fixed_cipher2->id = 0xC00A; - - library_init(); - - ctx = SSL_CTX_new(m); - ssl = SSL_new(ctx); - - ret = find_cipher_by_id(ssl, NULL, 0xC00A); - tt_int_op(ret, OP_EQ, 1); - - ret = find_cipher_by_id(ssl, m, 0xC00A); - tt_int_op(ret, OP_EQ, 1); - - ret = find_cipher_by_id(ssl, m, 0xFFFF); - tt_int_op(ret, OP_EQ, 0); - - ret = find_cipher_by_id(ssl, empty_method, 0xC00A); - tt_int_op(ret, OP_EQ, 1); - - ret = find_cipher_by_id(ssl, empty_method, 0xFFFF); -#ifdef HAVE_SSL_CIPHER_FIND - tt_int_op(ret, OP_EQ, 0); -#else - tt_int_op(ret, OP_EQ, 1); -#endif - - empty_method->get_cipher = fake_get_cipher; - ret = find_cipher_by_id(ssl, empty_method, 0xC00A); - tt_int_op(ret, OP_EQ, 1); - - empty_method->get_cipher = m->get_cipher; - empty_method->num_ciphers = m->num_ciphers; - ret = find_cipher_by_id(ssl, empty_method, 0xC00A); - tt_int_op(ret, OP_EQ, 1); - - empty_method->get_cipher = fake_get_cipher; - empty_method->num_ciphers = m->num_ciphers; - ret = find_cipher_by_id(ssl, empty_method, 0xC00A); - tt_int_op(ret, OP_EQ, 1); - - empty_method->num_ciphers = fake_num_ciphers; - ret = find_cipher_by_id(ssl, empty_method, 0xC00A); -#ifdef HAVE_SSL_CIPHER_FIND - tt_int_op(ret, OP_EQ, 1); -#else - tt_int_op(ret, OP_EQ, 0); -#endif - - done: - tor_free(empty_method); - SSL_free(ssl); - SSL_CTX_free(ctx); - tor_free(fixed_cipher1); -} -#endif /* !defined(OPENSSL_OPAQUE) */ - -#ifndef OPENSSL_OPAQUE static void test_tortls_debug_state_callback(void *ignored) { @@ -2068,20 +1597,21 @@ (void)ignored; int ret; tor_x509_cert_t *cert = NULL, *scert = NULL; + time_t now = cert_strings_valid_at; scert = tor_malloc_zero(sizeof(tor_x509_cert_t)); - ret = tor_tls_cert_is_valid(LOG_WARN, cert, scert, time(NULL), 0); + ret = tor_tls_cert_is_valid(LOG_WARN, cert, scert, now, 0); tt_int_op(ret, OP_EQ, 0); cert = tor_malloc_zero(sizeof(tor_x509_cert_t)); - ret = tor_tls_cert_is_valid(LOG_WARN, cert, scert, time(NULL), 0); + ret = tor_tls_cert_is_valid(LOG_WARN, cert, scert, now, 0); tt_int_op(ret, OP_EQ, 0); tor_free(scert); tor_free(cert); cert = tor_x509_cert_new(read_cert_from(validCertString)); scert = tor_x509_cert_new(read_cert_from(caCertString)); - ret = tor_tls_cert_is_valid(LOG_WARN, cert, scert, time(NULL), 0); + ret = tor_tls_cert_is_valid(LOG_WARN, cert, scert, now, 0); tt_int_op(ret, OP_EQ, 1); #ifndef OPENSSL_OPAQUE @@ -2092,7 +1622,7 @@ ASN1_TIME_free(cert->cert->cert_info->validity->notAfter); cert->cert->cert_info->validity->notAfter = ASN1_TIME_set(NULL, time(NULL)-1000000); - ret = tor_tls_cert_is_valid(LOG_WARN, cert, scert, time(NULL), 0); + ret = tor_tls_cert_is_valid(LOG_WARN, cert, scert, now, 0); tt_int_op(ret, OP_EQ, 0); tor_x509_cert_free(cert); @@ -2101,7 +1631,7 @@ scert = tor_x509_cert_new(read_cert_from(caCertString)); X509_PUBKEY_free(cert->cert->cert_info->key); cert->cert->cert_info->key = NULL; - ret = tor_tls_cert_is_valid(LOG_WARN, cert, scert, time(NULL), 1); + ret = tor_tls_cert_is_valid(LOG_WARN, cert, scert, now, 1); tt_int_op(ret, OP_EQ, 0); #endif /* !defined(OPENSSL_OPAQUE) */ @@ -2112,7 +1642,7 @@ scert = tor_x509_cert_new(read_cert_from(caCertString)); /* This doesn't actually change the key in the cert. XXXXXX */ BN_one(EVP_PKEY_get1_RSA(X509_get_pubkey(cert->cert))->n); - ret = tor_tls_cert_is_valid(LOG_WARN, cert, scert, time(NULL), 1); + ret = tor_tls_cert_is_valid(LOG_WARN, cert, scert, now, 1); tt_int_op(ret, OP_EQ, 0); tor_x509_cert_free(cert); @@ -2121,7 +1651,7 @@ scert = tor_x509_cert_new(read_cert_from(caCertString)); /* This doesn't actually change the key in the cert. XXXXXX */ X509_get_pubkey(cert->cert)->type = EVP_PKEY_EC; - ret = tor_tls_cert_is_valid(LOG_WARN, cert, scert, time(NULL), 1); + ret = tor_tls_cert_is_valid(LOG_WARN, cert, scert, now, 1); tt_int_op(ret, OP_EQ, 0); tor_x509_cert_free(cert); @@ -2130,7 +1660,7 @@ scert = tor_x509_cert_new(read_cert_from(caCertString)); /* This doesn't actually change the key in the cert. XXXXXX */ X509_get_pubkey(cert->cert)->type = EVP_PKEY_EC; - ret = tor_tls_cert_is_valid(LOG_WARN, cert, scert, time(NULL), 0); + ret = tor_tls_cert_is_valid(LOG_WARN, cert, scert, now, 0); tt_int_op(ret, OP_EQ, 1); tor_x509_cert_free(cert); @@ -2140,7 +1670,7 @@ /* This doesn't actually change the key in the cert. XXXXXX */ X509_get_pubkey(cert->cert)->type = EVP_PKEY_EC; X509_get_pubkey(cert->cert)->ameth = NULL; - ret = tor_tls_cert_is_valid(LOG_WARN, cert, scert, time(NULL), 0); + ret = tor_tls_cert_is_valid(LOG_WARN, cert, scert, now, 0); tt_int_op(ret, OP_EQ, 0); #endif /* 0 */ @@ -2187,15 +1717,10 @@ LOCAL_TEST_CASE(always_accept_verify_cb, 0), INTRUSIVE_TEST_CASE(x509_cert_free, 0), INTRUSIVE_TEST_CASE(cert_get_key, 0), - LOCAL_TEST_CASE(get_my_client_auth_key, TT_FORK), INTRUSIVE_TEST_CASE(get_ciphersuite_name, 0), INTRUSIVE_TEST_CASE(classify_client_ciphers, 0), - LOCAL_TEST_CASE(client_is_using_v2_ciphers, 0), INTRUSIVE_TEST_CASE(get_pending_bytes, 0), - INTRUSIVE_TEST_CASE(SSL_SESSION_get_master_key, 0), - INTRUSIVE_TEST_CASE(get_tlssecrets, 0), INTRUSIVE_TEST_CASE(get_buffer_sizes, 0), - INTRUSIVE_TEST_CASE(try_to_extract_certs_from_tls, 0), INTRUSIVE_TEST_CASE(get_peer_cert, 0), INTRUSIVE_TEST_CASE(peer_has_cert, 0), INTRUSIVE_TEST_CASE(finish_handshake, 0), @@ -2209,7 +1734,6 @@ INTRUSIVE_TEST_CASE(unblock_renegotiation, 0), INTRUSIVE_TEST_CASE(set_renegotiate_callback, 0), LOCAL_TEST_CASE(set_logged_address, 0), - INTRUSIVE_TEST_CASE(find_cipher_by_id, 0), INTRUSIVE_TEST_CASE(session_secret_cb, 0), INTRUSIVE_TEST_CASE(debug_state_callback, 0), INTRUSIVE_TEST_CASE(context_new, TT_FORK /* redundant */), diff -Nru tor-0.4.7.16/src/test/test_util.c tor-0.4.9.6/src/test/test_util.c --- tor-0.4.7.16/src/test/test_util.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/test/test_util.c 2026-03-25 14:30:34.000000000 +0000 @@ -2876,8 +2876,8 @@ size_t szr, szr2; int r; - const size_t big = 1024*1024; - /* one megabyte of 0s. */ + const size_t big = 5*1024*1024; + /* five megabytes of 0s. */ input = tor_malloc_zero(big); /* Compress it into "result": it should fail. */ @@ -2934,8 +2934,8 @@ * In Tor we try not to generate them, and we don't accept them. */ (void) arg; - size_t one_million = 1<<20; - char *one_mb = tor_malloc_zero(one_million); + size_t six_megabytes = 6 * 1024 * 1024; + char *buffer = tor_malloc_zero(six_megabytes); char *result = NULL; size_t result_len = 0; tor_compress_state_t *state = NULL; @@ -2943,29 +2943,29 @@ /* Make sure we can't produce a compression bomb */ setup_full_capture_of_logs(LOG_WARN); tt_int_op(-1, OP_EQ, tor_compress(&result, &result_len, - one_mb, one_million, + buffer, six_megabytes, ZLIB_METHOD)); - expect_single_log_msg_containing( + expect_log_msg_containing( "We compressed something and got an insanely high " "compression factor; other Tors would think this " "was a compression bomb."); teardown_capture_of_logs(); /* Here's a compression bomb that we made manually. */ - const char compression_bomb[1039] = - { 0x78, 0xDA, 0xED, 0xC1, 0x31, 0x01, 0x00, 0x00, 0x00, 0xC2, - 0xA0, 0xF5, 0x4F, 0x6D, 0x08, 0x5F, 0xA0 /* .... */ }; + #include "test/compression_bomb.h" + tt_int_op(-1, OP_EQ, tor_uncompress(&result, &result_len, - compression_bomb, 1039, - ZLIB_METHOD, 0, LOG_WARN)); + compression_bomb_gzip, + compression_bomb_gzip_len, + GZIP_METHOD, 0, LOG_WARN)); /* Now try streaming that. */ - state = tor_compress_new(0, ZLIB_METHOD, HIGH_COMPRESSION); + state = tor_compress_new(0, GZIP_METHOD, HIGH_COMPRESSION); tor_compress_output_t r; - const char *inp = compression_bomb; - size_t inlen = 1039; + const char *inp = compression_bomb_gzip; + size_t inlen = compression_bomb_gzip_len; do { - char *outp = one_mb; + char *outp = buffer; size_t outleft = 4096; /* small on purpose */ r = tor_compress_process(state, &outp, &outleft, &inp, &inlen, 0); tt_int_op(inlen, OP_NE, 0); @@ -2974,7 +2974,7 @@ tt_int_op(r, OP_EQ, TOR_COMPRESS_ERROR); done: - tor_free(one_mb); + tor_free(buffer); tor_compress_free(state); } @@ -4173,11 +4173,11 @@ "howdy world. how are you? i hope it's fine.\n" "hello kitty\n" "third line"; - char *line2 = strchr(long_string,'\n')+1; - char *line3 = strchr(line2,'\n')+1; + const char *line2 = strchr(long_string,'\n')+1; + const char *line3 = strchr(line2,'\n')+1; const char *short_string = "hello kitty\n" "second line\n"; - char *short_line2 = strchr(short_string,'\n')+1; + const char *short_line2 = strchr(short_string,'\n')+1; (void)ptr; diff -Nru tor-0.4.7.16/src/test/test_util_format.c tor-0.4.9.6/src/test/test_util_format.c --- tor-0.4.7.16/src/test/test_util_format.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/test/test_util_format.c 2026-03-25 14:30:34.000000000 +0000 @@ -13,7 +13,7 @@ test_util_format_unaligned_accessors(void *ignored) { (void)ignored; - char buf[9] = "onionsoup"; // 6f6e696f6e736f7570 + NONSTRING char buf[9] = "onionsoup"; // 6f6e696f6e736f7570 tt_u64_op(get_uint64(buf+1), OP_EQ, tor_htonll(UINT64_C(0x6e696f6e736f7570))); diff -Nru tor-0.4.7.16/src/test/test_voting_flags.c tor-0.4.9.6/src/test/test_voting_flags.c --- tor-0.4.7.16/src/test/test_voting_flags.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/test/test_voting_flags.c 2026-03-25 14:30:34.000000000 +0000 @@ -40,7 +40,6 @@ memset(c->ri.cache_info.signed_descriptor_digest, 0xee, DIGEST_LEN); c->ri.cache_info.published_on = c->now - 100; - c->expected.published_on = c->now - 100; tor_addr_from_ipv4h(&c->ri.ipv4_addr, 0x7f010105); tor_addr_from_ipv4h(&c->expected.ipv4_addr, 0x7f010105); @@ -65,7 +64,6 @@ dirauth_set_routerstatus_from_routerinfo(&rs, &c->node, &c->ri, c->now, 0, 0); - tt_i64_op(rs.published_on, OP_EQ, c->expected.published_on); tt_str_op(rs.nickname, OP_EQ, c->expected.nickname); // identity_digest and descriptor_digest are not set here. @@ -144,13 +142,11 @@ time_t now = cfg->now; cfg->ri.cache_info.published_on = now - DESC_IS_STALE_INTERVAL + 10; - cfg->expected.published_on = now - DESC_IS_STALE_INTERVAL + 10; // no change in expectations for is_staledesc if (!check_result(cfg)) goto done; cfg->ri.cache_info.published_on = now - DESC_IS_STALE_INTERVAL - 10; - cfg->expected.published_on = now - DESC_IS_STALE_INTERVAL - 10; cfg->expected.is_staledesc = 1; if (!check_result(cfg)) goto done; diff -Nru tor-0.4.7.16/src/test/testing_common.c tor-0.4.9.6/src/test/testing_common.c --- tor-0.4.7.16/src/test/testing_common.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/test/testing_common.c 2026-03-25 14:30:34.000000000 +0000 @@ -244,14 +244,18 @@ void tinytest_prefork(void) { +#ifdef ENABLE_NSS free_pregenerated_keys(); +#endif subsystems_prefork(); } void tinytest_postfork(void) { subsystems_postfork(); +#ifdef ENABLE_NSS init_pregenerated_keys(); +#endif } static void diff -Nru tor-0.4.7.16/src/tools/include.am tor-0.4.9.6/src/tools/include.am --- tor-0.4.7.16/src/tools/include.am 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/tools/include.am 2026-03-25 14:30:34.000000000 +0000 @@ -9,7 +9,7 @@ src_tools_tor_resolve_LDADD = \ src/trunnel/libor-trunnel.a \ $(TOR_UTIL_LIBS) \ - $(TOR_CRYPTO_LIBS) $(TOR_LIBS_CRYPTLIB)\ + $(TOR_CRYPTO_LIBS) $(TOR_LIBS_CRYPTLIB)\ @TOR_LIB_MATH@ @TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_SHLWAPI@ @TOR_LIB_USERENV@ if COVERAGE_ENABLED @@ -41,8 +41,8 @@ src_tools_tor_print_ed_signing_cert_LDFLAGS = @TOR_LDFLAGS_zlib@ @TOR_LDFLAGS_openssl@ src_tools_tor_print_ed_signing_cert_LDADD = \ src/trunnel/libor-trunnel.a \ - $(TOR_CRYPTO_LIBS) \ - $(TOR_UTIL_LIBS) \ + $(TOR_CRYPTO_LIBS) \ + $(TOR_UTIL_LIBS) \ @TOR_LIB_MATH@ $(TOR_LIBS_CRYPTLIB) \ @TOR_LIB_WS32@ @TOR_LIB_USERENV@ @TOR_LIB_SHLWAPI@ @TOR_LIB_GDI@ @@ -66,6 +66,6 @@ if BUILD_LIBTORRUNNER noinst_LIBRARIES += src/tools/libtorrunner.a src_tools_libtorrunner_a_SOURCES = \ - src/tools/tor_runner.c \ - src/feature/api/tor_api.c + src/tools/tor_runner.c \ + src/feature/api/tor_api.c endif diff -Nru tor-0.4.7.16/src/tools/tor-resolve.c tor-0.4.9.6/src/tools/tor-resolve.c --- tor-0.4.7.16/src/tools/tor-resolve.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/tools/tor-resolve.c 2026-03-25 14:30:34.000000000 +0000 @@ -385,7 +385,7 @@ tor_addr_make_unspec(result_addr); *result_hostname = NULL; - s = tor_open_socket(PF_INET,SOCK_STREAM,IPPROTO_TCP); + s = tor_open_socket(sockshost->family,SOCK_STREAM,IPPROTO_TCP); if (s<0) { log_sock_error("creating_socket", -1); return -1; diff -Nru tor-0.4.7.16/src/trunnel/conflux.c tor-0.4.9.6/src/trunnel/conflux.c --- tor-0.4.7.16/src/trunnel/conflux.c 1970-01-01 00:00:00.000000000 +0000 +++ tor-0.4.9.6/src/trunnel/conflux.c 2026-03-25 14:30:34.000000000 +0000 @@ -0,0 +1,1158 @@ +/* conflux.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 "conflux.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 conflux_deadcode_dummy__ = 0; +#define OR_DEADCODE_DUMMY || conflux_deadcode_dummy__ +#else +#define OR_DEADCODE_DUMMY +#endif + +#define CHECK_REMAINING(nbytes, label) \ + do { \ + if (remaining < (nbytes) OR_DEADCODE_DUMMY) { \ + goto label; \ + } \ + } while (0) + +trn_cell_conflux_link_t * +trn_cell_conflux_link_new(void) +{ + trn_cell_conflux_link_t *val = trunnel_calloc(1, sizeof(trn_cell_conflux_link_t)); + if (NULL == val) + return NULL; + val->version = 1; + return val; +} + +/** Release all storage held inside 'obj', but do not free 'obj'. + */ +static void +trn_cell_conflux_link_clear(trn_cell_conflux_link_t *obj) +{ + (void) obj; + TRUNNEL_DYNARRAY_WIPE(&obj->payload); + TRUNNEL_DYNARRAY_CLEAR(&obj->payload); +} + +void +trn_cell_conflux_link_free(trn_cell_conflux_link_t *obj) +{ + if (obj == NULL) + return; + trn_cell_conflux_link_clear(obj); + trunnel_memwipe(obj, sizeof(trn_cell_conflux_link_t)); + trunnel_free_(obj); +} + +uint8_t +trn_cell_conflux_link_get_version(const trn_cell_conflux_link_t *inp) +{ + return inp->version; +} +int +trn_cell_conflux_link_set_version(trn_cell_conflux_link_t *inp, uint8_t val) +{ + if (! ((val == 1))) { + TRUNNEL_SET_ERROR_CODE(inp); + return -1; + } + inp->version = val; + return 0; +} +size_t +trn_cell_conflux_link_getlen_payload(const trn_cell_conflux_link_t *inp) +{ + return TRUNNEL_DYNARRAY_LEN(&inp->payload); +} + +uint8_t +trn_cell_conflux_link_get_payload(trn_cell_conflux_link_t *inp, size_t idx) +{ + return TRUNNEL_DYNARRAY_GET(&inp->payload, idx); +} + +uint8_t +trn_cell_conflux_link_getconst_payload(const trn_cell_conflux_link_t *inp, size_t idx) +{ + return trn_cell_conflux_link_get_payload((trn_cell_conflux_link_t*)inp, idx); +} +int +trn_cell_conflux_link_set_payload(trn_cell_conflux_link_t *inp, size_t idx, uint8_t elt) +{ + TRUNNEL_DYNARRAY_SET(&inp->payload, idx, elt); + return 0; +} +int +trn_cell_conflux_link_add_payload(trn_cell_conflux_link_t *inp, uint8_t elt) +{ + TRUNNEL_DYNARRAY_ADD(uint8_t, &inp->payload, elt, {}); + return 0; + trunnel_alloc_failed: + TRUNNEL_SET_ERROR_CODE(inp); + return -1; +} + +uint8_t * +trn_cell_conflux_link_getarray_payload(trn_cell_conflux_link_t *inp) +{ + return inp->payload.elts_; +} +const uint8_t * +trn_cell_conflux_link_getconstarray_payload(const trn_cell_conflux_link_t *inp) +{ + return (const uint8_t *)trn_cell_conflux_link_getarray_payload((trn_cell_conflux_link_t*)inp); +} +int +trn_cell_conflux_link_setlen_payload(trn_cell_conflux_link_t *inp, size_t newlen) +{ + uint8_t *newptr; + newptr = trunnel_dynarray_setlen(&inp->payload.allocated_, + &inp->payload.n_, inp->payload.elts_, newlen, + sizeof(inp->payload.elts_[0]), (trunnel_free_fn_t) NULL, + &inp->trunnel_error_code_); + if (newlen != 0 && newptr == NULL) + goto trunnel_alloc_failed; + inp->payload.elts_ = newptr; + return 0; + trunnel_alloc_failed: + TRUNNEL_SET_ERROR_CODE(inp); + return -1; +} +const char * +trn_cell_conflux_link_check(const trn_cell_conflux_link_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 == 1)) + return "Integer out of bounds"; + return NULL; +} + +ssize_t +trn_cell_conflux_link_encoded_len(const trn_cell_conflux_link_t *obj) +{ + ssize_t result = 0; + + if (NULL != trn_cell_conflux_link_check(obj)) + return -1; + + + /* Length of u8 version IN [1] */ + result += 1; + + /* Length of u8 payload[] */ + result += TRUNNEL_DYNARRAY_LEN(&obj->payload); + return result; +} +int +trn_cell_conflux_link_clear_errors(trn_cell_conflux_link_t *obj) +{ + int r = obj->trunnel_error_code_; + obj->trunnel_error_code_ = 0; + return r; +} +ssize_t +trn_cell_conflux_link_encode(uint8_t *output, const size_t avail, const trn_cell_conflux_link_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 = trn_cell_conflux_link_encoded_len(obj); +#endif + + if (NULL != (msg = trn_cell_conflux_link_check(obj))) + goto check_failed; + +#ifdef TRUNNEL_CHECK_ENCODED_LEN + trunnel_assert(encoded_len >= 0); +#endif + + /* Encode u8 version IN [1] */ + trunnel_assert(written <= avail); + if (avail - written < 1) + goto truncated; + trunnel_set_uint8(ptr, (obj->version)); + written += 1; ptr += 1; + + /* Encode u8 payload[] */ + { + size_t elt_len = TRUNNEL_DYNARRAY_LEN(&obj->payload); + trunnel_assert(written <= avail); + if (avail - written < elt_len) + goto truncated; + if (elt_len) + memcpy(ptr, obj->payload.elts_, elt_len); + written += elt_len; ptr += elt_len; + } + + + 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 trn_cell_conflux_link_parse(), but do not allocate the output + * object. + */ +static ssize_t +trn_cell_conflux_link_parse_into(trn_cell_conflux_link_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 [1] */ + CHECK_REMAINING(1, truncated); + obj->version = (trunnel_get_uint8(ptr)); + remaining -= 1; ptr += 1; + if (! (obj->version == 1)) + goto fail; + + /* Parse u8 payload[] */ + TRUNNEL_DYNARRAY_EXPAND(uint8_t, &obj->payload, remaining, {}); + obj->payload.n_ = remaining; + if (remaining) + memcpy(obj->payload.elts_, ptr, remaining); + ptr += remaining; remaining -= remaining; + trunnel_assert(ptr + remaining == input + len_in); + return len_in - remaining; + + truncated: + return -2; + trunnel_alloc_failed: + return -1; + fail: + result = -1; + return result; +} + +ssize_t +trn_cell_conflux_link_parse(trn_cell_conflux_link_t **output, const uint8_t *input, const size_t len_in) +{ + ssize_t result; + *output = trn_cell_conflux_link_new(); + if (NULL == *output) + return -1; + result = trn_cell_conflux_link_parse_into(*output, input, len_in); + if (result < 0) { + trn_cell_conflux_link_free(*output); + *output = NULL; + } + return result; +} +trn_cell_conflux_link_payload_v1_t * +trn_cell_conflux_link_payload_v1_new(void) +{ + trn_cell_conflux_link_payload_v1_t *val = trunnel_calloc(1, sizeof(trn_cell_conflux_link_payload_v1_t)); + if (NULL == val) + return NULL; + val->desired_ux = CONFLUX_UX_HIGH_THROUGHPUT; + return val; +} + +/** Release all storage held inside 'obj', but do not free 'obj'. + */ +static void +trn_cell_conflux_link_payload_v1_clear(trn_cell_conflux_link_payload_v1_t *obj) +{ + (void) obj; +} + +void +trn_cell_conflux_link_payload_v1_free(trn_cell_conflux_link_payload_v1_t *obj) +{ + if (obj == NULL) + return; + trn_cell_conflux_link_payload_v1_clear(obj); + trunnel_memwipe(obj, sizeof(trn_cell_conflux_link_payload_v1_t)); + trunnel_free_(obj); +} + +size_t +trn_cell_conflux_link_payload_v1_getlen_nonce(const trn_cell_conflux_link_payload_v1_t *inp) +{ + (void)inp; return 32; +} + +uint8_t +trn_cell_conflux_link_payload_v1_get_nonce(trn_cell_conflux_link_payload_v1_t *inp, size_t idx) +{ + trunnel_assert(idx < 32); + return inp->nonce[idx]; +} + +uint8_t +trn_cell_conflux_link_payload_v1_getconst_nonce(const trn_cell_conflux_link_payload_v1_t *inp, size_t idx) +{ + return trn_cell_conflux_link_payload_v1_get_nonce((trn_cell_conflux_link_payload_v1_t*)inp, idx); +} +int +trn_cell_conflux_link_payload_v1_set_nonce(trn_cell_conflux_link_payload_v1_t *inp, size_t idx, uint8_t elt) +{ + trunnel_assert(idx < 32); + inp->nonce[idx] = elt; + return 0; +} + +uint8_t * +trn_cell_conflux_link_payload_v1_getarray_nonce(trn_cell_conflux_link_payload_v1_t *inp) +{ + return inp->nonce; +} +const uint8_t * +trn_cell_conflux_link_payload_v1_getconstarray_nonce(const trn_cell_conflux_link_payload_v1_t *inp) +{ + return (const uint8_t *)trn_cell_conflux_link_payload_v1_getarray_nonce((trn_cell_conflux_link_payload_v1_t*)inp); +} +uint64_t +trn_cell_conflux_link_payload_v1_get_last_seqno_sent(const trn_cell_conflux_link_payload_v1_t *inp) +{ + return inp->last_seqno_sent; +} +int +trn_cell_conflux_link_payload_v1_set_last_seqno_sent(trn_cell_conflux_link_payload_v1_t *inp, uint64_t val) +{ + inp->last_seqno_sent = val; + return 0; +} +uint64_t +trn_cell_conflux_link_payload_v1_get_last_seqno_recv(const trn_cell_conflux_link_payload_v1_t *inp) +{ + return inp->last_seqno_recv; +} +int +trn_cell_conflux_link_payload_v1_set_last_seqno_recv(trn_cell_conflux_link_payload_v1_t *inp, uint64_t val) +{ + inp->last_seqno_recv = val; + return 0; +} +uint8_t +trn_cell_conflux_link_payload_v1_get_desired_ux(const trn_cell_conflux_link_payload_v1_t *inp) +{ + return inp->desired_ux; +} +int +trn_cell_conflux_link_payload_v1_set_desired_ux(trn_cell_conflux_link_payload_v1_t *inp, uint8_t val) +{ + if (! ((val == CONFLUX_UX_HIGH_THROUGHPUT || val == CONFLUX_UX_LOW_MEM_LATENCY || val == CONFLUX_UX_LOW_MEM_THROUGHPUT || val == CONFLUX_UX_MIN_LATENCY || val == CONFLUX_UX_NO_OPINION))) { + TRUNNEL_SET_ERROR_CODE(inp); + return -1; + } + inp->desired_ux = val; + return 0; +} +const char * +trn_cell_conflux_link_payload_v1_check(const trn_cell_conflux_link_payload_v1_t *obj) +{ + if (obj == NULL) + return "Object was NULL"; + if (obj->trunnel_error_code_) + return "A set function failed on this object"; + if (! (obj->desired_ux == CONFLUX_UX_HIGH_THROUGHPUT || obj->desired_ux == CONFLUX_UX_LOW_MEM_LATENCY || obj->desired_ux == CONFLUX_UX_LOW_MEM_THROUGHPUT || obj->desired_ux == CONFLUX_UX_MIN_LATENCY || obj->desired_ux == CONFLUX_UX_NO_OPINION)) + return "Integer out of bounds"; + return NULL; +} + +ssize_t +trn_cell_conflux_link_payload_v1_encoded_len(const trn_cell_conflux_link_payload_v1_t *obj) +{ + ssize_t result = 0; + + if (NULL != trn_cell_conflux_link_payload_v1_check(obj)) + return -1; + + + /* Length of u8 nonce[32] */ + result += 32; + + /* Length of u64 last_seqno_sent */ + result += 8; + + /* Length of u64 last_seqno_recv */ + result += 8; + + /* Length of u8 desired_ux IN [CONFLUX_UX_HIGH_THROUGHPUT, CONFLUX_UX_LOW_MEM_LATENCY, CONFLUX_UX_LOW_MEM_THROUGHPUT, CONFLUX_UX_MIN_LATENCY, CONFLUX_UX_NO_OPINION] */ + result += 1; + return result; +} +int +trn_cell_conflux_link_payload_v1_clear_errors(trn_cell_conflux_link_payload_v1_t *obj) +{ + int r = obj->trunnel_error_code_; + obj->trunnel_error_code_ = 0; + return r; +} +ssize_t +trn_cell_conflux_link_payload_v1_encode(uint8_t *output, const size_t avail, const trn_cell_conflux_link_payload_v1_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 = trn_cell_conflux_link_payload_v1_encoded_len(obj); +#endif + + if (NULL != (msg = trn_cell_conflux_link_payload_v1_check(obj))) + goto check_failed; + +#ifdef TRUNNEL_CHECK_ENCODED_LEN + trunnel_assert(encoded_len >= 0); +#endif + + /* Encode u8 nonce[32] */ + trunnel_assert(written <= avail); + if (avail - written < 32) + goto truncated; + memcpy(ptr, obj->nonce, 32); + written += 32; ptr += 32; + + /* Encode u64 last_seqno_sent */ + trunnel_assert(written <= avail); + if (avail - written < 8) + goto truncated; + trunnel_set_uint64(ptr, trunnel_htonll(obj->last_seqno_sent)); + written += 8; ptr += 8; + + /* Encode u64 last_seqno_recv */ + trunnel_assert(written <= avail); + if (avail - written < 8) + goto truncated; + trunnel_set_uint64(ptr, trunnel_htonll(obj->last_seqno_recv)); + written += 8; ptr += 8; + + /* Encode u8 desired_ux IN [CONFLUX_UX_HIGH_THROUGHPUT, CONFLUX_UX_LOW_MEM_LATENCY, CONFLUX_UX_LOW_MEM_THROUGHPUT, CONFLUX_UX_MIN_LATENCY, CONFLUX_UX_NO_OPINION] */ + trunnel_assert(written <= avail); + if (avail - written < 1) + goto truncated; + trunnel_set_uint8(ptr, (obj->desired_ux)); + written += 1; ptr += 1; + + + 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 trn_cell_conflux_link_payload_v1_parse(), but do not allocate + * the output object. + */ +static ssize_t +trn_cell_conflux_link_payload_v1_parse_into(trn_cell_conflux_link_payload_v1_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 nonce[32] */ + CHECK_REMAINING(32, truncated); + memcpy(obj->nonce, ptr, 32); + remaining -= 32; ptr += 32; + + /* Parse u64 last_seqno_sent */ + CHECK_REMAINING(8, truncated); + obj->last_seqno_sent = trunnel_ntohll(trunnel_get_uint64(ptr)); + remaining -= 8; ptr += 8; + + /* Parse u64 last_seqno_recv */ + CHECK_REMAINING(8, truncated); + obj->last_seqno_recv = trunnel_ntohll(trunnel_get_uint64(ptr)); + remaining -= 8; ptr += 8; + + /* Parse u8 desired_ux IN [CONFLUX_UX_HIGH_THROUGHPUT, CONFLUX_UX_LOW_MEM_LATENCY, CONFLUX_UX_LOW_MEM_THROUGHPUT, CONFLUX_UX_MIN_LATENCY, CONFLUX_UX_NO_OPINION] */ + CHECK_REMAINING(1, truncated); + obj->desired_ux = (trunnel_get_uint8(ptr)); + remaining -= 1; ptr += 1; + if (! (obj->desired_ux == CONFLUX_UX_HIGH_THROUGHPUT || obj->desired_ux == CONFLUX_UX_LOW_MEM_LATENCY || obj->desired_ux == CONFLUX_UX_LOW_MEM_THROUGHPUT || obj->desired_ux == CONFLUX_UX_MIN_LATENCY || obj->desired_ux == CONFLUX_UX_NO_OPINION)) + goto fail; + trunnel_assert(ptr + remaining == input + len_in); + return len_in - remaining; + + truncated: + return -2; + fail: + result = -1; + return result; +} + +ssize_t +trn_cell_conflux_link_payload_v1_parse(trn_cell_conflux_link_payload_v1_t **output, const uint8_t *input, const size_t len_in) +{ + ssize_t result; + *output = trn_cell_conflux_link_payload_v1_new(); + if (NULL == *output) + return -1; + result = trn_cell_conflux_link_payload_v1_parse_into(*output, input, len_in); + if (result < 0) { + trn_cell_conflux_link_payload_v1_free(*output); + *output = NULL; + } + return result; +} +trn_cell_conflux_linked_t * +trn_cell_conflux_linked_new(void) +{ + trn_cell_conflux_linked_t *val = trunnel_calloc(1, sizeof(trn_cell_conflux_linked_t)); + if (NULL == val) + return NULL; + val->version = 1; + return val; +} + +/** Release all storage held inside 'obj', but do not free 'obj'. + */ +static void +trn_cell_conflux_linked_clear(trn_cell_conflux_linked_t *obj) +{ + (void) obj; + TRUNNEL_DYNARRAY_WIPE(&obj->payload); + TRUNNEL_DYNARRAY_CLEAR(&obj->payload); +} + +void +trn_cell_conflux_linked_free(trn_cell_conflux_linked_t *obj) +{ + if (obj == NULL) + return; + trn_cell_conflux_linked_clear(obj); + trunnel_memwipe(obj, sizeof(trn_cell_conflux_linked_t)); + trunnel_free_(obj); +} + +uint8_t +trn_cell_conflux_linked_get_version(const trn_cell_conflux_linked_t *inp) +{ + return inp->version; +} +int +trn_cell_conflux_linked_set_version(trn_cell_conflux_linked_t *inp, uint8_t val) +{ + if (! ((val == 1))) { + TRUNNEL_SET_ERROR_CODE(inp); + return -1; + } + inp->version = val; + return 0; +} +size_t +trn_cell_conflux_linked_getlen_payload(const trn_cell_conflux_linked_t *inp) +{ + return TRUNNEL_DYNARRAY_LEN(&inp->payload); +} + +uint8_t +trn_cell_conflux_linked_get_payload(trn_cell_conflux_linked_t *inp, size_t idx) +{ + return TRUNNEL_DYNARRAY_GET(&inp->payload, idx); +} + +uint8_t +trn_cell_conflux_linked_getconst_payload(const trn_cell_conflux_linked_t *inp, size_t idx) +{ + return trn_cell_conflux_linked_get_payload((trn_cell_conflux_linked_t*)inp, idx); +} +int +trn_cell_conflux_linked_set_payload(trn_cell_conflux_linked_t *inp, size_t idx, uint8_t elt) +{ + TRUNNEL_DYNARRAY_SET(&inp->payload, idx, elt); + return 0; +} +int +trn_cell_conflux_linked_add_payload(trn_cell_conflux_linked_t *inp, uint8_t elt) +{ + TRUNNEL_DYNARRAY_ADD(uint8_t, &inp->payload, elt, {}); + return 0; + trunnel_alloc_failed: + TRUNNEL_SET_ERROR_CODE(inp); + return -1; +} + +uint8_t * +trn_cell_conflux_linked_getarray_payload(trn_cell_conflux_linked_t *inp) +{ + return inp->payload.elts_; +} +const uint8_t * +trn_cell_conflux_linked_getconstarray_payload(const trn_cell_conflux_linked_t *inp) +{ + return (const uint8_t *)trn_cell_conflux_linked_getarray_payload((trn_cell_conflux_linked_t*)inp); +} +int +trn_cell_conflux_linked_setlen_payload(trn_cell_conflux_linked_t *inp, size_t newlen) +{ + uint8_t *newptr; + newptr = trunnel_dynarray_setlen(&inp->payload.allocated_, + &inp->payload.n_, inp->payload.elts_, newlen, + sizeof(inp->payload.elts_[0]), (trunnel_free_fn_t) NULL, + &inp->trunnel_error_code_); + if (newlen != 0 && newptr == NULL) + goto trunnel_alloc_failed; + inp->payload.elts_ = newptr; + return 0; + trunnel_alloc_failed: + TRUNNEL_SET_ERROR_CODE(inp); + return -1; +} +const char * +trn_cell_conflux_linked_check(const trn_cell_conflux_linked_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 == 1)) + return "Integer out of bounds"; + return NULL; +} + +ssize_t +trn_cell_conflux_linked_encoded_len(const trn_cell_conflux_linked_t *obj) +{ + ssize_t result = 0; + + if (NULL != trn_cell_conflux_linked_check(obj)) + return -1; + + + /* Length of u8 version IN [1] */ + result += 1; + + /* Length of u8 payload[] */ + result += TRUNNEL_DYNARRAY_LEN(&obj->payload); + return result; +} +int +trn_cell_conflux_linked_clear_errors(trn_cell_conflux_linked_t *obj) +{ + int r = obj->trunnel_error_code_; + obj->trunnel_error_code_ = 0; + return r; +} +ssize_t +trn_cell_conflux_linked_encode(uint8_t *output, const size_t avail, const trn_cell_conflux_linked_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 = trn_cell_conflux_linked_encoded_len(obj); +#endif + + if (NULL != (msg = trn_cell_conflux_linked_check(obj))) + goto check_failed; + +#ifdef TRUNNEL_CHECK_ENCODED_LEN + trunnel_assert(encoded_len >= 0); +#endif + + /* Encode u8 version IN [1] */ + trunnel_assert(written <= avail); + if (avail - written < 1) + goto truncated; + trunnel_set_uint8(ptr, (obj->version)); + written += 1; ptr += 1; + + /* Encode u8 payload[] */ + { + size_t elt_len = TRUNNEL_DYNARRAY_LEN(&obj->payload); + trunnel_assert(written <= avail); + if (avail - written < elt_len) + goto truncated; + if (elt_len) + memcpy(ptr, obj->payload.elts_, elt_len); + written += elt_len; ptr += elt_len; + } + + + 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 trn_cell_conflux_linked_parse(), but do not allocate the output + * object. + */ +static ssize_t +trn_cell_conflux_linked_parse_into(trn_cell_conflux_linked_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 [1] */ + CHECK_REMAINING(1, truncated); + obj->version = (trunnel_get_uint8(ptr)); + remaining -= 1; ptr += 1; + if (! (obj->version == 1)) + goto fail; + + /* Parse u8 payload[] */ + TRUNNEL_DYNARRAY_EXPAND(uint8_t, &obj->payload, remaining, {}); + obj->payload.n_ = remaining; + if (remaining) + memcpy(obj->payload.elts_, ptr, remaining); + ptr += remaining; remaining -= remaining; + trunnel_assert(ptr + remaining == input + len_in); + return len_in - remaining; + + truncated: + return -2; + trunnel_alloc_failed: + return -1; + fail: + result = -1; + return result; +} + +ssize_t +trn_cell_conflux_linked_parse(trn_cell_conflux_linked_t **output, const uint8_t *input, const size_t len_in) +{ + ssize_t result; + *output = trn_cell_conflux_linked_new(); + if (NULL == *output) + return -1; + result = trn_cell_conflux_linked_parse_into(*output, input, len_in); + if (result < 0) { + trn_cell_conflux_linked_free(*output); + *output = NULL; + } + return result; +} +trn_cell_conflux_linked_ack_t * +trn_cell_conflux_linked_ack_new(void) +{ + trn_cell_conflux_linked_ack_t *val = trunnel_calloc(1, sizeof(trn_cell_conflux_linked_ack_t)); + if (NULL == val) + return NULL; + return val; +} + +/** Release all storage held inside 'obj', but do not free 'obj'. + */ +static void +trn_cell_conflux_linked_ack_clear(trn_cell_conflux_linked_ack_t *obj) +{ + (void) obj; + TRUNNEL_DYNARRAY_WIPE(&obj->payload); + TRUNNEL_DYNARRAY_CLEAR(&obj->payload); +} + +void +trn_cell_conflux_linked_ack_free(trn_cell_conflux_linked_ack_t *obj) +{ + if (obj == NULL) + return; + trn_cell_conflux_linked_ack_clear(obj); + trunnel_memwipe(obj, sizeof(trn_cell_conflux_linked_ack_t)); + trunnel_free_(obj); +} + +size_t +trn_cell_conflux_linked_ack_getlen_payload(const trn_cell_conflux_linked_ack_t *inp) +{ + return TRUNNEL_DYNARRAY_LEN(&inp->payload); +} + +uint8_t +trn_cell_conflux_linked_ack_get_payload(trn_cell_conflux_linked_ack_t *inp, size_t idx) +{ + return TRUNNEL_DYNARRAY_GET(&inp->payload, idx); +} + +uint8_t +trn_cell_conflux_linked_ack_getconst_payload(const trn_cell_conflux_linked_ack_t *inp, size_t idx) +{ + return trn_cell_conflux_linked_ack_get_payload((trn_cell_conflux_linked_ack_t*)inp, idx); +} +int +trn_cell_conflux_linked_ack_set_payload(trn_cell_conflux_linked_ack_t *inp, size_t idx, uint8_t elt) +{ + TRUNNEL_DYNARRAY_SET(&inp->payload, idx, elt); + return 0; +} +int +trn_cell_conflux_linked_ack_add_payload(trn_cell_conflux_linked_ack_t *inp, uint8_t elt) +{ + TRUNNEL_DYNARRAY_ADD(uint8_t, &inp->payload, elt, {}); + return 0; + trunnel_alloc_failed: + TRUNNEL_SET_ERROR_CODE(inp); + return -1; +} + +uint8_t * +trn_cell_conflux_linked_ack_getarray_payload(trn_cell_conflux_linked_ack_t *inp) +{ + return inp->payload.elts_; +} +const uint8_t * +trn_cell_conflux_linked_ack_getconstarray_payload(const trn_cell_conflux_linked_ack_t *inp) +{ + return (const uint8_t *)trn_cell_conflux_linked_ack_getarray_payload((trn_cell_conflux_linked_ack_t*)inp); +} +int +trn_cell_conflux_linked_ack_setlen_payload(trn_cell_conflux_linked_ack_t *inp, size_t newlen) +{ + uint8_t *newptr; + newptr = trunnel_dynarray_setlen(&inp->payload.allocated_, + &inp->payload.n_, inp->payload.elts_, newlen, + sizeof(inp->payload.elts_[0]), (trunnel_free_fn_t) NULL, + &inp->trunnel_error_code_); + if (newlen != 0 && newptr == NULL) + goto trunnel_alloc_failed; + inp->payload.elts_ = newptr; + return 0; + trunnel_alloc_failed: + TRUNNEL_SET_ERROR_CODE(inp); + return -1; +} +const char * +trn_cell_conflux_linked_ack_check(const trn_cell_conflux_linked_ack_t *obj) +{ + if (obj == NULL) + return "Object was NULL"; + if (obj->trunnel_error_code_) + return "A set function failed on this object"; + return NULL; +} + +ssize_t +trn_cell_conflux_linked_ack_encoded_len(const trn_cell_conflux_linked_ack_t *obj) +{ + ssize_t result = 0; + + if (NULL != trn_cell_conflux_linked_ack_check(obj)) + return -1; + + + /* Length of u8 payload[] */ + result += TRUNNEL_DYNARRAY_LEN(&obj->payload); + return result; +} +int +trn_cell_conflux_linked_ack_clear_errors(trn_cell_conflux_linked_ack_t *obj) +{ + int r = obj->trunnel_error_code_; + obj->trunnel_error_code_ = 0; + return r; +} +ssize_t +trn_cell_conflux_linked_ack_encode(uint8_t *output, const size_t avail, const trn_cell_conflux_linked_ack_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 = trn_cell_conflux_linked_ack_encoded_len(obj); +#endif + + if (NULL != (msg = trn_cell_conflux_linked_ack_check(obj))) + goto check_failed; + +#ifdef TRUNNEL_CHECK_ENCODED_LEN + trunnel_assert(encoded_len >= 0); +#endif + + /* Encode u8 payload[] */ + { + size_t elt_len = TRUNNEL_DYNARRAY_LEN(&obj->payload); + trunnel_assert(written <= avail); + if (avail - written < elt_len) + goto truncated; + if (elt_len) + memcpy(ptr, obj->payload.elts_, elt_len); + written += elt_len; ptr += elt_len; + } + + + 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 trn_cell_conflux_linked_ack_parse(), but do not allocate the + * output object. + */ +static ssize_t +trn_cell_conflux_linked_ack_parse_into(trn_cell_conflux_linked_ack_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 payload[] */ + TRUNNEL_DYNARRAY_EXPAND(uint8_t, &obj->payload, remaining, {}); + obj->payload.n_ = remaining; + if (remaining) + memcpy(obj->payload.elts_, ptr, remaining); + ptr += remaining; remaining -= remaining; + trunnel_assert(ptr + remaining == input + len_in); + return len_in - remaining; + + trunnel_alloc_failed: + return -1; +} + +ssize_t +trn_cell_conflux_linked_ack_parse(trn_cell_conflux_linked_ack_t **output, const uint8_t *input, const size_t len_in) +{ + ssize_t result; + *output = trn_cell_conflux_linked_ack_new(); + if (NULL == *output) + return -1; + result = trn_cell_conflux_linked_ack_parse_into(*output, input, len_in); + if (result < 0) { + trn_cell_conflux_linked_ack_free(*output); + *output = NULL; + } + return result; +} +trn_cell_conflux_switch_t * +trn_cell_conflux_switch_new(void) +{ + trn_cell_conflux_switch_t *val = trunnel_calloc(1, sizeof(trn_cell_conflux_switch_t)); + if (NULL == val) + return NULL; + return val; +} + +/** Release all storage held inside 'obj', but do not free 'obj'. + */ +static void +trn_cell_conflux_switch_clear(trn_cell_conflux_switch_t *obj) +{ + (void) obj; +} + +void +trn_cell_conflux_switch_free(trn_cell_conflux_switch_t *obj) +{ + if (obj == NULL) + return; + trn_cell_conflux_switch_clear(obj); + trunnel_memwipe(obj, sizeof(trn_cell_conflux_switch_t)); + trunnel_free_(obj); +} + +uint32_t +trn_cell_conflux_switch_get_seqnum(const trn_cell_conflux_switch_t *inp) +{ + return inp->seqnum; +} +int +trn_cell_conflux_switch_set_seqnum(trn_cell_conflux_switch_t *inp, uint32_t val) +{ + inp->seqnum = val; + return 0; +} +const char * +trn_cell_conflux_switch_check(const trn_cell_conflux_switch_t *obj) +{ + if (obj == NULL) + return "Object was NULL"; + if (obj->trunnel_error_code_) + return "A set function failed on this object"; + return NULL; +} + +ssize_t +trn_cell_conflux_switch_encoded_len(const trn_cell_conflux_switch_t *obj) +{ + ssize_t result = 0; + + if (NULL != trn_cell_conflux_switch_check(obj)) + return -1; + + + /* Length of u32 seqnum */ + result += 4; + return result; +} +int +trn_cell_conflux_switch_clear_errors(trn_cell_conflux_switch_t *obj) +{ + int r = obj->trunnel_error_code_; + obj->trunnel_error_code_ = 0; + return r; +} +ssize_t +trn_cell_conflux_switch_encode(uint8_t *output, const size_t avail, const trn_cell_conflux_switch_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 = trn_cell_conflux_switch_encoded_len(obj); +#endif + + if (NULL != (msg = trn_cell_conflux_switch_check(obj))) + goto check_failed; + +#ifdef TRUNNEL_CHECK_ENCODED_LEN + trunnel_assert(encoded_len >= 0); +#endif + + /* Encode u32 seqnum */ + trunnel_assert(written <= avail); + if (avail - written < 4) + goto truncated; + trunnel_set_uint32(ptr, trunnel_htonl(obj->seqnum)); + written += 4; ptr += 4; + + + 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 trn_cell_conflux_switch_parse(), but do not allocate the output + * object. + */ +static ssize_t +trn_cell_conflux_switch_parse_into(trn_cell_conflux_switch_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 u32 seqnum */ + CHECK_REMAINING(4, truncated); + obj->seqnum = trunnel_ntohl(trunnel_get_uint32(ptr)); + remaining -= 4; ptr += 4; + trunnel_assert(ptr + remaining == input + len_in); + return len_in - remaining; + + truncated: + return -2; +} + +ssize_t +trn_cell_conflux_switch_parse(trn_cell_conflux_switch_t **output, const uint8_t *input, const size_t len_in) +{ + ssize_t result; + *output = trn_cell_conflux_switch_new(); + if (NULL == *output) + return -1; + result = trn_cell_conflux_switch_parse_into(*output, input, len_in); + if (result < 0) { + trn_cell_conflux_switch_free(*output); + *output = NULL; + } + return result; +} diff -Nru tor-0.4.7.16/src/trunnel/conflux.h tor-0.4.9.6/src/trunnel/conflux.h --- tor-0.4.7.16/src/trunnel/conflux.h 1970-01-01 00:00:00.000000000 +0000 +++ tor-0.4.9.6/src/trunnel/conflux.h 2026-03-25 14:30:34.000000000 +0000 @@ -0,0 +1,422 @@ +/* conflux.h -- generated by Trunnel v1.5.3. + * https://gitweb.torproject.org/trunnel.git + * You probably shouldn't edit this file. + */ +#ifndef TRUNNEL_CONFLUX_H +#define TRUNNEL_CONFLUX_H + +#include +#include "trunnel.h" + +#define CONFLUX_UX_NO_OPINION 0 +#define CONFLUX_UX_MIN_LATENCY 1 +#define CONFLUX_UX_LOW_MEM_LATENCY 2 +#define CONFLUX_UX_HIGH_THROUGHPUT 3 +#define CONFLUX_UX_LOW_MEM_THROUGHPUT 4 +#if !defined(TRUNNEL_OPAQUE) && !defined(TRUNNEL_OPAQUE_TRN_CELL_CONFLUX_LINK) +struct trn_cell_conflux_link_st { + uint8_t version; + TRUNNEL_DYNARRAY_HEAD(, uint8_t) payload; + uint8_t trunnel_error_code_; +}; +#endif +typedef struct trn_cell_conflux_link_st trn_cell_conflux_link_t; +#if !defined(TRUNNEL_OPAQUE) && !defined(TRUNNEL_OPAQUE_TRN_CELL_CONFLUX_LINK_PAYLOAD_V1) +struct trn_cell_conflux_link_payload_v1_st { + uint8_t nonce[32]; + uint64_t last_seqno_sent; + uint64_t last_seqno_recv; + uint8_t desired_ux; + uint8_t trunnel_error_code_; +}; +#endif +typedef struct trn_cell_conflux_link_payload_v1_st trn_cell_conflux_link_payload_v1_t; +#if !defined(TRUNNEL_OPAQUE) && !defined(TRUNNEL_OPAQUE_TRN_CELL_CONFLUX_LINKED) +struct trn_cell_conflux_linked_st { + uint8_t version; + TRUNNEL_DYNARRAY_HEAD(, uint8_t) payload; + uint8_t trunnel_error_code_; +}; +#endif +typedef struct trn_cell_conflux_linked_st trn_cell_conflux_linked_t; +#if !defined(TRUNNEL_OPAQUE) && !defined(TRUNNEL_OPAQUE_TRN_CELL_CONFLUX_LINKED_ACK) +struct trn_cell_conflux_linked_ack_st { + TRUNNEL_DYNARRAY_HEAD(, uint8_t) payload; + uint8_t trunnel_error_code_; +}; +#endif +typedef struct trn_cell_conflux_linked_ack_st trn_cell_conflux_linked_ack_t; +#if !defined(TRUNNEL_OPAQUE) && !defined(TRUNNEL_OPAQUE_TRN_CELL_CONFLUX_SWITCH) +struct trn_cell_conflux_switch_st { + uint32_t seqnum; + uint8_t trunnel_error_code_; +}; +#endif +typedef struct trn_cell_conflux_switch_st trn_cell_conflux_switch_t; +/** Return a newly allocated trn_cell_conflux_link with all elements + * set to zero. + */ +trn_cell_conflux_link_t *trn_cell_conflux_link_new(void); +/** Release all storage held by the trn_cell_conflux_link in 'victim'. + * (Do nothing if 'victim' is NULL.) + */ +void trn_cell_conflux_link_free(trn_cell_conflux_link_t *victim); +/** Try to parse a trn_cell_conflux_link 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 trn_cell_conflux_link_t. On failure, return -2 if the + * input appears truncated, and -1 if the input is otherwise invalid. + */ +ssize_t trn_cell_conflux_link_parse(trn_cell_conflux_link_t **output, const uint8_t *input, const size_t len_in); +/** Return the number of bytes we expect to need to encode the + * trn_cell_conflux_link 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 trn_cell_conflux_link_encoded_len(const trn_cell_conflux_link_t *obj); +/** Try to encode the trn_cell_conflux_link 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 trn_cell_conflux_link_encode(uint8_t *output, size_t avail, const trn_cell_conflux_link_t *input); +/** Check whether the internal state of the trn_cell_conflux_link in + * 'obj' is consistent. Return NULL if it is, and a short message if + * it is not. + */ +const char *trn_cell_conflux_link_check(const trn_cell_conflux_link_t *obj); +/** Clear any errors that were set on the object 'obj' by its setter + * functions. Return true iff errors were cleared. + */ +int trn_cell_conflux_link_clear_errors(trn_cell_conflux_link_t *obj); +/** Return the value of the version field of the + * trn_cell_conflux_link_t in 'inp' + */ +uint8_t trn_cell_conflux_link_get_version(const trn_cell_conflux_link_t *inp); +/** Set the value of the version field of the trn_cell_conflux_link_t + * in 'inp' to 'val'. Return 0 on success; return -1 and set the error + * code on 'inp' on failure. + */ +int trn_cell_conflux_link_set_version(trn_cell_conflux_link_t *inp, uint8_t val); +/** Return the length of the dynamic array holding the payload field + * of the trn_cell_conflux_link_t in 'inp'. + */ +size_t trn_cell_conflux_link_getlen_payload(const trn_cell_conflux_link_t *inp); +/** Return the element at position 'idx' of the dynamic array field + * payload of the trn_cell_conflux_link_t in 'inp'. + */ +uint8_t trn_cell_conflux_link_get_payload(trn_cell_conflux_link_t *inp, size_t idx); +/** As trn_cell_conflux_link_get_payload, but take and return a const + * pointer + */ +uint8_t trn_cell_conflux_link_getconst_payload(const trn_cell_conflux_link_t *inp, size_t idx); +/** Change the element at position 'idx' of the dynamic array field + * payload of the trn_cell_conflux_link_t in 'inp', so that it will + * hold the value 'elt'. + */ +int trn_cell_conflux_link_set_payload(trn_cell_conflux_link_t *inp, size_t idx, uint8_t elt); +/** Append a new element 'elt' to the dynamic array field payload of + * the trn_cell_conflux_link_t in 'inp'. + */ +int trn_cell_conflux_link_add_payload(trn_cell_conflux_link_t *inp, uint8_t elt); +/** Return a pointer to the variable-length array field payload of + * 'inp'. + */ +uint8_t * trn_cell_conflux_link_getarray_payload(trn_cell_conflux_link_t *inp); +/** As trn_cell_conflux_link_get_payload, but take and return a const + * pointer + */ +const uint8_t * trn_cell_conflux_link_getconstarray_payload(const trn_cell_conflux_link_t *inp); +/** Change the length of the variable-length array field payload of + * 'inp' to 'newlen'.Fill extra elements with 0. Return 0 on success; + * return -1 and set the error code on 'inp' on failure. + */ +int trn_cell_conflux_link_setlen_payload(trn_cell_conflux_link_t *inp, size_t newlen); +/** Return a newly allocated trn_cell_conflux_link_payload_v1 with all + * elements set to zero. + */ +trn_cell_conflux_link_payload_v1_t *trn_cell_conflux_link_payload_v1_new(void); +/** Release all storage held by the trn_cell_conflux_link_payload_v1 + * in 'victim'. (Do nothing if 'victim' is NULL.) + */ +void trn_cell_conflux_link_payload_v1_free(trn_cell_conflux_link_payload_v1_t *victim); +/** Try to parse a trn_cell_conflux_link_payload_v1 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 trn_cell_conflux_link_payload_v1_t. On failure, + * return -2 if the input appears truncated, and -1 if the input is + * otherwise invalid. + */ +ssize_t trn_cell_conflux_link_payload_v1_parse(trn_cell_conflux_link_payload_v1_t **output, const uint8_t *input, const size_t len_in); +/** Return the number of bytes we expect to need to encode the + * trn_cell_conflux_link_payload_v1 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 trn_cell_conflux_link_payload_v1_encoded_len(const trn_cell_conflux_link_payload_v1_t *obj); +/** Try to encode the trn_cell_conflux_link_payload_v1 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 trn_cell_conflux_link_payload_v1_encode(uint8_t *output, size_t avail, const trn_cell_conflux_link_payload_v1_t *input); +/** Check whether the internal state of the + * trn_cell_conflux_link_payload_v1 in 'obj' is consistent. Return + * NULL if it is, and a short message if it is not. + */ +const char *trn_cell_conflux_link_payload_v1_check(const trn_cell_conflux_link_payload_v1_t *obj); +/** Clear any errors that were set on the object 'obj' by its setter + * functions. Return true iff errors were cleared. + */ +int trn_cell_conflux_link_payload_v1_clear_errors(trn_cell_conflux_link_payload_v1_t *obj); +/** Return the (constant) length of the array holding the nonce field + * of the trn_cell_conflux_link_payload_v1_t in 'inp'. + */ +size_t trn_cell_conflux_link_payload_v1_getlen_nonce(const trn_cell_conflux_link_payload_v1_t *inp); +/** Return the element at position 'idx' of the fixed array field + * nonce of the trn_cell_conflux_link_payload_v1_t in 'inp'. + */ +uint8_t trn_cell_conflux_link_payload_v1_get_nonce(trn_cell_conflux_link_payload_v1_t *inp, size_t idx); +/** As trn_cell_conflux_link_payload_v1_get_nonce, but take and return + * a const pointer + */ +uint8_t trn_cell_conflux_link_payload_v1_getconst_nonce(const trn_cell_conflux_link_payload_v1_t *inp, size_t idx); +/** Change the element at position 'idx' of the fixed array field + * nonce of the trn_cell_conflux_link_payload_v1_t in 'inp', so that + * it will hold the value 'elt'. + */ +int trn_cell_conflux_link_payload_v1_set_nonce(trn_cell_conflux_link_payload_v1_t *inp, size_t idx, uint8_t elt); +/** Return a pointer to the 32-element array field nonce of 'inp'. + */ +uint8_t * trn_cell_conflux_link_payload_v1_getarray_nonce(trn_cell_conflux_link_payload_v1_t *inp); +/** As trn_cell_conflux_link_payload_v1_get_nonce, but take and return + * a const pointer + */ +const uint8_t * trn_cell_conflux_link_payload_v1_getconstarray_nonce(const trn_cell_conflux_link_payload_v1_t *inp); +/** Return the value of the last_seqno_sent field of the + * trn_cell_conflux_link_payload_v1_t in 'inp' + */ +uint64_t trn_cell_conflux_link_payload_v1_get_last_seqno_sent(const trn_cell_conflux_link_payload_v1_t *inp); +/** Set the value of the last_seqno_sent field of the + * trn_cell_conflux_link_payload_v1_t in 'inp' to 'val'. Return 0 on + * success; return -1 and set the error code on 'inp' on failure. + */ +int trn_cell_conflux_link_payload_v1_set_last_seqno_sent(trn_cell_conflux_link_payload_v1_t *inp, uint64_t val); +/** Return the value of the last_seqno_recv field of the + * trn_cell_conflux_link_payload_v1_t in 'inp' + */ +uint64_t trn_cell_conflux_link_payload_v1_get_last_seqno_recv(const trn_cell_conflux_link_payload_v1_t *inp); +/** Set the value of the last_seqno_recv field of the + * trn_cell_conflux_link_payload_v1_t in 'inp' to 'val'. Return 0 on + * success; return -1 and set the error code on 'inp' on failure. + */ +int trn_cell_conflux_link_payload_v1_set_last_seqno_recv(trn_cell_conflux_link_payload_v1_t *inp, uint64_t val); +/** Return the value of the desired_ux field of the + * trn_cell_conflux_link_payload_v1_t in 'inp' + */ +uint8_t trn_cell_conflux_link_payload_v1_get_desired_ux(const trn_cell_conflux_link_payload_v1_t *inp); +/** Set the value of the desired_ux field of the + * trn_cell_conflux_link_payload_v1_t in 'inp' to 'val'. Return 0 on + * success; return -1 and set the error code on 'inp' on failure. + */ +int trn_cell_conflux_link_payload_v1_set_desired_ux(trn_cell_conflux_link_payload_v1_t *inp, uint8_t val); +/** Return a newly allocated trn_cell_conflux_linked with all elements + * set to zero. + */ +trn_cell_conflux_linked_t *trn_cell_conflux_linked_new(void); +/** Release all storage held by the trn_cell_conflux_linked in + * 'victim'. (Do nothing if 'victim' is NULL.) + */ +void trn_cell_conflux_linked_free(trn_cell_conflux_linked_t *victim); +/** Try to parse a trn_cell_conflux_linked 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 trn_cell_conflux_linked_t. On failure, return -2 if the + * input appears truncated, and -1 if the input is otherwise invalid. + */ +ssize_t trn_cell_conflux_linked_parse(trn_cell_conflux_linked_t **output, const uint8_t *input, const size_t len_in); +/** Return the number of bytes we expect to need to encode the + * trn_cell_conflux_linked 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 trn_cell_conflux_linked_encoded_len(const trn_cell_conflux_linked_t *obj); +/** Try to encode the trn_cell_conflux_linked 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 trn_cell_conflux_linked_encode(uint8_t *output, size_t avail, const trn_cell_conflux_linked_t *input); +/** Check whether the internal state of the trn_cell_conflux_linked in + * 'obj' is consistent. Return NULL if it is, and a short message if + * it is not. + */ +const char *trn_cell_conflux_linked_check(const trn_cell_conflux_linked_t *obj); +/** Clear any errors that were set on the object 'obj' by its setter + * functions. Return true iff errors were cleared. + */ +int trn_cell_conflux_linked_clear_errors(trn_cell_conflux_linked_t *obj); +/** Return the value of the version field of the + * trn_cell_conflux_linked_t in 'inp' + */ +uint8_t trn_cell_conflux_linked_get_version(const trn_cell_conflux_linked_t *inp); +/** Set the value of the version field of the + * trn_cell_conflux_linked_t in 'inp' to 'val'. Return 0 on success; + * return -1 and set the error code on 'inp' on failure. + */ +int trn_cell_conflux_linked_set_version(trn_cell_conflux_linked_t *inp, uint8_t val); +/** Return the length of the dynamic array holding the payload field + * of the trn_cell_conflux_linked_t in 'inp'. + */ +size_t trn_cell_conflux_linked_getlen_payload(const trn_cell_conflux_linked_t *inp); +/** Return the element at position 'idx' of the dynamic array field + * payload of the trn_cell_conflux_linked_t in 'inp'. + */ +uint8_t trn_cell_conflux_linked_get_payload(trn_cell_conflux_linked_t *inp, size_t idx); +/** As trn_cell_conflux_linked_get_payload, but take and return a + * const pointer + */ +uint8_t trn_cell_conflux_linked_getconst_payload(const trn_cell_conflux_linked_t *inp, size_t idx); +/** Change the element at position 'idx' of the dynamic array field + * payload of the trn_cell_conflux_linked_t in 'inp', so that it will + * hold the value 'elt'. + */ +int trn_cell_conflux_linked_set_payload(trn_cell_conflux_linked_t *inp, size_t idx, uint8_t elt); +/** Append a new element 'elt' to the dynamic array field payload of + * the trn_cell_conflux_linked_t in 'inp'. + */ +int trn_cell_conflux_linked_add_payload(trn_cell_conflux_linked_t *inp, uint8_t elt); +/** Return a pointer to the variable-length array field payload of + * 'inp'. + */ +uint8_t * trn_cell_conflux_linked_getarray_payload(trn_cell_conflux_linked_t *inp); +/** As trn_cell_conflux_linked_get_payload, but take and return a + * const pointer + */ +const uint8_t * trn_cell_conflux_linked_getconstarray_payload(const trn_cell_conflux_linked_t *inp); +/** Change the length of the variable-length array field payload of + * 'inp' to 'newlen'.Fill extra elements with 0. Return 0 on success; + * return -1 and set the error code on 'inp' on failure. + */ +int trn_cell_conflux_linked_setlen_payload(trn_cell_conflux_linked_t *inp, size_t newlen); +/** Return a newly allocated trn_cell_conflux_linked_ack with all + * elements set to zero. + */ +trn_cell_conflux_linked_ack_t *trn_cell_conflux_linked_ack_new(void); +/** Release all storage held by the trn_cell_conflux_linked_ack in + * 'victim'. (Do nothing if 'victim' is NULL.) + */ +void trn_cell_conflux_linked_ack_free(trn_cell_conflux_linked_ack_t *victim); +/** Try to parse a trn_cell_conflux_linked_ack 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 trn_cell_conflux_linked_ack_t. On failure, return + * -2 if the input appears truncated, and -1 if the input is otherwise + * invalid. + */ +ssize_t trn_cell_conflux_linked_ack_parse(trn_cell_conflux_linked_ack_t **output, const uint8_t *input, const size_t len_in); +/** Return the number of bytes we expect to need to encode the + * trn_cell_conflux_linked_ack 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 trn_cell_conflux_linked_ack_encoded_len(const trn_cell_conflux_linked_ack_t *obj); +/** Try to encode the trn_cell_conflux_linked_ack 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 trn_cell_conflux_linked_ack_encode(uint8_t *output, size_t avail, const trn_cell_conflux_linked_ack_t *input); +/** Check whether the internal state of the + * trn_cell_conflux_linked_ack in 'obj' is consistent. Return NULL if + * it is, and a short message if it is not. + */ +const char *trn_cell_conflux_linked_ack_check(const trn_cell_conflux_linked_ack_t *obj); +/** Clear any errors that were set on the object 'obj' by its setter + * functions. Return true iff errors were cleared. + */ +int trn_cell_conflux_linked_ack_clear_errors(trn_cell_conflux_linked_ack_t *obj); +/** Return the length of the dynamic array holding the payload field + * of the trn_cell_conflux_linked_ack_t in 'inp'. + */ +size_t trn_cell_conflux_linked_ack_getlen_payload(const trn_cell_conflux_linked_ack_t *inp); +/** Return the element at position 'idx' of the dynamic array field + * payload of the trn_cell_conflux_linked_ack_t in 'inp'. + */ +uint8_t trn_cell_conflux_linked_ack_get_payload(trn_cell_conflux_linked_ack_t *inp, size_t idx); +/** As trn_cell_conflux_linked_ack_get_payload, but take and return a + * const pointer + */ +uint8_t trn_cell_conflux_linked_ack_getconst_payload(const trn_cell_conflux_linked_ack_t *inp, size_t idx); +/** Change the element at position 'idx' of the dynamic array field + * payload of the trn_cell_conflux_linked_ack_t in 'inp', so that it + * will hold the value 'elt'. + */ +int trn_cell_conflux_linked_ack_set_payload(trn_cell_conflux_linked_ack_t *inp, size_t idx, uint8_t elt); +/** Append a new element 'elt' to the dynamic array field payload of + * the trn_cell_conflux_linked_ack_t in 'inp'. + */ +int trn_cell_conflux_linked_ack_add_payload(trn_cell_conflux_linked_ack_t *inp, uint8_t elt); +/** Return a pointer to the variable-length array field payload of + * 'inp'. + */ +uint8_t * trn_cell_conflux_linked_ack_getarray_payload(trn_cell_conflux_linked_ack_t *inp); +/** As trn_cell_conflux_linked_ack_get_payload, but take and return a + * const pointer + */ +const uint8_t * trn_cell_conflux_linked_ack_getconstarray_payload(const trn_cell_conflux_linked_ack_t *inp); +/** Change the length of the variable-length array field payload of + * 'inp' to 'newlen'.Fill extra elements with 0. Return 0 on success; + * return -1 and set the error code on 'inp' on failure. + */ +int trn_cell_conflux_linked_ack_setlen_payload(trn_cell_conflux_linked_ack_t *inp, size_t newlen); +/** Return a newly allocated trn_cell_conflux_switch with all elements + * set to zero. + */ +trn_cell_conflux_switch_t *trn_cell_conflux_switch_new(void); +/** Release all storage held by the trn_cell_conflux_switch in + * 'victim'. (Do nothing if 'victim' is NULL.) + */ +void trn_cell_conflux_switch_free(trn_cell_conflux_switch_t *victim); +/** Try to parse a trn_cell_conflux_switch 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 trn_cell_conflux_switch_t. On failure, return -2 if the + * input appears truncated, and -1 if the input is otherwise invalid. + */ +ssize_t trn_cell_conflux_switch_parse(trn_cell_conflux_switch_t **output, const uint8_t *input, const size_t len_in); +/** Return the number of bytes we expect to need to encode the + * trn_cell_conflux_switch 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 trn_cell_conflux_switch_encoded_len(const trn_cell_conflux_switch_t *obj); +/** Try to encode the trn_cell_conflux_switch 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 trn_cell_conflux_switch_encode(uint8_t *output, size_t avail, const trn_cell_conflux_switch_t *input); +/** Check whether the internal state of the trn_cell_conflux_switch in + * 'obj' is consistent. Return NULL if it is, and a short message if + * it is not. + */ +const char *trn_cell_conflux_switch_check(const trn_cell_conflux_switch_t *obj); +/** Clear any errors that were set on the object 'obj' by its setter + * functions. Return true iff errors were cleared. + */ +int trn_cell_conflux_switch_clear_errors(trn_cell_conflux_switch_t *obj); +/** Return the value of the seqnum field of the + * trn_cell_conflux_switch_t in 'inp' + */ +uint32_t trn_cell_conflux_switch_get_seqnum(const trn_cell_conflux_switch_t *inp); +/** Set the value of the seqnum field of the trn_cell_conflux_switch_t + * in 'inp' to 'val'. Return 0 on success; return -1 and set the error + * code on 'inp' on failure. + */ +int trn_cell_conflux_switch_set_seqnum(trn_cell_conflux_switch_t *inp, uint32_t val); + + +#endif diff -Nru tor-0.4.7.16/src/trunnel/hs/cell_introduce1.c tor-0.4.9.6/src/trunnel/hs/cell_introduce1.c --- tor-0.4.7.16/src/trunnel/hs/cell_introduce1.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/trunnel/hs/cell_introduce1.c 2026-03-25 14:30:34.000000000 +0000 @@ -44,6 +44,350 @@ ssize_t link_specifier_encode(uint8_t *output, size_t avail, const link_specifier_t *input); const char *link_specifier_check(const link_specifier_t *obj); int link_specifier_clear_errors(link_specifier_t *obj); +trn_cell_extension_pow_t * +trn_cell_extension_pow_new(void) +{ + trn_cell_extension_pow_t *val = trunnel_calloc(1, sizeof(trn_cell_extension_pow_t)); + if (NULL == val) + return NULL; + val->pow_version = 1; + return val; +} + +/** Release all storage held inside 'obj', but do not free 'obj'. + */ +static void +trn_cell_extension_pow_clear(trn_cell_extension_pow_t *obj) +{ + (void) obj; +} + +void +trn_cell_extension_pow_free(trn_cell_extension_pow_t *obj) +{ + if (obj == NULL) + return; + trn_cell_extension_pow_clear(obj); + trunnel_memwipe(obj, sizeof(trn_cell_extension_pow_t)); + trunnel_free_(obj); +} + +uint8_t +trn_cell_extension_pow_get_pow_version(const trn_cell_extension_pow_t *inp) +{ + return inp->pow_version; +} +int +trn_cell_extension_pow_set_pow_version(trn_cell_extension_pow_t *inp, uint8_t val) +{ + if (! ((val == 1))) { + TRUNNEL_SET_ERROR_CODE(inp); + return -1; + } + inp->pow_version = val; + return 0; +} +size_t +trn_cell_extension_pow_getlen_pow_nonce(const trn_cell_extension_pow_t *inp) +{ + (void)inp; return TRUNNEL_POW_NONCE_LEN; +} + +uint8_t +trn_cell_extension_pow_get_pow_nonce(trn_cell_extension_pow_t *inp, size_t idx) +{ + trunnel_assert(idx < TRUNNEL_POW_NONCE_LEN); + return inp->pow_nonce[idx]; +} + +uint8_t +trn_cell_extension_pow_getconst_pow_nonce(const trn_cell_extension_pow_t *inp, size_t idx) +{ + return trn_cell_extension_pow_get_pow_nonce((trn_cell_extension_pow_t*)inp, idx); +} +int +trn_cell_extension_pow_set_pow_nonce(trn_cell_extension_pow_t *inp, size_t idx, uint8_t elt) +{ + trunnel_assert(idx < TRUNNEL_POW_NONCE_LEN); + inp->pow_nonce[idx] = elt; + return 0; +} + +uint8_t * +trn_cell_extension_pow_getarray_pow_nonce(trn_cell_extension_pow_t *inp) +{ + return inp->pow_nonce; +} +const uint8_t * +trn_cell_extension_pow_getconstarray_pow_nonce(const trn_cell_extension_pow_t *inp) +{ + return (const uint8_t *)trn_cell_extension_pow_getarray_pow_nonce((trn_cell_extension_pow_t*)inp); +} +uint32_t +trn_cell_extension_pow_get_pow_effort(const trn_cell_extension_pow_t *inp) +{ + return inp->pow_effort; +} +int +trn_cell_extension_pow_set_pow_effort(trn_cell_extension_pow_t *inp, uint32_t val) +{ + inp->pow_effort = val; + return 0; +} +size_t +trn_cell_extension_pow_getlen_pow_seed(const trn_cell_extension_pow_t *inp) +{ + (void)inp; return TRUNNEL_POW_SEED_HEAD_LEN; +} + +uint8_t +trn_cell_extension_pow_get_pow_seed(trn_cell_extension_pow_t *inp, size_t idx) +{ + trunnel_assert(idx < TRUNNEL_POW_SEED_HEAD_LEN); + return inp->pow_seed[idx]; +} + +uint8_t +trn_cell_extension_pow_getconst_pow_seed(const trn_cell_extension_pow_t *inp, size_t idx) +{ + return trn_cell_extension_pow_get_pow_seed((trn_cell_extension_pow_t*)inp, idx); +} +int +trn_cell_extension_pow_set_pow_seed(trn_cell_extension_pow_t *inp, size_t idx, uint8_t elt) +{ + trunnel_assert(idx < TRUNNEL_POW_SEED_HEAD_LEN); + inp->pow_seed[idx] = elt; + return 0; +} + +uint8_t * +trn_cell_extension_pow_getarray_pow_seed(trn_cell_extension_pow_t *inp) +{ + return inp->pow_seed; +} +const uint8_t * +trn_cell_extension_pow_getconstarray_pow_seed(const trn_cell_extension_pow_t *inp) +{ + return (const uint8_t *)trn_cell_extension_pow_getarray_pow_seed((trn_cell_extension_pow_t*)inp); +} +size_t +trn_cell_extension_pow_getlen_pow_solution(const trn_cell_extension_pow_t *inp) +{ + (void)inp; return TRUNNEL_POW_SOLUTION_LEN; +} + +uint8_t +trn_cell_extension_pow_get_pow_solution(trn_cell_extension_pow_t *inp, size_t idx) +{ + trunnel_assert(idx < TRUNNEL_POW_SOLUTION_LEN); + return inp->pow_solution[idx]; +} + +uint8_t +trn_cell_extension_pow_getconst_pow_solution(const trn_cell_extension_pow_t *inp, size_t idx) +{ + return trn_cell_extension_pow_get_pow_solution((trn_cell_extension_pow_t*)inp, idx); +} +int +trn_cell_extension_pow_set_pow_solution(trn_cell_extension_pow_t *inp, size_t idx, uint8_t elt) +{ + trunnel_assert(idx < TRUNNEL_POW_SOLUTION_LEN); + inp->pow_solution[idx] = elt; + return 0; +} + +uint8_t * +trn_cell_extension_pow_getarray_pow_solution(trn_cell_extension_pow_t *inp) +{ + return inp->pow_solution; +} +const uint8_t * +trn_cell_extension_pow_getconstarray_pow_solution(const trn_cell_extension_pow_t *inp) +{ + return (const uint8_t *)trn_cell_extension_pow_getarray_pow_solution((trn_cell_extension_pow_t*)inp); +} +const char * +trn_cell_extension_pow_check(const trn_cell_extension_pow_t *obj) +{ + if (obj == NULL) + return "Object was NULL"; + if (obj->trunnel_error_code_) + return "A set function failed on this object"; + if (! (obj->pow_version == 1)) + return "Integer out of bounds"; + return NULL; +} + +ssize_t +trn_cell_extension_pow_encoded_len(const trn_cell_extension_pow_t *obj) +{ + ssize_t result = 0; + + if (NULL != trn_cell_extension_pow_check(obj)) + return -1; + + + /* Length of u8 pow_version IN [1] */ + result += 1; + + /* Length of u8 pow_nonce[TRUNNEL_POW_NONCE_LEN] */ + result += TRUNNEL_POW_NONCE_LEN; + + /* Length of u32 pow_effort */ + result += 4; + + /* Length of u8 pow_seed[TRUNNEL_POW_SEED_HEAD_LEN] */ + result += TRUNNEL_POW_SEED_HEAD_LEN; + + /* Length of u8 pow_solution[TRUNNEL_POW_SOLUTION_LEN] */ + result += TRUNNEL_POW_SOLUTION_LEN; + return result; +} +int +trn_cell_extension_pow_clear_errors(trn_cell_extension_pow_t *obj) +{ + int r = obj->trunnel_error_code_; + obj->trunnel_error_code_ = 0; + return r; +} +ssize_t +trn_cell_extension_pow_encode(uint8_t *output, const size_t avail, const trn_cell_extension_pow_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 = trn_cell_extension_pow_encoded_len(obj); +#endif + + if (NULL != (msg = trn_cell_extension_pow_check(obj))) + goto check_failed; + +#ifdef TRUNNEL_CHECK_ENCODED_LEN + trunnel_assert(encoded_len >= 0); +#endif + + /* Encode u8 pow_version IN [1] */ + trunnel_assert(written <= avail); + if (avail - written < 1) + goto truncated; + trunnel_set_uint8(ptr, (obj->pow_version)); + written += 1; ptr += 1; + + /* Encode u8 pow_nonce[TRUNNEL_POW_NONCE_LEN] */ + trunnel_assert(written <= avail); + if (avail - written < TRUNNEL_POW_NONCE_LEN) + goto truncated; + memcpy(ptr, obj->pow_nonce, TRUNNEL_POW_NONCE_LEN); + written += TRUNNEL_POW_NONCE_LEN; ptr += TRUNNEL_POW_NONCE_LEN; + + /* Encode u32 pow_effort */ + trunnel_assert(written <= avail); + if (avail - written < 4) + goto truncated; + trunnel_set_uint32(ptr, trunnel_htonl(obj->pow_effort)); + written += 4; ptr += 4; + + /* Encode u8 pow_seed[TRUNNEL_POW_SEED_HEAD_LEN] */ + trunnel_assert(written <= avail); + if (avail - written < TRUNNEL_POW_SEED_HEAD_LEN) + goto truncated; + memcpy(ptr, obj->pow_seed, TRUNNEL_POW_SEED_HEAD_LEN); + written += TRUNNEL_POW_SEED_HEAD_LEN; ptr += TRUNNEL_POW_SEED_HEAD_LEN; + + /* Encode u8 pow_solution[TRUNNEL_POW_SOLUTION_LEN] */ + trunnel_assert(written <= avail); + if (avail - written < TRUNNEL_POW_SOLUTION_LEN) + goto truncated; + memcpy(ptr, obj->pow_solution, TRUNNEL_POW_SOLUTION_LEN); + written += TRUNNEL_POW_SOLUTION_LEN; ptr += TRUNNEL_POW_SOLUTION_LEN; + + + 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 trn_cell_extension_pow_parse(), but do not allocate the output + * object. + */ +static ssize_t +trn_cell_extension_pow_parse_into(trn_cell_extension_pow_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 pow_version IN [1] */ + CHECK_REMAINING(1, truncated); + obj->pow_version = (trunnel_get_uint8(ptr)); + remaining -= 1; ptr += 1; + if (! (obj->pow_version == 1)) + goto fail; + + /* Parse u8 pow_nonce[TRUNNEL_POW_NONCE_LEN] */ + CHECK_REMAINING(TRUNNEL_POW_NONCE_LEN, truncated); + memcpy(obj->pow_nonce, ptr, TRUNNEL_POW_NONCE_LEN); + remaining -= TRUNNEL_POW_NONCE_LEN; ptr += TRUNNEL_POW_NONCE_LEN; + + /* Parse u32 pow_effort */ + CHECK_REMAINING(4, truncated); + obj->pow_effort = trunnel_ntohl(trunnel_get_uint32(ptr)); + remaining -= 4; ptr += 4; + + /* Parse u8 pow_seed[TRUNNEL_POW_SEED_HEAD_LEN] */ + CHECK_REMAINING(TRUNNEL_POW_SEED_HEAD_LEN, truncated); + memcpy(obj->pow_seed, ptr, TRUNNEL_POW_SEED_HEAD_LEN); + remaining -= TRUNNEL_POW_SEED_HEAD_LEN; ptr += TRUNNEL_POW_SEED_HEAD_LEN; + + /* Parse u8 pow_solution[TRUNNEL_POW_SOLUTION_LEN] */ + CHECK_REMAINING(TRUNNEL_POW_SOLUTION_LEN, truncated); + memcpy(obj->pow_solution, ptr, TRUNNEL_POW_SOLUTION_LEN); + remaining -= TRUNNEL_POW_SOLUTION_LEN; ptr += TRUNNEL_POW_SOLUTION_LEN; + trunnel_assert(ptr + remaining == input + len_in); + return len_in - remaining; + + truncated: + return -2; + fail: + result = -1; + return result; +} + +ssize_t +trn_cell_extension_pow_parse(trn_cell_extension_pow_t **output, const uint8_t *input, const size_t len_in) +{ + ssize_t result; + *output = trn_cell_extension_pow_new(); + if (NULL == *output) + return -1; + result = trn_cell_extension_pow_parse_into(*output, input, len_in); + if (result < 0) { + trn_cell_extension_pow_free(*output); + *output = NULL; + } + return result; +} trn_cell_introduce1_t * trn_cell_introduce1_new(void) { diff -Nru tor-0.4.7.16/src/trunnel/hs/cell_introduce1.h tor-0.4.9.6/src/trunnel/hs/cell_introduce1.h --- tor-0.4.7.16/src/trunnel/hs/cell_introduce1.h 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/trunnel/hs/cell_introduce1.h 2026-03-25 14:30:34.000000000 +0000 @@ -19,6 +19,23 @@ #define TRUNNEL_HS_INTRO_AUTH_KEY_TYPE_LEGACY1 1 #define TRUNNEL_HS_INTRO_AUTH_KEY_TYPE_ED25519 2 #define TRUNNEL_HS_INTRO_ONION_KEY_TYPE_NTOR 1 +#define TRUNNEL_EXT_TYPE_CC_REQUEST 1 +#define TRUNNEL_EXT_TYPE_POW 2 +#define TRUNNEL_POW_NONCE_LEN 16 +#define TRUNNEL_POW_SOLUTION_LEN 16 +#define TRUNNEL_POW_SEED_HEAD_LEN 4 +#define TRUNNEL_POW_VERSION_EQUIX 1 +#if !defined(TRUNNEL_OPAQUE) && !defined(TRUNNEL_OPAQUE_TRN_CELL_EXTENSION_POW) +struct trn_cell_extension_pow_st { + uint8_t pow_version; + uint8_t pow_nonce[TRUNNEL_POW_NONCE_LEN]; + uint32_t pow_effort; + uint8_t pow_seed[TRUNNEL_POW_SEED_HEAD_LEN]; + uint8_t pow_solution[TRUNNEL_POW_SOLUTION_LEN]; + uint8_t trunnel_error_code_; +}; +#endif +typedef struct trn_cell_extension_pow_st trn_cell_extension_pow_t; #if !defined(TRUNNEL_OPAQUE) && !defined(TRUNNEL_OPAQUE_TRN_CELL_INTRODUCE1) struct trn_cell_introduce1_st { uint8_t legacy_key_id[TRUNNEL_SHA1_LEN]; @@ -53,6 +70,135 @@ }; #endif typedef struct trn_cell_introduce_encrypted_st trn_cell_introduce_encrypted_t; +/** Return a newly allocated trn_cell_extension_pow with all elements + * set to zero. + */ +trn_cell_extension_pow_t *trn_cell_extension_pow_new(void); +/** Release all storage held by the trn_cell_extension_pow in + * 'victim'. (Do nothing if 'victim' is NULL.) + */ +void trn_cell_extension_pow_free(trn_cell_extension_pow_t *victim); +/** Try to parse a trn_cell_extension_pow 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 trn_cell_extension_pow_t. On failure, return -2 if the + * input appears truncated, and -1 if the input is otherwise invalid. + */ +ssize_t trn_cell_extension_pow_parse(trn_cell_extension_pow_t **output, const uint8_t *input, const size_t len_in); +/** Return the number of bytes we expect to need to encode the + * trn_cell_extension_pow 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 trn_cell_extension_pow_encoded_len(const trn_cell_extension_pow_t *obj); +/** Try to encode the trn_cell_extension_pow 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 trn_cell_extension_pow_encode(uint8_t *output, size_t avail, const trn_cell_extension_pow_t *input); +/** Check whether the internal state of the trn_cell_extension_pow in + * 'obj' is consistent. Return NULL if it is, and a short message if + * it is not. + */ +const char *trn_cell_extension_pow_check(const trn_cell_extension_pow_t *obj); +/** Clear any errors that were set on the object 'obj' by its setter + * functions. Return true iff errors were cleared. + */ +int trn_cell_extension_pow_clear_errors(trn_cell_extension_pow_t *obj); +/** Return the value of the pow_version field of the + * trn_cell_extension_pow_t in 'inp' + */ +uint8_t trn_cell_extension_pow_get_pow_version(const trn_cell_extension_pow_t *inp); +/** Set the value of the pow_version field of the + * trn_cell_extension_pow_t in 'inp' to 'val'. Return 0 on success; + * return -1 and set the error code on 'inp' on failure. + */ +int trn_cell_extension_pow_set_pow_version(trn_cell_extension_pow_t *inp, uint8_t val); +/** Return the (constant) length of the array holding the pow_nonce + * field of the trn_cell_extension_pow_t in 'inp'. + */ +size_t trn_cell_extension_pow_getlen_pow_nonce(const trn_cell_extension_pow_t *inp); +/** Return the element at position 'idx' of the fixed array field + * pow_nonce of the trn_cell_extension_pow_t in 'inp'. + */ +uint8_t trn_cell_extension_pow_get_pow_nonce(trn_cell_extension_pow_t *inp, size_t idx); +/** As trn_cell_extension_pow_get_pow_nonce, but take and return a + * const pointer + */ +uint8_t trn_cell_extension_pow_getconst_pow_nonce(const trn_cell_extension_pow_t *inp, size_t idx); +/** Change the element at position 'idx' of the fixed array field + * pow_nonce of the trn_cell_extension_pow_t in 'inp', so that it will + * hold the value 'elt'. + */ +int trn_cell_extension_pow_set_pow_nonce(trn_cell_extension_pow_t *inp, size_t idx, uint8_t elt); +/** Return a pointer to the TRUNNEL_POW_NONCE_LEN-element array field + * pow_nonce of 'inp'. + */ +uint8_t * trn_cell_extension_pow_getarray_pow_nonce(trn_cell_extension_pow_t *inp); +/** As trn_cell_extension_pow_get_pow_nonce, but take and return a + * const pointer + */ +const uint8_t * trn_cell_extension_pow_getconstarray_pow_nonce(const trn_cell_extension_pow_t *inp); +/** Return the value of the pow_effort field of the + * trn_cell_extension_pow_t in 'inp' + */ +uint32_t trn_cell_extension_pow_get_pow_effort(const trn_cell_extension_pow_t *inp); +/** Set the value of the pow_effort field of the + * trn_cell_extension_pow_t in 'inp' to 'val'. Return 0 on success; + * return -1 and set the error code on 'inp' on failure. + */ +int trn_cell_extension_pow_set_pow_effort(trn_cell_extension_pow_t *inp, uint32_t val); +/** Return the (constant) length of the array holding the pow_seed + * field of the trn_cell_extension_pow_t in 'inp'. + */ +size_t trn_cell_extension_pow_getlen_pow_seed(const trn_cell_extension_pow_t *inp); +/** Return the element at position 'idx' of the fixed array field + * pow_seed of the trn_cell_extension_pow_t in 'inp'. + */ +uint8_t trn_cell_extension_pow_get_pow_seed(trn_cell_extension_pow_t *inp, size_t idx); +/** As trn_cell_extension_pow_get_pow_seed, but take and return a + * const pointer + */ +uint8_t trn_cell_extension_pow_getconst_pow_seed(const trn_cell_extension_pow_t *inp, size_t idx); +/** Change the element at position 'idx' of the fixed array field + * pow_seed of the trn_cell_extension_pow_t in 'inp', so that it will + * hold the value 'elt'. + */ +int trn_cell_extension_pow_set_pow_seed(trn_cell_extension_pow_t *inp, size_t idx, uint8_t elt); +/** Return a pointer to the TRUNNEL_POW_SEED_HEAD_LEN-element array + * field pow_seed of 'inp'. + */ +uint8_t * trn_cell_extension_pow_getarray_pow_seed(trn_cell_extension_pow_t *inp); +/** As trn_cell_extension_pow_get_pow_seed, but take and return a + * const pointer + */ +const uint8_t * trn_cell_extension_pow_getconstarray_pow_seed(const trn_cell_extension_pow_t *inp); +/** Return the (constant) length of the array holding the pow_solution + * field of the trn_cell_extension_pow_t in 'inp'. + */ +size_t trn_cell_extension_pow_getlen_pow_solution(const trn_cell_extension_pow_t *inp); +/** Return the element at position 'idx' of the fixed array field + * pow_solution of the trn_cell_extension_pow_t in 'inp'. + */ +uint8_t trn_cell_extension_pow_get_pow_solution(trn_cell_extension_pow_t *inp, size_t idx); +/** As trn_cell_extension_pow_get_pow_solution, but take and return a + * const pointer + */ +uint8_t trn_cell_extension_pow_getconst_pow_solution(const trn_cell_extension_pow_t *inp, size_t idx); +/** Change the element at position 'idx' of the fixed array field + * pow_solution of the trn_cell_extension_pow_t in 'inp', so that it + * will hold the value 'elt'. + */ +int trn_cell_extension_pow_set_pow_solution(trn_cell_extension_pow_t *inp, size_t idx, uint8_t elt); +/** Return a pointer to the TRUNNEL_POW_SOLUTION_LEN-element array + * field pow_solution of 'inp'. + */ +uint8_t * trn_cell_extension_pow_getarray_pow_solution(trn_cell_extension_pow_t *inp); +/** As trn_cell_extension_pow_get_pow_solution, but take and return a + * const pointer + */ +const uint8_t * trn_cell_extension_pow_getconstarray_pow_solution(const trn_cell_extension_pow_t *inp); /** Return a newly allocated trn_cell_introduce1 with all elements set * to zero. */ diff -Nru tor-0.4.7.16/src/trunnel/include.am tor-0.4.9.6/src/trunnel/include.am --- tor-0.4.7.16/src/trunnel/include.am 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/trunnel/include.am 2026-03-25 14:30:34.000000000 +0000 @@ -16,43 +16,49 @@ src/trunnel/flow_control_cells.trunnel \ src/trunnel/congestion_control.trunnel \ src/trunnel/socks5.trunnel \ - src/trunnel/circpad_negotiation.trunnel + src/trunnel/circpad_negotiation.trunnel \ + src/trunnel/conflux.trunnel \ + src/trunnel/subproto_request.trunnel TRUNNELSOURCES = \ src/ext/trunnel/trunnel.c \ src/trunnel/ed25519_cert.c \ src/trunnel/extension.c \ src/trunnel/link_handshake.c \ - src/trunnel/pwbox.c \ - src/trunnel/hs/cell_establish_intro.c \ + src/trunnel/pwbox.c \ + src/trunnel/hs/cell_establish_intro.c \ src/trunnel/hs/cell_introduce1.c \ src/trunnel/hs/cell_rendezvous.c \ src/trunnel/channelpadding_negotiation.c \ - src/trunnel/sendme_cell.c \ - src/trunnel/flow_control_cells.c \ - src/trunnel/congestion_control.c \ + src/trunnel/sendme_cell.c \ + src/trunnel/flow_control_cells.c \ + src/trunnel/congestion_control.c \ src/trunnel/socks5.c \ src/trunnel/netinfo.c \ - src/trunnel/circpad_negotiation.c + src/trunnel/circpad_negotiation.c \ + src/trunnel/conflux.c \ + src/trunnel/subproto_request.c TRUNNELHEADERS = \ - src/ext/trunnel/trunnel.h \ - src/ext/trunnel/trunnel-impl.h \ - src/trunnel/trunnel-local.h \ - src/trunnel/ed25519_cert.h \ + src/ext/trunnel/trunnel.h \ + src/ext/trunnel/trunnel-impl.h \ + src/trunnel/trunnel-local.h \ + src/trunnel/ed25519_cert.h \ src/trunnel/extension.h \ - src/trunnel/link_handshake.h \ - src/trunnel/pwbox.h \ - src/trunnel/hs/cell_establish_intro.h \ + src/trunnel/link_handshake.h \ + src/trunnel/pwbox.h \ + src/trunnel/hs/cell_establish_intro.h \ src/trunnel/hs/cell_introduce1.h \ src/trunnel/hs/cell_rendezvous.h \ src/trunnel/channelpadding_negotiation.h \ - src/trunnel/sendme_cell.h \ - src/trunnel/flow_control_cells.h \ - src/trunnel/congestion_control.h \ - src/trunnel/socks5.h \ + src/trunnel/sendme_cell.h \ + src/trunnel/flow_control_cells.h \ + src/trunnel/congestion_control.h \ + src/trunnel/socks5.h \ src/trunnel/netinfo.h \ - src/trunnel/circpad_negotiation.h + src/trunnel/circpad_negotiation.h \ + src/trunnel/conflux.h \ + src/trunnel/subproto_request.h src_trunnel_libor_trunnel_a_SOURCES = $(TRUNNELSOURCES) src_trunnel_libor_trunnel_a_CPPFLAGS = \ diff -Nru tor-0.4.7.16/src/trunnel/link_handshake.c tor-0.4.9.6/src/trunnel/link_handshake.c --- tor-0.4.7.16/src/trunnel/link_handshake.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/trunnel/link_handshake.c 2026-03-25 14:30:34.000000000 +0000 @@ -28,6 +28,738 @@ } \ } while (0) +auth1_t * +auth1_new(void) +{ + auth1_t *val = trunnel_calloc(1, sizeof(auth1_t)); + if (NULL == val) + return NULL; + return val; +} + +/** Release all storage held inside 'obj', but do not free 'obj'. + */ +static void +auth1_clear(auth1_t *obj) +{ + (void) obj; + TRUNNEL_DYNARRAY_WIPE(&obj->sig); + TRUNNEL_DYNARRAY_CLEAR(&obj->sig); +} + +void +auth1_free(auth1_t *obj) +{ + if (obj == NULL) + return; + auth1_clear(obj); + trunnel_memwipe(obj, sizeof(auth1_t)); + trunnel_free_(obj); +} + +size_t +auth1_getlen_type(const auth1_t *inp) +{ + (void)inp; return 8; +} + +uint8_t +auth1_get_type(auth1_t *inp, size_t idx) +{ + trunnel_assert(idx < 8); + return inp->type[idx]; +} + +uint8_t +auth1_getconst_type(const auth1_t *inp, size_t idx) +{ + return auth1_get_type((auth1_t*)inp, idx); +} +int +auth1_set_type(auth1_t *inp, size_t idx, uint8_t elt) +{ + trunnel_assert(idx < 8); + inp->type[idx] = elt; + return 0; +} + +uint8_t * +auth1_getarray_type(auth1_t *inp) +{ + return inp->type; +} +const uint8_t * +auth1_getconstarray_type(const auth1_t *inp) +{ + return (const uint8_t *)auth1_getarray_type((auth1_t*)inp); +} +size_t +auth1_getlen_cid(const auth1_t *inp) +{ + (void)inp; return 32; +} + +uint8_t +auth1_get_cid(auth1_t *inp, size_t idx) +{ + trunnel_assert(idx < 32); + return inp->cid[idx]; +} + +uint8_t +auth1_getconst_cid(const auth1_t *inp, size_t idx) +{ + return auth1_get_cid((auth1_t*)inp, idx); +} +int +auth1_set_cid(auth1_t *inp, size_t idx, uint8_t elt) +{ + trunnel_assert(idx < 32); + inp->cid[idx] = elt; + return 0; +} + +uint8_t * +auth1_getarray_cid(auth1_t *inp) +{ + return inp->cid; +} +const uint8_t * +auth1_getconstarray_cid(const auth1_t *inp) +{ + return (const uint8_t *)auth1_getarray_cid((auth1_t*)inp); +} +size_t +auth1_getlen_sid(const auth1_t *inp) +{ + (void)inp; return 32; +} + +uint8_t +auth1_get_sid(auth1_t *inp, size_t idx) +{ + trunnel_assert(idx < 32); + return inp->sid[idx]; +} + +uint8_t +auth1_getconst_sid(const auth1_t *inp, size_t idx) +{ + return auth1_get_sid((auth1_t*)inp, idx); +} +int +auth1_set_sid(auth1_t *inp, size_t idx, uint8_t elt) +{ + trunnel_assert(idx < 32); + inp->sid[idx] = elt; + return 0; +} + +uint8_t * +auth1_getarray_sid(auth1_t *inp) +{ + return inp->sid; +} +const uint8_t * +auth1_getconstarray_sid(const auth1_t *inp) +{ + return (const uint8_t *)auth1_getarray_sid((auth1_t*)inp); +} +size_t +auth1_getlen_cid_ed(const auth1_t *inp) +{ + (void)inp; return 32; +} + +uint8_t +auth1_get_cid_ed(auth1_t *inp, size_t idx) +{ + trunnel_assert(idx < 32); + return inp->cid_ed[idx]; +} + +uint8_t +auth1_getconst_cid_ed(const auth1_t *inp, size_t idx) +{ + return auth1_get_cid_ed((auth1_t*)inp, idx); +} +int +auth1_set_cid_ed(auth1_t *inp, size_t idx, uint8_t elt) +{ + trunnel_assert(idx < 32); + inp->cid_ed[idx] = elt; + return 0; +} + +uint8_t * +auth1_getarray_cid_ed(auth1_t *inp) +{ + return inp->cid_ed; +} +const uint8_t * +auth1_getconstarray_cid_ed(const auth1_t *inp) +{ + return (const uint8_t *)auth1_getarray_cid_ed((auth1_t*)inp); +} +size_t +auth1_getlen_sid_ed(const auth1_t *inp) +{ + (void)inp; return 32; +} + +uint8_t +auth1_get_sid_ed(auth1_t *inp, size_t idx) +{ + trunnel_assert(idx < 32); + return inp->sid_ed[idx]; +} + +uint8_t +auth1_getconst_sid_ed(const auth1_t *inp, size_t idx) +{ + return auth1_get_sid_ed((auth1_t*)inp, idx); +} +int +auth1_set_sid_ed(auth1_t *inp, size_t idx, uint8_t elt) +{ + trunnel_assert(idx < 32); + inp->sid_ed[idx] = elt; + return 0; +} + +uint8_t * +auth1_getarray_sid_ed(auth1_t *inp) +{ + return inp->sid_ed; +} +const uint8_t * +auth1_getconstarray_sid_ed(const auth1_t *inp) +{ + return (const uint8_t *)auth1_getarray_sid_ed((auth1_t*)inp); +} +size_t +auth1_getlen_slog(const auth1_t *inp) +{ + (void)inp; return 32; +} + +uint8_t +auth1_get_slog(auth1_t *inp, size_t idx) +{ + trunnel_assert(idx < 32); + return inp->slog[idx]; +} + +uint8_t +auth1_getconst_slog(const auth1_t *inp, size_t idx) +{ + return auth1_get_slog((auth1_t*)inp, idx); +} +int +auth1_set_slog(auth1_t *inp, size_t idx, uint8_t elt) +{ + trunnel_assert(idx < 32); + inp->slog[idx] = elt; + return 0; +} + +uint8_t * +auth1_getarray_slog(auth1_t *inp) +{ + return inp->slog; +} +const uint8_t * +auth1_getconstarray_slog(const auth1_t *inp) +{ + return (const uint8_t *)auth1_getarray_slog((auth1_t*)inp); +} +size_t +auth1_getlen_clog(const auth1_t *inp) +{ + (void)inp; return 32; +} + +uint8_t +auth1_get_clog(auth1_t *inp, size_t idx) +{ + trunnel_assert(idx < 32); + return inp->clog[idx]; +} + +uint8_t +auth1_getconst_clog(const auth1_t *inp, size_t idx) +{ + return auth1_get_clog((auth1_t*)inp, idx); +} +int +auth1_set_clog(auth1_t *inp, size_t idx, uint8_t elt) +{ + trunnel_assert(idx < 32); + inp->clog[idx] = elt; + return 0; +} + +uint8_t * +auth1_getarray_clog(auth1_t *inp) +{ + return inp->clog; +} +const uint8_t * +auth1_getconstarray_clog(const auth1_t *inp) +{ + return (const uint8_t *)auth1_getarray_clog((auth1_t*)inp); +} +size_t +auth1_getlen_scert(const auth1_t *inp) +{ + (void)inp; return 32; +} + +uint8_t +auth1_get_scert(auth1_t *inp, size_t idx) +{ + trunnel_assert(idx < 32); + return inp->scert[idx]; +} + +uint8_t +auth1_getconst_scert(const auth1_t *inp, size_t idx) +{ + return auth1_get_scert((auth1_t*)inp, idx); +} +int +auth1_set_scert(auth1_t *inp, size_t idx, uint8_t elt) +{ + trunnel_assert(idx < 32); + inp->scert[idx] = elt; + return 0; +} + +uint8_t * +auth1_getarray_scert(auth1_t *inp) +{ + return inp->scert; +} +const uint8_t * +auth1_getconstarray_scert(const auth1_t *inp) +{ + return (const uint8_t *)auth1_getarray_scert((auth1_t*)inp); +} +size_t +auth1_getlen_tlssecrets(const auth1_t *inp) +{ + (void)inp; return 32; +} + +uint8_t +auth1_get_tlssecrets(auth1_t *inp, size_t idx) +{ + trunnel_assert(idx < 32); + return inp->tlssecrets[idx]; +} + +uint8_t +auth1_getconst_tlssecrets(const auth1_t *inp, size_t idx) +{ + return auth1_get_tlssecrets((auth1_t*)inp, idx); +} +int +auth1_set_tlssecrets(auth1_t *inp, size_t idx, uint8_t elt) +{ + trunnel_assert(idx < 32); + inp->tlssecrets[idx] = elt; + return 0; +} + +uint8_t * +auth1_getarray_tlssecrets(auth1_t *inp) +{ + return inp->tlssecrets; +} +const uint8_t * +auth1_getconstarray_tlssecrets(const auth1_t *inp) +{ + return (const uint8_t *)auth1_getarray_tlssecrets((auth1_t*)inp); +} +const uint8_t * +auth1_get_end_of_fixed_part(const auth1_t *inp) +{ + return inp->end_of_fixed_part; +} +size_t +auth1_getlen_rand(const auth1_t *inp) +{ + (void)inp; return 24; +} + +uint8_t +auth1_get_rand(auth1_t *inp, size_t idx) +{ + trunnel_assert(idx < 24); + return inp->rand[idx]; +} + +uint8_t +auth1_getconst_rand(const auth1_t *inp, size_t idx) +{ + return auth1_get_rand((auth1_t*)inp, idx); +} +int +auth1_set_rand(auth1_t *inp, size_t idx, uint8_t elt) +{ + trunnel_assert(idx < 24); + inp->rand[idx] = elt; + return 0; +} + +uint8_t * +auth1_getarray_rand(auth1_t *inp) +{ + return inp->rand; +} +const uint8_t * +auth1_getconstarray_rand(const auth1_t *inp) +{ + return (const uint8_t *)auth1_getarray_rand((auth1_t*)inp); +} +const uint8_t * +auth1_get_end_of_signed(const auth1_t *inp) +{ + return inp->end_of_signed; +} +size_t +auth1_getlen_sig(const auth1_t *inp) +{ + return TRUNNEL_DYNARRAY_LEN(&inp->sig); +} + +uint8_t +auth1_get_sig(auth1_t *inp, size_t idx) +{ + return TRUNNEL_DYNARRAY_GET(&inp->sig, idx); +} + +uint8_t +auth1_getconst_sig(const auth1_t *inp, size_t idx) +{ + return auth1_get_sig((auth1_t*)inp, idx); +} +int +auth1_set_sig(auth1_t *inp, size_t idx, uint8_t elt) +{ + TRUNNEL_DYNARRAY_SET(&inp->sig, idx, elt); + return 0; +} +int +auth1_add_sig(auth1_t *inp, uint8_t elt) +{ + TRUNNEL_DYNARRAY_ADD(uint8_t, &inp->sig, elt, {}); + return 0; + trunnel_alloc_failed: + TRUNNEL_SET_ERROR_CODE(inp); + return -1; +} + +uint8_t * +auth1_getarray_sig(auth1_t *inp) +{ + return inp->sig.elts_; +} +const uint8_t * +auth1_getconstarray_sig(const auth1_t *inp) +{ + return (const uint8_t *)auth1_getarray_sig((auth1_t*)inp); +} +int +auth1_setlen_sig(auth1_t *inp, size_t newlen) +{ + uint8_t *newptr; + newptr = trunnel_dynarray_setlen(&inp->sig.allocated_, + &inp->sig.n_, inp->sig.elts_, newlen, + sizeof(inp->sig.elts_[0]), (trunnel_free_fn_t) NULL, + &inp->trunnel_error_code_); + if (newlen != 0 && newptr == NULL) + goto trunnel_alloc_failed; + inp->sig.elts_ = newptr; + return 0; + trunnel_alloc_failed: + TRUNNEL_SET_ERROR_CODE(inp); + return -1; +} +const char * +auth1_check(const auth1_t *obj) +{ + if (obj == NULL) + return "Object was NULL"; + if (obj->trunnel_error_code_) + return "A set function failed on this object"; + return NULL; +} + +ssize_t +auth1_encoded_len(const auth1_t *obj) +{ + ssize_t result = 0; + + if (NULL != auth1_check(obj)) + return -1; + + + /* Length of u8 type[8] */ + result += 8; + + /* Length of u8 cid[32] */ + result += 32; + + /* Length of u8 sid[32] */ + result += 32; + + /* Length of u8 cid_ed[32] */ + result += 32; + + /* Length of u8 sid_ed[32] */ + result += 32; + + /* Length of u8 slog[32] */ + result += 32; + + /* Length of u8 clog[32] */ + result += 32; + + /* Length of u8 scert[32] */ + result += 32; + + /* Length of u8 tlssecrets[32] */ + result += 32; + + /* Length of u8 rand[24] */ + result += 24; + + /* Length of u8 sig[] */ + result += TRUNNEL_DYNARRAY_LEN(&obj->sig); + return result; +} +int +auth1_clear_errors(auth1_t *obj) +{ + int r = obj->trunnel_error_code_; + obj->trunnel_error_code_ = 0; + return r; +} +ssize_t +auth1_encode(uint8_t *output, const size_t avail, const auth1_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 = auth1_encoded_len(obj); +#endif + + if (NULL != (msg = auth1_check(obj))) + goto check_failed; + +#ifdef TRUNNEL_CHECK_ENCODED_LEN + trunnel_assert(encoded_len >= 0); +#endif + + /* Encode u8 type[8] */ + trunnel_assert(written <= avail); + if (avail - written < 8) + goto truncated; + memcpy(ptr, obj->type, 8); + written += 8; ptr += 8; + + /* Encode u8 cid[32] */ + trunnel_assert(written <= avail); + if (avail - written < 32) + goto truncated; + memcpy(ptr, obj->cid, 32); + written += 32; ptr += 32; + + /* Encode u8 sid[32] */ + trunnel_assert(written <= avail); + if (avail - written < 32) + goto truncated; + memcpy(ptr, obj->sid, 32); + written += 32; ptr += 32; + + /* Encode u8 cid_ed[32] */ + trunnel_assert(written <= avail); + if (avail - written < 32) + goto truncated; + memcpy(ptr, obj->cid_ed, 32); + written += 32; ptr += 32; + + /* Encode u8 sid_ed[32] */ + trunnel_assert(written <= avail); + if (avail - written < 32) + goto truncated; + memcpy(ptr, obj->sid_ed, 32); + written += 32; ptr += 32; + + /* Encode u8 slog[32] */ + trunnel_assert(written <= avail); + if (avail - written < 32) + goto truncated; + memcpy(ptr, obj->slog, 32); + written += 32; ptr += 32; + + /* Encode u8 clog[32] */ + trunnel_assert(written <= avail); + if (avail - written < 32) + goto truncated; + memcpy(ptr, obj->clog, 32); + written += 32; ptr += 32; + + /* Encode u8 scert[32] */ + trunnel_assert(written <= avail); + if (avail - written < 32) + goto truncated; + memcpy(ptr, obj->scert, 32); + written += 32; ptr += 32; + + /* Encode u8 tlssecrets[32] */ + trunnel_assert(written <= avail); + if (avail - written < 32) + goto truncated; + memcpy(ptr, obj->tlssecrets, 32); + written += 32; ptr += 32; + + /* Encode u8 rand[24] */ + trunnel_assert(written <= avail); + if (avail - written < 24) + goto truncated; + memcpy(ptr, obj->rand, 24); + written += 24; ptr += 24; + + /* Encode u8 sig[] */ + { + size_t elt_len = TRUNNEL_DYNARRAY_LEN(&obj->sig); + trunnel_assert(written <= avail); + if (avail - written < elt_len) + goto truncated; + if (elt_len) + memcpy(ptr, obj->sig.elts_, elt_len); + written += elt_len; ptr += elt_len; + } + + + 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 auth1_parse(), but do not allocate the output object. + */ +static ssize_t +auth1_parse_into(auth1_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 type[8] */ + CHECK_REMAINING(8, truncated); + memcpy(obj->type, ptr, 8); + remaining -= 8; ptr += 8; + + /* Parse u8 cid[32] */ + CHECK_REMAINING(32, truncated); + memcpy(obj->cid, ptr, 32); + remaining -= 32; ptr += 32; + + /* Parse u8 sid[32] */ + CHECK_REMAINING(32, truncated); + memcpy(obj->sid, ptr, 32); + remaining -= 32; ptr += 32; + + /* Parse u8 cid_ed[32] */ + CHECK_REMAINING(32, truncated); + memcpy(obj->cid_ed, ptr, 32); + remaining -= 32; ptr += 32; + + /* Parse u8 sid_ed[32] */ + CHECK_REMAINING(32, truncated); + memcpy(obj->sid_ed, ptr, 32); + remaining -= 32; ptr += 32; + + /* Parse u8 slog[32] */ + CHECK_REMAINING(32, truncated); + memcpy(obj->slog, ptr, 32); + remaining -= 32; ptr += 32; + + /* Parse u8 clog[32] */ + CHECK_REMAINING(32, truncated); + memcpy(obj->clog, ptr, 32); + remaining -= 32; ptr += 32; + + /* Parse u8 scert[32] */ + CHECK_REMAINING(32, truncated); + memcpy(obj->scert, ptr, 32); + remaining -= 32; ptr += 32; + + /* Parse u8 tlssecrets[32] */ + CHECK_REMAINING(32, truncated); + memcpy(obj->tlssecrets, ptr, 32); + remaining -= 32; ptr += 32; + obj->end_of_fixed_part = ptr; + + /* Parse u8 rand[24] */ + CHECK_REMAINING(24, truncated); + memcpy(obj->rand, ptr, 24); + remaining -= 24; ptr += 24; + obj->end_of_signed = ptr; + + /* Parse u8 sig[] */ + TRUNNEL_DYNARRAY_EXPAND(uint8_t, &obj->sig, remaining, {}); + obj->sig.n_ = remaining; + if (remaining) + memcpy(obj->sig.elts_, ptr, remaining); + ptr += remaining; remaining -= remaining; + trunnel_assert(ptr + remaining == input + len_in); + return len_in - remaining; + + truncated: + return -2; + trunnel_alloc_failed: + return -1; +} + +ssize_t +auth1_parse(auth1_t **output, const uint8_t *input, const size_t len_in) +{ + ssize_t result; + *output = auth1_new(); + if (NULL == *output) + return -1; + result = auth1_parse_into(*output, input, len_in); + if (result < 0) { + auth1_free(*output); + *output = NULL; + } + return result; +} auth_challenge_cell_t * auth_challenge_cell_new(void) { @@ -334,44 +1066,6 @@ } return result; } -auth_ctx_t * -auth_ctx_new(void) -{ - auth_ctx_t *val = trunnel_calloc(1, sizeof(auth_ctx_t)); - if (NULL == val) - return NULL; - return val; -} - -/** Release all storage held inside 'obj', but do not free 'obj'. - */ -static void -auth_ctx_clear(auth_ctx_t *obj) -{ - (void) obj; -} - -void -auth_ctx_free(auth_ctx_t *obj) -{ - if (obj == NULL) - return; - auth_ctx_clear(obj); - trunnel_memwipe(obj, sizeof(auth_ctx_t)); - trunnel_free_(obj); -} - -uint8_t -auth_ctx_get_is_ed(const auth_ctx_t *inp) -{ - return inp->is_ed; -} -int -auth_ctx_set_is_ed(auth_ctx_t *inp, uint8_t val) -{ - inp->is_ed = val; - return 0; -} certs_cell_cert_t * certs_cell_cert_new(void) { @@ -977,798 +1671,6 @@ *output = NULL; } return result; -} -auth1_t * -auth1_new(void) -{ - auth1_t *val = trunnel_calloc(1, sizeof(auth1_t)); - if (NULL == val) - return NULL; - return val; -} - -/** Release all storage held inside 'obj', but do not free 'obj'. - */ -static void -auth1_clear(auth1_t *obj) -{ - (void) obj; - TRUNNEL_DYNARRAY_WIPE(&obj->sig); - TRUNNEL_DYNARRAY_CLEAR(&obj->sig); -} - -void -auth1_free(auth1_t *obj) -{ - if (obj == NULL) - return; - auth1_clear(obj); - trunnel_memwipe(obj, sizeof(auth1_t)); - trunnel_free_(obj); -} - -size_t -auth1_getlen_type(const auth1_t *inp) -{ - (void)inp; return 8; -} - -uint8_t -auth1_get_type(auth1_t *inp, size_t idx) -{ - trunnel_assert(idx < 8); - return inp->type[idx]; -} - -uint8_t -auth1_getconst_type(const auth1_t *inp, size_t idx) -{ - return auth1_get_type((auth1_t*)inp, idx); -} -int -auth1_set_type(auth1_t *inp, size_t idx, uint8_t elt) -{ - trunnel_assert(idx < 8); - inp->type[idx] = elt; - return 0; -} - -uint8_t * -auth1_getarray_type(auth1_t *inp) -{ - return inp->type; -} -const uint8_t * -auth1_getconstarray_type(const auth1_t *inp) -{ - return (const uint8_t *)auth1_getarray_type((auth1_t*)inp); -} -size_t -auth1_getlen_cid(const auth1_t *inp) -{ - (void)inp; return 32; -} - -uint8_t -auth1_get_cid(auth1_t *inp, size_t idx) -{ - trunnel_assert(idx < 32); - return inp->cid[idx]; -} - -uint8_t -auth1_getconst_cid(const auth1_t *inp, size_t idx) -{ - return auth1_get_cid((auth1_t*)inp, idx); -} -int -auth1_set_cid(auth1_t *inp, size_t idx, uint8_t elt) -{ - trunnel_assert(idx < 32); - inp->cid[idx] = elt; - return 0; -} - -uint8_t * -auth1_getarray_cid(auth1_t *inp) -{ - return inp->cid; -} -const uint8_t * -auth1_getconstarray_cid(const auth1_t *inp) -{ - return (const uint8_t *)auth1_getarray_cid((auth1_t*)inp); -} -size_t -auth1_getlen_sid(const auth1_t *inp) -{ - (void)inp; return 32; -} - -uint8_t -auth1_get_sid(auth1_t *inp, size_t idx) -{ - trunnel_assert(idx < 32); - return inp->sid[idx]; -} - -uint8_t -auth1_getconst_sid(const auth1_t *inp, size_t idx) -{ - return auth1_get_sid((auth1_t*)inp, idx); -} -int -auth1_set_sid(auth1_t *inp, size_t idx, uint8_t elt) -{ - trunnel_assert(idx < 32); - inp->sid[idx] = elt; - return 0; -} - -uint8_t * -auth1_getarray_sid(auth1_t *inp) -{ - return inp->sid; -} -const uint8_t * -auth1_getconstarray_sid(const auth1_t *inp) -{ - return (const uint8_t *)auth1_getarray_sid((auth1_t*)inp); -} -size_t -auth1_getlen_u1_cid_ed(const auth1_t *inp) -{ - (void)inp; return 32; -} - -uint8_t -auth1_get_u1_cid_ed(auth1_t *inp, size_t idx) -{ - trunnel_assert(idx < 32); - return inp->u1_cid_ed[idx]; -} - -uint8_t -auth1_getconst_u1_cid_ed(const auth1_t *inp, size_t idx) -{ - return auth1_get_u1_cid_ed((auth1_t*)inp, idx); -} -int -auth1_set_u1_cid_ed(auth1_t *inp, size_t idx, uint8_t elt) -{ - trunnel_assert(idx < 32); - inp->u1_cid_ed[idx] = elt; - return 0; -} - -uint8_t * -auth1_getarray_u1_cid_ed(auth1_t *inp) -{ - return inp->u1_cid_ed; -} -const uint8_t * -auth1_getconstarray_u1_cid_ed(const auth1_t *inp) -{ - return (const uint8_t *)auth1_getarray_u1_cid_ed((auth1_t*)inp); -} -size_t -auth1_getlen_u1_sid_ed(const auth1_t *inp) -{ - (void)inp; return 32; -} - -uint8_t -auth1_get_u1_sid_ed(auth1_t *inp, size_t idx) -{ - trunnel_assert(idx < 32); - return inp->u1_sid_ed[idx]; -} - -uint8_t -auth1_getconst_u1_sid_ed(const auth1_t *inp, size_t idx) -{ - return auth1_get_u1_sid_ed((auth1_t*)inp, idx); -} -int -auth1_set_u1_sid_ed(auth1_t *inp, size_t idx, uint8_t elt) -{ - trunnel_assert(idx < 32); - inp->u1_sid_ed[idx] = elt; - return 0; -} - -uint8_t * -auth1_getarray_u1_sid_ed(auth1_t *inp) -{ - return inp->u1_sid_ed; -} -const uint8_t * -auth1_getconstarray_u1_sid_ed(const auth1_t *inp) -{ - return (const uint8_t *)auth1_getarray_u1_sid_ed((auth1_t*)inp); -} -size_t -auth1_getlen_slog(const auth1_t *inp) -{ - (void)inp; return 32; -} - -uint8_t -auth1_get_slog(auth1_t *inp, size_t idx) -{ - trunnel_assert(idx < 32); - return inp->slog[idx]; -} - -uint8_t -auth1_getconst_slog(const auth1_t *inp, size_t idx) -{ - return auth1_get_slog((auth1_t*)inp, idx); -} -int -auth1_set_slog(auth1_t *inp, size_t idx, uint8_t elt) -{ - trunnel_assert(idx < 32); - inp->slog[idx] = elt; - return 0; -} - -uint8_t * -auth1_getarray_slog(auth1_t *inp) -{ - return inp->slog; -} -const uint8_t * -auth1_getconstarray_slog(const auth1_t *inp) -{ - return (const uint8_t *)auth1_getarray_slog((auth1_t*)inp); -} -size_t -auth1_getlen_clog(const auth1_t *inp) -{ - (void)inp; return 32; -} - -uint8_t -auth1_get_clog(auth1_t *inp, size_t idx) -{ - trunnel_assert(idx < 32); - return inp->clog[idx]; -} - -uint8_t -auth1_getconst_clog(const auth1_t *inp, size_t idx) -{ - return auth1_get_clog((auth1_t*)inp, idx); -} -int -auth1_set_clog(auth1_t *inp, size_t idx, uint8_t elt) -{ - trunnel_assert(idx < 32); - inp->clog[idx] = elt; - return 0; -} - -uint8_t * -auth1_getarray_clog(auth1_t *inp) -{ - return inp->clog; -} -const uint8_t * -auth1_getconstarray_clog(const auth1_t *inp) -{ - return (const uint8_t *)auth1_getarray_clog((auth1_t*)inp); -} -size_t -auth1_getlen_scert(const auth1_t *inp) -{ - (void)inp; return 32; -} - -uint8_t -auth1_get_scert(auth1_t *inp, size_t idx) -{ - trunnel_assert(idx < 32); - return inp->scert[idx]; -} - -uint8_t -auth1_getconst_scert(const auth1_t *inp, size_t idx) -{ - return auth1_get_scert((auth1_t*)inp, idx); -} -int -auth1_set_scert(auth1_t *inp, size_t idx, uint8_t elt) -{ - trunnel_assert(idx < 32); - inp->scert[idx] = elt; - return 0; -} - -uint8_t * -auth1_getarray_scert(auth1_t *inp) -{ - return inp->scert; -} -const uint8_t * -auth1_getconstarray_scert(const auth1_t *inp) -{ - return (const uint8_t *)auth1_getarray_scert((auth1_t*)inp); -} -size_t -auth1_getlen_tlssecrets(const auth1_t *inp) -{ - (void)inp; return 32; -} - -uint8_t -auth1_get_tlssecrets(auth1_t *inp, size_t idx) -{ - trunnel_assert(idx < 32); - return inp->tlssecrets[idx]; -} - -uint8_t -auth1_getconst_tlssecrets(const auth1_t *inp, size_t idx) -{ - return auth1_get_tlssecrets((auth1_t*)inp, idx); -} -int -auth1_set_tlssecrets(auth1_t *inp, size_t idx, uint8_t elt) -{ - trunnel_assert(idx < 32); - inp->tlssecrets[idx] = elt; - return 0; -} - -uint8_t * -auth1_getarray_tlssecrets(auth1_t *inp) -{ - return inp->tlssecrets; -} -const uint8_t * -auth1_getconstarray_tlssecrets(const auth1_t *inp) -{ - return (const uint8_t *)auth1_getarray_tlssecrets((auth1_t*)inp); -} -const uint8_t * -auth1_get_end_of_fixed_part(const auth1_t *inp) -{ - return inp->end_of_fixed_part; -} -size_t -auth1_getlen_rand(const auth1_t *inp) -{ - (void)inp; return 24; -} - -uint8_t -auth1_get_rand(auth1_t *inp, size_t idx) -{ - trunnel_assert(idx < 24); - return inp->rand[idx]; -} - -uint8_t -auth1_getconst_rand(const auth1_t *inp, size_t idx) -{ - return auth1_get_rand((auth1_t*)inp, idx); -} -int -auth1_set_rand(auth1_t *inp, size_t idx, uint8_t elt) -{ - trunnel_assert(idx < 24); - inp->rand[idx] = elt; - return 0; -} - -uint8_t * -auth1_getarray_rand(auth1_t *inp) -{ - return inp->rand; -} -const uint8_t * -auth1_getconstarray_rand(const auth1_t *inp) -{ - return (const uint8_t *)auth1_getarray_rand((auth1_t*)inp); -} -const uint8_t * -auth1_get_end_of_signed(const auth1_t *inp) -{ - return inp->end_of_signed; -} -size_t -auth1_getlen_sig(const auth1_t *inp) -{ - return TRUNNEL_DYNARRAY_LEN(&inp->sig); -} - -uint8_t -auth1_get_sig(auth1_t *inp, size_t idx) -{ - return TRUNNEL_DYNARRAY_GET(&inp->sig, idx); -} - -uint8_t -auth1_getconst_sig(const auth1_t *inp, size_t idx) -{ - return auth1_get_sig((auth1_t*)inp, idx); -} -int -auth1_set_sig(auth1_t *inp, size_t idx, uint8_t elt) -{ - TRUNNEL_DYNARRAY_SET(&inp->sig, idx, elt); - return 0; -} -int -auth1_add_sig(auth1_t *inp, uint8_t elt) -{ - TRUNNEL_DYNARRAY_ADD(uint8_t, &inp->sig, elt, {}); - return 0; - trunnel_alloc_failed: - TRUNNEL_SET_ERROR_CODE(inp); - return -1; -} - -uint8_t * -auth1_getarray_sig(auth1_t *inp) -{ - return inp->sig.elts_; -} -const uint8_t * -auth1_getconstarray_sig(const auth1_t *inp) -{ - return (const uint8_t *)auth1_getarray_sig((auth1_t*)inp); -} -int -auth1_setlen_sig(auth1_t *inp, size_t newlen) -{ - uint8_t *newptr; - newptr = trunnel_dynarray_setlen(&inp->sig.allocated_, - &inp->sig.n_, inp->sig.elts_, newlen, - sizeof(inp->sig.elts_[0]), (trunnel_free_fn_t) NULL, - &inp->trunnel_error_code_); - if (newlen != 0 && newptr == NULL) - goto trunnel_alloc_failed; - inp->sig.elts_ = newptr; - return 0; - trunnel_alloc_failed: - TRUNNEL_SET_ERROR_CODE(inp); - return -1; -} -const char * -auth1_check(const auth1_t *obj, const auth_ctx_t *auth_ctx_ctx) -{ - if (obj == NULL) - return "Object was NULL"; - if (obj->trunnel_error_code_) - return "A set function failed on this object"; - if (auth_ctx_ctx == NULL) - return "Context was NULL"; - switch (auth_ctx_ctx->is_ed) { - - case 0: - break; - - case 1: - break; - - default: - return "Bad tag for union"; - break; - } - return NULL; -} - -ssize_t -auth1_encoded_len(const auth1_t *obj, const auth_ctx_t *auth_ctx_ctx) -{ - ssize_t result = 0; - - if (NULL != auth1_check(obj, auth_ctx_ctx)) - return -1; - - - /* Length of u8 type[8] */ - result += 8; - - /* Length of u8 cid[32] */ - result += 32; - - /* Length of u8 sid[32] */ - result += 32; - switch (auth_ctx_ctx->is_ed) { - - case 0: - break; - - case 1: - - /* Length of u8 u1_cid_ed[32] */ - result += 32; - - /* Length of u8 u1_sid_ed[32] */ - result += 32; - break; - - default: - trunnel_assert(0); - break; - } - - /* Length of u8 slog[32] */ - result += 32; - - /* Length of u8 clog[32] */ - result += 32; - - /* Length of u8 scert[32] */ - result += 32; - - /* Length of u8 tlssecrets[32] */ - result += 32; - - /* Length of u8 rand[24] */ - result += 24; - - /* Length of u8 sig[] */ - result += TRUNNEL_DYNARRAY_LEN(&obj->sig); - return result; -} -int -auth1_clear_errors(auth1_t *obj) -{ - int r = obj->trunnel_error_code_; - obj->trunnel_error_code_ = 0; - return r; -} -ssize_t -auth1_encode(uint8_t *output, const size_t avail, const auth1_t *obj, const auth_ctx_t *auth_ctx_ctx) -{ - 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 = auth1_encoded_len(obj, auth_ctx_ctx); -#endif - - if (NULL != (msg = auth1_check(obj, auth_ctx_ctx))) - goto check_failed; - -#ifdef TRUNNEL_CHECK_ENCODED_LEN - trunnel_assert(encoded_len >= 0); -#endif - - /* Encode u8 type[8] */ - trunnel_assert(written <= avail); - if (avail - written < 8) - goto truncated; - memcpy(ptr, obj->type, 8); - written += 8; ptr += 8; - - /* Encode u8 cid[32] */ - trunnel_assert(written <= avail); - if (avail - written < 32) - goto truncated; - memcpy(ptr, obj->cid, 32); - written += 32; ptr += 32; - - /* Encode u8 sid[32] */ - trunnel_assert(written <= avail); - if (avail - written < 32) - goto truncated; - memcpy(ptr, obj->sid, 32); - written += 32; ptr += 32; - - /* Encode union u1[auth_ctx.is_ed] */ - trunnel_assert(written <= avail); - switch (auth_ctx_ctx->is_ed) { - - case 0: - break; - - case 1: - - /* Encode u8 u1_cid_ed[32] */ - trunnel_assert(written <= avail); - if (avail - written < 32) - goto truncated; - memcpy(ptr, obj->u1_cid_ed, 32); - written += 32; ptr += 32; - - /* Encode u8 u1_sid_ed[32] */ - trunnel_assert(written <= avail); - if (avail - written < 32) - goto truncated; - memcpy(ptr, obj->u1_sid_ed, 32); - written += 32; ptr += 32; - break; - - default: - trunnel_assert(0); - break; - } - - /* Encode u8 slog[32] */ - trunnel_assert(written <= avail); - if (avail - written < 32) - goto truncated; - memcpy(ptr, obj->slog, 32); - written += 32; ptr += 32; - - /* Encode u8 clog[32] */ - trunnel_assert(written <= avail); - if (avail - written < 32) - goto truncated; - memcpy(ptr, obj->clog, 32); - written += 32; ptr += 32; - - /* Encode u8 scert[32] */ - trunnel_assert(written <= avail); - if (avail - written < 32) - goto truncated; - memcpy(ptr, obj->scert, 32); - written += 32; ptr += 32; - - /* Encode u8 tlssecrets[32] */ - trunnel_assert(written <= avail); - if (avail - written < 32) - goto truncated; - memcpy(ptr, obj->tlssecrets, 32); - written += 32; ptr += 32; - - /* Encode u8 rand[24] */ - trunnel_assert(written <= avail); - if (avail - written < 24) - goto truncated; - memcpy(ptr, obj->rand, 24); - written += 24; ptr += 24; - - /* Encode u8 sig[] */ - { - size_t elt_len = TRUNNEL_DYNARRAY_LEN(&obj->sig); - trunnel_assert(written <= avail); - if (avail - written < elt_len) - goto truncated; - if (elt_len) - memcpy(ptr, obj->sig.elts_, elt_len); - written += elt_len; ptr += elt_len; - } - - - 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 auth1_parse(), but do not allocate the output object. - */ -static ssize_t -auth1_parse_into(auth1_t *obj, const uint8_t *input, const size_t len_in, const auth_ctx_t *auth_ctx_ctx) -{ - const uint8_t *ptr = input; - size_t remaining = len_in; - ssize_t result = 0; - (void)result; - if (auth_ctx_ctx == NULL) - return -1; - - /* Parse u8 type[8] */ - CHECK_REMAINING(8, truncated); - memcpy(obj->type, ptr, 8); - remaining -= 8; ptr += 8; - - /* Parse u8 cid[32] */ - CHECK_REMAINING(32, truncated); - memcpy(obj->cid, ptr, 32); - remaining -= 32; ptr += 32; - - /* Parse u8 sid[32] */ - CHECK_REMAINING(32, truncated); - memcpy(obj->sid, ptr, 32); - remaining -= 32; ptr += 32; - - /* Parse union u1[auth_ctx.is_ed] */ - switch (auth_ctx_ctx->is_ed) { - - case 0: - break; - - case 1: - - /* Parse u8 u1_cid_ed[32] */ - CHECK_REMAINING(32, truncated); - memcpy(obj->u1_cid_ed, ptr, 32); - remaining -= 32; ptr += 32; - - /* Parse u8 u1_sid_ed[32] */ - CHECK_REMAINING(32, truncated); - memcpy(obj->u1_sid_ed, ptr, 32); - remaining -= 32; ptr += 32; - break; - - default: - goto fail; - break; - } - - /* Parse u8 slog[32] */ - CHECK_REMAINING(32, truncated); - memcpy(obj->slog, ptr, 32); - remaining -= 32; ptr += 32; - - /* Parse u8 clog[32] */ - CHECK_REMAINING(32, truncated); - memcpy(obj->clog, ptr, 32); - remaining -= 32; ptr += 32; - - /* Parse u8 scert[32] */ - CHECK_REMAINING(32, truncated); - memcpy(obj->scert, ptr, 32); - remaining -= 32; ptr += 32; - - /* Parse u8 tlssecrets[32] */ - CHECK_REMAINING(32, truncated); - memcpy(obj->tlssecrets, ptr, 32); - remaining -= 32; ptr += 32; - obj->end_of_fixed_part = ptr; - - /* Parse u8 rand[24] */ - CHECK_REMAINING(24, truncated); - memcpy(obj->rand, ptr, 24); - remaining -= 24; ptr += 24; - obj->end_of_signed = ptr; - - /* Parse u8 sig[] */ - TRUNNEL_DYNARRAY_EXPAND(uint8_t, &obj->sig, remaining, {}); - obj->sig.n_ = remaining; - if (remaining) - memcpy(obj->sig.elts_, ptr, remaining); - ptr += remaining; remaining -= remaining; - trunnel_assert(ptr + remaining == input + len_in); - return len_in - remaining; - - truncated: - return -2; - trunnel_alloc_failed: - return -1; - fail: - result = -1; - return result; -} - -ssize_t -auth1_parse(auth1_t **output, const uint8_t *input, const size_t len_in, const auth_ctx_t *auth_ctx_ctx) -{ - ssize_t result; - *output = auth1_new(); - if (NULL == *output) - return -1; - result = auth1_parse_into(*output, input, len_in, auth_ctx_ctx); - if (result < 0) { - auth1_free(*output); - *output = NULL; - } - return result; } certs_cell_t * certs_cell_new(void) diff -Nru tor-0.4.7.16/src/trunnel/link_handshake.h tor-0.4.9.6/src/trunnel/link_handshake.h --- tor-0.4.7.16/src/trunnel/link_handshake.h 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/trunnel/link_handshake.h 2026-03-25 14:30:34.000000000 +0000 @@ -15,6 +15,25 @@ #define CERTTYPE_ED_SIGN_LINK 5 #define CERTTYPE_ED_SIGN_AUTH 6 #define CERTTYPE_RSA1024_ID_EDID 7 +#if !defined(TRUNNEL_OPAQUE) && !defined(TRUNNEL_OPAQUE_AUTH1) +struct auth1_st { + uint8_t type[8]; + uint8_t cid[32]; + uint8_t sid[32]; + uint8_t cid_ed[32]; + uint8_t sid_ed[32]; + uint8_t slog[32]; + uint8_t clog[32]; + uint8_t scert[32]; + uint8_t tlssecrets[32]; + const uint8_t *end_of_fixed_part; + uint8_t rand[24]; + const uint8_t *end_of_signed; + TRUNNEL_DYNARRAY_HEAD(, uint8_t) sig; + uint8_t trunnel_error_code_; +}; +#endif +typedef struct auth1_st auth1_t; #if !defined(TRUNNEL_OPAQUE) && !defined(TRUNNEL_OPAQUE_AUTH_CHALLENGE_CELL) struct auth_challenge_cell_st { uint8_t challenge[32]; @@ -24,13 +43,6 @@ }; #endif typedef struct auth_challenge_cell_st auth_challenge_cell_t; -#if !defined(TRUNNEL_OPAQUE) && !defined(TRUNNEL_OPAQUE_AUTH_CTX) -struct auth_ctx_st { - uint8_t is_ed; - uint8_t trunnel_error_code_; -}; -#endif -typedef struct auth_ctx_st auth_ctx_t; #if !defined(TRUNNEL_OPAQUE) && !defined(TRUNNEL_OPAQUE_CERTS_CELL_CERT) struct certs_cell_cert_st { uint8_t cert_type; @@ -51,25 +63,6 @@ }; #endif typedef struct rsa_ed_crosscert_st rsa_ed_crosscert_t; -#if !defined(TRUNNEL_OPAQUE) && !defined(TRUNNEL_OPAQUE_AUTH1) -struct auth1_st { - uint8_t type[8]; - uint8_t cid[32]; - uint8_t sid[32]; - uint8_t u1_cid_ed[32]; - uint8_t u1_sid_ed[32]; - uint8_t slog[32]; - uint8_t clog[32]; - uint8_t scert[32]; - uint8_t tlssecrets[32]; - const uint8_t *end_of_fixed_part; - uint8_t rand[24]; - const uint8_t *end_of_signed; - TRUNNEL_DYNARRAY_HEAD(, uint8_t) sig; - uint8_t trunnel_error_code_; -}; -#endif -typedef struct auth1_st auth1_t; #if !defined(TRUNNEL_OPAQUE) && !defined(TRUNNEL_OPAQUE_CERTS_CELL) struct certs_cell_st { uint8_t n_certs; @@ -78,6 +71,292 @@ }; #endif typedef struct certs_cell_st certs_cell_t; +/** Return a newly allocated auth1 with all elements set to zero. + */ +auth1_t *auth1_new(void); +/** Release all storage held by the auth1 in 'victim'. (Do nothing if + * 'victim' is NULL.) + */ +void auth1_free(auth1_t *victim); +/** Try to parse a auth1 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 auth1_t. + * On failure, return -2 if the input appears truncated, and -1 if the + * input is otherwise invalid. + */ +ssize_t auth1_parse(auth1_t **output, const uint8_t *input, const size_t len_in); +/** Return the number of bytes we expect to need to encode the auth1 + * 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 auth1_encoded_len(const auth1_t *obj); +/** Try to encode the auth1 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 auth1_encode(uint8_t *output, size_t avail, const auth1_t *input); +/** Check whether the internal state of the auth1 in 'obj' is + * consistent. Return NULL if it is, and a short message if it is not. + */ +const char *auth1_check(const auth1_t *obj); +/** Clear any errors that were set on the object 'obj' by its setter + * functions. Return true iff errors were cleared. + */ +int auth1_clear_errors(auth1_t *obj); +/** Return the (constant) length of the array holding the type field + * of the auth1_t in 'inp'. + */ +size_t auth1_getlen_type(const auth1_t *inp); +/** Return the element at position 'idx' of the fixed array field type + * of the auth1_t in 'inp'. + */ +uint8_t auth1_get_type(auth1_t *inp, size_t idx); +/** As auth1_get_type, but take and return a const pointer + */ +uint8_t auth1_getconst_type(const auth1_t *inp, size_t idx); +/** Change the element at position 'idx' of the fixed array field type + * of the auth1_t in 'inp', so that it will hold the value 'elt'. + */ +int auth1_set_type(auth1_t *inp, size_t idx, uint8_t elt); +/** Return a pointer to the 8-element array field type of 'inp'. + */ +uint8_t * auth1_getarray_type(auth1_t *inp); +/** As auth1_get_type, but take and return a const pointer + */ +const uint8_t * auth1_getconstarray_type(const auth1_t *inp); +/** Return the (constant) length of the array holding the cid field of + * the auth1_t in 'inp'. + */ +size_t auth1_getlen_cid(const auth1_t *inp); +/** Return the element at position 'idx' of the fixed array field cid + * of the auth1_t in 'inp'. + */ +uint8_t auth1_get_cid(auth1_t *inp, size_t idx); +/** As auth1_get_cid, but take and return a const pointer + */ +uint8_t auth1_getconst_cid(const auth1_t *inp, size_t idx); +/** Change the element at position 'idx' of the fixed array field cid + * of the auth1_t in 'inp', so that it will hold the value 'elt'. + */ +int auth1_set_cid(auth1_t *inp, size_t idx, uint8_t elt); +/** Return a pointer to the 32-element array field cid of 'inp'. + */ +uint8_t * auth1_getarray_cid(auth1_t *inp); +/** As auth1_get_cid, but take and return a const pointer + */ +const uint8_t * auth1_getconstarray_cid(const auth1_t *inp); +/** Return the (constant) length of the array holding the sid field of + * the auth1_t in 'inp'. + */ +size_t auth1_getlen_sid(const auth1_t *inp); +/** Return the element at position 'idx' of the fixed array field sid + * of the auth1_t in 'inp'. + */ +uint8_t auth1_get_sid(auth1_t *inp, size_t idx); +/** As auth1_get_sid, but take and return a const pointer + */ +uint8_t auth1_getconst_sid(const auth1_t *inp, size_t idx); +/** Change the element at position 'idx' of the fixed array field sid + * of the auth1_t in 'inp', so that it will hold the value 'elt'. + */ +int auth1_set_sid(auth1_t *inp, size_t idx, uint8_t elt); +/** Return a pointer to the 32-element array field sid of 'inp'. + */ +uint8_t * auth1_getarray_sid(auth1_t *inp); +/** As auth1_get_sid, but take and return a const pointer + */ +const uint8_t * auth1_getconstarray_sid(const auth1_t *inp); +/** Return the (constant) length of the array holding the cid_ed field + * of the auth1_t in 'inp'. + */ +size_t auth1_getlen_cid_ed(const auth1_t *inp); +/** Return the element at position 'idx' of the fixed array field + * cid_ed of the auth1_t in 'inp'. + */ +uint8_t auth1_get_cid_ed(auth1_t *inp, size_t idx); +/** As auth1_get_cid_ed, but take and return a const pointer + */ +uint8_t auth1_getconst_cid_ed(const auth1_t *inp, size_t idx); +/** Change the element at position 'idx' of the fixed array field + * cid_ed of the auth1_t in 'inp', so that it will hold the value + * 'elt'. + */ +int auth1_set_cid_ed(auth1_t *inp, size_t idx, uint8_t elt); +/** Return a pointer to the 32-element array field cid_ed of 'inp'. + */ +uint8_t * auth1_getarray_cid_ed(auth1_t *inp); +/** As auth1_get_cid_ed, but take and return a const pointer + */ +const uint8_t * auth1_getconstarray_cid_ed(const auth1_t *inp); +/** Return the (constant) length of the array holding the sid_ed field + * of the auth1_t in 'inp'. + */ +size_t auth1_getlen_sid_ed(const auth1_t *inp); +/** Return the element at position 'idx' of the fixed array field + * sid_ed of the auth1_t in 'inp'. + */ +uint8_t auth1_get_sid_ed(auth1_t *inp, size_t idx); +/** As auth1_get_sid_ed, but take and return a const pointer + */ +uint8_t auth1_getconst_sid_ed(const auth1_t *inp, size_t idx); +/** Change the element at position 'idx' of the fixed array field + * sid_ed of the auth1_t in 'inp', so that it will hold the value + * 'elt'. + */ +int auth1_set_sid_ed(auth1_t *inp, size_t idx, uint8_t elt); +/** Return a pointer to the 32-element array field sid_ed of 'inp'. + */ +uint8_t * auth1_getarray_sid_ed(auth1_t *inp); +/** As auth1_get_sid_ed, but take and return a const pointer + */ +const uint8_t * auth1_getconstarray_sid_ed(const auth1_t *inp); +/** Return the (constant) length of the array holding the slog field + * of the auth1_t in 'inp'. + */ +size_t auth1_getlen_slog(const auth1_t *inp); +/** Return the element at position 'idx' of the fixed array field slog + * of the auth1_t in 'inp'. + */ +uint8_t auth1_get_slog(auth1_t *inp, size_t idx); +/** As auth1_get_slog, but take and return a const pointer + */ +uint8_t auth1_getconst_slog(const auth1_t *inp, size_t idx); +/** Change the element at position 'idx' of the fixed array field slog + * of the auth1_t in 'inp', so that it will hold the value 'elt'. + */ +int auth1_set_slog(auth1_t *inp, size_t idx, uint8_t elt); +/** Return a pointer to the 32-element array field slog of 'inp'. + */ +uint8_t * auth1_getarray_slog(auth1_t *inp); +/** As auth1_get_slog, but take and return a const pointer + */ +const uint8_t * auth1_getconstarray_slog(const auth1_t *inp); +/** Return the (constant) length of the array holding the clog field + * of the auth1_t in 'inp'. + */ +size_t auth1_getlen_clog(const auth1_t *inp); +/** Return the element at position 'idx' of the fixed array field clog + * of the auth1_t in 'inp'. + */ +uint8_t auth1_get_clog(auth1_t *inp, size_t idx); +/** As auth1_get_clog, but take and return a const pointer + */ +uint8_t auth1_getconst_clog(const auth1_t *inp, size_t idx); +/** Change the element at position 'idx' of the fixed array field clog + * of the auth1_t in 'inp', so that it will hold the value 'elt'. + */ +int auth1_set_clog(auth1_t *inp, size_t idx, uint8_t elt); +/** Return a pointer to the 32-element array field clog of 'inp'. + */ +uint8_t * auth1_getarray_clog(auth1_t *inp); +/** As auth1_get_clog, but take and return a const pointer + */ +const uint8_t * auth1_getconstarray_clog(const auth1_t *inp); +/** Return the (constant) length of the array holding the scert field + * of the auth1_t in 'inp'. + */ +size_t auth1_getlen_scert(const auth1_t *inp); +/** Return the element at position 'idx' of the fixed array field + * scert of the auth1_t in 'inp'. + */ +uint8_t auth1_get_scert(auth1_t *inp, size_t idx); +/** As auth1_get_scert, but take and return a const pointer + */ +uint8_t auth1_getconst_scert(const auth1_t *inp, size_t idx); +/** Change the element at position 'idx' of the fixed array field + * scert of the auth1_t in 'inp', so that it will hold the value + * 'elt'. + */ +int auth1_set_scert(auth1_t *inp, size_t idx, uint8_t elt); +/** Return a pointer to the 32-element array field scert of 'inp'. + */ +uint8_t * auth1_getarray_scert(auth1_t *inp); +/** As auth1_get_scert, but take and return a const pointer + */ +const uint8_t * auth1_getconstarray_scert(const auth1_t *inp); +/** Return the (constant) length of the array holding the tlssecrets + * field of the auth1_t in 'inp'. + */ +size_t auth1_getlen_tlssecrets(const auth1_t *inp); +/** Return the element at position 'idx' of the fixed array field + * tlssecrets of the auth1_t in 'inp'. + */ +uint8_t auth1_get_tlssecrets(auth1_t *inp, size_t idx); +/** As auth1_get_tlssecrets, but take and return a const pointer + */ +uint8_t auth1_getconst_tlssecrets(const auth1_t *inp, size_t idx); +/** Change the element at position 'idx' of the fixed array field + * tlssecrets of the auth1_t in 'inp', so that it will hold the value + * 'elt'. + */ +int auth1_set_tlssecrets(auth1_t *inp, size_t idx, uint8_t elt); +/** Return a pointer to the 32-element array field tlssecrets of + * 'inp'. + */ +uint8_t * auth1_getarray_tlssecrets(auth1_t *inp); +/** As auth1_get_tlssecrets, but take and return a const pointer + */ +const uint8_t * auth1_getconstarray_tlssecrets(const auth1_t *inp); +/** Return the position for end_of_fixed_part when we parsed this + * object + */ +const uint8_t * auth1_get_end_of_fixed_part(const auth1_t *inp); +/** Return the (constant) length of the array holding the rand field + * of the auth1_t in 'inp'. + */ +size_t auth1_getlen_rand(const auth1_t *inp); +/** Return the element at position 'idx' of the fixed array field rand + * of the auth1_t in 'inp'. + */ +uint8_t auth1_get_rand(auth1_t *inp, size_t idx); +/** As auth1_get_rand, but take and return a const pointer + */ +uint8_t auth1_getconst_rand(const auth1_t *inp, size_t idx); +/** Change the element at position 'idx' of the fixed array field rand + * of the auth1_t in 'inp', so that it will hold the value 'elt'. + */ +int auth1_set_rand(auth1_t *inp, size_t idx, uint8_t elt); +/** Return a pointer to the 24-element array field rand of 'inp'. + */ +uint8_t * auth1_getarray_rand(auth1_t *inp); +/** As auth1_get_rand, but take and return a const pointer + */ +const uint8_t * auth1_getconstarray_rand(const auth1_t *inp); +/** Return the position for end_of_signed when we parsed this object + */ +const uint8_t * auth1_get_end_of_signed(const auth1_t *inp); +/** Return the length of the dynamic array holding the sig field of + * the auth1_t in 'inp'. + */ +size_t auth1_getlen_sig(const auth1_t *inp); +/** Return the element at position 'idx' of the dynamic array field + * sig of the auth1_t in 'inp'. + */ +uint8_t auth1_get_sig(auth1_t *inp, size_t idx); +/** As auth1_get_sig, but take and return a const pointer + */ +uint8_t auth1_getconst_sig(const auth1_t *inp, size_t idx); +/** Change the element at position 'idx' of the dynamic array field + * sig of the auth1_t in 'inp', so that it will hold the value 'elt'. + */ +int auth1_set_sig(auth1_t *inp, size_t idx, uint8_t elt); +/** Append a new element 'elt' to the dynamic array field sig of the + * auth1_t in 'inp'. + */ +int auth1_add_sig(auth1_t *inp, uint8_t elt); +/** Return a pointer to the variable-length array field sig of 'inp'. + */ +uint8_t * auth1_getarray_sig(auth1_t *inp); +/** As auth1_get_sig, but take and return a const pointer + */ +const uint8_t * auth1_getconstarray_sig(const auth1_t *inp); +/** Change the length of the variable-length array field sig of 'inp' + * to 'newlen'.Fill extra elements with 0. Return 0 on success; return + * -1 and set the error code on 'inp' on failure. + */ +int auth1_setlen_sig(auth1_t *inp, size_t newlen); /** Return a newly allocated auth_challenge_cell with all elements set * to zero. */ @@ -181,21 +460,6 @@ * return -1 and set the error code on 'inp' on failure. */ int auth_challenge_cell_setlen_methods(auth_challenge_cell_t *inp, size_t newlen); -/** Return a newly allocated auth_ctx with all elements set to zero. - */ -auth_ctx_t *auth_ctx_new(void); -/** Release all storage held by the auth_ctx in 'victim'. (Do nothing - * if 'victim' is NULL.) - */ -void auth_ctx_free(auth_ctx_t *victim); -/** Return the value of the is_ed field of the auth_ctx_t in 'inp' - */ -uint8_t auth_ctx_get_is_ed(const auth_ctx_t *inp); -/** Set the value of the is_ed field of the auth_ctx_t in 'inp' to - * 'val'. Return 0 on success; return -1 and set the error code on - * 'inp' on failure. - */ -int auth_ctx_set_is_ed(auth_ctx_t *inp, uint8_t val); /** Return a newly allocated certs_cell_cert with all elements set to * zero. */ @@ -393,292 +657,6 @@ * -1 and set the error code on 'inp' on failure. */ int rsa_ed_crosscert_setlen_sig(rsa_ed_crosscert_t *inp, size_t newlen); -/** Return a newly allocated auth1 with all elements set to zero. - */ -auth1_t *auth1_new(void); -/** Release all storage held by the auth1 in 'victim'. (Do nothing if - * 'victim' is NULL.) - */ -void auth1_free(auth1_t *victim); -/** Try to parse a auth1 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 auth1_t. - * On failure, return -2 if the input appears truncated, and -1 if the - * input is otherwise invalid. - */ -ssize_t auth1_parse(auth1_t **output, const uint8_t *input, const size_t len_in, const auth_ctx_t *auth_ctx_ctx); -/** Return the number of bytes we expect to need to encode the auth1 - * 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 auth1_encoded_len(const auth1_t *obj, const auth_ctx_t *auth_ctx_ctx); -/** Try to encode the auth1 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 auth1_encode(uint8_t *output, size_t avail, const auth1_t *input, const auth_ctx_t *auth_ctx_ctx); -/** Check whether the internal state of the auth1 in 'obj' is - * consistent. Return NULL if it is, and a short message if it is not. - */ -const char *auth1_check(const auth1_t *obj, const auth_ctx_t *auth_ctx_ctx); -/** Clear any errors that were set on the object 'obj' by its setter - * functions. Return true iff errors were cleared. - */ -int auth1_clear_errors(auth1_t *obj); -/** Return the (constant) length of the array holding the type field - * of the auth1_t in 'inp'. - */ -size_t auth1_getlen_type(const auth1_t *inp); -/** Return the element at position 'idx' of the fixed array field type - * of the auth1_t in 'inp'. - */ -uint8_t auth1_get_type(auth1_t *inp, size_t idx); -/** As auth1_get_type, but take and return a const pointer - */ -uint8_t auth1_getconst_type(const auth1_t *inp, size_t idx); -/** Change the element at position 'idx' of the fixed array field type - * of the auth1_t in 'inp', so that it will hold the value 'elt'. - */ -int auth1_set_type(auth1_t *inp, size_t idx, uint8_t elt); -/** Return a pointer to the 8-element array field type of 'inp'. - */ -uint8_t * auth1_getarray_type(auth1_t *inp); -/** As auth1_get_type, but take and return a const pointer - */ -const uint8_t * auth1_getconstarray_type(const auth1_t *inp); -/** Return the (constant) length of the array holding the cid field of - * the auth1_t in 'inp'. - */ -size_t auth1_getlen_cid(const auth1_t *inp); -/** Return the element at position 'idx' of the fixed array field cid - * of the auth1_t in 'inp'. - */ -uint8_t auth1_get_cid(auth1_t *inp, size_t idx); -/** As auth1_get_cid, but take and return a const pointer - */ -uint8_t auth1_getconst_cid(const auth1_t *inp, size_t idx); -/** Change the element at position 'idx' of the fixed array field cid - * of the auth1_t in 'inp', so that it will hold the value 'elt'. - */ -int auth1_set_cid(auth1_t *inp, size_t idx, uint8_t elt); -/** Return a pointer to the 32-element array field cid of 'inp'. - */ -uint8_t * auth1_getarray_cid(auth1_t *inp); -/** As auth1_get_cid, but take and return a const pointer - */ -const uint8_t * auth1_getconstarray_cid(const auth1_t *inp); -/** Return the (constant) length of the array holding the sid field of - * the auth1_t in 'inp'. - */ -size_t auth1_getlen_sid(const auth1_t *inp); -/** Return the element at position 'idx' of the fixed array field sid - * of the auth1_t in 'inp'. - */ -uint8_t auth1_get_sid(auth1_t *inp, size_t idx); -/** As auth1_get_sid, but take and return a const pointer - */ -uint8_t auth1_getconst_sid(const auth1_t *inp, size_t idx); -/** Change the element at position 'idx' of the fixed array field sid - * of the auth1_t in 'inp', so that it will hold the value 'elt'. - */ -int auth1_set_sid(auth1_t *inp, size_t idx, uint8_t elt); -/** Return a pointer to the 32-element array field sid of 'inp'. - */ -uint8_t * auth1_getarray_sid(auth1_t *inp); -/** As auth1_get_sid, but take and return a const pointer - */ -const uint8_t * auth1_getconstarray_sid(const auth1_t *inp); -/** Return the (constant) length of the array holding the u1_cid_ed - * field of the auth1_t in 'inp'. - */ -size_t auth1_getlen_u1_cid_ed(const auth1_t *inp); -/** Return the element at position 'idx' of the fixed array field - * u1_cid_ed of the auth1_t in 'inp'. - */ -uint8_t auth1_get_u1_cid_ed(auth1_t *inp, size_t idx); -/** As auth1_get_u1_cid_ed, but take and return a const pointer - */ -uint8_t auth1_getconst_u1_cid_ed(const auth1_t *inp, size_t idx); -/** Change the element at position 'idx' of the fixed array field - * u1_cid_ed of the auth1_t in 'inp', so that it will hold the value - * 'elt'. - */ -int auth1_set_u1_cid_ed(auth1_t *inp, size_t idx, uint8_t elt); -/** Return a pointer to the 32-element array field u1_cid_ed of 'inp'. - */ -uint8_t * auth1_getarray_u1_cid_ed(auth1_t *inp); -/** As auth1_get_u1_cid_ed, but take and return a const pointer - */ -const uint8_t * auth1_getconstarray_u1_cid_ed(const auth1_t *inp); -/** Return the (constant) length of the array holding the u1_sid_ed - * field of the auth1_t in 'inp'. - */ -size_t auth1_getlen_u1_sid_ed(const auth1_t *inp); -/** Return the element at position 'idx' of the fixed array field - * u1_sid_ed of the auth1_t in 'inp'. - */ -uint8_t auth1_get_u1_sid_ed(auth1_t *inp, size_t idx); -/** As auth1_get_u1_sid_ed, but take and return a const pointer - */ -uint8_t auth1_getconst_u1_sid_ed(const auth1_t *inp, size_t idx); -/** Change the element at position 'idx' of the fixed array field - * u1_sid_ed of the auth1_t in 'inp', so that it will hold the value - * 'elt'. - */ -int auth1_set_u1_sid_ed(auth1_t *inp, size_t idx, uint8_t elt); -/** Return a pointer to the 32-element array field u1_sid_ed of 'inp'. - */ -uint8_t * auth1_getarray_u1_sid_ed(auth1_t *inp); -/** As auth1_get_u1_sid_ed, but take and return a const pointer - */ -const uint8_t * auth1_getconstarray_u1_sid_ed(const auth1_t *inp); -/** Return the (constant) length of the array holding the slog field - * of the auth1_t in 'inp'. - */ -size_t auth1_getlen_slog(const auth1_t *inp); -/** Return the element at position 'idx' of the fixed array field slog - * of the auth1_t in 'inp'. - */ -uint8_t auth1_get_slog(auth1_t *inp, size_t idx); -/** As auth1_get_slog, but take and return a const pointer - */ -uint8_t auth1_getconst_slog(const auth1_t *inp, size_t idx); -/** Change the element at position 'idx' of the fixed array field slog - * of the auth1_t in 'inp', so that it will hold the value 'elt'. - */ -int auth1_set_slog(auth1_t *inp, size_t idx, uint8_t elt); -/** Return a pointer to the 32-element array field slog of 'inp'. - */ -uint8_t * auth1_getarray_slog(auth1_t *inp); -/** As auth1_get_slog, but take and return a const pointer - */ -const uint8_t * auth1_getconstarray_slog(const auth1_t *inp); -/** Return the (constant) length of the array holding the clog field - * of the auth1_t in 'inp'. - */ -size_t auth1_getlen_clog(const auth1_t *inp); -/** Return the element at position 'idx' of the fixed array field clog - * of the auth1_t in 'inp'. - */ -uint8_t auth1_get_clog(auth1_t *inp, size_t idx); -/** As auth1_get_clog, but take and return a const pointer - */ -uint8_t auth1_getconst_clog(const auth1_t *inp, size_t idx); -/** Change the element at position 'idx' of the fixed array field clog - * of the auth1_t in 'inp', so that it will hold the value 'elt'. - */ -int auth1_set_clog(auth1_t *inp, size_t idx, uint8_t elt); -/** Return a pointer to the 32-element array field clog of 'inp'. - */ -uint8_t * auth1_getarray_clog(auth1_t *inp); -/** As auth1_get_clog, but take and return a const pointer - */ -const uint8_t * auth1_getconstarray_clog(const auth1_t *inp); -/** Return the (constant) length of the array holding the scert field - * of the auth1_t in 'inp'. - */ -size_t auth1_getlen_scert(const auth1_t *inp); -/** Return the element at position 'idx' of the fixed array field - * scert of the auth1_t in 'inp'. - */ -uint8_t auth1_get_scert(auth1_t *inp, size_t idx); -/** As auth1_get_scert, but take and return a const pointer - */ -uint8_t auth1_getconst_scert(const auth1_t *inp, size_t idx); -/** Change the element at position 'idx' of the fixed array field - * scert of the auth1_t in 'inp', so that it will hold the value - * 'elt'. - */ -int auth1_set_scert(auth1_t *inp, size_t idx, uint8_t elt); -/** Return a pointer to the 32-element array field scert of 'inp'. - */ -uint8_t * auth1_getarray_scert(auth1_t *inp); -/** As auth1_get_scert, but take and return a const pointer - */ -const uint8_t * auth1_getconstarray_scert(const auth1_t *inp); -/** Return the (constant) length of the array holding the tlssecrets - * field of the auth1_t in 'inp'. - */ -size_t auth1_getlen_tlssecrets(const auth1_t *inp); -/** Return the element at position 'idx' of the fixed array field - * tlssecrets of the auth1_t in 'inp'. - */ -uint8_t auth1_get_tlssecrets(auth1_t *inp, size_t idx); -/** As auth1_get_tlssecrets, but take and return a const pointer - */ -uint8_t auth1_getconst_tlssecrets(const auth1_t *inp, size_t idx); -/** Change the element at position 'idx' of the fixed array field - * tlssecrets of the auth1_t in 'inp', so that it will hold the value - * 'elt'. - */ -int auth1_set_tlssecrets(auth1_t *inp, size_t idx, uint8_t elt); -/** Return a pointer to the 32-element array field tlssecrets of - * 'inp'. - */ -uint8_t * auth1_getarray_tlssecrets(auth1_t *inp); -/** As auth1_get_tlssecrets, but take and return a const pointer - */ -const uint8_t * auth1_getconstarray_tlssecrets(const auth1_t *inp); -/** Return the position for end_of_fixed_part when we parsed this - * object - */ -const uint8_t * auth1_get_end_of_fixed_part(const auth1_t *inp); -/** Return the (constant) length of the array holding the rand field - * of the auth1_t in 'inp'. - */ -size_t auth1_getlen_rand(const auth1_t *inp); -/** Return the element at position 'idx' of the fixed array field rand - * of the auth1_t in 'inp'. - */ -uint8_t auth1_get_rand(auth1_t *inp, size_t idx); -/** As auth1_get_rand, but take and return a const pointer - */ -uint8_t auth1_getconst_rand(const auth1_t *inp, size_t idx); -/** Change the element at position 'idx' of the fixed array field rand - * of the auth1_t in 'inp', so that it will hold the value 'elt'. - */ -int auth1_set_rand(auth1_t *inp, size_t idx, uint8_t elt); -/** Return a pointer to the 24-element array field rand of 'inp'. - */ -uint8_t * auth1_getarray_rand(auth1_t *inp); -/** As auth1_get_rand, but take and return a const pointer - */ -const uint8_t * auth1_getconstarray_rand(const auth1_t *inp); -/** Return the position for end_of_signed when we parsed this object - */ -const uint8_t * auth1_get_end_of_signed(const auth1_t *inp); -/** Return the length of the dynamic array holding the sig field of - * the auth1_t in 'inp'. - */ -size_t auth1_getlen_sig(const auth1_t *inp); -/** Return the element at position 'idx' of the dynamic array field - * sig of the auth1_t in 'inp'. - */ -uint8_t auth1_get_sig(auth1_t *inp, size_t idx); -/** As auth1_get_sig, but take and return a const pointer - */ -uint8_t auth1_getconst_sig(const auth1_t *inp, size_t idx); -/** Change the element at position 'idx' of the dynamic array field - * sig of the auth1_t in 'inp', so that it will hold the value 'elt'. - */ -int auth1_set_sig(auth1_t *inp, size_t idx, uint8_t elt); -/** Append a new element 'elt' to the dynamic array field sig of the - * auth1_t in 'inp'. - */ -int auth1_add_sig(auth1_t *inp, uint8_t elt); -/** Return a pointer to the variable-length array field sig of 'inp'. - */ -uint8_t * auth1_getarray_sig(auth1_t *inp); -/** As auth1_get_sig, but take and return a const pointer - */ -const uint8_t * auth1_getconstarray_sig(const auth1_t *inp); -/** Change the length of the variable-length array field sig of 'inp' - * to 'newlen'.Fill extra elements with 0. Return 0 on success; return - * -1 and set the error code on 'inp' on failure. - */ -int auth1_setlen_sig(auth1_t *inp, size_t newlen); /** Return a newly allocated certs_cell with all elements set to zero. */ certs_cell_t *certs_cell_new(void); diff -Nru tor-0.4.7.16/src/trunnel/sendme_cell.c tor-0.4.9.6/src/trunnel/sendme_cell.c --- tor-0.4.7.16/src/trunnel/sendme_cell.c 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/trunnel/sendme_cell.c 2026-03-25 14:30:34.000000000 +0000 @@ -34,6 +34,7 @@ sendme_cell_t *val = trunnel_calloc(1, sizeof(sendme_cell_t)); if (NULL == val) return NULL; + val->data_len = 16; return val; } @@ -43,6 +44,8 @@ sendme_cell_clear(sendme_cell_t *obj) { (void) obj; + TRUNNEL_DYNARRAY_WIPE(&obj->data_v1_digest); + TRUNNEL_DYNARRAY_CLEAR(&obj->data_v1_digest); } void @@ -78,20 +81,23 @@ int sendme_cell_set_data_len(sendme_cell_t *inp, uint16_t val) { + if (! ((val == 16 || val == 20))) { + TRUNNEL_SET_ERROR_CODE(inp); + return -1; + } 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; + return TRUNNEL_DYNARRAY_LEN(&inp->data_v1_digest); } 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]; + return TRUNNEL_DYNARRAY_GET(&inp->data_v1_digest, idx); } uint8_t @@ -102,21 +108,45 @@ 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; + TRUNNEL_DYNARRAY_SET(&inp->data_v1_digest, idx, elt); + return 0; +} +int +sendme_cell_add_data_v1_digest(sendme_cell_t *inp, uint8_t elt) +{ + TRUNNEL_DYNARRAY_ADD(uint8_t, &inp->data_v1_digest, elt, {}); return 0; + trunnel_alloc_failed: + TRUNNEL_SET_ERROR_CODE(inp); + return -1; } uint8_t * sendme_cell_getarray_data_v1_digest(sendme_cell_t *inp) { - return inp->data_v1_digest; + return inp->data_v1_digest.elts_; } 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); } +int +sendme_cell_setlen_data_v1_digest(sendme_cell_t *inp, size_t newlen) +{ + uint8_t *newptr; + newptr = trunnel_dynarray_setlen(&inp->data_v1_digest.allocated_, + &inp->data_v1_digest.n_, inp->data_v1_digest.elts_, newlen, + sizeof(inp->data_v1_digest.elts_[0]), (trunnel_free_fn_t) NULL, + &inp->trunnel_error_code_); + if (newlen != 0 && newptr == NULL) + goto trunnel_alloc_failed; + inp->data_v1_digest.elts_ = newptr; + return 0; + trunnel_alloc_failed: + TRUNNEL_SET_ERROR_CODE(inp); + return -1; +} const char * sendme_cell_check(const sendme_cell_t *obj) { @@ -126,6 +156,8 @@ return "A set function failed on this object"; if (! (obj->version == 0 || obj->version == 1)) return "Integer out of bounds"; + if (! (obj->data_len == 16 || obj->data_len == 20)) + return "Integer out of bounds"; switch (obj->version) { case 0: @@ -153,7 +185,7 @@ /* Length of u8 version IN [0, 1] */ result += 1; - /* Length of u16 data_len */ + /* Length of u16 data_len IN [16, 20] */ result += 2; switch (obj->version) { @@ -162,8 +194,8 @@ case 1: - /* Length of u8 data_v1_digest[TRUNNEL_SENDME_V1_DIGEST_LEN] */ - result += TRUNNEL_SENDME_V1_DIGEST_LEN; + /* Length of u8 data_v1_digest[] */ + result += TRUNNEL_DYNARRAY_LEN(&obj->data_v1_digest); break; default: @@ -206,7 +238,7 @@ trunnel_set_uint8(ptr, (obj->version)); written += 1; ptr += 1; - /* Encode u16 data_len */ + /* Encode u16 data_len IN [16, 20] */ backptr_data_len = ptr; trunnel_assert(written <= avail); if (avail - written < 2) @@ -225,12 +257,16 @@ 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; + /* Encode u8 data_v1_digest[] */ + { + size_t elt_len = TRUNNEL_DYNARRAY_LEN(&obj->data_v1_digest); + trunnel_assert(written <= avail); + if (avail - written < elt_len) + goto truncated; + if (elt_len) + memcpy(ptr, obj->data_v1_digest.elts_, elt_len); + written += elt_len; ptr += elt_len; + } break; default: @@ -287,10 +323,12 @@ if (! (obj->version == 0 || obj->version == 1)) goto fail; - /* Parse u16 data_len */ + /* Parse u16 data_len IN [16, 20] */ CHECK_REMAINING(2, truncated); obj->data_len = trunnel_ntohs(trunnel_get_uint16(ptr)); remaining -= 2; ptr += 2; + if (! (obj->data_len == 16 || obj->data_len == 20)) + goto fail; { size_t remaining_after; CHECK_REMAINING(obj->data_len, truncated); @@ -307,10 +345,12 @@ 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; + /* Parse u8 data_v1_digest[] */ + TRUNNEL_DYNARRAY_EXPAND(uint8_t, &obj->data_v1_digest, remaining, {}); + obj->data_v1_digest.n_ = remaining; + if (remaining) + memcpy(obj->data_v1_digest.elts_, ptr, remaining); + ptr += remaining; remaining -= remaining; break; default: @@ -326,6 +366,8 @@ truncated: return -2; + trunnel_alloc_failed: + return -1; fail: result = -1; return result; diff -Nru tor-0.4.7.16/src/trunnel/sendme_cell.h tor-0.4.9.6/src/trunnel/sendme_cell.h --- tor-0.4.7.16/src/trunnel/sendme_cell.h 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/trunnel/sendme_cell.h 2026-03-25 14:30:34.000000000 +0000 @@ -8,12 +8,11 @@ #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]; + TRUNNEL_DYNARRAY_HEAD(, uint8_t) data_v1_digest; uint8_t trunnel_error_code_; }; #endif @@ -71,11 +70,11 @@ * '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'. +/** Return the length of the dynamic 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 +/** Return the element at position 'idx' of the dynamic 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); @@ -83,19 +82,29 @@ * 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 +/** Change the element at position 'idx' of the dynamic 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'. +/** Append a new element 'elt' to the dynamic array field + * data_v1_digest of the sendme_cell_t in 'inp'. + */ +int sendme_cell_add_data_v1_digest(sendme_cell_t *inp, uint8_t elt); +/** Return a pointer to the variable-length 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); +/** Change the length of the variable-length array field + * data_v1_digest of 'inp' to 'newlen'.Fill extra elements with 0. + * Return 0 on success; return -1 and set the error code on 'inp' on + * failure. + */ +int sendme_cell_setlen_data_v1_digest(sendme_cell_t *inp, size_t newlen); #endif diff -Nru tor-0.4.7.16/src/trunnel/subproto_request.c tor-0.4.9.6/src/trunnel/subproto_request.c --- tor-0.4.7.16/src/trunnel/subproto_request.c 1970-01-01 00:00:00.000000000 +0000 +++ tor-0.4.9.6/src/trunnel/subproto_request.c 2026-03-25 14:30:34.000000000 +0000 @@ -0,0 +1,456 @@ +/* subproto_request.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 "subproto_request.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 subprotorequest_deadcode_dummy__ = 0; +#define OR_DEADCODE_DUMMY || subprotorequest_deadcode_dummy__ +#else +#define OR_DEADCODE_DUMMY +#endif + +#define CHECK_REMAINING(nbytes, label) \ + do { \ + if (remaining < (nbytes) OR_DEADCODE_DUMMY) { \ + goto label; \ + } \ + } while (0) + +trn_subproto_request_t * +trn_subproto_request_new(void) +{ + trn_subproto_request_t *val = trunnel_calloc(1, sizeof(trn_subproto_request_t)); + if (NULL == val) + return NULL; + return val; +} + +/** Release all storage held inside 'obj', but do not free 'obj'. + */ +static void +trn_subproto_request_clear(trn_subproto_request_t *obj) +{ + (void) obj; +} + +void +trn_subproto_request_free(trn_subproto_request_t *obj) +{ + if (obj == NULL) + return; + trn_subproto_request_clear(obj); + trunnel_memwipe(obj, sizeof(trn_subproto_request_t)); + trunnel_free_(obj); +} + +uint8_t +trn_subproto_request_get_protocol_id(const trn_subproto_request_t *inp) +{ + return inp->protocol_id; +} +int +trn_subproto_request_set_protocol_id(trn_subproto_request_t *inp, uint8_t val) +{ + inp->protocol_id = val; + return 0; +} +uint8_t +trn_subproto_request_get_proto_cap_number(const trn_subproto_request_t *inp) +{ + return inp->proto_cap_number; +} +int +trn_subproto_request_set_proto_cap_number(trn_subproto_request_t *inp, uint8_t val) +{ + inp->proto_cap_number = val; + return 0; +} +const char * +trn_subproto_request_check(const trn_subproto_request_t *obj) +{ + if (obj == NULL) + return "Object was NULL"; + if (obj->trunnel_error_code_) + return "A set function failed on this object"; + return NULL; +} + +ssize_t +trn_subproto_request_encoded_len(const trn_subproto_request_t *obj) +{ + ssize_t result = 0; + + if (NULL != trn_subproto_request_check(obj)) + return -1; + + + /* Length of u8 protocol_id */ + result += 1; + + /* Length of u8 proto_cap_number */ + result += 1; + return result; +} +int +trn_subproto_request_clear_errors(trn_subproto_request_t *obj) +{ + int r = obj->trunnel_error_code_; + obj->trunnel_error_code_ = 0; + return r; +} +ssize_t +trn_subproto_request_encode(uint8_t *output, const size_t avail, const trn_subproto_request_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 = trn_subproto_request_encoded_len(obj); +#endif + + if (NULL != (msg = trn_subproto_request_check(obj))) + goto check_failed; + +#ifdef TRUNNEL_CHECK_ENCODED_LEN + trunnel_assert(encoded_len >= 0); +#endif + + /* Encode u8 protocol_id */ + trunnel_assert(written <= avail); + if (avail - written < 1) + goto truncated; + trunnel_set_uint8(ptr, (obj->protocol_id)); + written += 1; ptr += 1; + + /* Encode u8 proto_cap_number */ + trunnel_assert(written <= avail); + if (avail - written < 1) + goto truncated; + trunnel_set_uint8(ptr, (obj->proto_cap_number)); + written += 1; ptr += 1; + + + 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 trn_subproto_request_parse(), but do not allocate the output + * object. + */ +static ssize_t +trn_subproto_request_parse_into(trn_subproto_request_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 protocol_id */ + CHECK_REMAINING(1, truncated); + obj->protocol_id = (trunnel_get_uint8(ptr)); + remaining -= 1; ptr += 1; + + /* Parse u8 proto_cap_number */ + CHECK_REMAINING(1, truncated); + obj->proto_cap_number = (trunnel_get_uint8(ptr)); + remaining -= 1; ptr += 1; + trunnel_assert(ptr + remaining == input + len_in); + return len_in - remaining; + + truncated: + return -2; +} + +ssize_t +trn_subproto_request_parse(trn_subproto_request_t **output, const uint8_t *input, const size_t len_in) +{ + ssize_t result; + *output = trn_subproto_request_new(); + if (NULL == *output) + return -1; + result = trn_subproto_request_parse_into(*output, input, len_in); + if (result < 0) { + trn_subproto_request_free(*output); + *output = NULL; + } + return result; +} +trn_subproto_request_ext_t * +trn_subproto_request_ext_new(void) +{ + trn_subproto_request_ext_t *val = trunnel_calloc(1, sizeof(trn_subproto_request_ext_t)); + if (NULL == val) + return NULL; + return val; +} + +/** Release all storage held inside 'obj', but do not free 'obj'. + */ +static void +trn_subproto_request_ext_clear(trn_subproto_request_ext_t *obj) +{ + (void) obj; + { + + unsigned idx; + for (idx = 0; idx < TRUNNEL_DYNARRAY_LEN(&obj->reqs); ++idx) { + trn_subproto_request_free(TRUNNEL_DYNARRAY_GET(&obj->reqs, idx)); + } + } + TRUNNEL_DYNARRAY_WIPE(&obj->reqs); + TRUNNEL_DYNARRAY_CLEAR(&obj->reqs); +} + +void +trn_subproto_request_ext_free(trn_subproto_request_ext_t *obj) +{ + if (obj == NULL) + return; + trn_subproto_request_ext_clear(obj); + trunnel_memwipe(obj, sizeof(trn_subproto_request_ext_t)); + trunnel_free_(obj); +} + +size_t +trn_subproto_request_ext_getlen_reqs(const trn_subproto_request_ext_t *inp) +{ + return TRUNNEL_DYNARRAY_LEN(&inp->reqs); +} + +struct trn_subproto_request_st * +trn_subproto_request_ext_get_reqs(trn_subproto_request_ext_t *inp, size_t idx) +{ + return TRUNNEL_DYNARRAY_GET(&inp->reqs, idx); +} + + const struct trn_subproto_request_st * +trn_subproto_request_ext_getconst_reqs(const trn_subproto_request_ext_t *inp, size_t idx) +{ + return trn_subproto_request_ext_get_reqs((trn_subproto_request_ext_t*)inp, idx); +} +int +trn_subproto_request_ext_set_reqs(trn_subproto_request_ext_t *inp, size_t idx, struct trn_subproto_request_st * elt) +{ + trn_subproto_request_t *oldval = TRUNNEL_DYNARRAY_GET(&inp->reqs, idx); + if (oldval && oldval != elt) + trn_subproto_request_free(oldval); + return trn_subproto_request_ext_set0_reqs(inp, idx, elt); +} +int +trn_subproto_request_ext_set0_reqs(trn_subproto_request_ext_t *inp, size_t idx, struct trn_subproto_request_st * elt) +{ + TRUNNEL_DYNARRAY_SET(&inp->reqs, idx, elt); + return 0; +} +int +trn_subproto_request_ext_add_reqs(trn_subproto_request_ext_t *inp, struct trn_subproto_request_st * elt) +{ + TRUNNEL_DYNARRAY_ADD(struct trn_subproto_request_st *, &inp->reqs, elt, {}); + return 0; + trunnel_alloc_failed: + TRUNNEL_SET_ERROR_CODE(inp); + return -1; +} + +struct trn_subproto_request_st * * +trn_subproto_request_ext_getarray_reqs(trn_subproto_request_ext_t *inp) +{ + return inp->reqs.elts_; +} +const struct trn_subproto_request_st * const * +trn_subproto_request_ext_getconstarray_reqs(const trn_subproto_request_ext_t *inp) +{ + return (const struct trn_subproto_request_st * const *)trn_subproto_request_ext_getarray_reqs((trn_subproto_request_ext_t*)inp); +} +int +trn_subproto_request_ext_setlen_reqs(trn_subproto_request_ext_t *inp, size_t newlen) +{ + struct trn_subproto_request_st * *newptr; + newptr = trunnel_dynarray_setlen(&inp->reqs.allocated_, + &inp->reqs.n_, inp->reqs.elts_, newlen, + sizeof(inp->reqs.elts_[0]), (trunnel_free_fn_t) trn_subproto_request_free, + &inp->trunnel_error_code_); + if (newlen != 0 && newptr == NULL) + goto trunnel_alloc_failed; + inp->reqs.elts_ = newptr; + return 0; + trunnel_alloc_failed: + TRUNNEL_SET_ERROR_CODE(inp); + return -1; +} +const char * +trn_subproto_request_ext_check(const trn_subproto_request_ext_t *obj) +{ + if (obj == NULL) + return "Object was NULL"; + if (obj->trunnel_error_code_) + return "A set function failed on this object"; + { + const char *msg; + + unsigned idx; + for (idx = 0; idx < TRUNNEL_DYNARRAY_LEN(&obj->reqs); ++idx) { + if (NULL != (msg = trn_subproto_request_check(TRUNNEL_DYNARRAY_GET(&obj->reqs, idx)))) + return msg; + } + } + return NULL; +} + +ssize_t +trn_subproto_request_ext_encoded_len(const trn_subproto_request_ext_t *obj) +{ + ssize_t result = 0; + + if (NULL != trn_subproto_request_ext_check(obj)) + return -1; + + + /* Length of struct trn_subproto_request reqs[] */ + { + + unsigned idx; + for (idx = 0; idx < TRUNNEL_DYNARRAY_LEN(&obj->reqs); ++idx) { + result += trn_subproto_request_encoded_len(TRUNNEL_DYNARRAY_GET(&obj->reqs, idx)); + } + } + return result; +} +int +trn_subproto_request_ext_clear_errors(trn_subproto_request_ext_t *obj) +{ + int r = obj->trunnel_error_code_; + obj->trunnel_error_code_ = 0; + return r; +} +ssize_t +trn_subproto_request_ext_encode(uint8_t *output, const size_t avail, const trn_subproto_request_ext_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 = trn_subproto_request_ext_encoded_len(obj); +#endif + + if (NULL != (msg = trn_subproto_request_ext_check(obj))) + goto check_failed; + +#ifdef TRUNNEL_CHECK_ENCODED_LEN + trunnel_assert(encoded_len >= 0); +#endif + + /* Encode struct trn_subproto_request reqs[] */ + { + + unsigned idx; + for (idx = 0; idx < TRUNNEL_DYNARRAY_LEN(&obj->reqs); ++idx) { + trunnel_assert(written <= avail); + result = trn_subproto_request_encode(ptr, avail - written, TRUNNEL_DYNARRAY_GET(&obj->reqs, idx)); + if (result < 0) + goto fail; /* XXXXXXX !*/ + written += result; ptr += result; + } + } + + + 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; + + check_failed: + (void)msg; + result = -1; + goto fail; + fail: + trunnel_assert(result < 0); + return result; +} + +/** As trn_subproto_request_ext_parse(), but do not allocate the + * output object. + */ +static ssize_t +trn_subproto_request_ext_parse_into(trn_subproto_request_ext_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 struct trn_subproto_request reqs[] */ + { + trn_subproto_request_t * elt; + while (remaining > 0) { + result = trn_subproto_request_parse(&elt, ptr, remaining); + if (result < 0) + goto fail; + trunnel_assert((size_t)result <= remaining); + remaining -= result; ptr += result; + TRUNNEL_DYNARRAY_ADD(trn_subproto_request_t *, &obj->reqs, elt, {trn_subproto_request_free(elt);}); + } + } + trunnel_assert(ptr + remaining == input + len_in); + return len_in - remaining; + + trunnel_alloc_failed: + return -1; + fail: + result = -1; + return result; +} + +ssize_t +trn_subproto_request_ext_parse(trn_subproto_request_ext_t **output, const uint8_t *input, const size_t len_in) +{ + ssize_t result; + *output = trn_subproto_request_ext_new(); + if (NULL == *output) + return -1; + result = trn_subproto_request_ext_parse_into(*output, input, len_in); + if (result < 0) { + trn_subproto_request_ext_free(*output); + *output = NULL; + } + return result; +} diff -Nru tor-0.4.7.16/src/trunnel/subproto_request.h tor-0.4.9.6/src/trunnel/subproto_request.h --- tor-0.4.7.16/src/trunnel/subproto_request.h 1970-01-01 00:00:00.000000000 +0000 +++ tor-0.4.9.6/src/trunnel/subproto_request.h 2026-03-25 14:30:34.000000000 +0000 @@ -0,0 +1,157 @@ +/* subproto_request.h -- generated by Trunnel v1.5.3. + * https://gitweb.torproject.org/trunnel.git + * You probably shouldn't edit this file. + */ +#ifndef TRUNNEL_SUBPROTO_REQUEST_H +#define TRUNNEL_SUBPROTO_REQUEST_H + +#include +#include "trunnel.h" + +#if !defined(TRUNNEL_OPAQUE) && !defined(TRUNNEL_OPAQUE_TRN_SUBPROTO_REQUEST) +struct trn_subproto_request_st { + uint8_t protocol_id; + uint8_t proto_cap_number; + uint8_t trunnel_error_code_; +}; +#endif +typedef struct trn_subproto_request_st trn_subproto_request_t; +#if !defined(TRUNNEL_OPAQUE) && !defined(TRUNNEL_OPAQUE_TRN_SUBPROTO_REQUEST_EXT) +struct trn_subproto_request_ext_st { + TRUNNEL_DYNARRAY_HEAD(, struct trn_subproto_request_st *) reqs; + uint8_t trunnel_error_code_; +}; +#endif +typedef struct trn_subproto_request_ext_st trn_subproto_request_ext_t; +/** Return a newly allocated trn_subproto_request with all elements + * set to zero. + */ +trn_subproto_request_t *trn_subproto_request_new(void); +/** Release all storage held by the trn_subproto_request in 'victim'. + * (Do nothing if 'victim' is NULL.) + */ +void trn_subproto_request_free(trn_subproto_request_t *victim); +/** Try to parse a trn_subproto_request 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 trn_subproto_request_t. On failure, return -2 if the + * input appears truncated, and -1 if the input is otherwise invalid. + */ +ssize_t trn_subproto_request_parse(trn_subproto_request_t **output, const uint8_t *input, const size_t len_in); +/** Return the number of bytes we expect to need to encode the + * trn_subproto_request 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 trn_subproto_request_encoded_len(const trn_subproto_request_t *obj); +/** Try to encode the trn_subproto_request 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 trn_subproto_request_encode(uint8_t *output, size_t avail, const trn_subproto_request_t *input); +/** Check whether the internal state of the trn_subproto_request in + * 'obj' is consistent. Return NULL if it is, and a short message if + * it is not. + */ +const char *trn_subproto_request_check(const trn_subproto_request_t *obj); +/** Clear any errors that were set on the object 'obj' by its setter + * functions. Return true iff errors were cleared. + */ +int trn_subproto_request_clear_errors(trn_subproto_request_t *obj); +/** Return the value of the protocol_id field of the + * trn_subproto_request_t in 'inp' + */ +uint8_t trn_subproto_request_get_protocol_id(const trn_subproto_request_t *inp); +/** Set the value of the protocol_id field of the + * trn_subproto_request_t in 'inp' to 'val'. Return 0 on success; + * return -1 and set the error code on 'inp' on failure. + */ +int trn_subproto_request_set_protocol_id(trn_subproto_request_t *inp, uint8_t val); +/** Return the value of the proto_cap_number field of the + * trn_subproto_request_t in 'inp' + */ +uint8_t trn_subproto_request_get_proto_cap_number(const trn_subproto_request_t *inp); +/** Set the value of the proto_cap_number field of the + * trn_subproto_request_t in 'inp' to 'val'. Return 0 on success; + * return -1 and set the error code on 'inp' on failure. + */ +int trn_subproto_request_set_proto_cap_number(trn_subproto_request_t *inp, uint8_t val); +/** Return a newly allocated trn_subproto_request_ext with all + * elements set to zero. + */ +trn_subproto_request_ext_t *trn_subproto_request_ext_new(void); +/** Release all storage held by the trn_subproto_request_ext in + * 'victim'. (Do nothing if 'victim' is NULL.) + */ +void trn_subproto_request_ext_free(trn_subproto_request_ext_t *victim); +/** Try to parse a trn_subproto_request_ext 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 trn_subproto_request_ext_t. On failure, return -2 + * if the input appears truncated, and -1 if the input is otherwise + * invalid. + */ +ssize_t trn_subproto_request_ext_parse(trn_subproto_request_ext_t **output, const uint8_t *input, const size_t len_in); +/** Return the number of bytes we expect to need to encode the + * trn_subproto_request_ext 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 trn_subproto_request_ext_encoded_len(const trn_subproto_request_ext_t *obj); +/** Try to encode the trn_subproto_request_ext 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 trn_subproto_request_ext_encode(uint8_t *output, size_t avail, const trn_subproto_request_ext_t *input); +/** Check whether the internal state of the trn_subproto_request_ext + * in 'obj' is consistent. Return NULL if it is, and a short message + * if it is not. + */ +const char *trn_subproto_request_ext_check(const trn_subproto_request_ext_t *obj); +/** Clear any errors that were set on the object 'obj' by its setter + * functions. Return true iff errors were cleared. + */ +int trn_subproto_request_ext_clear_errors(trn_subproto_request_ext_t *obj); +/** Return the length of the dynamic array holding the reqs field of + * the trn_subproto_request_ext_t in 'inp'. + */ +size_t trn_subproto_request_ext_getlen_reqs(const trn_subproto_request_ext_t *inp); +/** Return the element at position 'idx' of the dynamic array field + * reqs of the trn_subproto_request_ext_t in 'inp'. + */ +struct trn_subproto_request_st * trn_subproto_request_ext_get_reqs(trn_subproto_request_ext_t *inp, size_t idx); +/** As trn_subproto_request_ext_get_reqs, but take and return a const + * pointer + */ + const struct trn_subproto_request_st * trn_subproto_request_ext_getconst_reqs(const trn_subproto_request_ext_t *inp, size_t idx); +/** Change the element at position 'idx' of the dynamic array field + * reqs of the trn_subproto_request_ext_t in 'inp', so that it will + * hold the value 'elt'. Free the previous value, if any. + */ +int trn_subproto_request_ext_set_reqs(trn_subproto_request_ext_t *inp, size_t idx, struct trn_subproto_request_st * elt); +/** As trn_subproto_request_ext_set_reqs, but does not free the + * previous value. + */ +int trn_subproto_request_ext_set0_reqs(trn_subproto_request_ext_t *inp, size_t idx, struct trn_subproto_request_st * elt); +/** Append a new element 'elt' to the dynamic array field reqs of the + * trn_subproto_request_ext_t in 'inp'. + */ +int trn_subproto_request_ext_add_reqs(trn_subproto_request_ext_t *inp, struct trn_subproto_request_st * elt); +/** Return a pointer to the variable-length array field reqs of 'inp'. + */ +struct trn_subproto_request_st * * trn_subproto_request_ext_getarray_reqs(trn_subproto_request_ext_t *inp); +/** As trn_subproto_request_ext_get_reqs, but take and return a const + * pointer + */ +const struct trn_subproto_request_st * const * trn_subproto_request_ext_getconstarray_reqs(const trn_subproto_request_ext_t *inp); +/** Change the length of the variable-length array field reqs of 'inp' + * to 'newlen'.Fill extra elements with NULL; free removed elements. + * Return 0 on success; return -1 and set the error code on 'inp' on + * failure. + */ +int trn_subproto_request_ext_setlen_reqs(trn_subproto_request_ext_t *inp, size_t newlen); + + +#endif diff -Nru tor-0.4.7.16/src/win32/include.am tor-0.4.9.6/src/win32/include.am --- tor-0.4.7.16/src/win32/include.am 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/win32/include.am 1970-01-01 00:00:00.000000000 +0000 @@ -1,3 +0,0 @@ - -EXTRA_DIST+= src/win32/orconfig.h - diff -Nru tor-0.4.7.16/src/win32/orconfig.h tor-0.4.9.6/src/win32/orconfig.h --- tor-0.4.7.16/src/win32/orconfig.h 2023-11-03 13:36:40.000000000 +0000 +++ tor-0.4.9.6/src/win32/orconfig.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,242 +0,0 @@ -/* orconfig.h for Windows -- This file is *not* generated by autoconf. - * Instead, it has to be hand-edited to keep Win32 happy. - */ - -/* Windows-only defines. */ -#define CONFDIR "" - -/* Define to 1 if you have the header file. */ -#undef HAVE_ARPA_INET_H - -/* Define to 1 if you have the header file. */ -#define HAVE_ASSERT_H - -/* Define to 1 if you have the header file. */ -#define HAVE_CTYPE_H - -/* Define to 1 if you have the header file. */ -#define HAVE_ERRNO_H - -/* Define to 1 if you have the header file. */ -#define HAVE_FCNTL_H - -/* Define to 1 if you have the `ftime' function. */ -#define HAVE_FTIME - -/* Define to 1 if you have the `gettimeofday' function. */ -#undef HAVE_GETTIMEOFDAY - -/* Define to 1 if you have the header file. */ -#undef HAVE_GRP_H - -/* Define to 1 if you have the `inet_aton' function. */ -#undef HAVE_INET_ATON - -/* Define to 1 if you have the header file. */ -/* #define HAVE_INTTYPES_H */ - -/* Define to 1 if you have the header file. */ -#define HAVE_LIMITS_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_MACHINE_LIMITS_H - -/* Define to 1 if you have the header file. */ -#define HAVE_MEMORY_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_NETDB_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_NETINET_IN_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_POLL_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_PWD_H - -/* Define to 1 if you have the header file. */ -#define HAVE_SIGNAL_H - -/* Define to 1 if you have the `socketpair' function. */ -#undef HAVE_SOCKETPAIR - -/* Define to 1 if you have the header file. */ -#undef HAVE_STDINT_H - -/* Define to 1 if you have the header file. */ -#define HAVE_STDLIB_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_STRINGS_H - -/* Define to 1 if you have the header file. */ -#define HAVE_STRING_H - -/* Define to 1 if you have the `strlcat' function. */ -#undef HAVE_STRLCAT - -/* Define to 1 if you have the `strlcpy' function. */ -#undef HAVE_STRLCPY - -/* Define to 1 if you have the `strptime' function. */ -#undef HAVE_STRPTIME - -/* Define to 1 if your timeval has a tv_sec element. */ -#define HAVE_STRUCT_TIMEVAL_TV_SEC -/* Change to #undef if you're using BCC */ - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_FCNTL_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_IOCTL_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_LIMITS_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_POLL_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_SOCKET_H - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_STAT_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_TIME_H - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_TYPES_H - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_UTIME_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_WAIT_H - -/* Define to 1 if you have the header file. */ -#define HAVE_TIME_H - -/* Define to 1 if you have the `uname' function. */ -#undef HAVE_UNAME - -/* Define to 1 if you have the header file. */ -#undef HAVE_UNISTD_H - -/* Define to 1 if you have the `_vscprintf' function. */ -#define HAVE__VSCPRINTF 1 - -/* Define to 1 iff NULL is represented by a 0 in memory. */ -#define NULL_REP_IS_ZERO_BYTES 1 - -/* Define to 1 iff memset(0) sets doubles to 0.0 */ -#define DOUBLE_0_REP_IS_ZERO_BYTES 1 - -/* Name of package */ -#define PACKAGE "tor" - -/* Define to the address where bug reports for this package should be sent. */ -#undef PACKAGE_BUGREPORT - -/* Define to the full name of this package. */ -#undef PACKAGE_NAME - -/* Define to the full name and version of this package. */ -#undef PACKAGE_STRING - -/* Define to the one symbol short name of this package. */ -#undef PACKAGE_TARNAME - -/* Define to the version of this package. */ -#undef PACKAGE_VERSION - -/* The size of a `char', as computed by sizeof. */ -#define SIZEOF_CHAR 1 - -/* The size of a `int', as computed by sizeof. */ -#define SIZEOF_INT 4 - -/* The size of a `int16_t', as computed by sizeof. */ -#undef SIZEOF_INT16_T - -/* The size of a `int32_t', as computed by sizeof. */ -#undef SIZEOF_INT32_T - -/* The size of a `int64_t', as computed by sizeof. */ -#undef SIZEOF_INT64_T - -/* The size of a `int8_t', as computed by sizeof. */ -#undef SIZEOF_INT8_T - -/* The size of a `long', as computed by sizeof. */ -#define SIZEOF_LONG 4 - -/* The size of a `long long', as computed by sizeof. */ -#undef SIZEOF_LONG_LONG - -/* The size of `pid_t', as computed by sizeof. */ -#define SIZEOF_PID_T 0 - -/* The size of a `short', as computed by sizeof. */ -#define SIZEOF_SHORT 2 - -/* The size of a `time_t', as computed by sizeof. */ -#define SIZEOF_TIME_T 4 - -/* The size of a `uint16_t', as computed by sizeof. */ -#undef SIZEOF_UINT16_T - -/* The size of a `uint32_t', as computed by sizeof. */ -#undef SIZEOF_UINT32_T - -/* The size of a `uint64_t', as computed by sizeof. */ -#undef SIZEOF_UINT64_T - -/* The size of a `uint8_t', as computed by sizeof. */ -#undef SIZEOF_UINT8_T - -/* The size of a `void *', as computed by sizeof. */ -#define SIZEOF_VOID_P 4 - -/* The size of a `__int64', as computed by sizeof. */ -#define SIZEOF___INT64 8 - -/* The sizeof a size_t, as computed by sizeof. */ -#define SIZEOF_SIZE_T 4 - -/* Define to 1 if you have the ANSI C header files. */ -#define STDC_HEADERS - -/* Define to 1 iff unaligned int access is allowed */ -#define UNALIGNED_INT_ACCESS_OK - -/* Define to 1 iff we represent negative integers with two's complement */ -#define USING_TWOS_COMPLEMENT - -/* Version number of package */ -#define VERSION "0.4.7.16" - -#define HAVE_STRUCT_SOCKADDR_IN6 -#define HAVE_STRUCT_IN6_ADDR -#define RSHIFT_DOES_SIGN_EXTEND -#define FLEXIBLE_ARRAY_MEMBER 0 -#define SHARE_DATADIR "" -#define USE_CURVE25519_DONNA - -#define ENUM_VALS_ARE_SIGNED 1 - -#ifndef STDOUT_FILENO -#define STDOUT_FILENO 1 -#endif - -#ifndef STDERR_FILENO -#define STDERR_FILENO 2 -#endif - -#define WINVER 0x0501 -#define _WIN32_WINNT 0x0501 -#define WIN32_LEAN_AND_MEAN 1 -