aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore3
-rw-r--r--.gitlab-ci.yml33
-rw-r--r--Cargo.lock385
-rw-r--r--Cargo.toml15
-rw-r--r--ChangeLog847
-rw-r--r--Makefile.am8
-rw-r--r--Makefile.nmake19
-rw-r--r--ReleaseNotes805
-rw-r--r--changes/bug405638
-rw-r--r--changes/bug406395
-rw-r--r--changes/bug406429
-rw-r--r--changes/bug406448
-rw-r--r--changes/bug406455
-rw-r--r--changes/bug406737
-rw-r--r--changes/bug406846
-rw-r--r--changes/bug4069811
-rw-r--r--changes/bug407327
-rw-r--r--changes/bug407513
-rw-r--r--changes/bug408057
-rw-r--r--changes/bug408415
-rw-r--r--changes/bug408424
-rw-r--r--changes/bug408556
-rw-r--r--changes/bug408623
-rw-r--r--changes/bug408693
-rw-r--r--changes/bug408784
-rw-r--r--changes/fallbackdirs-2022-08-112
-rw-r--r--changes/fallbackdirs-2022-11-102
-rw-r--r--changes/fallbackdirs-2022-12-062
-rw-r--r--changes/fallbackdirs-2023-01-122
-rw-r--r--changes/fallbackdirs-2023-07-262
-rw-r--r--changes/fallbackdirs-2023-08-302
-rw-r--r--changes/fallbackdirs-2023-09-252
-rw-r--r--changes/geoip-2022-08-125
-rw-r--r--changes/geoip-2022-12-063
-rw-r--r--changes/geoip-2023-01-123
-rw-r--r--changes/geoip-2023-07-263
-rw-r--r--changes/geoip-2023-08-30 (renamed from changes/geoip-2022-08-11)2
-rw-r--r--changes/geoip-2023-09-25 (renamed from changes/geoip-2022-11-10)2
-rw-r--r--changes/ip_bind_address_no_port5
-rw-r--r--changes/issue406133
-rw-r--r--changes/ticket401949
-rw-r--r--changes/ticket406045
-rw-r--r--changes/ticket406234
-rw-r--r--changes/ticket406483
-rw-r--r--changes/ticket406494
-rw-r--r--changes/ticket4065210
-rw-r--r--changes/ticket406633
-rw-r--r--changes/ticket406643
-rw-r--r--changes/ticket406743
-rw-r--r--changes/ticket406806
-rw-r--r--changes/ticket406836
-rw-r--r--changes/ticket406872
-rw-r--r--changes/ticket406883
-rw-r--r--changes/ticket406923
-rw-r--r--changes/ticket406945
-rw-r--r--changes/ticket406963
-rw-r--r--changes/ticket407034
-rw-r--r--changes/ticket407046
-rw-r--r--changes/ticket407083
-rw-r--r--changes/ticket407193
-rw-r--r--changes/ticket407225
-rw-r--r--changes/ticket407243
-rw-r--r--changes/ticket407273
-rw-r--r--changes/ticket407293
-rw-r--r--changes/ticket407305
-rw-r--r--changes/ticket407399
-rw-r--r--changes/ticket407412
-rw-r--r--changes/ticket407453
-rw-r--r--changes/ticket407535
-rw-r--r--changes/ticket407996
-rw-r--r--changes/ticket408244
-rw-r--r--changes/ticket408433
-rw-r--r--changes/ticket408444
-rw-r--r--changes/ticket408484
-rw-r--r--changes/ticket408594
-rw-r--r--configure.ac71
-rwxr-xr-xcontrib/client-tools/torify19
-rw-r--r--contrib/win32build/tor-mingw.nsi.in10
-rw-r--r--contrib/win32build/tor.nsi.in4
-rw-r--r--doc/HACKING/ReleasingTor.md34
-rw-r--r--doc/HACKING/Rust.md43
-rw-r--r--doc/HACKING/WritingTests.md2
-rwxr-xr-xdoc/asciidoc-helper.sh2
-rw-r--r--doc/building-tor-msvc.txt122
-rw-r--r--doc/include.am8
-rw-r--r--doc/man/tor.1.txt81
-rw-r--r--m4/ax_check_compile_flag.m451
-rwxr-xr-xscripts/ci/ci-driver.sh75
-rwxr-xr-xscripts/git/git-list-tor-branches.sh9
-rwxr-xr-xscripts/git/git-pull-all.sh18
-rw-r--r--scripts/maint/checkOptionDocs.pl.in9
-rw-r--r--scripts/maint/geoip/geoip-db-tool/Cargo.lock110
-rw-r--r--scripts/maint/geoip/geoip-db-tool/src/db.rs16
-rw-r--r--scripts/maint/geoip/geoip-db-tool/src/main.rs11
-rwxr-xr-xscripts/maint/geoip/update_geoip.sh14
-rwxr-xr-xscripts/maint/update_versions.py5
-rw-r--r--src/app/config/config.c77
-rw-r--r--src/app/config/fallback_dirs.inc983
-rw-r--r--src/app/config/or_options_st.h15
-rw-r--r--src/app/config/resolve_addr.c2
-rw-r--r--src/app/config/testnet.inc1
-rw-r--r--src/app/main/main.c8
-rw-r--r--src/app/main/shutdown.c2
-rw-r--r--src/app/main/subsystem_list.c2
-rw-r--r--src/config/geoip2198
-rw-r--r--src/config/geoip6772
-rw-r--r--src/config/include.am6
-rw-r--r--src/config/torrc.sample.in20
-rw-r--r--src/core/crypto/onion_crypto.c3
-rw-r--r--src/core/include.am1
-rw-r--r--src/core/mainloop/connection.c62
-rw-r--r--src/core/mainloop/connection.h1
-rw-r--r--src/core/mainloop/cpuworker.c7
-rw-r--r--src/core/mainloop/cpuworker.h4
-rw-r--r--src/core/mainloop/mainloop.c30
-rw-r--r--src/core/mainloop/mainloop.h2
-rw-r--r--src/core/or/channel.c53
-rw-r--r--src/core/or/channeltls.c10
-rw-r--r--src/core/or/circuit_st.h29
-rw-r--r--src/core/or/circuitbuild.c82
-rw-r--r--src/core/or/circuitbuild.h9
-rw-r--r--src/core/or/circuitlist.c59
-rw-r--r--src/core/or/circuitlist.h11
-rw-r--r--src/core/or/circuitpadding.c7
-rw-r--r--src/core/or/circuitstats.c14
-rw-r--r--src/core/or/circuituse.c109
-rw-r--r--src/core/or/circuituse.h7
-rw-r--r--src/core/or/conflux.c906
-rw-r--r--src/core/or/conflux.h84
-rw-r--r--src/core/or/conflux_cell.c349
-rw-r--r--src/core/or/conflux_cell.h50
-rw-r--r--src/core/or/conflux_params.c290
-rw-r--r--src/core/or/conflux_params.h29
-rw-r--r--src/core/or/conflux_pool.c2144
-rw-r--r--src/core/or/conflux_pool.h51
-rw-r--r--src/core/or/conflux_st.h155
-rw-r--r--src/core/or/conflux_sys.c37
-rw-r--r--src/core/or/conflux_sys.h23
-rw-r--r--src/core/or/conflux_util.c437
-rw-r--r--src/core/or/conflux_util.h59
-rw-r--r--src/core/or/congestion_control_common.c362
-rw-r--r--src/core/or/congestion_control_common.h19
-rw-r--r--src/core/or/congestion_control_flow.c47
-rw-r--r--src/core/or/congestion_control_flow.h2
-rw-r--r--src/core/or/congestion_control_nola.c139
-rw-r--r--src/core/or/congestion_control_nola.h33
-rw-r--r--src/core/or/congestion_control_st.h48
-rw-r--r--src/core/or/congestion_control_vegas.c31
-rw-r--r--src/core/or/congestion_control_vegas.h3
-rw-r--r--src/core/or/congestion_control_westwood.c241
-rw-r--r--src/core/or/congestion_control_westwood.h33
-rw-r--r--src/core/or/connection_edge.c53
-rw-r--r--src/core/or/connection_edge.h1
-rw-r--r--src/core/or/connection_or.c10
-rw-r--r--src/core/or/connection_st.h2
-rw-r--r--src/core/or/cpath_build_state_st.h2
-rw-r--r--src/core/or/dos.c19
-rw-r--r--src/core/or/edge_connection_st.h13
-rw-r--r--src/core/or/entry_connection_st.h4
-rw-r--r--src/core/or/include.am17
-rw-r--r--src/core/or/lttng_cc.inc8
-rw-r--r--src/core/or/or.h16
-rw-r--r--src/core/or/or_circuit_st.h12
-rw-r--r--src/core/or/or_connection_st.h2
-rw-r--r--src/core/or/origin_circuit_st.h25
-rw-r--r--src/core/or/policies.c2
-rw-r--r--src/core/or/policies.h1
-rw-r--r--src/core/or/protover.c4
-rw-r--r--src/core/or/protover.h3
-rw-r--r--src/core/or/relay.c422
-rw-r--r--src/core/or/scheduler.h6
-rw-r--r--src/core/or/scheduler_kist.c14
-rw-r--r--src/core/or/sendme.c4
-rw-r--r--src/core/or/versions.c7
-rw-r--r--src/ext/.may_include4
-rw-r--r--src/ext/Makefile.nmake12
-rw-r--r--src/ext/compat_blake2.h47
-rw-r--r--src/ext/equix/CMakeLists.txt75
-rw-r--r--src/ext/equix/Cargo.toml23
-rw-r--r--src/ext/equix/LICENSE165
-rw-r--r--src/ext/equix/README.md77
-rw-r--r--src/ext/equix/build.rs53
-rw-r--r--src/ext/equix/devlog.md178
-rw-r--r--src/ext/equix/hashx/CMakeLists.txt95
-rw-r--r--src/ext/equix/hashx/LICENSE165
-rw-r--r--src/ext/equix/hashx/README.md162
-rw-r--r--src/ext/equix/hashx/include/hashx.h195
-rw-r--r--src/ext/equix/hashx/src/bench.c147
-rw-r--r--src/ext/equix/hashx/src/blake2.c462
-rw-r--r--src/ext/equix/hashx/src/blake2.h73
-rw-r--r--src/ext/equix/hashx/src/compiler.c19
-rw-r--r--src/ext/equix/hashx/src/compiler.h77
-rw-r--r--src/ext/equix/hashx/src/compiler_a64.c164
-rw-r--r--src/ext/equix/hashx/src/compiler_x86.c159
-rw-r--r--src/ext/equix/hashx/src/context.c67
-rw-r--r--src/ext/equix/hashx/src/context.h39
-rw-r--r--src/ext/equix/hashx/src/force_inline.h9
-rw-r--r--src/ext/equix/hashx/src/hashx.c172
-rw-r--r--src/ext/equix/hashx/src/hashx_endian.h103
-rw-r--r--src/ext/equix/hashx/src/hashx_thread.c27
-rw-r--r--src/ext/equix/hashx/src/hashx_thread.h27
-rw-r--r--src/ext/equix/hashx/src/hashx_time.c35
-rw-r--r--src/ext/equix/hashx/src/hashx_time.h9
-rw-r--r--src/ext/equix/hashx/src/instruction.h31
-rw-r--r--src/ext/equix/hashx/src/program.c777
-rw-r--r--src/ext/equix/hashx/src/program.h52
-rw-r--r--src/ext/equix/hashx/src/program_exec.c158
-rw-r--r--src/ext/equix/hashx/src/siphash.c66
-rw-r--r--src/ext/equix/hashx/src/siphash.h35
-rw-r--r--src/ext/equix/hashx/src/siphash_rng.c41
-rw-r--r--src/ext/equix/hashx/src/siphash_rng.h34
-rw-r--r--src/ext/equix/hashx/src/test_utils.h60
-rw-r--r--src/ext/equix/hashx/src/tests.c275
-rw-r--r--src/ext/equix/hashx/src/unreachable.h9
-rw-r--r--src/ext/equix/hashx/src/virtual_memory.c140
-rw-r--r--src/ext/equix/hashx/src/virtual_memory.h23
-rw-r--r--src/ext/equix/include/equix.h166
-rw-r--r--src/ext/equix/src/bench.c181
-rw-r--r--src/ext/equix/src/context.c66
-rw-r--r--src/ext/equix/src/context.h18
-rw-r--r--src/ext/equix/src/equix.c131
-rw-r--r--src/ext/equix/src/lib.rs997
-rw-r--r--src/ext/equix/src/solver.c283
-rw-r--r--src/ext/equix/src/solver.h44
-rw-r--r--src/ext/equix/src/solver_heap.h108
-rw-r--r--src/ext/equix/src/tests.c129
-rw-r--r--src/ext/include.am59
-rw-r--r--src/feature/client/bridges.c35
-rw-r--r--src/feature/client/bridges.h1
-rw-r--r--src/feature/client/circpathbias.c13
-rw-r--r--src/feature/client/entrynodes.c48
-rw-r--r--src/feature/client/entrynodes.h14
-rw-r--r--src/feature/client/transports.c99
-rw-r--r--src/feature/client/transports.h2
-rw-r--r--src/feature/control/control_fmt.c7
-rw-r--r--src/feature/control/getinfo_geoip.c5
-rw-r--r--src/feature/dirauth/dirauth_options.inc5
-rw-r--r--src/feature/dirauth/dirvote.c38
-rw-r--r--src/feature/dirauth/dirvote.h8
-rw-r--r--src/feature/dirauth/process_descs.c15
-rw-r--r--src/feature/dirclient/dirclient.c25
-rw-r--r--src/feature/dirparse/ns_parse.c5
-rw-r--r--src/feature/dirparse/parsecommon.h1
-rw-r--r--src/feature/hs/hs_cache.c9
-rw-r--r--src/feature/hs/hs_cell.c201
-rw-r--r--src/feature/hs/hs_cell.h35
-rw-r--r--src/feature/hs/hs_circuit.c410
-rw-r--r--src/feature/hs/hs_circuit.h31
-rw-r--r--src/feature/hs/hs_client.c224
-rw-r--r--src/feature/hs/hs_client.h12
-rw-r--r--src/feature/hs/hs_common.c4
-rw-r--r--src/feature/hs/hs_common.h7
-rw-r--r--src/feature/hs/hs_config.c29
-rw-r--r--src/feature/hs/hs_config.h3
-rw-r--r--src/feature/hs/hs_descriptor.c134
-rw-r--r--src/feature/hs/hs_descriptor.h11
-rw-r--r--src/feature/hs/hs_dos.c5
-rw-r--r--src/feature/hs/hs_intropoint.c21
-rw-r--r--src/feature/hs/hs_metrics.c148
-rw-r--r--src/feature/hs/hs_metrics.h78
-rw-r--r--src/feature/hs/hs_metrics_entry.c97
-rw-r--r--src/feature/hs/hs_metrics_entry.h56
-rw-r--r--src/feature/hs/hs_options.inc3
-rw-r--r--src/feature/hs/hs_pow.c569
-rw-r--r--src/feature/hs/hs_pow.h228
-rw-r--r--src/feature/hs/hs_service.c309
-rw-r--r--src/feature/hs/hs_service.h18
-rw-r--r--src/feature/hs/include.am9
-rw-r--r--src/feature/nodelist/fmt_routerstatus.c16
-rw-r--r--src/feature/nodelist/fmt_routerstatus.h3
-rw-r--r--src/feature/nodelist/microdesc.c2
-rw-r--r--src/feature/nodelist/networkstatus.c15
-rw-r--r--src/feature/nodelist/node_select.h2
-rw-r--r--src/feature/nodelist/nodelist.c11
-rw-r--r--src/feature/nodelist/nodelist.h1
-rw-r--r--src/feature/nodelist/routerlist.c41
-rw-r--r--src/feature/nodelist/routerstatus_st.h1
-rw-r--r--src/feature/nodelist/vote_routerstatus_st.h1
-rw-r--r--src/feature/relay/dns.c10
-rw-r--r--src/feature/relay/onion_queue.c2
-rw-r--r--src/feature/relay/relay_config.c21
-rw-r--r--src/feature/relay/relay_find_addr.c18
-rw-r--r--src/feature/relay/relay_metrics.c379
-rw-r--r--src/feature/relay/relay_metrics.h60
-rw-r--r--src/feature/relay/relay_periodic.c4
-rw-r--r--src/feature/relay/relay_stub.c25
-rw-r--r--src/feature/relay/router.c13
-rw-r--r--src/feature/relay/router.h2
-rw-r--r--src/feature/relay/routerkeys.h1
-rw-r--r--src/feature/rend/rendmid.c13
-rw-r--r--src/feature/stats/geoip_stats.h2
-rw-r--r--src/feature/stats/rephist.c4
-rw-r--r--src/include.am1
-rw-r--r--src/lib/compress/compress.c10
-rw-r--r--src/lib/crypt_ops/compat_openssl.h22
-rw-r--r--src/lib/crypt_ops/crypto_openssl_mgt.h3
-rw-r--r--src/lib/crypt_ops/crypto_rsa_openssl.c8
-rw-r--r--src/lib/dispatch/dispatch_cfg_st.h4
-rw-r--r--src/lib/evloop/compat_libevent.c2
-rw-r--r--src/lib/evloop/token_bucket.c111
-rw-r--r--src/lib/evloop/token_bucket.h12
-rw-r--r--src/lib/evloop/workqueue.c5
-rw-r--r--src/lib/geoip/geoip.c4
-rw-r--r--src/lib/geoip/geoip.h6
-rw-r--r--src/lib/malloc/malloc.h4
-rw-r--r--src/lib/math/prob_distr.c2
-rw-r--r--src/lib/math/stats.h2
-rw-r--r--src/lib/metrics/metrics_common.c2
-rw-r--r--src/lib/metrics/metrics_common.h23
-rw-r--r--src/lib/metrics/metrics_store.c6
-rw-r--r--src/lib/metrics/metrics_store.h6
-rw-r--r--src/lib/metrics/metrics_store_entry.c177
-rw-r--r--src/lib/metrics/metrics_store_entry.h16
-rw-r--r--src/lib/metrics/prometheus.c70
-rw-r--r--src/lib/osinfo/libc.c19
-rw-r--r--src/lib/process/process_win32.c2
-rw-r--r--src/lib/sandbox/sandbox.c137
-rw-r--r--src/lib/time/compat_time.c17
-rw-r--r--src/lib/time/compat_time.h16
-rw-r--r--src/lib/tls/tortls_openssl.c9
-rw-r--r--src/test/Makefile.nmake35
-rw-r--r--src/test/bench.c1
-rw-r--r--src/test/conf_examples/large_1/expected2
-rw-r--r--src/test/conf_examples/large_1/expected_no_dirauth2
-rw-r--r--src/test/conf_examples/large_1/torrc1
-rw-r--r--src/test/fakecircs.c10
-rw-r--r--src/test/hs_test_helpers.c12
-rw-r--r--src/test/include.am5
-rw-r--r--src/test/test.c4
-rw-r--r--src/test/test.h5
-rw-r--r--src/test/test_bwmgt.c24
-rw-r--r--src/test/test_channel.c25
-rw-r--r--src/test/test_channelpadding.c2
-rw-r--r--src/test/test_config.c2
-rw-r--r--src/test/test_conflux_cell.c60
-rw-r--r--src/test/test_conflux_pool.c1339
-rw-r--r--src/test/test_congestion_control.c390
-rw-r--r--src/test/test_connection.c21
-rw-r--r--src/test/test_crypto.c187
-rw-r--r--src/test/test_crypto_slow.c135
-rw-r--r--src/test/test_dir.c23
-rw-r--r--src/test/test_dir_common.c8
-rw-r--r--src/test/test_dir_handle_get.c2
-rw-r--r--src/test/test_dos.c56
-rw-r--r--src/test/test_hs_client.c5
-rw-r--r--src/test/test_hs_common.c75
-rw-r--r--src/test/test_hs_control.c2
-rw-r--r--src/test/test_hs_descriptor.c98
-rw-r--r--src/test/test_hs_dos.c18
-rw-r--r--src/test/test_hs_intropoint.c3
-rw-r--r--src/test/test_hs_metrics.c38
-rw-r--r--src/test/test_hs_pow.c500
-rw-r--r--src/test/test_hs_pow_slow.c273
-rw-r--r--src/test/test_hs_service.c117
-rw-r--r--src/test/test_metrics.c146
-rw-r--r--src/test/test_nodelist.c8
-rw-r--r--src/test/test_ntor_v3.c3
-rw-r--r--src/test/test_options.c38
-rw-r--r--src/test/test_parsecommon.c45
-rwxr-xr-xsrc/test/test_parseconf.sh6
-rw-r--r--src/test/test_periodic_event.c2
-rw-r--r--src/test/test_process_descs.c8
-rwxr-xr-xsrc/test/test_rebind.sh1
-rw-r--r--src/test/test_router.c14
-rw-r--r--src/test/test_sandbox.c56
-rw-r--r--src/test/test_scheduler.c10
-rw-r--r--src/test/test_slow.c1
-rw-r--r--src/test/test_util.c2
-rw-r--r--src/test/test_voting_flags.c4
-rw-r--r--src/test/testing_common.c4
-rw-r--r--src/tools/Makefile.nmake22
-rw-r--r--src/trunnel/conflux.c1158
-rw-r--r--src/trunnel/conflux.h422
-rw-r--r--src/trunnel/conflux.trunnel66
-rw-r--r--src/trunnel/hs/cell_introduce1.c344
-rw-r--r--src/trunnel/hs/cell_introduce1.h146
-rw-r--r--src/trunnel/hs/cell_introduce1.trunnel37
-rw-r--r--src/trunnel/include.am9
-rw-r--r--src/win32/include.am3
-rw-r--r--src/win32/orconfig.h242
380 files changed, 26722 insertions, 4519 deletions
diff --git a/.gitignore b/.gitignore
index 379d532fda..6d7dc6606c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -71,6 +71,7 @@ core.*
/stamp-h1
/tags
/TAGS
+/target
/test-driver
/tor.sh
/tor.spec
@@ -138,6 +139,8 @@ core.*
# /scripts
/scripts/maint/checkOptionDocs.pl
/scripts/maint/updateVersions.pl
+scripts/maint/geoip/geoip
+scripts/maint/geoip/geoip6
# /src/
/src/Makefile
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 41caa95537..3f4a9b7af5 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -42,6 +42,7 @@ variables:
.x86-64-template: &x86-64-template
tags:
- amd64
+ - physical
# This template should be usable on any system that's based on apt.
.apt-template: &apt-template |
@@ -51,9 +52,9 @@ variables:
export APT_CACHE_DIR="$(pwd)/apt-cache"
rm -f /etc/apt/apt.conf.d/docker-clean
echo 'quiet "1";' \
+ 'Acquire::Retries "20";' \
'APT::Install-Recommends "0";' \
'APT::Install-Suggests "0";' \
- 'APT::Acquire::Retries "20";' \
'APT::Get::Assume-Yes "true";' \
'Dpkg::Use-Pty "0";' \
"Dir::Cache::Archives \"${APT_CACHE_DIR}\"; " \
@@ -100,6 +101,8 @@ variables:
- if [ "$STEM" = yes ]; then apt-get install timelimit; fi
- if [ "$CC" = clang ]; then apt-get install clang; fi
- if [ "$NSS" = yes ]; then apt-get install libnss3 libnss3-dev; fi
+ # llvm-symbolizer for sanitizer backtrace
+ - if [ "$HARDENING" = yes ]; then apt-get install llvm; fi
# TODO: This next line should not be debian-only.
- if [ "$STEM" = yes ]; then git clone --depth 1 https://gitlab.torproject.org/tpo/network-health/stem.git ; export STEM_PATH="$(pwd)/stem"; fi
# TODO: This next line should not be debian-only.
@@ -114,7 +117,7 @@ debian-minimal:
script:
- ./scripts/ci/ci-driver.sh
-# Minmal check on debian/i386: just make, make check.
+# Minimal check on debian/i386: just make, make check.
#
debian-i386-minimal:
image: i386/debian:bullseye
@@ -215,6 +218,16 @@ debian-disable-relay:
- ./scripts/ci/ci-driver.sh
#####
+# GPL licensed mode, enables pow module
+debian-gpl:
+ image: debian:buster
+ <<: *debian-template
+ variables:
+ GPL: "yes"
+ script:
+ - ./scripts/ci/ci-driver.sh
+
+#####
# NSS check on debian
debian-nss:
image: debian:bullseye
@@ -242,3 +255,19 @@ debian-packaging-0.4.6:
rules:
- if: $CI_PROJECT_NAMESPACE == "tpo/core" &&
$CI_COMMIT_BRANCH == "maint-0.4.6"
+
+#####
+# Run tests written in Rust, and run clippy on all Rust code here.
+rust-latest:
+ image: rust:latest
+ <<: *debian-template
+ script:
+ - apt-get install llvm-dev libclang-dev clang
+ - rustup show
+ - cargo build --locked --verbose
+ - cargo test --verbose
+ - rustup component add clippy
+ - rustup show
+ - cargo clippy --all-features --all-targets -- -D warnings
+ after_script:
+ - cargo clean \ No newline at end of file
diff --git a/Cargo.lock b/Cargo.lock
new file mode 100644
index 0000000000..5a55cac0e8
--- /dev/null
+++ b/Cargo.lock
@@ -0,0 +1,385 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 3
+
+[[package]]
+name = "aho-corasick"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6748e8def348ed4d14996fa801f4122cd763fff530258cdc03f64b25f89d3a5a"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
+name = "argh"
+version = "0.1.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a7e7e4aa7e40747e023c0761dafcb42333a9517575bbf1241747f68dd3177a62"
+dependencies = [
+ "argh_derive",
+ "argh_shared",
+]
+
+[[package]]
+name = "argh_derive"
+version = "0.1.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "69f2bd7ff6ed6414f4e5521bd509bae46454bbd513801767ced3f21a751ab4bc"
+dependencies = [
+ "argh_shared",
+ "heck",
+ "proc-macro2",
+ "quote",
+ "syn 1.0.99",
+]
+
+[[package]]
+name = "argh_shared"
+version = "0.1.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "47253b98986dafc7a3e1cf3259194f1f47ac61abb57a57f46ec09e48d004ecda"
+
+[[package]]
+name = "bindgen"
+version = "0.66.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f2b84e06fc203107bfbad243f4aba2af864eb7db3b1cf46ea0a023b0b433d2a7"
+dependencies = [
+ "bitflags",
+ "cexpr",
+ "clang-sys",
+ "lazy_static",
+ "lazycell",
+ "log",
+ "peeking_take_while",
+ "prettyplease",
+ "proc-macro2",
+ "quote",
+ "regex",
+ "rustc-hash",
+ "shlex",
+ "syn 2.0.28",
+ "which",
+]
+
+[[package]]
+name = "bitflags"
+version = "2.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635"
+
+[[package]]
+name = "cc"
+version = "1.0.82"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "305fe645edc1442a0fa8b6726ba61d422798d37a52e12eaecf4b022ebbb88f01"
+dependencies = [
+ "jobserver",
+ "libc",
+]
+
+[[package]]
+name = "cexpr"
+version = "0.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766"
+dependencies = [
+ "nom",
+]
+
+[[package]]
+name = "cfg-if"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
+
+[[package]]
+name = "clang-sys"
+version = "1.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c688fc74432808e3eb684cae8830a86be1d66a2bd58e1f248ed0960a590baf6f"
+dependencies = [
+ "glob",
+ "libc",
+ "libloading",
+]
+
+[[package]]
+name = "either"
+version = "1.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07"
+
+[[package]]
+name = "geoip-db-tool"
+version = "0.1.0"
+dependencies = [
+ "argh",
+ "ipnetwork",
+ "rangemap",
+]
+
+[[package]]
+name = "glob"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b"
+
+[[package]]
+name = "heck"
+version = "0.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c"
+dependencies = [
+ "unicode-segmentation",
+]
+
+[[package]]
+name = "hex-literal"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46"
+
+[[package]]
+name = "ipnetwork"
+version = "0.17.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "02c3eaab3ac0ede60ffa41add21970a7df7d91772c03383aac6c2c3d53cc716b"
+dependencies = [
+ "serde",
+]
+
+[[package]]
+name = "jobserver"
+version = "0.1.26"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "936cfd212a0155903bcbc060e316fb6cc7cbf2e1907329391ebadc1fe0ce77c2"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "lazy_static"
+version = "1.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
+
+[[package]]
+name = "lazycell"
+version = "1.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
+
+[[package]]
+name = "libc"
+version = "0.2.147"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3"
+
+[[package]]
+name = "libloading"
+version = "0.7.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f"
+dependencies = [
+ "cfg-if",
+ "winapi",
+]
+
+[[package]]
+name = "log"
+version = "0.4.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f"
+
+[[package]]
+name = "memchr"
+version = "2.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
+
+[[package]]
+name = "minimal-lexical"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
+
+[[package]]
+name = "nom"
+version = "7.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a"
+dependencies = [
+ "memchr",
+ "minimal-lexical",
+]
+
+[[package]]
+name = "once_cell"
+version = "1.18.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d"
+
+[[package]]
+name = "peeking_take_while"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099"
+
+[[package]]
+name = "prettyplease"
+version = "0.2.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6c64d9ba0963cdcea2e1b2230fbae2bab30eb25a174be395c41e764bfb65dd62"
+dependencies = [
+ "proc-macro2",
+ "syn 2.0.28",
+]
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.66"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9"
+dependencies = [
+ "unicode-ident",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.32"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "50f3b39ccfb720540debaa0164757101c08ecb8d326b15358ce76a62c7e85965"
+dependencies = [
+ "proc-macro2",
+]
+
+[[package]]
+name = "rangemap"
+version = "0.1.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3929836cb64d09ee7deee59635c3d9bffbc1c0373e247efff6272abd62a11baa"
+
+[[package]]
+name = "regex"
+version = "1.9.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "81bc1d4caf89fac26a70747fe603c130093b53c773888797a6329091246d651a"
+dependencies = [
+ "aho-corasick",
+ "memchr",
+ "regex-automata",
+ "regex-syntax",
+]
+
+[[package]]
+name = "regex-automata"
+version = "0.3.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fed1ceff11a1dddaee50c9dc8e4938bd106e9d89ae372f192311e7da498e3b69"
+dependencies = [
+ "aho-corasick",
+ "memchr",
+ "regex-syntax",
+]
+
+[[package]]
+name = "regex-syntax"
+version = "0.7.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e5ea92a5b6195c6ef2a0295ea818b312502c6fc94dde986c5553242e18fd4ce2"
+
+[[package]]
+name = "rustc-hash"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
+
+[[package]]
+name = "serde"
+version = "1.0.143"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "53e8e5d5b70924f74ff5c6d64d9a5acd91422117c60f48c4e07855238a254553"
+
+[[package]]
+name = "shlex"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "43b2853a4d09f215c24cc5489c992ce46052d359b5109343cbafbf26bc62f8a3"
+
+[[package]]
+name = "syn"
+version = "1.0.99"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "58dbef6ec655055e20b86b15a8cc6d439cca19b667537ac6a1369572d151ab13"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
+[[package]]
+name = "syn"
+version = "2.0.28"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "04361975b3f5e348b2189d8dc55bc942f278b2d482a6a0365de5bdd62d351567"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
+[[package]]
+name = "tor-c-equix"
+version = "0.2.0"
+dependencies = [
+ "bindgen",
+ "cc",
+ "hex-literal",
+]
+
+[[package]]
+name = "unicode-ident"
+version = "1.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c4f5b37a154999a8f3f98cc23a628d850e154479cd94decf3414696e12e31aaf"
+
+[[package]]
+name = "unicode-segmentation"
+version = "1.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7e8820f5d777f6224dc4be3632222971ac30164d4a258d595640799554ebfd99"
+
+[[package]]
+name = "which"
+version = "4.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2441c784c52b289a054b7201fc93253e288f094e2f4be9058343127c4226a269"
+dependencies = [
+ "either",
+ "libc",
+ "once_cell",
+]
+
+[[package]]
+name = "winapi"
+version = "0.3.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
+dependencies = [
+ "winapi-i686-pc-windows-gnu",
+ "winapi-x86_64-pc-windows-gnu",
+]
+
+[[package]]
+name = "winapi-i686-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
+
+[[package]]
+name = "winapi-x86_64-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
diff --git a/Cargo.toml b/Cargo.toml
new file mode 100644
index 0000000000..2b93096234
--- /dev/null
+++ b/Cargo.toml
@@ -0,0 +1,15 @@
+# See doc/HACKING/Rust.md
+#
+# There is no plan to offer a stable Rust API to the C implementation of Tor.
+# This workspace is for wrapper crates that are used internally by Arti for
+# cross-compatibility and comparison testing.
+
+[workspace]
+
+members = [
+ "src/ext/equix",
+ "scripts/maint/geoip/geoip-db-tool",
+]
+
+resolver = "2"
+
diff --git a/ChangeLog b/ChangeLog
index 0ed1710d7b..3669a5c39f 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,850 @@
+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):
+ - 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
+ 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".
+
+
+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.
+
+ 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 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
+ 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 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 inifinite 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 June 01, 2023.
+
+ o Minor features (geoip data):
+ - Update the geoip files to match the IPFire Location Database, as
+ 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 (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
+ This version contains three major bugfixes, two for relays and one for
+ client being a security fix, TROVE-2022-002. We have added, for Linux, the
+ support for IP_BIND_ADDRESS_NO_PORT for relays using OutboundBindAddress.
+ We strongly recommend to upgrade to this version considering the important
+ congestion control fix detailed below.
+
+ 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
+ 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;
+ bugfix on 0.4.7.5-alpha.
+
+ 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 feature (authority):
+ - Reject 0.4.6.x series at the authority level. Closes ticket 40664.
+
+ 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.
+
+ o Minor features (relays):
+ - Set the Linux-specific IP_BIND_ADDRESS_NO_PORT option on outgoing
+ sockets, allowing relays using OutboundBindAddress to make more
+ outgoing connections than ephemeral ports, as long as they are to
+ separate destinations. Related to issue 40597; patch by Alex
+ Xu (Hello71).
+
+ o Minor bugfixes (relay, metrics):
+ - Fix typo in a congestion control label on the MetricsPort. Fixes
+ bug 40727; bugfix on 0.4.7.12.
+
+ o Minor bugfixes (sandbox, authority):
+ - With the sandbox enabled, allow to write "my-consensus-
+ {ns|microdesc}" and to rename them as well. Fixes bug 40729;
+ bugfix on 0.3.5.1-alpha.
+
+ o Code simplifications and refactoring:
+ - Rely on actual error returned by the kernel when choosing what
+ resource exhaustion to log. Fixes issue 40613; Fix
+ 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
+ subsystem.
+
+ 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 Minor feature (Congestion control metrics):
+ - Add additional metricsport relay metrics for congestion control.
+ Closes ticket 40724.
+
+ 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.
+
+ o Minor bugfixes (cpuworker, relay):
+ - Fix an off by one overload calculation on the number of CPUs being
+ 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
+ for relays to help us gather more internal data to investigate performance
+ and attacks.
+
+ We strongly recommend to upgrade to this version especially for Exit relays
+ in order to help the network defend against this ongoing DDoS.
+
+ o Directory authority changes (dizum, Faravahar):
+ - Change dizum IP address. Closes ticket 40687.
+ - Remove Faravahar until its operator, Sina, set it back up online
+ outside of Team Cymru network. Closes ticket 40688.
+
+ 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.
+
+ o Major bugfixes (onion service):
+ - Set a much higher circuit build timeout for opened client rendezvous
+ circuit. Before this, tor would time them out very quickly leading to
+ unnecessary retries meaning more load on the network. Fixes bug 40694;
+ bugfix on 0.3.5.1-alpha.
+
+ 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 feature (Mac and iOS build):
+ - Change how combine_libs works on Darwin like platforms to make
+ sure we don't include any `__.SYMDEF` and `__.SYMDEF SORTED`
+ symbols on the archive before we repack and run ${RANLIB} on the
+ archive. This fixes a build issue with recent Xcode versions on
+ Mac Silicon and iOS. Closes ticket 40683.
+
+ o Minor feature (metrics):
+ - Add various congestion control counters to the MetricsPort. Closes
+ ticket 40708.
+
+ o Minor feature (performance):
+ - Bump the maximum amount of CPU that can be used from 16 to 128. Note
+ that NumCPUs torrc option overrides this hardcoded maximum. Fixes bug
+ 40703; bugfix on 0.3.5.1-alpha.
+
+ o Minor feature (relay):
+ - Make an hardcoded value for the maximum of per CPU tasks into a
+ consensus parameter.
+ - Two new consensus parameters are added to control the wait time in
+ queue of the onionskins. One of them is the torrc
+ MaxOnionQueueDelay options which supersedes the consensus
+ parameter. Closes ticket 40704.
+
+ o Minor feature (relay, DoS):
+ - Apply circuit creation anti-DoS defenses if the outbound circuit
+ max cell queue size is reached too many times. This introduces two
+ new consensus parameters to control the queue size limit and
+ number of times allowed to go over that limit. Closes ticket 40680.
+
+ o Minor feature (relay, metrics):
+ - Add DoS defenses counter to MetricsPort.
+ - Add congestion control RTT reset counter to MetricsPort.
+ - Add counters to the MetricsPort how many connections, per type,
+ are currently opened and how many were created.
+ - Add relay flags from the consensus to the MetricsPort.
+ - Add total number of opened circuits to MetricsPort.
+ - Add total number of streams seen by an Exit to the MetricsPort.
+ - Add traffic stats as in number of read/written bytes in total.
+ - Related to ticket 40194.
+
+ o Minor features (fallbackdir):
+ - Regenerate fallback directories generated on November 10, 2022.
+
+ o Minor features (geoip data):
+ - Update the geoip files to match the IPFire Location Database, as
+ retrieved on 2022/11/10.
+
+ o Minor bugfixes (authorities, sandbox):
+ - Allow to write file my-consensus-<flavor-name> to disk when
+ sandbox is activated. Fixes bug 40663; bugfix on 0.3.5.1-alpha.
+
+ o Minor bugfixes (dirauth):
+ - Directory authorities stop voting a consensus "Measured" weight
+ for relays with the Authority flag. Now these relays will be
+ considered unmeasured, which should reserve their bandwidth for
+ their dir auth role and minimize distractions from other roles. In
+ place of the "Measured" weight, they now include a
+ "MeasuredButAuthority" weight (not used by anything) so the
+ bandwidth authority's opinion on this relay can be recorded for
+ posterity. Lastly, remove the AuthDirDontVoteOnDirAuthBandwidth
+ torrc option which never worked right. Fixes bugs 40698 and 40700;
+ bugfix on 0.4.7.2-alpha.
+
+ o Minor bugfixes (onion service client):
+ - A collapsing onion service circuit should be seen as an
+ "unreachable" error so it can be retried. Fixes bug 40692; bugfix
+ on 0.3.5.1-alpha.
+
+ o Minor bugfixes (onion service):
+ - Make the service retry a rendezvous if the circuit is being
+ repurposed for measurements. Fixes bug 40696; bugfix
+ on 0.3.5.1-alpha.
+
+ o Minor bugfixes (relay overload statistics):
+ - Count total create cells vs dropped create cells properly, when
+ assessing if our fraction of dropped cells is too high. We only
+ count non-client circuits in the denominator, but we would include
+ client circuits in the numerator, leading to surprising log lines
+ claiming that we had dropped more than 100% of incoming create
+ cells. Fixes bug 40673; bugfix on 0.4.7.1-alpha.
+
+ o Code simplification and refactoring (bridges):
+ - Remove unused code related to ExtPort connection ID. Fixes bug
+ 40648; bugfix on 0.3.5.1-alpha.
+
+
+Changes in version 0.4.7.10 - 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.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
+ congestion control also aimed at reducing memory pressure on relays.
+ Finally, there is last one major bugfix related to Vanguard L2 layer node
+ selection.
+
+ We strongly recommend to upgrade to this version especially for Exit relays
+ in order to help the network defend against this ongoing DDoS.
+
+ o Major bugfixes (congestion control):
+ - Implement RFC3742 Limited Slow Start. Congestion control was
+ overshooting the congestion window during slow start, particularly
+ for onion service activity. With this fix, we now update the
+ congestion window more often during slow start, as well as dampen
+ the exponential growth when the congestion window grows above a
+ capping parameter. This should reduce the memory increases guard
+ relays were seeing, as well as allow us to set lower queue limits
+ to defend against ongoing DoS attacks. Fixes bug 40642; bugfix
+ on 0.4.7.5-alpha.
+
+ 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 Major bugfixes (vanguards):
+ - We had omitted some checks for whether our vanguards (second layer
+ guards from proposal 333) overlapped. Now make sure to pick each
+ of them to be independent. Also, change the design to allow them
+ to come from the same family. Fixes bug 40639; bugfix
+ on 0.4.7.1-alpha.
+
+ o Minor features (dirauth):
+ - Add a torrc option to control the Guard flag bandwidth threshold
+ percentile. Closes ticket 40652.
+ - Add an AuthDirVoteGuard torrc option that can allow authorities to
+ assign the Guard flag to the given fingerprints/country code/IPs.
+ This is a needed feature mostly for defense purposes in case a DoS
+ hits the network and relay start losing the Guard flags too fast.
+ - Make UPTIME_TO_GUARANTEE_STABLE, MTBF_TO_GUARANTEE_STABLE,
+ TIME_KNOWN_TO_GUARANTEE_FAMILIAR WFU_TO_GUARANTEE_GUARD tunable
+ from torrc.
+
+ 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 bugfixes (congestion control):
+ - Add a check for an integer underflow condition that might happen
+ in cases where the system clock is stopped, the ORconn is blocked,
+ and the endpoint sends more than a congestion window worth of non-
+ data control cells at once. This would cause a large congestion
+ window to be calculated instead of a small one. No security
+ impact. Fixes bug 40644; bugfix on 0.4.7.5-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 (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.
+
+
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
diff --git a/Makefile.am b/Makefile.am
index 2181d74de0..7567ca99c7 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -114,6 +114,10 @@ TOR_CRYPTO_LIBS = \
$(LIBKECCAK_TINY) \
$(LIBDONNA)
+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)
if UNITTESTS_ENABLED
@@ -121,7 +125,8 @@ TOR_CRYPTO_TESTING_LIBS = \
src/lib/libtor-tls-testing.a \
src/lib/libtor-crypt-ops-testing.a \
$(LIBKECCAK_TINY) \
- $(LIBDONNA)
+ $(LIBDONNA) \
+ $(EQUIX_LIBS)
endif
# All static libraries used to link tor.
@@ -185,7 +190,6 @@ EXTRA_DIST+= \
CODE_OF_CONDUCT \
INSTALL \
LICENSE \
- Makefile.nmake \
README.md \
ReleaseNotes \
scripts/build/combine_libs \
diff --git a/Makefile.nmake b/Makefile.nmake
deleted file mode 100644
index 32401b50b7..0000000000
--- a/Makefile.nmake
+++ /dev/null
@@ -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 --git a/ReleaseNotes b/ReleaseNotes
index ae90f71510..3504ec179c 100644
--- a/ReleaseNotes
+++ b/ReleaseNotes
@@ -2,6 +2,811 @@ This document summarizes new features and bugfixes in each stable
release of Tor. If you want to see more detailed descriptions of the
changes in each development snapshot, see the ChangeLog file.
+Changes in version 0.4.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.
+
+ 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 June 01, 2023.
+
+ o Minor features (geoip data):
+ - Update the geoip files to match the IPFire Location Database, as
+ 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 (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 inifinite 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
+ This version contains three major bugfixes, two for relays and one for
+ client being a security fix, TROVE-2022-002. We have added, for Linux, the
+ support for IP_BIND_ADDRESS_NO_PORT for relays using OutboundBindAddress.
+ We strongly recommend to upgrade to this version considering the important
+ congestion control fix detailed below.
+
+ 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
+ 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;
+ bugfix on 0.4.7.5-alpha.
+
+ 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 feature (authority):
+ - Reject 0.4.6.x series at the authority level. Closes ticket 40664.
+
+ 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.
+
+ o Minor features (relays):
+ - Set the Linux-specific IP_BIND_ADDRESS_NO_PORT option on outgoing
+ sockets, allowing relays using OutboundBindAddress to make more
+ outgoing connections than ephemeral ports, as long as they are to
+ separate destinations. Related to issue 40597; patch by Alex
+ Xu (Hello71).
+
+ o Minor bugfixes (relay, metrics):
+ - Fix typo in a congestion control label on the MetricsPort. Fixes
+ bug 40727; bugfix on 0.4.7.12.
+
+ o Minor bugfixes (sandbox, authority):
+ - With the sandbox enabled, allow to write "my-consensus-
+ {ns|microdesc}" and to rename them as well. Fixes bug 40729;
+ bugfix on 0.3.5.1-alpha.
+
+ o Code simplifications and refactoring:
+ - Rely on actual error returned by the kernel when choosing what
+ resource exhaustion to log. Fixes issue 40613; Fix
+ 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
+ subsystem.
+
+ 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 Minor feature (Congestion control metrics):
+ - Add additional metricsport relay metrics for congestion control.
+ Closes ticket 40724.
+
+ 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.
+
+ o Minor bugfixes (cpuworker, relay):
+ - Fix an off by one overload calculation on the number of CPUs being
+ 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
+ for relays to help us gather more internal data to investigate performance
+ and attacks.
+
+ We strongly recommend to upgrade to this version especially for Exit relays
+ in order to help the network defend against this ongoing DDoS.
+
+ o Directory authority changes (dizum, Faravahar):
+ - Change dizum IP address. Closes ticket 40687.
+ - Remove Faravahar until its operator, Sina, set it back up online
+ outside of Team Cymru network. Closes ticket 40688.
+
+ 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.
+
+ o Major bugfixes (onion service):
+ - Set a much higher circuit build timeout for opened client rendezvous
+ circuit. Before this, tor would time them out very quickly leading to
+ unnecessary retries meaning more load on the network. Fixes bug 40694;
+ bugfix on 0.3.5.1-alpha.
+
+ 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 feature (Mac and iOS build):
+ - Change how combine_libs works on Darwin like platforms to make
+ sure we don't include any `__.SYMDEF` and `__.SYMDEF SORTED`
+ symbols on the archive before we repack and run ${RANLIB} on the
+ archive. This fixes a build issue with recent Xcode versions on
+ Mac Silicon and iOS. Closes ticket 40683.
+
+ o Minor feature (metrics):
+ - Add various congestion control counters to the MetricsPort. Closes
+ ticket 40708.
+
+ o Minor feature (performance):
+ - Bump the maximum amount of CPU that can be used from 16 to 128. Note
+ that NumCPUs torrc option overrides this hardcoded maximum. Fixes bug
+ 40703; bugfix on 0.3.5.1-alpha.
+
+ o Minor feature (relay):
+ - Make an hardcoded value for the maximum of per CPU tasks into a
+ consensus parameter.
+ - Two new consensus parameters are added to control the wait time in
+ queue of the onionskins. One of them is the torrc
+ MaxOnionQueueDelay options which supersedes the consensus
+ parameter. Closes ticket 40704.
+
+ o Minor feature (relay, DoS):
+ - Apply circuit creation anti-DoS defenses if the outbound circuit
+ max cell queue size is reached too many times. This introduces two
+ new consensus parameters to control the queue size limit and
+ number of times allowed to go over that limit. Closes ticket 40680.
+
+ o Minor feature (relay, metrics):
+ - Add DoS defenses counter to MetricsPort.
+ - Add congestion control RTT reset counter to MetricsPort.
+ - Add counters to the MetricsPort how many connections, per type,
+ are currently opened and how many were created.
+ - Add relay flags from the consensus to the MetricsPort.
+ - Add total number of opened circuits to MetricsPort.
+ - Add total number of streams seen by an Exit to the MetricsPort.
+ - Add traffic stats as in number of read/written bytes in total.
+ - Related to ticket 40194.
+
+ o Minor features (fallbackdir):
+ - Regenerate fallback directories generated on November 10, 2022.
+
+ o Minor features (geoip data):
+ - Update the geoip files to match the IPFire Location Database, as
+ retrieved on 2022/11/10.
+
+ o Minor bugfixes (authorities, sandbox):
+ - Allow to write file my-consensus-<flavor-name> to disk when
+ sandbox is activated. Fixes bug 40663; bugfix on 0.3.5.1-alpha.
+
+ o Minor bugfixes (dirauth):
+ - Directory authorities stop voting a consensus "Measured" weight
+ for relays with the Authority flag. Now these relays will be
+ considered unmeasured, which should reserve their bandwidth for
+ their dir auth role and minimize distractions from other roles. In
+ place of the "Measured" weight, they now include a
+ "MeasuredButAuthority" weight (not used by anything) so the
+ bandwidth authority's opinion on this relay can be recorded for
+ posterity. Lastly, remove the AuthDirDontVoteOnDirAuthBandwidth
+ torrc option which never worked right. Fixes bugs 40698 and 40700;
+ bugfix on 0.4.7.2-alpha.
+
+ o Minor bugfixes (onion service client):
+ - A collapsing onion service circuit should be seen as an
+ "unreachable" error so it can be retried. Fixes bug 40692; bugfix
+ on 0.3.5.1-alpha.
+
+ o Minor bugfixes (onion service):
+ - Make the service retry a rendezvous if the circuit is being
+ repurposed for measurements. Fixes bug 40696; bugfix
+ on 0.3.5.1-alpha.
+
+ o Minor bugfixes (relay overload statistics):
+ - Count total create cells vs dropped create cells properly, when
+ assessing if our fraction of dropped cells is too high. We only
+ count non-client circuits in the denominator, but we would include
+ client circuits in the numerator, leading to surprising log lines
+ claiming that we had dropped more than 100% of incoming create
+ cells. Fixes bug 40673; bugfix on 0.4.7.1-alpha.
+
+ o Code simplification and refactoring (bridges):
+ - Remove unused code related to ExtPort connection ID. Fixes bug
+ 40648; bugfix on 0.3.5.1-alpha.
+
+
+Changes in version 0.4.7.10 - 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.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
+ congestion control also aimed at reducing memory pressure on relays.
+ Finally, there is last one major bugfix related to Vanguard L2 layer node
+ selection.
+
+ We strongly recommend to upgrade to this version especially for Exit relays
+ in order to help the network defend against this ongoing DDoS.
+
+ o Major bugfixes (congestion control):
+ - Implement RFC3742 Limited Slow Start. Congestion control was
+ overshooting the congestion window during slow start, particularly
+ for onion service activity. With this fix, we now update the
+ congestion window more often during slow start, as well as dampen
+ the exponential growth when the congestion window grows above a
+ capping parameter. This should reduce the memory increases guard
+ relays were seeing, as well as allow us to set lower queue limits
+ to defend against ongoing DoS attacks. Fixes bug 40642; bugfix
+ on 0.4.7.5-alpha.
+
+ 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 Major bugfixes (vanguards):
+ - We had omitted some checks for whether our vanguards (second layer
+ guards from proposal 333) overlapped. Now make sure to pick each
+ of them to be independent. Also, change the design to allow them
+ to come from the same family. Fixes bug 40639; bugfix
+ on 0.4.7.1-alpha.
+
+ o Minor features (dirauth):
+ - Add a torrc option to control the Guard flag bandwidth threshold
+ percentile. Closes ticket 40652.
+ - Add an AuthDirVoteGuard torrc option that can allow authorities to
+ assign the Guard flag to the given fingerprints/country code/IPs.
+ This is a needed feature mostly for defense purposes in case a DoS
+ hits the network and relay start losing the Guard flags too fast.
+ - Make UPTIME_TO_GUARANTEE_STABLE, MTBF_TO_GUARANTEE_STABLE,
+ TIME_KNOWN_TO_GUARANTEE_FAMILIAR WFU_TO_GUARANTEE_GUARD tunable
+ from torrc.
+
+ 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 bugfixes (congestion control):
+ - Add a check for an integer underflow condition that might happen
+ in cases where the system clock is stopped, the ORconn is blocked,
+ and the endpoint sends more than a congestion window worth of non-
+ data control cells at once. This would cause a large congestion
+ window to be calculated instead of a small one. No security
+ impact. Fixes bug 40644; bugfix on 0.4.7.5-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 (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.
+
+
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
diff --git a/changes/bug40563 b/changes/bug40563
deleted file mode 100644
index e7a3deec6d..0000000000
--- a/changes/bug40563
+++ /dev/null
@@ -1,8 +0,0 @@
- 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".
diff --git a/changes/bug40639 b/changes/bug40639
deleted file mode 100644
index d975e9ad22..0000000000
--- a/changes/bug40639
+++ /dev/null
@@ -1,5 +0,0 @@
- o Major bugfixes (vanguards):
- - We had omitted some checks for whether our vanguards (second layer
- guards from proposal 333) overlapped. Now make sure to pick each
- of them to be independent. Also, change the design to allow them to
- come from the same family. Fixes bug 40639; bugfix on 0.4.7.1-alpha.
diff --git a/changes/bug40642 b/changes/bug40642
deleted file mode 100644
index f50d87e031..0000000000
--- a/changes/bug40642
+++ /dev/null
@@ -1,9 +0,0 @@
- o Major bugfixes (congestion control):
- - Implement RFC3742 Limited Slow Start. Congestion control was
- overshooting the congestion window during slow start, particularly for
- onion service activity. With this fix, we now update the congestion
- window more often during slow start, as well as dampen the exponential
- growth when the congestion window grows above a capping parameter.
- This should reduce the memory increases guard relays were seeing, as
- well as allow us to set lower queue limits to defend against
- ongoing DoS attacks. Fixes bug 40642; bugfix on 0.4.7.5-alpha.
diff --git a/changes/bug40644 b/changes/bug40644
deleted file mode 100644
index a27c63ede2..0000000000
--- a/changes/bug40644
+++ /dev/null
@@ -1,8 +0,0 @@
- o Minor bugfixes (congestion control):
- - Add a check for an integer underflow condition that might
- happen in cases where the system clock is stopped, the
- ORconn is blocked, and the endpoint sends more than a
- congestion window worth of non-data control cells at once.
- This would cause a large congestion window to be calculated
- instead of a small one. No security impact. Fixes bug 40644;
- bugfix on 0.4.7.5-alpha.
diff --git a/changes/bug40645 b/changes/bug40645
deleted file mode 100644
index 044d5b67d2..0000000000
--- a/changes/bug40645
+++ /dev/null
@@ -1,5 +0,0 @@
- 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.
diff --git a/changes/bug40673 b/changes/bug40673
deleted file mode 100644
index 1bbf42649b..0000000000
--- a/changes/bug40673
+++ /dev/null
@@ -1,7 +0,0 @@
- o Minor bugfixes (relay overload statistics):
- - Count total create cells vs dropped create cells properly, when
- assessing if our fraction of dropped cells is too high. We only
- count non-client circuits in the denominator, but we would include
- client circuits in the numerator, leading to surprising log lines
- claiming that we had dropped more than 100% of incoming create
- cells. Fixes bug 40673; bugfix on 0.4.7.1-alpha.
diff --git a/changes/bug40684 b/changes/bug40684
deleted file mode 100644
index 8c751ede2c..0000000000
--- a/changes/bug40684
+++ /dev/null
@@ -1,6 +0,0 @@
- 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.
diff --git a/changes/bug40698 b/changes/bug40698
deleted file mode 100644
index 98ddd4f968..0000000000
--- a/changes/bug40698
+++ /dev/null
@@ -1,11 +0,0 @@
- o Minor bugfixes (dirauth):
- - Directory authorities stop voting a consensus "Measured" weight
- for relays with the Authority flag. Now these relays will be
- considered unmeasured, which should reserve their bandwidth
- for their dir auth role and minimize distractions from other
- roles. In place of the "Measured" weight, they now include a
- "MeasuredButAuthority" weight (not used by anything) so the
- bandwidth authority's opinion on this relay can be recorded for
- posterity. Lastly, remove the AuthDirDontVoteOnDirAuthBandwidth
- torrc option which never worked right. Fixes bugs 40698 and 40700;
- bugfix on 0.4.7.2-alpha.
diff --git a/changes/bug40732 b/changes/bug40732
deleted file mode 100644
index f2388e7e8d..0000000000
--- a/changes/bug40732
+++ /dev/null
@@ -1,7 +0,0 @@
- 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
- 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;
- bugfix on 0.4.7.5-alpha.
diff --git a/changes/bug40751 b/changes/bug40751
deleted file mode 100644
index baa5e90397..0000000000
--- a/changes/bug40751
+++ /dev/null
@@ -1,3 +0,0 @@
- o Minor bugfixes (metrics):
- - Decrement hs_intro_established_count on introduction circuit close. Fixes
- bug 40751; bugfix on 0.4.7.12.
diff --git a/changes/bug40805 b/changes/bug40805
deleted file mode 100644
index bed27c5e43..0000000000
--- a/changes/bug40805
+++ /dev/null
@@ -1,7 +0,0 @@
- 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.
diff --git a/changes/bug40841 b/changes/bug40841
new file mode 100644
index 0000000000..2e67db3261
--- /dev/null
+++ b/changes/bug40841
@@ -0,0 +1,5 @@
+ 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.
diff --git a/changes/bug40842 b/changes/bug40842
new file mode 100644
index 0000000000..bf3bd8bd03
--- /dev/null
+++ b/changes/bug40842
@@ -0,0 +1,4 @@
+ o Minor bugfixes (conflux):
+ - Prevent non-fatal assert stacktrace caused by using conflux
+ sets during their teardown process. Fixes bug 40842;
+ bugfix on 0.4.8.1-alpha.
diff --git a/changes/bug40855 b/changes/bug40855
new file mode 100644
index 0000000000..b455ac9a48
--- /dev/null
+++ b/changes/bug40855
@@ -0,0 +1,6 @@
+ 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.
diff --git a/changes/bug40862 b/changes/bug40862
new file mode 100644
index 0000000000..83ad9376d9
--- /dev/null
+++ b/changes/bug40862
@@ -0,0 +1,3 @@
+ 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.
diff --git a/changes/bug40869 b/changes/bug40869
new file mode 100644
index 0000000000..da9666333f
--- /dev/null
+++ b/changes/bug40869
@@ -0,0 +1,3 @@
+ 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.
diff --git a/changes/bug40878 b/changes/bug40878
new file mode 100644
index 0000000000..503ace69da
--- /dev/null
+++ b/changes/bug40878
@@ -0,0 +1,4 @@
+ 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.
diff --git a/changes/fallbackdirs-2022-08-11 b/changes/fallbackdirs-2022-08-11
deleted file mode 100644
index 21200700ad..0000000000
--- a/changes/fallbackdirs-2022-08-11
+++ /dev/null
@@ -1,2 +0,0 @@
- o Minor features (fallbackdir):
- - Regenerate fallback directories generated on August 11, 2022.
diff --git a/changes/fallbackdirs-2022-11-10 b/changes/fallbackdirs-2022-11-10
deleted file mode 100644
index 64df9c5f10..0000000000
--- a/changes/fallbackdirs-2022-11-10
+++ /dev/null
@@ -1,2 +0,0 @@
- o Minor features (fallbackdir):
- - Regenerate fallback directories generated on November 10, 2022.
diff --git a/changes/fallbackdirs-2022-12-06 b/changes/fallbackdirs-2022-12-06
deleted file mode 100644
index 17daf63f53..0000000000
--- a/changes/fallbackdirs-2022-12-06
+++ /dev/null
@@ -1,2 +0,0 @@
- o Minor features (fallbackdir):
- - Regenerate fallback directories generated on December 06, 2022.
diff --git a/changes/fallbackdirs-2023-01-12 b/changes/fallbackdirs-2023-01-12
deleted file mode 100644
index e3788a16ae..0000000000
--- a/changes/fallbackdirs-2023-01-12
+++ /dev/null
@@ -1,2 +0,0 @@
- o Minor features (fallbackdir):
- - Regenerate fallback directories generated on January 12, 2023.
diff --git a/changes/fallbackdirs-2023-07-26 b/changes/fallbackdirs-2023-07-26
deleted file mode 100644
index 131d76339a..0000000000
--- a/changes/fallbackdirs-2023-07-26
+++ /dev/null
@@ -1,2 +0,0 @@
- o Minor features (fallbackdir):
- - Regenerate fallback directories generated on July 26, 2023.
diff --git a/changes/fallbackdirs-2023-08-30 b/changes/fallbackdirs-2023-08-30
new file mode 100644
index 0000000000..499fc8e168
--- /dev/null
+++ b/changes/fallbackdirs-2023-08-30
@@ -0,0 +1,2 @@
+ o Minor features (fallbackdir):
+ - Regenerate fallback directories generated on August 30, 2023.
diff --git a/changes/fallbackdirs-2023-09-25 b/changes/fallbackdirs-2023-09-25
new file mode 100644
index 0000000000..b5cd48d5d1
--- /dev/null
+++ b/changes/fallbackdirs-2023-09-25
@@ -0,0 +1,2 @@
+ o Minor features (fallbackdir):
+ - Regenerate fallback directories generated on September 25, 2023.
diff --git a/changes/geoip-2022-08-12 b/changes/geoip-2022-08-12
deleted file mode 100644
index e8f282db01..0000000000
--- a/changes/geoip-2022-08-12
+++ /dev/null
@@ -1,5 +0,0 @@
- 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.
diff --git a/changes/geoip-2022-12-06 b/changes/geoip-2022-12-06
deleted file mode 100644
index f96e833e63..0000000000
--- a/changes/geoip-2022-12-06
+++ /dev/null
@@ -1,3 +0,0 @@
- o Minor features (geoip data):
- - Update the geoip files to match the IPFire Location Database,
- as retrieved on 2022/12/06.
diff --git a/changes/geoip-2023-01-12 b/changes/geoip-2023-01-12
deleted file mode 100644
index 8378d34fbf..0000000000
--- a/changes/geoip-2023-01-12
+++ /dev/null
@@ -1,3 +0,0 @@
- o Minor features (geoip data):
- - Update the geoip files to match the IPFire Location Database,
- as retrieved on 2023/01/12.
diff --git a/changes/geoip-2023-07-26 b/changes/geoip-2023-07-26
deleted file mode 100644
index f8e4feb573..0000000000
--- a/changes/geoip-2023-07-26
+++ /dev/null
@@ -1,3 +0,0 @@
- o Minor features (geoip data):
- - Update the geoip files to match the IPFire Location Database,
- as retrieved on 2023/07/26.
diff --git a/changes/geoip-2022-08-11 b/changes/geoip-2023-08-30
index aad2392f1f..2238cbf788 100644
--- a/changes/geoip-2022-08-11
+++ b/changes/geoip-2023-08-30
@@ -1,3 +1,3 @@
o Minor features (geoip data):
- Update the geoip files to match the IPFire Location Database,
- as retrieved on 2022/08/11.
+ as retrieved on 2023/08/30.
diff --git a/changes/geoip-2022-11-10 b/changes/geoip-2023-09-25
index dce05f50c4..a6ec201381 100644
--- a/changes/geoip-2022-11-10
+++ b/changes/geoip-2023-09-25
@@ -1,3 +1,3 @@
o Minor features (geoip data):
- Update the geoip files to match the IPFire Location Database,
- as retrieved on 2022/11/10.
+ as retrieved on 2023/09/25.
diff --git a/changes/ip_bind_address_no_port b/changes/ip_bind_address_no_port
deleted file mode 100644
index 9c4f712a9e..0000000000
--- a/changes/ip_bind_address_no_port
+++ /dev/null
@@ -1,5 +0,0 @@
- o Minor features (relays):
- - Set the Linux-specific IP_BIND_ADDRESS_NO_PORT option on outgoing
- sockets, allowing relays using OutboundBindAddress to make more outgoing
- connections than ephemeral ports, as long as they are to separate
- destinations. Related to issue 40597; patch by Alex Xu (Hello71).
diff --git a/changes/issue40613 b/changes/issue40613
deleted file mode 100644
index 76434beba2..0000000000
--- a/changes/issue40613
+++ /dev/null
@@ -1,3 +0,0 @@
- o Code simplifications and refactoring:
- - Rely on actual error returned by the kernel when choosing what resource
- exhaustion to log. Fixes issue 40613; Fix on tor-0.4.6.1-alpha.
diff --git a/changes/ticket40194 b/changes/ticket40194
deleted file mode 100644
index 9f3a4833cf..0000000000
--- a/changes/ticket40194
+++ /dev/null
@@ -1,9 +0,0 @@
- o Minor feature (relay, metrics):
- - Add counters to the MetricsPort how many connections, per type, are
- currently opened and how many were created. Part of ticket 40194.
- - Add total number of streams seen by an Exit to the MetricsPort.
- - Add congestion control RTT reset counter to MetricsPort.
- - Add DoS defenses counter to MetricsPort.
- - Add relay flags from the consensus to the MetricsPort.
- - Add total number of opened circuits to MetricsPort.
- - Add traffic stats as in number of read/written bytes in total.
diff --git a/changes/ticket40604 b/changes/ticket40604
deleted file mode 100644
index ec24a46e66..0000000000
--- a/changes/ticket40604
+++ /dev/null
@@ -1,5 +0,0 @@
- o Major bugfixes (relay):
- - Remove OR connections btrack subsystem entries when the connections
- closes normally. Before this, we would only close it on error and thus
- leaking memory for each normal OR connections. Fixes bug 40604; bugfix
- on 0.4.0.1-alpha.
diff --git a/changes/ticket40623 b/changes/ticket40623
deleted file mode 100644
index d2a0e7eaad..0000000000
--- a/changes/ticket40623
+++ /dev/null
@@ -1,4 +0,0 @@
- o Major bugfixes (relay):
- - Stop sending TRUNCATED cell and instead close the circuits which sends a
- DESTROY cell so every relay in the circuit path can stop queuing cells.
- Fixes bug 40623; bugfix on 0.1.0.2-rc.
diff --git a/changes/ticket40648 b/changes/ticket40648
deleted file mode 100644
index a891e30204..0000000000
--- a/changes/ticket40648
+++ /dev/null
@@ -1,3 +0,0 @@
- o Code simplification and refactoring (bridges):
- - Remove unused code related to ExtPort connection ID. Fixes bug 40648;
- bugfix on 0.3.5.1-alpha.
diff --git a/changes/ticket40649 b/changes/ticket40649
deleted file mode 100644
index 28df58f106..0000000000
--- a/changes/ticket40649
+++ /dev/null
@@ -1,4 +0,0 @@
- o Minor bugfixes (relay):
- - Do not propagate either forward or backward a DESTROY remote reason when
- closing a circuit so to avoid a possible side channel. Fixes bug 40649;
- bugfix on 0.1.2.4-alpha.
diff --git a/changes/ticket40652 b/changes/ticket40652
deleted file mode 100644
index ff9f4d0591..0000000000
--- a/changes/ticket40652
+++ /dev/null
@@ -1,10 +0,0 @@
- o Minor features (dirauth):
- - Add an AuthDirVoteGuard torrc option that can allow authorities to
- assign the Guard flag to the given fingerprints/country code/IPs. This
- is a needed feature mostly for defense purposes in case a DoS hits the
- network and relay start losing the Guard flags too fast.
- - Make UPTIME_TO_GUARANTEE_STABLE, MTBF_TO_GUARANTEE_STABLE,
- TIME_KNOWN_TO_GUARANTEE_FAMILIAR WFU_TO_GUARANTEE_GUARD tunable from
- torrc.
- - Add a torrc option to control the Guard flag bandwidth threshold
- percentile. Closes ticket 40652.
diff --git a/changes/ticket40663 b/changes/ticket40663
deleted file mode 100644
index 3992d8e2b5..0000000000
--- a/changes/ticket40663
+++ /dev/null
@@ -1,3 +0,0 @@
- o Minor bugfixes (authorities, sandbox):
- - Allow to write file my-consensus-<flavor-name> to disk when sandbox is
- activated. Fixes bug 40663; bugfix on 0.3.5.1-alpha.
diff --git a/changes/ticket40664 b/changes/ticket40664
deleted file mode 100644
index 729b6ff02a..0000000000
--- a/changes/ticket40664
+++ /dev/null
@@ -1,3 +0,0 @@
- o Minor feature (authority):
- - Reject 0.4.6.x series at the authority level. Closes ticket 40664.
-
diff --git a/changes/ticket40674 b/changes/ticket40674
deleted file mode 100644
index b371cafcf0..0000000000
--- a/changes/ticket40674
+++ /dev/null
@@ -1,3 +0,0 @@
- 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.
diff --git a/changes/ticket40680 b/changes/ticket40680
deleted file mode 100644
index 1383844969..0000000000
--- a/changes/ticket40680
+++ /dev/null
@@ -1,6 +0,0 @@
- o Minor feature (relay, DoS):
- - Apply circuit creation anti-DoS defenses if the outbound circuit max cell
- queue size is reached too many times. This introduces two new consensus
- parameters to control the queue size limit and number of times allowed to
- go over that limit. Close ticket 40680.
-
diff --git a/changes/ticket40683 b/changes/ticket40683
deleted file mode 100644
index 6df078ebae..0000000000
--- a/changes/ticket40683
+++ /dev/null
@@ -1,6 +0,0 @@
- o Minor feature (Mac and iOS build):
- - Change how combine_libs works on Darwin like platforms to
- make sure we don't include any `__.SYMDEF` and `__.SYMDEF SORTED`
- symbols on the archive before we repack and run ${RANLIB} on the
- archive. This fixes a build issue with recent Xcode versions on
- Mac Silicon and iOS. Closes ticket 40683.
diff --git a/changes/ticket40687 b/changes/ticket40687
deleted file mode 100644
index e96119cf49..0000000000
--- a/changes/ticket40687
+++ /dev/null
@@ -1,2 +0,0 @@
- o Directory authority changes (dizum):
- - Change dizum IP address. Closes ticket 40687.
diff --git a/changes/ticket40688 b/changes/ticket40688
deleted file mode 100644
index 79350cb836..0000000000
--- a/changes/ticket40688
+++ /dev/null
@@ -1,3 +0,0 @@
- o Directory authority changes (Faravahar):
- - Remove Faravahar until its operator, Sina, set it back up online outside
- of Team Cymru network. Closes ticket 40688.
diff --git a/changes/ticket40692 b/changes/ticket40692
deleted file mode 100644
index 8405486115..0000000000
--- a/changes/ticket40692
+++ /dev/null
@@ -1,3 +0,0 @@
- o Minor bugfixes (onion service client):
- - A collapsing onion service circuit should be seen as an "unreachable"
- error so it can be retried. Fixes bug 40692; bugfix on 0.3.5.1-alpha.
diff --git a/changes/ticket40694 b/changes/ticket40694
deleted file mode 100644
index f17639cc27..0000000000
--- a/changes/ticket40694
+++ /dev/null
@@ -1,5 +0,0 @@
- o Major bugfixes (onion service):
- - Set a much higher circuit build timeout for opened client rendezvous
- circuit. Before this, tor would time them out very quickly leading to many
- unnecessary retries and thus more load on the network. Fixes bug 40694;
- bugfix on 0.3.5.1-alpha.
diff --git a/changes/ticket40696 b/changes/ticket40696
deleted file mode 100644
index a2c09f6a83..0000000000
--- a/changes/ticket40696
+++ /dev/null
@@ -1,3 +0,0 @@
- o Minor bugfixes (onion service):
- - Make the service retry a rendezvous if the circuit is being repurposed for
- measurements. Fixes bug 40696; bugfix on 0.3.5.1-alpha.
diff --git a/changes/ticket40703 b/changes/ticket40703
deleted file mode 100644
index f005f8f851..0000000000
--- a/changes/ticket40703
+++ /dev/null
@@ -1,4 +0,0 @@
- o Minor feature (performance):
- - Bump the maximum amount of CPU to use from 16 to 128. Note that NumCPUs
- torrc option overrides this hardcoded maximum. Fixes bug 40703; bugfix on
- 0.3.5.1-alpha.
diff --git a/changes/ticket40704 b/changes/ticket40704
deleted file mode 100644
index b1a83488da..0000000000
--- a/changes/ticket40704
+++ /dev/null
@@ -1,6 +0,0 @@
- o Minor feature (relay):
- - Two new consensus parameters are added to control the wait time in queue
- of the onionskins. One of them is the torrc MaxOnionQueueDelay options
- which supersedes the consensus parameter. Closes ticket 40704.
- - Change a hardcoded value for the maximum of per CPU tasks into a
- consensus parameter.
diff --git a/changes/ticket40708 b/changes/ticket40708
deleted file mode 100644
index 1c4a044a0b..0000000000
--- a/changes/ticket40708
+++ /dev/null
@@ -1,3 +0,0 @@
- o Minor feature (metrics):
- - Add various congestion control counters to the MetricsPort. Closes ticket
- 40708.
diff --git a/changes/ticket40719 b/changes/ticket40719
deleted file mode 100644
index eec84dce0f..0000000000
--- a/changes/ticket40719
+++ /dev/null
@@ -1,3 +0,0 @@
- o Minor bugfixes (cpuworker, relay):
- - Fix an off by one overload calculation on the number of CPUs being used by
- our thread pool. Fixes bug 40719; bugfix on 0.3.5.1-alpha.
diff --git a/changes/ticket40722 b/changes/ticket40722
deleted file mode 100644
index a9a9f520a9..0000000000
--- a/changes/ticket40722
+++ /dev/null
@@ -1,5 +0,0 @@
- 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.
diff --git a/changes/ticket40724 b/changes/ticket40724
deleted file mode 100644
index aeb6f9ae8b..0000000000
--- a/changes/ticket40724
+++ /dev/null
@@ -1,3 +0,0 @@
- o Minor feature (Congestion control metrics):
- - Add additional metricsport relay metrics for congestion control.
- Closes ticket 40724.
diff --git a/changes/ticket40727 b/changes/ticket40727
deleted file mode 100644
index ce462481f4..0000000000
--- a/changes/ticket40727
+++ /dev/null
@@ -1,3 +0,0 @@
- o Minor bugfixes (relay, metrics):
- - Fix typo in a congestion control label on the MetricsPort. Fixes bug
- 40727; bugfix on 0.4.7.12.
diff --git a/changes/ticket40729 b/changes/ticket40729
deleted file mode 100644
index 1c2d43d14f..0000000000
--- a/changes/ticket40729
+++ /dev/null
@@ -1,3 +0,0 @@
- o Minor bugfixes (sandbox, authority):
- - With the sandbox enabled, allow to write "my-consensus-{ns|microdesc}" and
- to rename them as well. Fixes bug 40729; bugfix on 0.3.5.1-alpha.
diff --git a/changes/ticket40730 b/changes/ticket40730
deleted file mode 100644
index f6d4c9de3b..0000000000
--- a/changes/ticket40730
+++ /dev/null
@@ -1,5 +0,0 @@
- 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.
diff --git a/changes/ticket40739 b/changes/ticket40739
index d65c143c56..f60bfc5d87 100644
--- a/changes/ticket40739
+++ b/changes/ticket40739
@@ -1,6 +1,3 @@
- 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 features (debugging, compression):
+ - Log the input and output buffer sizes when we detect a potential
+ compression bomb. Diagnostic for ticket 40739.
diff --git a/changes/ticket40741 b/changes/ticket40741
deleted file mode 100644
index 2a9f72489d..0000000000
--- a/changes/ticket40741
+++ /dev/null
@@ -1,2 +0,0 @@
- o Minor feature (lzma):
- - Fix compiler warnings for liblzma >= 5.3.1. Closes ticket 40741.
diff --git a/changes/ticket40745 b/changes/ticket40745
deleted file mode 100644
index 988dbc5f33..0000000000
--- a/changes/ticket40745
+++ /dev/null
@@ -1,3 +0,0 @@
- 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.
diff --git a/changes/ticket40753 b/changes/ticket40753
deleted file mode 100644
index c5dc76b006..0000000000
--- a/changes/ticket40753
+++ /dev/null
@@ -1,5 +0,0 @@
- 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.
diff --git a/changes/ticket40799 b/changes/ticket40799
deleted file mode 100644
index 4e2afe6e4b..0000000000
--- a/changes/ticket40799
+++ /dev/null
@@ -1,6 +0,0 @@
- 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.
-
- o Minor feature (CI):
- - Update CI to use Debian Bullseye for runners.
diff --git a/changes/ticket40824 b/changes/ticket40824
deleted file mode 100644
index a4d389ddc2..0000000000
--- a/changes/ticket40824
+++ /dev/null
@@ -1,4 +0,0 @@
- o Minor bugfixes (compilation):
- - Fix all -Werror=enum-int-mismatch warnings. No behavior change. Fixes bug
- 40824; bugfix on 0.3.5.1-alpha.
-
diff --git a/changes/ticket40843 b/changes/ticket40843
new file mode 100644
index 0000000000..3af63a9164
--- /dev/null
+++ b/changes/ticket40843
@@ -0,0 +1,3 @@
+ 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. \ No newline at end of file
diff --git a/changes/ticket40844 b/changes/ticket40844
new file mode 100644
index 0000000000..73d3bb2b76
--- /dev/null
+++ b/changes/ticket40844
@@ -0,0 +1,4 @@
+ 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. \ No newline at end of file
diff --git a/changes/ticket40848 b/changes/ticket40848
new file mode 100644
index 0000000000..a50a9a028f
--- /dev/null
+++ b/changes/ticket40848
@@ -0,0 +1,4 @@
+ 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.
diff --git a/changes/ticket40859 b/changes/ticket40859
deleted file mode 100644
index a6cdaa9df7..0000000000
--- a/changes/ticket40859
+++ /dev/null
@@ -1,4 +0,0 @@
- 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.
diff --git a/configure.ac b/configure.ac
index 64b1e61459..2a230d4892 100644
--- a/configure.ac
+++ b/configure.ac
@@ -4,7 +4,7 @@ dnl Copyright (c) 2007-2019, The Tor Project, Inc.
dnl See LICENSE for licensing information
AC_PREREQ([2.63])
-AC_INIT([tor],[0.4.7.15-dev])
+AC_INIT([tor],[0.4.8.8-dev])
AC_CONFIG_SRCDIR([src/app/main/tor_main.c])
AC_CONFIG_MACRO_DIR([m4])
@@ -18,7 +18,7 @@ AC_DEFINE_UNQUOTED([CONFIG_FLAGS], ["$configure_flags"], [Flags passed to config
# 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-09-18"], # for 0.4.7.15-dev
+AC_DEFINE(APPROX_RELEASE_DATE, ["2023-09-25"], # for 0.4.8.8-dev
[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 @@ if test "x$PKG_CONFIG_PATH" = "x" && test "x$prefix" != "xNONE" && test "$host"
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 Tor modules options. These options are namespaced with --disable-module-XXX
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_define(MODULES, relay dirauth dircache)
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 @@ AM_COND_IF(BUILD_MODULE_DIRCACHE,
[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 @@ AM_COND_IF(BUILD_MODULE_DIRAUTH,
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], [
@@ -1022,7 +1054,7 @@ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
AC_MSG_CHECKING([for OpenSSL < 1.0.1])
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
#include <openssl/opensslv.h>
-#if !defined(LIBRESSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER < 0x1000100fL
+#if OPENSSL_VERSION_NUMBER < 0x1000100fL
#error "too old"
#endif
]], [[]])],
@@ -2357,7 +2389,6 @@ if test "x$enable_gcc_warnings_advisory" != "xno"; then
-Wexplicit-ownership-type
-Wextern-initializer
-Wextra
- -Wextra-semi
-Wextra-tokens
-Wflexible-array-extensions
-Wfloat-conversion
@@ -2505,6 +2536,8 @@ if test "x$enable_gcc_warnings_advisory" != "xno"; then
[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 +2600,17 @@ if test "$enable_coverage" = "yes" && test "$have_clang" = "no"; then
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 +2689,7 @@ PPRINT_SUBTITLE([Build Features])
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 +2758,22 @@ PPRINT_PROP_BOOL([Fragile Hardening (--enable-fragile-hardening, dev only)], $va
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(<name>)" 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 --git a/contrib/client-tools/torify b/contrib/client-tools/torify
index ac4c9b5c7f..94640c0faf 100755
--- a/contrib/client-tools/torify
+++ b/contrib/client-tools/torify
@@ -37,25 +37,8 @@ case $1 in -v|--verbose)
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 --git a/contrib/win32build/tor-mingw.nsi.in b/contrib/win32build/tor-mingw.nsi.in
index 4d6ec37c51..022e383baf 100644
--- a/contrib/win32build/tor-mingw.nsi.in
+++ b/contrib/win32build/tor-mingw.nsi.in
@@ -8,13 +8,13 @@
!include "LogicLib.nsh"
!include "FileFunc.nsh"
!insertmacro GetParameters
-!define VERSION "0.4.7.15-dev"
+!define VERSION "0.4.8.8-dev"
!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 @@ VIProductVersion "${VERSION}"
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 @@ SectionEnd
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 --git a/contrib/win32build/tor.nsi.in b/contrib/win32build/tor.nsi.in
index dd24df454c..2d8c2b9adf 100644
--- a/contrib/win32build/tor.nsi.in
+++ b/contrib/win32build/tor.nsi.in
@@ -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 --git a/doc/HACKING/ReleasingTor.md b/doc/HACKING/ReleasingTor.md
index a32bb10dad..af3805f38e 100644
--- a/doc/HACKING/ReleasingTor.md
+++ b/doc/HACKING/ReleasingTor.md
@@ -53,6 +53,12 @@ been merged upstream.
(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 @@ Steps are:
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 @@ do the following:
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).
+
+### New Stable
- 2. Add the new version in `./scripts/ci/ci-driver.sh`.
+ 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.
- 3. Forward port the ChangeLog and ReleaseNotes into main branch. Remove any
- change logs of stable releases in ReleaseNotes.
+ 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 --git a/doc/HACKING/Rust.md b/doc/HACKING/Rust.md
new file mode 100644
index 0000000000..a52807e540
--- /dev/null
+++ b/doc/HACKING/Rust.md
@@ -0,0 +1,43 @@
+# Rust support in C Tor
+
+The [Arti project](https://gitlab.torproject.org/tpo/core/arti) is the team's
+ongoing effort to write a pure-Rust implementation of Tor.
+
+Arti is not yet feature complete but it's in active development. That's where
+you want to go if you're interested in Tor and Rust together.
+
+This document describes something with niche interest: the C implementation of
+Tor can expose Rust crates which are used for internal testing, benchmarking,
+comparison, fuzzing, and so on. This could be useful for comparing the C
+implementation against new Rust implementations, or for simply using Rust
+tooling for writing tests against C.
+
+## Crates
+
+Right now we are only using this mechanism for one crate:
+
+- `tor-c-equix` -- Wraps the `src/ext/equix` module,
+ containing Equi-X and HashX algorithms.
+
+## Stability
+
+This is not a stable API and we have no plans to develop a stable Rust interface
+to the C implementation of Tor.
+
+## Files
+
+We use only a few of the standard Rust file types in order to build our
+wrapper crates. Here's a summary:
+
+- `Cargo.toml` in the repository root defines a Cargo *workspace*. It will
+ list all subdirectories that contain crates with their own `Cargo.toml`.
+- A per-crate `Cargo.toml` defines metadata and dependencies. These crates
+ should all be marked `publish = false`.
+- `build.rs` implements a simple build system that does not interact with
+ autotools. It uses the `cc` and `bindgen` crates to get from `.c`/`.h`
+ files to a static library and matching auto-generated bindings. Prefer to
+ include bindgen wrapper headers inline within `build.rs` instead of adding
+ `.h` files that are only used by the Rust bindings.
+- `lib.rs` publishes the low-level `ffi` interface produced with `cc` and
+ `bindgen`. This is also where we can add any wrappers or additions we want
+ for making the Rust API more convenient.
diff --git a/doc/HACKING/WritingTests.md b/doc/HACKING/WritingTests.md
index 129b79a854..463a4ad4af 100644
--- a/doc/HACKING/WritingTests.md
+++ b/doc/HACKING/WritingTests.md
@@ -336,7 +336,7 @@ glass-box one is one you implement while looking at how the function is
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 --git a/doc/asciidoc-helper.sh b/doc/asciidoc-helper.sh
index 98e216e68a..a3e2f8f9bf 100755
--- a/doc/asciidoc-helper.sh
+++ b/doc/asciidoc-helper.sh
@@ -12,7 +12,7 @@ if [ $# != 3 ]; then
exit 1
fi
-SOURCE_DATE_EPOCH="$(git show --no-patch --format='%ct')"
+SOURCE_DATE_EPOCH="$(git -C "$(dirname "$0")" show --no-patch --format='%ct')"
export SOURCE_DATE_EPOCH
output=$3
diff --git a/doc/building-tor-msvc.txt b/doc/building-tor-msvc.txt
deleted file mode 100644
index dbc644d172..0000000000
--- a/doc/building-tor-msvc.txt
+++ /dev/null
@@ -1,122 +0,0 @@
-Building Tor with MSVC.
-=======================
-
-NOTE: This is not the preferred method for building Tor on windows: we use
-mingw for our packages.
-
-Last updated 9 September 2014.
-
-
-Requirements:
--------------
-
- * Visual Studio 2010
- https://go.microsoft.com/fwlink/?LinkId=323467
- * CMake 2.8.12.2
- https://www.cmake.org/download/
- * Perl 5.16
- https://www.activestate.com/activeperl/downloads
- * Latest stable OpenSSL tarball
- https://www.openssl.org/source/
- * Latest stable zlib tarball
- https://zlib.net/
- * Latest stable libevent Libevent tarball
- https://github.com/libevent/libevent/releases
-
-Make sure you check signatures for all these packages.
-
-Steps:
-------
-
-Building OpenSSL from source as a shared library:
-
- cd <openssl source dir>
- perl Configure VC-WIN32
- perl util\mkfiles.pl >MINFO
- perl util\mk1mf.pl no-asm dll VC-WIN32 >32dll.mak
- perl util\mkdef.pl 32 libeay > ms\libeay32.def
- perl util\mkdef.pl 32 ssleay > ms\ssleay32.def
- nmake -f 32dll.mak
-
-Making OpenSSL final package:
-
- Create <openssl final package dir>, I'd recommend using a name like <openssl
- source dir>-vc10.
-
- Copy the following directories and files to their respective locations
- <openssl source dir>\inc32\openssl => <openssl final package dir>\include\openssl
- <openssl source dir>\out32dll\libeay32.lib => <openssl final package dir>\lib\libeay32.lib
- <openssl source dir>\out32dll\ssleay32.lib => <openssl final package dir>\lib\ssleay32.lib
- <openssl source dir>\out32dll\libeay32.dll => <openssl final package dir>\bin\libeay32.dll
- <openssl source dir>\out32dll\openssl.exe => <openssl final package dir>\bin\openssl.exe
- <openssl source dir>\out32dll\ssleay32.dll => <openssl final package dir>\bin\ssleay32.dll
-
-Building Zlib from source:
-
- cd <zlib source dir>
- nmake -f win32/Makefile.msc
-
-Building libevent:
-
- cd <libevent source dir>
- mkdir build && cd build
- SET OPENSSL_ROOT_DIR=<openssl final package dir>
- cmake -G "NMake Makefiles" .. -DCMAKE_BUILD_TYPE:STRING=RelWithDebInfo -DCMAKE_C_FLAGS_RELWITHDEBINFO:STRING="/MT /Zi /O2 /Ob1 /D NDEBUG" -DZLIB_LIBRARY:FILEPATH="<zlib source dir>\zdll.lib" -DZLIB_INCLUDE_DIR:PATH="<zlib source dir>"
- nmake event
-
-Building Tor:
-
- Create a dir above tor source dir named build-alpha and two subdirs include
- and lib.
-
- Your build tree should now be similar to this one:
- * build-alpha
- - include
- - lib
- * <libevent source dir>
- - build
- - cmake
- - ...
- * <openssl source dir>
- - ...
- - ms
- - util
- - ...
- * <openssl final package dir>
- - bin
- - include
- - lib
- * <tor source dir>
- - ...
- - src
- - ...
- * <zlib source dir>
- - ...
- - win32
- - ...
-
- Copy the following dirs and files to the following locations:
- <openssl final package dir>\include\openssl => build-alpha\include\openssl
- <libevent source dir>\include => build-alpha\include
- <libevent source dir>\WIN32-Code\nmake\event2 => build-alpha\include\event2
- <zlib source dir>\z*.h => build-alpha\include\z*.h
-
- Now copy the following files to the following locations and rename them
- according new names:
-
- <libevent source dir>\build\lib\event.lib => build-alpha\lib\libevent.lib
- <openssl final package dir>\lib\libeay32.lib => build-alpha\lib\libcrypto.lib
- <openssl final package dir>\lib\ssleay32.lib => build-alpha\lib\libssl.lib
- <zlib source dir>\zdll.lib => build-alpha\lib\libz.lib
-
- And we are now ready for the build process:
-
- cd <tor source dir>
- nmake -f Makefile.nmake
-
- After the above process is completed there should be a tor.exe in <tor
- source dir>\src\or
-
- Copy tor.exe to desired location and also copy zlib1.dll, libeay32.dll and
- ssleay32.dll from built zlib and openssl packages
-
diff --git a/doc/include.am b/doc/include.am
index d10f380e7f..7570978ddb 100644
--- a/doc/include.am
+++ b/doc/include.am
@@ -56,10 +56,10 @@ EXTRA_DIST+= doc/asciidoc-helper.sh \
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 --git a/doc/man/tor.1.txt b/doc/man/tor.1.txt
index 3672444c5d..1589809b1a 100644
--- a/doc/man/tor.1.txt
+++ b/doc/man/tor.1.txt
@@ -335,7 +335,7 @@ forward slash (/) in the configuration file and on the command line.
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 +348,19 @@ forward slash (/) in the configuration file and on the command line.
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 +873,7 @@ forward slash (/) in the configuration file and on the command line.
\_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 +883,7 @@ forward slash (/) in the configuration file and on the command line.
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,
@@ -1172,7 +1187,7 @@ The following options are useful only for clients (that is, if
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
@@ -3013,14 +3028,14 @@ Denial of Service mitigation subsystem described above.
(Default: auto)
-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.
+For onion services, mitigations are a work in progress and multiple options
+are currently available.
-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.
The following options are per onion service:
@@ -3074,6 +3089,51 @@ 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]] **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 <<opt-list-modules,`--list-modules`>>, these proof of work options
+have no effect unless the "`pow`" module is enabled at compile time.
== DIRECTORY AUTHORITY SERVER OPTIONS
@@ -3532,7 +3592,7 @@ Service side:
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 +3648,6 @@ The following options are used for running a testing Tor network.
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
diff --git a/m4/ax_check_compile_flag.m4 b/m4/ax_check_compile_flag.m4
new file mode 100644
index 0000000000..95df39679e
--- /dev/null
+++ b/m4/ax_check_compile_flag.m4
@@ -0,0 +1,51 @@
+ # Copyright (c) 2008 Guido U. Draheim <guidod@gmx.de>
+ # Copyright (c) 2011 Maarten Bosmans <mkbosmans@gmail.com>
+ #
+ # This program is free software: you can redistribute it and/or modify it
+ # under the terms of the GNU General Public License as published by the
+ # Free Software Foundation, either version 3 of the License, or (at your
+ # option) any later version.
+ #
+ # This program is distributed in the hope that it will be useful, but
+ # WITHOUT ANY WARRANTY; without even the implied warranty of
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+ # Public License for more details.
+ #
+ # You should have received a copy of the GNU General Public License along
+ # with this program. If not, see <https://www.gnu.org/licenses/>.
+ #
+ # As a special exception, the respective Autoconf Macro's copyright owner
+ # gives unlimited permission to copy, distribute and modify the configure
+ # scripts that are the output of Autoconf when processing the Macro. You
+ # need not follow the terms of the GNU General Public License when using
+ # or distributing such scripts, even though portions of the text of the
+ # Macro appear in them. The GNU General Public License (GPL) does govern
+ # all other use of the material that constitutes the Autoconf Macro.
+ #
+ # This special exception to the GPL applies to versions of the Autoconf
+ # Macro released by the Autoconf Archive. When you make and distribute a
+ # modified version of the Autoconf Macro, you may extend this special
+ # exception to the GPL to apply to your modified version as well.
+ # 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 5
+ #serial 6
+
+ 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 _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 --git a/scripts/ci/ci-driver.sh b/scripts/ci/ci-driver.sh
index 6ab8b67a77..15eab04d41 100755
--- a/scripts/ci/ci-driver.sh
+++ b/scripts/ci/ci-driver.sh
@@ -37,6 +37,7 @@ ALL_BUGS_ARE_FATAL="${ALL_BUGS_ARE_FATAL:-no}"
DISABLE_DIRAUTH="${DISABLE_DIRAUTH:-no}"
DISABLE_RELAY="${DISABLE_RELAY:-no}"
NSS="${NSS:-no}"
+GPL="${GPL:-no}"
# Options for which tests to run. All should be yes/no.
CHECK="${CHECK:-yes}"
@@ -200,6 +201,7 @@ yes_or_no ALL_BUGS_ARE_FATAL
yes_or_no DISABLE_DIRAUTH
yes_or_no DISABLE_RELAY
yes_or_no NSS
+yes_or_no GPL
yes_or_no RUN_STAGE_CONFIGURE
yes_or_no RUN_STAGE_BUILD
@@ -262,6 +264,9 @@ fi
if [[ "$NSS" == "yes" ]]; then
configure_options+=("--enable-nss")
fi
+if [[ "$GPL" == "yes" ]]; then
+ configure_options+=("--enable-gpl")
+fi
#############################################################################
# Tell the user about our versions of different tools and packages.
@@ -285,6 +290,24 @@ fi
TOR_VERSION=$(grep -m 1 AC_INIT "${CI_SRCDIR}"/configure.ac | sed -e 's/.*\[//; s/\].*//;')
+# Use variables like these when we need to behave differently depending on
+# Tor version. Only create the variables we need.
+TOR_VER_AT_LEAST_043=no
+TOR_VER_AT_LEAST_044=no
+
+# These are the currently supported Tor versions; no need to work with anything
+# ancient in this script.
+case "$TOR_VERSION" in
+ 0.4.7.*)
+ TOR_VER_AT_LEAST_043=yes
+ TOR_VER_AT_LEAST_044=yes
+ ;;
+ 0.4.8.*)
+ TOR_VER_AT_LEAST_043=yes
+ TOR_VER_AT_LEAST_044=yes
+ ;;
+esac
+
#############################################################################
# Make sure the directories are all there.
@@ -376,10 +399,14 @@ FAILED_TESTS=""
if [[ "${DOXYGEN}" = 'yes' ]]; then
start_section Doxygen
- if runcmd make doxygen; then
- hooray "make doxygen has succeeded."
+ if [[ "${TOR_VER_AT_LEAST_043}" = 'yes' ]]; then
+ if runcmd make doxygen; then
+ hooray "make doxygen has succeeded."
+ else
+ FAILED_TESTS="${FAILED_TESTS} doxygen"
+ fi
else
- FAILED_TESTS="${FAILED_TESTS} doxygen"
+ skipping "make doxygen: doxygen is broken for Tor < 0.4.3"
fi
end_section Doxygen
fi
@@ -431,26 +458,30 @@ if [[ "${STEM}" = "yes" ]]; then
# 0.3.5 and onward have now disabled onion service v2 so we need to exclude
# these Stem tests from now on.
EXCLUDE_TESTS="--exclude-test control.controller.test_ephemeral_hidden_services_v2 --exclude-test control.controller.test_hidden_services_conf --exclude-test control.controller.test_with_ephemeral_hidden_services_basic_auth --exclude-test control.controller.test_without_ephemeral_hidden_services --exclude-test control.controller.test_with_ephemeral_hidden_services_basic_auth_no_credentials --exclude-test control.controller.test_with_detached_ephemeral_hidden_services --exclude-test control.controller.test_with_invalid_ephemeral_hidden_service_port --exclude-test control.controller.test_ephemeral_hidden_services_v3"
- # XXXX This should probably be part of some test-stem make target.
-
- # Disable the check around EXCLUDE_TESTS that requires double quote. We
- # need it to be expanded.
- # shellcheck disable=SC2086
- if runcmd timelimit -p -t 520 -s USR1 -T 30 -S ABRT \
- python3 "${STEM_PATH}/run_tests.py" \
- --tor src/app/tor \
- --integ --test control.controller \
- $EXCLUDE_TESTS \
- --test control.base_controller \
- --test process \
- --log TRACE \
- --log-file stem.log ; then
- hooray "Stem tests have succeeded"
+ if [[ "${TOR_VER_AT_LEAST_044}" = 'yes' ]]; then
+ # XXXX This should probably be part of some test-stem make target.
+
+ # Disable the check around EXCLUDE_TESTS that requires double quote. We
+ # need it to be expanded.
+ # shellcheck disable=SC2086
+ if runcmd timelimit -p -t 520 -s USR1 -T 30 -S ABRT \
+ python3 "${STEM_PATH}/run_tests.py" \
+ --tor src/app/tor \
+ --integ --test control.controller \
+ $EXCLUDE_TESTS \
+ --test control.base_controller \
+ --test process \
+ --log TRACE \
+ --log-file stem.log ; then
+ hooray "Stem tests have succeeded"
+ else
+ error "Stem output:"
+ runcmd tail -1000 "${STEM_PATH}"/test/data/tor_log
+ runcmd grep -v "SocketClosed" stem.log | tail -1000
+ FAILED_TESTS="${FAILED_TESTS} stem"
+ fi
else
- error "Stem output:"
- runcmd tail -1000 "${STEM_PATH}"/test/data/tor_log
- runcmd grep -v "SocketClosed" stem.log | tail -1000
- FAILED_TESTS="${FAILED_TESTS} stem"
+ skipping "Stem: broken with <= 0.4.3. See bug tor#40077"
fi
end_section "Stem"
fi
diff --git a/scripts/git/git-list-tor-branches.sh b/scripts/git/git-list-tor-branches.sh
index dd3cf154b4..61e7b4a947 100755
--- a/scripts/git/git-list-tor-branches.sh
+++ b/scripts/git/git-list-tor-branches.sh
@@ -143,15 +143,12 @@ finish() {
# List of all branches. These must be in order, from oldest to newest, with
# maint before release.
-branch maint-0.4.5
-branch release-0.4.5
-
-branch maint-0.4.6
-branch release-0.4.6
-
branch maint-0.4.7
branch release-0.4.7
+branch maint-0.4.8
+branch release-0.4.8
+
branch main
finish
diff --git a/scripts/git/git-pull-all.sh b/scripts/git/git-pull-all.sh
index bbe2576d8e..12a0372f73 100755
--- a/scripts/git/git-pull-all.sh
+++ b/scripts/git/git-pull-all.sh
@@ -168,19 +168,6 @@ function fetch_origin
fi
}
-# Fetch tor-gitlab pull requests. No arguments.
-function fetch_tor_gitlab
-{
- local cmd="git fetch tor-gitlab"
- printf "%s Fetching tor-gitlab..." "$MARKER"
- if [ $DRY_RUN -eq 0 ]; then
- msg=$( eval "$cmd" 2>&1 )
- validate_ret $? "$msg"
- else
- printf "\\n %s\\n" "${IWTH}$cmd${CNRM}"
- fi
-}
-
###############
# Entry point #
###############
@@ -188,10 +175,7 @@ function fetch_tor_gitlab
# Get into our origin repository.
goto_repo "$ORIGIN_PATH"
-# First, fetch tor-gitlab
-fetch_tor_gitlab
-
-# Then, fetch the origin.
+# Fetch the origin.
fetch_origin
# Go over all configured worktree.
diff --git a/scripts/maint/checkOptionDocs.pl.in b/scripts/maint/checkOptionDocs.pl.in
index 2d4a7884f5..d2c2a838d6 100644
--- a/scripts/maint/checkOptionDocs.pl.in
+++ b/scripts/maint/checkOptionDocs.pl.in
@@ -41,9 +41,16 @@ loadTorrc("@abs_top_srcdir@/src/config/torrc.sample.in", \%torrcSampleOptions);
my $considerNextLine = 0;
open(F, "@abs_top_srcdir@/doc/man/tor.1.txt") or die;
while (<F>) {
- 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 --git a/scripts/maint/geoip/geoip-db-tool/Cargo.lock b/scripts/maint/geoip/geoip-db-tool/Cargo.lock
deleted file mode 100644
index ba610d4fc3..0000000000
--- a/scripts/maint/geoip/geoip-db-tool/Cargo.lock
+++ /dev/null
@@ -1,110 +0,0 @@
-# This file is automatically @generated by Cargo.
-# It is not intended for manual editing.
-[[package]]
-name = "argh"
-version = "0.1.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "91792f088f87cdc7a2cfb1d617fa5ea18d7f1dc22ef0e1b5f82f3157cdc522be"
-dependencies = [
- "argh_derive",
- "argh_shared",
-]
-
-[[package]]
-name = "argh_derive"
-version = "0.1.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c4eb0c0c120ad477412dc95a4ce31e38f2113e46bd13511253f79196ca68b067"
-dependencies = [
- "argh_shared",
- "heck",
- "proc-macro2",
- "quote",
- "syn",
-]
-
-[[package]]
-name = "argh_shared"
-version = "0.1.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "781f336cc9826dbaddb9754cb5db61e64cab4f69668bd19dcc4a0394a86f4cb1"
-
-[[package]]
-name = "geoip-db-tool"
-version = "0.1.0"
-dependencies = [
- "argh",
- "ipnetwork",
- "rangemap",
-]
-
-[[package]]
-name = "heck"
-version = "0.3.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "87cbf45460356b7deeb5e3415b5563308c0a9b057c85e12b06ad551f98d0a6ac"
-dependencies = [
- "unicode-segmentation",
-]
-
-[[package]]
-name = "ipnetwork"
-version = "0.17.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "02c3eaab3ac0ede60ffa41add21970a7df7d91772c03383aac6c2c3d53cc716b"
-dependencies = [
- "serde",
-]
-
-[[package]]
-name = "proc-macro2"
-version = "1.0.24"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71"
-dependencies = [
- "unicode-xid",
-]
-
-[[package]]
-name = "quote"
-version = "1.0.9"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7"
-dependencies = [
- "proc-macro2",
-]
-
-[[package]]
-name = "rangemap"
-version = "0.1.10"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "90531bef860f96441c4cb74a1e43c281cd1366143928f944546ef0b1c60392b0"
-
-[[package]]
-name = "serde"
-version = "1.0.123"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "92d5161132722baa40d802cc70b15262b98258453e85e5d1d365c757c73869ae"
-
-[[package]]
-name = "syn"
-version = "1.0.60"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c700597eca8a5a762beb35753ef6b94df201c81cca676604f547495a0d7f0081"
-dependencies = [
- "proc-macro2",
- "quote",
- "unicode-xid",
-]
-
-[[package]]
-name = "unicode-segmentation"
-version = "1.7.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bb0d2e7be6ae3a5fa87eed5fb451aff96f2573d2694942e40543ae0bbe19c796"
-
-[[package]]
-name = "unicode-xid"
-version = "0.2.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564"
diff --git a/scripts/maint/geoip/geoip-db-tool/src/db.rs b/scripts/maint/geoip/geoip-db-tool/src/db.rs
index 316182d823..3d631a3f98 100644
--- a/scripts/maint/geoip/geoip-db-tool/src/db.rs
+++ b/scripts/maint/geoip/geoip-db-tool/src/db.rs
@@ -13,9 +13,9 @@ where
}
pub enum AnyBlock {
- NetBlock(NetBlock),
- AsBlock(AsBlock),
- OtherBlock,
+ Net(NetBlock),
+ As(AsBlock),
+ Other,
}
impl<I> BlockReader<I>
@@ -50,13 +50,13 @@ where
fn get_block(&mut self) -> Option<std::io::Result<AnyBlock>> {
let mut kv = HashMap::new();
- while let Some(line) = self.iter.next() {
+ for line in self.iter.by_ref() {
//dbg!(&line);
if let Err(e) = line {
return Some(Err(e));
}
let line_orig = line.unwrap();
- let line = line_orig.splitn(2, '#').next().unwrap().trim();
+ let line = line_orig.split('#').next().unwrap().trim();
if line.is_empty() {
if kv.is_empty() {
continue;
@@ -80,13 +80,13 @@ where
let asn = kv.get("aut-num").unwrap(); // XXXX handle error better
assert!(asn.starts_with("AS"));
let asn = asn[2..].parse().unwrap();
- return Some(Ok(AnyBlock::AsBlock(AsBlock { name, asn })));
+ return Some(Ok(AnyBlock::As(AsBlock { name, asn })));
}
let net = if let Some(net) = kv.get("net") {
net.parse().unwrap() //XXXX handle the error better.
} else {
- return Some(Ok(AnyBlock::OtherBlock));
+ return Some(Ok(AnyBlock::Other));
};
let asn = if let Some(asn) = kv.get("aut-num") {
@@ -113,7 +113,7 @@ where
let is_anycast = is_true(kv.get("is-anycast-proxy"));
let is_satellite = is_true(kv.get("is-satellite-provider"));
- Some(Ok(AnyBlock::NetBlock(NetBlock {
+ Some(Ok(AnyBlock::Net(NetBlock {
net,
asn,
cc,
diff --git a/scripts/maint/geoip/geoip-db-tool/src/main.rs b/scripts/maint/geoip/geoip-db-tool/src/main.rs
index 9a22598a35..cbadd6623f 100644
--- a/scripts/maint/geoip/geoip-db-tool/src/main.rs
+++ b/scripts/maint/geoip/geoip-db-tool/src/main.rs
@@ -122,8 +122,11 @@ impl NetDefn {
const PROLOGUE: &str = "\
# This file has been converted from the IPFire Location database
-# using Tor's geoip-db-tool. For more information on the data, see
-# https://location.ipfire.org/.
+# using Tor's geoip-db-tool, which is available in the
+# scripts/maint/geoip/geoip-db-tool directory in the Tor source
+# code repository at https://gitlab.torproject.org/tpo/core/tor/ .
+#
+# For more information on the data, see https://location.ipfire.org/.
#
# Below is the header from the original export:
#
@@ -149,8 +152,8 @@ fn convert(args: Args) -> std::io::Result<()> {
// Read blocks, and then sort them by specificity and address.
for nb in reader {
match nb {
- db::AnyBlock::AsBlock(a) => networks.push(a),
- db::AnyBlock::NetBlock(n) => blocks.push(n),
+ db::AnyBlock::As(a) => networks.push(a),
+ db::AnyBlock::Net(n) => blocks.push(n),
_ => {}
}
}
diff --git a/scripts/maint/geoip/update_geoip.sh b/scripts/maint/geoip/update_geoip.sh
index 743683ab62..c48f4b1b45 100755
--- a/scripts/maint/geoip/update_geoip.sh
+++ b/scripts/maint/geoip/update_geoip.sh
@@ -5,12 +5,22 @@ set -e
DIR=$(cd "$(dirname "$0")" && pwd)
TMP=$(mktemp -d)
-location --quiet update
+DB_PATH="/var/lib/location/database.db"
+
+# In case it exists as a dead symlink.
+if [ -h "$DB_PATH" ]; then
+ unlink "$DB_PATH"
+elif [ -e "$DB_PATH" ]; then
+ rm -f "$DB_PATH"
+fi
+
+curl -o "$DB_PATH.xz" "https://location.ipfire.org/databases/1/location.db.xz"
+xz -d "$DB_PATH.xz"
location dump "$TMP/geoip-dump.txt"
OLDDIR=$(pwd)
cd "$DIR/geoip-db-tool/"
-cargo build --release
+cargo build --release --target-dir "target"
cd "$OLDDIR"
"$DIR/geoip-db-tool/target/release/geoip-db-tool" -i "$TMP/geoip-dump.txt"
diff --git a/scripts/maint/update_versions.py b/scripts/maint/update_versions.py
index 07de1c343a..361dbe2cd3 100755
--- a/scripts/maint/update_versions.py
+++ b/scripts/maint/update_versions.py
@@ -129,8 +129,3 @@ update_file(P("contrib/win32build/tor-mingw.nsi.in"),
re.compile(r'!define VERSION .*'),
u'!define VERSION "{}"'.format(version),
encoding="iso-8859-1")
-
-# In src/win32/orconfig.h, we replace the definition of VERSION.
-update_file(P("src/win32/orconfig.h"),
- re.compile(r'#define VERSION .*'),
- u'#define VERSION "{}"'.format(version))
diff --git a/src/app/config/config.c b/src/app/config/config.c
index e02bcf0387..a10329c552 100644
--- a/src/app/config/config.c
+++ b/src/app/config/config.c
@@ -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 @@ static const char unix_q_socket_prefix[] = "unix:\"";
#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 @@ static const config_var_t option_vars_[] = {
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"),
@@ -507,6 +514,9 @@ static const config_var_t option_vars_[] = {
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"),
@@ -624,7 +634,6 @@ static const config_var_t option_vars_[] = {
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"),
@@ -2728,11 +2737,19 @@ list_deprecated_options(void)
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 +2991,11 @@ config_ensure_bandwidth_cap(uint64_t *value, const char *desc, char **msg)
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 +3549,27 @@ options_validate_cb(const void *old_options_, void *options_, char **msg)
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 +4505,10 @@ options_init_from_torrc(int argc, char **argv)
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(),
@@ -7280,7 +7293,7 @@ getinfo_helper_config(control_connection_t *conn,
}
/* 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 --git a/src/app/config/fallback_dirs.inc b/src/app/config/fallback_dirs.inc
index 728dde41b1..6f197cb141 100644
--- a/src/app/config/fallback_dirs.inc
+++ b/src/app/config/fallback_dirs.inc
@@ -3,1103 +3,1090 @@
/* timestamp=20210412000000 */
/* source=offer-list */
//
-// Generated on: Mon, 18 Sep 2023 13:45:53 +0000
+// Generated on: Mon, 25 Sep 2023 13:48:54 +0000
-"51.38.54.48 orport=9001 id=76F3A81A0784DCF536F6DE19F98EAEB1F89DECCF"
-" ipv6=[2001:41d0:403:1830:14::1]:9001"
-/* nickname=stalkr */
+"89.191.217.1 orport=9001 id=F2ED5032B52021E7BADBBB82E6594F1A872FFD09"
+/* nickname=runninglizard */
/* extrainfo=0 */
/* ===== */
,
-"80.67.167.86 orport=9001 id=22D2314BC5146890A8E5C19C884D96C0CBFEAA24"
-" ipv6=[2a0b:cbc0:1100:7::1]:9001"
-/* nickname=Pegase */
+"142.93.169.197 orport=9001 id=B0F17A56FA8686CCB33D3F302FC40F06F463B4AE"
+/* nickname=ididntedittheconfig */
/* extrainfo=0 */
/* ===== */
,
-"45.138.16.42 orport=8100 id=BB41436AE501C20C5F4403BA25E8288FE924138A"
-/* nickname=Quetzalcoatl */
+"185.162.251.135 orport=9001 id=166850D169CC7956E77525A1A9228BC4563CFC8B"
+" ipv6=[2a03:4000:1a:5c5:38dc:87ff:fe07:85fb]:9001"
+/* nickname=Piratenpartei10 */
/* extrainfo=0 */
/* ===== */
,
-"79.158.144.126 orport=50007 id=59EDD139D9551A25B7DB7CDD82F12C0C378A92CC"
-/* nickname=toronada */
+"185.220.101.83 orport=9000 id=D8357F50057C0F8754A9CDB67860A0A36FD74A82"
+/* nickname=CCCStuttgartBer */
/* extrainfo=0 */
/* ===== */
,
-"217.172.180.4 orport=9001 id=E282ECAA9DD45ABE12D56FCBB33B168487C48AF7"
-/* nickname=obersee */
+"95.222.201.84 orport=9001 id=39DF2E6803720BC0750FA69872A3E3F432108BA0"
+/* nickname=ManInABlueBox */
/* extrainfo=0 */
/* ===== */
,
-"134.119.32.208 orport=9001 id=CFA7447C66A709932F038FEE6B028B84A6E676E8"
-/* nickname=serv */
+"23.141.40.7 orport=443 id=375DCBB2DBD94E5263BC0C015F0C9E756669617E"
+" ipv6=[2620:b0:2000:102::7]:443"
+/* nickname=nitrogen */
/* extrainfo=0 */
/* ===== */
,
-"23.137.57.100 orport=8443 id=79E2258804C826FE2927D0E1540DE42DBE104638"
-/* nickname=sethforprivacy */
+"193.42.36.82 orport=443 id=62F875123AD985B6EFE51AFF81228E5F4B46B633"
+" ipv6=[2a01:8640:a::6163:8bf8]:443"
+/* nickname=TorRelayPoland */
/* extrainfo=0 */
/* ===== */
,
-"192.42.116.27 orport=443 id=9E624E0E5EBA3156BFDA98AC703BCFF95E9A2FF6"
-" ipv6=[2001:67c:6ec:203:218:33ff:fe44:5527]:443"
-/* nickname=hviv127 */
+"94.156.175.85 orport=9001 id=A151005A71B878158266576DCAE6D82EE5CBCDBC"
+/* nickname=leech4 */
/* extrainfo=0 */
/* ===== */
,
-"80.99.212.114 orport=443 id=53527CD1157043AB893CB02B1ACC32B3FD6E93DD"
-/* nickname=FenyVagyok */
+"213.252.245.202 orport=9001 id=96275921105DC2D41B79AD75804A301738B51E47"
+" ipv6=[2a04:2180:0:1::e308:9180]:9001"
+/* nickname=Assange015lt */
/* extrainfo=0 */
/* ===== */
,
-"85.184.251.28 orport=9001 id=48FF61C74DE518ED83497E1659187B22EA9C06BE"
-/* nickname=temp00000013373 */
+"50.47.238.242 orport=49092 id=210E9B4AE14D78627105EEDBDA8D2C3EFA64D482"
+/* nickname=relay */
/* extrainfo=0 */
/* ===== */
,
-"45.141.215.97 orport=9100 id=DE3931572AF2F997C3F7F1D432E8CE658E62D775"
-/* nickname=Quetzalcoatl */
+"87.236.195.216 orport=80 id=45BCBE2EE9C96B129975A42C4E284F4B4C2D1707"
+/* nickname=Perseverance */
/* extrainfo=0 */
/* ===== */
,
-"140.78.100.43 orport=5443 id=40B334132EB4D680AC00202E0186DBB57BFF17CE"
-/* nickname=INSRelay43at5443 */
+"23.153.248.35 orport=443 id=802D905052FF43467F8A8785153C36076A56E5D6"
+" ipv6=[2602:2da:0:35::1]:443"
+/* nickname=0x7c0 */
/* extrainfo=0 */
/* ===== */
,
-"178.17.170.77 orport=443 id=9C962AEF978496612C521D09632E59ED055D53ED"
-/* nickname=santaclaus */
+"151.115.77.111 orport=443 id=8B21F74537503DF97949E3D3D00983616C10BD90"
+/* nickname=tirz */
/* extrainfo=0 */
/* ===== */
,
-"23.111.179.98 orport=443 id=F39B2BE0F0B9DCFD3D43AAA12D6BE16B14B13A79"
-/* nickname=Dingle */
+"89.147.111.157 orport=443 id=EA12AD87353D4ADBCA7B6451980F57262DCB2BFF"
+/* nickname=RecapturePrivacy */
/* extrainfo=0 */
/* ===== */
,
-"23.129.64.130 orport=443 id=09DCA3360179C6C8A5A20DDDE1C54662965EF1BA"
-" ipv6=[2620:18c:0:192::130]:443"
-/* nickname=ageis */
+"107.189.12.49 orport=443 id=FE097DC0CF900B5923E0F07FA230EB77139E2AE7"
+" ipv6=[2605:6400:30:f45b::]:443"
+/* nickname=MooExitLU */
/* extrainfo=0 */
/* ===== */
,
-"91.136.165.199 orport=12222 id=AAED86E667BBD3DCE910883B0BE3F2DB626EA0D7"
-/* nickname=OneMoreLinuxTor6 */
+"107.189.10.141 orport=9000 id=127E803888D82F33CC3C311ECC6CCEB7708831CB"
+" ipv6=[2605:6400:30:f8e6:9fae:c86f:2d71:6c28]:9000"
+/* nickname=Quetzalcoatl */
/* extrainfo=0 */
/* ===== */
,
-"77.48.28.206 orport=443 id=12D0E4EFCAD3D68DED5B0F1070F1B03330082D6F"
-/* nickname=hamilton */
+"144.217.95.12 orport=9001 id=8885EA6F74A694825B13B8A7080F6CF164DF74FB"
+" ipv6=[2607:5300:201:3000::49be]:9001"
+/* nickname=Unnamed */
/* extrainfo=0 */
/* ===== */
,
-"139.99.238.17 orport=443 id=4BF3D299BC500C350868F078749291C766C7AA6F"
-" ipv6=[2402:1f00:8100:400::3a8]:443"
-/* nickname=rinderwahnRelay33L */
+"185.220.101.33 orport=10033 id=E49F3696DC13946A68DF2AAA6EDA460BC15D8F03"
+" ipv6=[2a0b:f4c2:2::33]:10033"
+/* nickname=ForPrivacyNET */
/* extrainfo=0 */
/* ===== */
,
-"190.211.254.182 orport=9001 id=3B557E3F0C29D4339A904AD8C641F582151FEF71"
-/* nickname=ForestIsland */
+"185.173.200.125 orport=9001 id=46D4F491955C0989D04277F23A305AED568DEFD2"
+" ipv6=[2a0e:e080:8007:9c00:9209:d0ff:fe19:18df]:9001"
+/* nickname=alcxcor */
/* extrainfo=0 */
/* ===== */
,
-"148.251.90.115 orport=4080 id=FF353F5D011E69ECDA10A57B46D06BC7B3FEB196"
-" ipv6=[2a01:4f8:202:7071::2]:4080"
-/* nickname=fuego */
+"194.182.179.34 orport=443 id=EFE89ECF4EE11613A19248777EBBA28719BF5FF7"
+" ipv6=[2a04:c47:e00:7cdf:4b9:a0ff:fe00:2f0]:443"
+/* nickname=Slavyanka */
/* extrainfo=0 */
/* ===== */
,
-"51.81.57.7 orport=443 id=4F0E831A998B6442BAF41B6FB33D0B445E6AB238"
-/* nickname=VivaLaRevolution */
+"216.73.159.106 orport=9001 id=61EE67E18D8DF3C3A06133DF54EA5A294C9379D1"
+/* nickname=LukeCage */
/* extrainfo=0 */
/* ===== */
,
-"185.243.218.41 orport=8126 id=E2B7CE01E2086332986EF6D94F6ECC80A0C4FEF6"
-" ipv6=[2a03:94e0:ffff:185:243:218:0:41]:8126"
-/* nickname=terNOicebeer16 */
+"199.249.230.144 orport=443 id=00DCAEAE3E54C32809E7F7CC4BF2A6FC68FC552F"
+" ipv6=[2620:7:6001::144]:80"
+/* nickname=Quintex55 */
/* extrainfo=0 */
/* ===== */
,
-"38.103.195.2 orport=9001 id=D130B7A9322906D397C9CB41BC21450D3D64B324"
-" ipv6=[2001:550:9601::2]:9001"
-/* nickname=AugustTORRelay */
+"62.171.137.169 orport=9001 id=BAF223E9DF62D3261F1675C6CFC4E5D50F15FA57"
+/* nickname=darkwizard */
/* extrainfo=0 */
/* ===== */
,
-"54.37.139.118 orport=9001 id=90A5D1355C4B5840E950EB61E673863A6AE3ACA1"
-" ipv6=[2001:41d0:601:1100::1b8]:9001"
-/* nickname=rofltor09 */
+"85.214.165.61 orport=9001 id=C6EBD3F26064CDA0CB4C81BC5544538F5E615C0B"
+/* nickname=hasselba */
/* extrainfo=0 */
/* ===== */
,
-"188.165.26.13 orport=9100 id=0E9CF92A1840341AECB39D1F9700C1BAEA51C284"
-/* nickname=Unnamed */
+"94.168.120.10 orport=9001 id=6DF0C5B39FE6DC963E02583497CD8774C9FED064"
+/* nickname=tiasrelay */
/* extrainfo=0 */
/* ===== */
,
-"179.43.128.16 orport=9001 id=815AE924755F1E63986E434A92A88EA1F75A60A3"
-/* nickname=thealbum */
+"185.220.100.241 orport=9100 id=50AA9FEA6A3A609686276C4CF0C2A1AFB2ECCA1B"
+" ipv6=[2a0b:f4c0:16c:15::1]:9100"
+/* nickname=F3Netze */
/* extrainfo=0 */
/* ===== */
,
-"185.243.218.110 orport=8443 id=6972CDE063E6DD9C4432F44EE7A190BDA916A8E3"
-" ipv6=[2a03:94e0:ffff:185:243:218:0:110]:8443"
-/* nickname=bauruine */
+"5.200.21.144 orport=443 id=0C039F35C2E40DCB71CD8A07E97C7FD7787D42D6"
+/* nickname=libel */
/* extrainfo=0 */
/* ===== */
,
-"45.141.215.56 orport=8430 id=5A7DE9083BE6228A433955A4649C9865C909676A"
-/* nickname=Quetzalcoatl */
+"51.38.110.234 orport=9000 id=0CAA2E9044A86B11915C413B5A0911DF29E9A1AC"
+/* nickname=cray */
/* extrainfo=0 */
/* ===== */
,
-"51.158.146.152 orport=443 id=55580D71B317A072F4A4DCF6EA4EDB015734AEE7"
-" ipv6=[2001:bc8:6010:213:208:a2ff:fe0c:8128]:443"
-/* nickname=VeilsOfTheOnion */
+"79.193.43.32 orport=10222 id=C4C462506D54EDC8EFC8E88E32F4AE014755035A"
+/* nickname=s0yb3an */
/* extrainfo=0 */
/* ===== */
,
-"45.95.169.225 orport=443 id=8C8ABA28F3E8D11BBAFE80D8E281B75343B52DCF"
-/* nickname=Lugano */
+"37.120.174.249 orport=443 id=11DF0017A43AF1F08825CD5D973297F81AB00FF3"
+" ipv6=[2a03:4000:6:724c:df98:15f9:b34d:443]:443"
+/* nickname=gGDHjdcC6zAlM8k08lX */
/* extrainfo=0 */
/* ===== */
,
-"94.100.6.27 orport=443 id=D6670FB54B21818CE7C13524AA003258B8E35D38"
-/* nickname=drogo */
+"91.208.184.123 orport=443 id=ACF8FC6C14032A045B44F6B98525EE5C0472DD50"
+/* nickname=TorDiversity */
/* extrainfo=0 */
/* ===== */
,
-"85.240.252.128 orport=9001 id=2CD5474E33D12629156B92FBD61FAAB22D07B0F7"
-/* nickname=onYourOwn */
+"92.60.37.105 orport=9001 id=7E317CFA44E7B6013DE4BC5F837C376A77179C72"
+" ipv6=[2a03:4000:33:1c8::13]:9001"
+/* nickname=15T01 */
/* extrainfo=0 */
/* ===== */
,
-"185.244.192.184 orport=9000 id=CC8412A0CE31C55CFBF32CBA8EA5C05348846C3F"
-" ipv6=[2a03:4000:27:36:c813:6dff:fe0e:b93e]:9000"
-/* nickname=Quetzalcoatl */
+"177.104.142.225 orport=443 id=040D6001435CDAA8D3DAE2EE51CF2F48C4530E76"
+/* nickname=red6 */
/* extrainfo=0 */
/* ===== */
,
-"31.133.0.37 orport=443 id=FDE1A5F7D1288F10FB3E95CE5A67DF2D560DFC54"
-" ipv6=[2001:67c:2044:c141:0:1:4571:1]:443"
-/* nickname=marmotte */
+"185.32.222.237 orport=9444 id=7F0B0ACEEF829710E51CC3EE3A2A0E0C0993255B"
+" ipv6=[2a0b:ee80:e:fefe::41]:9444"
+/* nickname=bauruine */
/* extrainfo=0 */
/* ===== */
,
-"185.82.219.85 orport=9001 id=6389ECB4891334B846300FDD8A68250EBB5B7C52"
-" ipv6=[2a02:27aa::505]:9001"
-/* nickname=FlashLizard */
+"185.220.101.202 orport=8443 id=9A338F384C5FD3A3604E3250CCF5F5F7629D7717"
+" ipv6=[2a0b:f4c2:2:1::202]:8443"
+/* nickname=ForPrivacyNET */
/* extrainfo=0 */
/* ===== */
,
-"84.60.79.56 orport=443 id=58EF95F98B119B0A0B2A2AFD5A7FC6B54CC69860"
-/* nickname=uncreativeGuardian */
+"38.103.195.2 orport=9001 id=D130B7A9322906D397C9CB41BC21450D3D64B324"
+" ipv6=[2001:550:9601::2]:9001"
+/* nickname=AugustTORRelay */
/* extrainfo=0 */
/* ===== */
,
-"193.142.147.204 orport=9100 id=71C7808B784658D92BF178B8152A76C4F5845BDC"
-/* nickname=prsv */
+"45.61.187.139 orport=443 id=410EBF5532DDE6C9BFAFE42DFEC987B8DC8F984C"
+" ipv6=[2605:6400:40:fe95:b91a:eae5:66fe:996a]:443"
+/* nickname=wisemansfear */
/* extrainfo=0 */
/* ===== */
,
-"198.251.88.142 orport=53 id=4D4B2695D6D02DFDCDE390ED5DF4A6798924CBBB"
-" ipv6=[2605:6400:30:f174:42:42:42:0]:443"
-/* nickname=Polyphemus8 */
+"199.195.251.78 orport=9000 id=AC249C56C11FDDFA9E8DE56B182B13AC8A4672BE"
+" ipv6=[2605:6400:10:8a2:de49:ffd1:46f5:99a2]:9000"
+/* nickname=Quetzalcoatl */
/* extrainfo=0 */
/* ===== */
,
-"199.249.230.114 orport=443 id=E480D577F58E782A5BC4FA6F49A6650E9389302F"
-" ipv6=[2620:7:6001::114]:80"
-/* nickname=Quintex34 */
+"104.244.76.184 orport=443 id=D5A2B3AE1E8047017A0BBC7209FD624DB84D47CE"
+" ipv6=[2605:6400:30:f99f::1]:443"
+/* nickname=komeru2 */
/* extrainfo=0 */
/* ===== */
,
-"116.203.159.176 orport=9001 id=B536B71A1F5599C39FC8B1915D2EBE3A0DEB1403"
-/* nickname=dreamwriter */
+"5.100.255.254 orport=443 id=6B6E105925B91647749468E23E7EE15008201CC2"
+/* nickname=wts */
/* extrainfo=0 */
/* ===== */
,
-"185.103.135.20 orport=9002 id=1B471B9FD70BD4D9E46C4E8B5B5AE075D6E2DD17"
-/* nickname=CinemaField */
+"54.36.101.21 orport=9001 id=D9C55AC5549BF4940BE0ABBBE0E34CCC8D6D06E5"
+" ipv6=[2001:41d0:304:200::9dce]:9006"
+/* nickname=ExiTOR */
/* extrainfo=0 */
/* ===== */
,
-"5.75.249.160 orport=1337 id=0C9B3C686421C5A8C20BAA0D7369CD929F43A174"
-" ipv6=[2a01:4f8:c17:ba99::1]:1337"
-/* nickname=nsaPwned */
+"51.15.142.0 orport=443 id=7B53DA28813258A20335C8E8985C05D0D089B441"
+/* nickname=iscariote */
/* extrainfo=0 */
/* ===== */
,
-"66.165.241.230 orport=9001 id=D20A88A4C6C212DD08A916A80C4A676AEFAA402A"
-" ipv6=[2604:4500:8:14::8]:9001"
-/* nickname=bibble */
+"188.165.236.18 orport=9001 id=941985CDE2DC9D67FEC0703A8FFD061E3B4BA8A9"
+" ipv6=[2001:41d0:2:b712::1]:9001"
+/* nickname=kogis */
/* extrainfo=0 */
/* ===== */
,
-"5.2.78.126 orport=9001 id=E5DEA9F6570207DB9841CA04C240BCDCFEC3200D"
-/* nickname=Unnamed */
+"87.236.195.216 orport=1000 id=50161FF42B11B87C4CDD210CF9CB490A7B088DBB"
+/* nickname=Perseverance */
/* extrainfo=0 */
/* ===== */
,
-"185.220.101.87 orport=9000 id=3301463CC85D578704C0322C018E3BF96C962FA0"
-/* nickname=CCCStuttgartBer */
+"45.143.99.133 orport=9300 id=BE42F23B2086928B38444CB68CE95038AAEC9CBB"
+/* nickname=prsv */
/* extrainfo=0 */
/* ===== */
,
-"37.218.245.79 orport=443 id=C683052FD8BACF5230103F794E9694BEED1ED0B4"
-" ipv6=[2a00:c6c0:0:154:5::10]:443"
-/* nickname=EhrenRelay */
+"45.134.225.36 orport=443 id=00CC3A3D92C33E171BBDAEACC4601173BFA24150"
+/* nickname=bauruine */
/* extrainfo=0 */
/* ===== */
,
-"95.153.31.8 orport=443 id=8DC832ABDC9C97B8B71F74AB041D3CB3FA9578AA"
-/* nickname=alnutt */
+"116.203.93.236 orport=9001 id=6A2676DACAFDBD00C5B94BD343690957A12BB758"
+" ipv6=[2a01:4f8:c2c:86ca::2]:9001"
+/* nickname=neurodump */
/* extrainfo=0 */
/* ===== */
,
-"84.83.93.100 orport=9001 id=10DF0DD9AA44A86F576A23218D50E7D3EFA15DD3"
-/* nickname=ByteBob */
+"207.180.216.146 orport=9001 id=9BA1289CDCFD907B8D40A8AB12F36BE620DD4085"
+" ipv6=[2a02:c207:3003:1052::1]:9001"
+/* nickname=Pivo */
/* extrainfo=0 */
/* ===== */
,
-"93.99.255.254 orport=8443 id=074B20C33D4A03453FB19A8535CDCE1352658A56"
-" ipv6=[2a01:5e0:0:2:20c:29ff:fecf:4819]:8443"
-/* nickname=Unnamed */
+"45.132.74.182 orport=443 id=7447785F4485524B1EEDF4FE5A770E45A43C40AA"
+/* nickname=tionverphous */
/* extrainfo=0 */
/* ===== */
,
-"94.230.208.148 orport=443 id=1BDBE9C0F7034E6789A9BF7BED82BE2045F0F5B7"
-" ipv6=[2a02:418:6017::148]:443"
-/* nickname=DigiGesTor3e3 */
+"23.137.249.143 orport=443 id=53A5C88DF5862DC3FF8BB938926C094879FAA806"
+" ipv6=[2602:fc24:11:4441::1]:443"
+/* nickname=cozybeardev */
/* extrainfo=0 */
/* ===== */
,
-"185.82.126.230 orport=443 id=637A3233320D57D969841BF5D8D0AD82CABFDB46"
-/* nickname=inconnu6 */
+"108.181.100.49 orport=443 id=FCA52A291DEDFCE72D6B7E538A5A91BE903E15FF"
+/* nickname=urkle */
/* extrainfo=0 */
/* ===== */
,
-"89.147.111.157 orport=443 id=EA12AD87353D4ADBCA7B6451980F57262DCB2BFF"
-/* nickname=RecapturePrivacy */
+"87.229.85.197 orport=9001 id=C148A3CCBAC39858FFA631BD0EF07EA4044662FF"
+/* nickname=secondtry */
/* extrainfo=0 */
/* ===== */
,
-"95.216.3.171 orport=9001 id=C3ACB0492A644E27A549BC3CDF3B7A129186E3BF"
-" ipv6=[2a01:4f9:2a:3d4::2]:9001"
-/* nickname=privexrelayfin1 */
+"42.241.7.195 orport=9001 id=18AF0A4ABEBC388E5DAA81DBF188C9B92A380917"
+/* nickname=lst97 */
/* extrainfo=0 */
/* ===== */
,
-"82.118.242.226 orport=9001 id=614656D126EC3434046476DB6FD631B71124DAB4"
-/* nickname=TheBoundTome */
+"185.220.102.8 orport=443 id=CA94704217260E7483DA88719CACD7A94C564D5C"
+" ipv6=[2a0b:f4c1::8]:443"
+/* nickname=renewablefreedom */
/* extrainfo=0 */
/* ===== */
,
-"185.220.101.201 orport=443 id=EBF648E1CF3FA3AC46AA272857BCAFCCD70D49FC"
-" ipv6=[2a0b:f4c2:2:1::201]:443"
-/* nickname=ForPrivacyNET */
+"94.23.149.136 orport=9100 id=38316AF9D28F99A451C8789BE21C363ADD0F6846"
+/* nickname=Unnamed */
/* extrainfo=0 */
/* ===== */
,
-"193.142.147.204 orport=9000 id=54D08EF64FC006EB5F19C9549DC40E52BB8C854D"
-/* nickname=prsv */
+"51.158.96.122 orport=443 id=32364BEF873944BE481E8BCC7FAE9297F5F39781"
+/* nickname=tirz */
/* extrainfo=0 */
/* ===== */
,
-"107.189.4.12 orport=9000 id=8657A9B481BA39A60C29E49AFAD5CE5523677812"
-" ipv6=[2605:6400:30:f51a:f826:ecfc:47b6:92a9]:9000"
-/* nickname=Quetzalcoatl */
+"108.181.56.161 orport=443 id=A162AB33A75096A780CD8D15A47DC9EC6ABDC4C7"
+/* nickname=Reeses2 */
/* extrainfo=0 */
/* ===== */
,
-"94.100.6.30 orport=9001 id=669102E6FA8E116AC05FE823B0634B44499944E3"
-/* nickname=Quiv */
+"51.81.93.109 orport=443 id=F5612A75455800DCD427C8FD919EF5CCE1D51952"
+/* nickname=Sol */
/* extrainfo=0 */
/* ===== */
,
-"45.141.215.21 orport=9100 id=A549E57FC2A060FA20051537E6738B3ED5B98463"
-/* nickname=Aramis */
+"147.135.31.134 orport=443 id=7460C77412E8C8E65ABE1797C652161FE903EBFB"
+/* nickname=AOP */
/* extrainfo=0 */
/* ===== */
,
-"193.239.232.102 orport=9001 id=7F3E59A4EA056F3DF009568D0CFF80F850F5E9A7"
-/* nickname=sveahosting */
+"135.148.149.23 orport=22 id=786835D15C33DCD2B7FD9E70CACBCDA3D6187300"
+" ipv6=[2604:2dc0:101:200::b63]:22"
+/* nickname=Lamia2 */
/* extrainfo=0 */
/* ===== */
,
-"107.189.11.111 orport=9000 id=477E2B8AE380BD24C7EE5D9FF5AC98D8E0249368"
-" ipv6=[2605:6400:30:f440:757e:adf1:55f7:5a31]:9000"
-/* nickname=Quetzalcoatl */
+"147.135.112.139 orport=9001 id=E0023AC14180112A2FFF00A84C6049862BB3E6C3"
+/* nickname=DerrickJensen */
/* extrainfo=0 */
/* ===== */
,
-"45.128.232.102 orport=9300 id=321EB5D1E02737D9511748DFF16183DFABE85224"
-" ipv6=[2a05:dfc7:417d::1]:9300"
-/* nickname=prsv */
+"109.100.59.186 orport=30097 id=E35118AF4EDA980BB841070496A66BB3CF9C6FEC"
+/* nickname=rika */
/* extrainfo=0 */
/* ===== */
,
-"84.226.16.207 orport=9001 id=6C5875AB92C8979D0D66C952D017E9866148DDEF"
-/* nickname=OdyX */
+"82.66.197.211 orport=9001 id=1850585BE9BCA1F80D0A051909C94E49D1C49ED3"
+" ipv6=[2a01:e0a:b5:7f50:7278:4422:dc14:89ea]:9001"
+/* nickname=xmtx */
/* extrainfo=0 */
/* ===== */
,
-"5.255.124.150 orport=9001 id=4C6FDAF59FFF2E62BA3C8709ED82008045027D95"
-/* nickname=BetwixtTor */
+"51.79.221.8 orport=9001 id=1E326EFE355AB98912272AF724D59176B5C23792"
+/* nickname=slotor03 */
/* extrainfo=0 */
/* ===== */
,
-"198.24.168.226 orport=443 id=6A6F6DDA0C1F07FEC3A21E4401EE235336EC6ED9"
-/* nickname=Frogger */
+"94.16.123.171 orport=9001 id=E612306325AE03F0C82C290ACAFB8C724A8B5B91"
+" ipv6=[2a03:4000:21:89c:b8d4:46ff:fe68:40db]:9001"
+/* nickname=theark2 */
/* extrainfo=0 */
/* ===== */
,
-"82.223.114.35 orport=443 id=5DDFF053624BAD3126663545B5FCAB0D9FB10E72"
-" ipv6=[2001:ba0:1800:81dd::1]:443"
-/* nickname=ZwiebelRouter05 */
+"162.251.166.210 orport=443 id=BB9C5D15BC3B77C8AF5CBC733F7E54553A1B7BD5"
+/* nickname=onionmatic */
/* extrainfo=0 */
/* ===== */
,
-"107.189.12.3 orport=9100 id=BF8021D2EC8A8DC724D35D9590F9FEF251F006D9"
-" ipv6=[2605:6400:30:eb71:51b7:4869:7579:3aa1]:9100"
+"194.26.192.64 orport=8100 id=B0897E4B7B42B20AC1A89856BC0F87658158795C"
/* nickname=Quetzalcoatl */
/* extrainfo=0 */
/* ===== */
,
-"45.145.166.104 orport=9100 id=E912766A93A7B9C2A7126AAA0F760C8063B1767D"
-" ipv6=[2a04:ecc0:8:a8:4567:801:0:1]:9100"
-/* nickname=prsv */
+"95.110.254.231 orport=443 id=8BB55A3AFBB7E5D9EB83215DEC8F219E68DF9B6D"
+" ipv6=[2a00:6d41:200:2::e7]:443"
+/* nickname=PoloUnivAretino */
/* extrainfo=0 */
/* ===== */
,
-"51.79.170.198 orport=80 id=1E1BEF2C8E1695AC021C9010425D35080204937B"
-/* nickname=allstars2 */
+"209.141.55.26 orport=9001 id=4954B51AF0CBADA08E4BC389DF1E3E419535165A"
+" ipv6=[2605:6400:20:be7::1]:9001"
+/* nickname=andr788k */
/* extrainfo=0 */
/* ===== */
,
-"5.2.79.179 orport=9001 id=285B3195256DEA66C7F58C0596B17D923788056C"
-/* nickname=8596678972910979 */
+"77.105.146.42 orport=443 id=EBD7520D6CA3CD325ADE5C3C802A7DAFA0BA6C71"
+" ipv6=[2a0e:d602:1:14bc::2]:443"
+/* nickname=cozybeardev */
/* extrainfo=0 */
/* ===== */
,
-"85.204.116.239 orport=8443 id=0DF4CB956237DB411A19DF0935B322F75E69533D"
-" ipv6=[2a02:13f0:8100:6:3dc:f2:43cb:1]:8443"
-/* nickname=hogman2 */
+"90.146.187.6 orport=9004 id=65F86FD8B92C3AC01887D86B2171E657D5C19F79"
+/* nickname=eclipse03 */
/* extrainfo=0 */
/* ===== */
,
-"45.86.86.146 orport=9090 id=41FF4A829027FFDCA32CC23D30DA492AB7E1ED36"
-/* nickname=Unnamed */
+"185.7.33.120 orport=9002 id=2B37283CA3C140B35ABAD4628A873A860DDFF050"
+/* nickname=Stormpaw */
/* extrainfo=0 */
/* ===== */
,
-"146.190.224.96 orport=9001 id=D70CADC1A398D9ACC28909C09B160DAEF59384CF"
-" ipv6=[2a03:b0c0:2:d0::14cb:6001]:9001"
-/* nickname=slarty2 */
+"5.75.249.160 orport=1337 id=0C9B3C686421C5A8C20BAA0D7369CD929F43A174"
+" ipv6=[2a01:4f8:c17:ba99::1]:1337"
+/* nickname=nsaPwned */
/* extrainfo=0 */
/* ===== */
,
-"77.105.107.21 orport=9001 id=EABB390323F80D4457BAA5CEEE511455700E929D"
-/* nickname=TORB */
+"185.66.91.18 orport=9001 id=95333D86240F6402656D2EB96716255634F6C007"
+/* nickname=BuNGOfAr */
/* extrainfo=0 */
/* ===== */
,
-"185.82.127.213 orport=443 id=24E9CFAE081B16E87B490C596C18B00EE6FF8413"
-/* nickname=se3andersio */
+"185.177.229.16 orport=9001 id=76C8B133363101B3C6C09DAF0F395C53A9A0A7CF"
+" ipv6=[2604:86c0:f001:d:fda:37c6:e9ee:d00f]:9001"
+/* nickname=Doedelkiste77 */
/* extrainfo=0 */
/* ===== */
,
-"77.91.86.95 orport=443 id=034ED155E6DA8277BC7F294896BFD7013D7BD7B0"
-" ipv6=[2a0e:d602:2:2a2::2]:443"
-/* nickname=cozybeardev */
+"116.202.169.25 orport=2443 id=E6B7816862EA2DAFA80C8C41C31380C1FA785621"
+/* nickname=Unnamed */
/* extrainfo=0 */
/* ===== */
,
-"140.78.100.40 orport=8443 id=B8C9CA7A90A2D94406C6D9899340EB68DA4265B8"
-/* nickname=INSRelay40at8443 */
+"107.189.30.60 orport=9001 id=97188863FDFF9D21F7560AED3F037F316CA6AE20"
+/* nickname=IronServer */
/* extrainfo=0 */
/* ===== */
,
-"87.118.122.51 orport=444 id=C36C76992198329C0D8F34E01D092BF2ACE0B6B0"
-" ipv6=[2001:1b60:3:239:1003:106:0:1]:444"
-/* nickname=artikel5ev3c */
+"199.249.230.78 orport=443 id=CB7C0D841FE376EF43F7845FF201B0290C0A239E"
+" ipv6=[2620:7:6001::ffff:c759:e64e]:80"
+/* nickname=QuintexAirVPN25 */
/* extrainfo=0 */
/* ===== */
,
-"179.43.134.242 orport=9001 id=8881954D8C664D485B0099D7D5E0AF26108B1872"
-/* nickname=BASEL */
+"51.14.214.219 orport=9001 id=B3D621E06020A858A06C37835FD19A07D7480F45"
+/* nickname=geheimschreiber */
/* extrainfo=0 */
/* ===== */
,
-"104.244.77.80 orport=9100 id=2392ECD14824B46C0F2EAAC4862BA40EC9B930AE"
-" ipv6=[2605:6400:30:fa92:5f11:1ed9:9615:fcc6]:9100"
-/* nickname=Quetzalcoatl */
+"94.23.150.210 orport=9001 id=C6C2F339836E2A1EFF64B9DAFCB00C1A0D48D5C7"
+/* nickname=Unnamed */
/* extrainfo=0 */
/* ===== */
,
-"37.120.187.104 orport=9001 id=C8B23EA543FAD6F820E5841A8380DC28C83AEA0F"
-" ipv6=[2a03:4000:f:64f:5443:78ff:fe62:7ad8]:9001"
-/* nickname=Piratenpartei07 */
+"176.123.8.5 orport=9001 id=8A169EB231D1CCF2F8A9705F8F7C9808AAA32257"
+/* nickname=kalunk */
/* extrainfo=0 */
/* ===== */
,
-"95.217.231.111 orport=9001 id=133D3D8F3B7220A314BAF02A42A566E230234638"
-" ipv6=[2a01:4f9:4a:48d0::11]:9001"
-/* nickname=galtlandeu3 */
+"108.181.132.237 orport=443 id=E4ECCD8EE889E8CC3E839E0D8EB3D350DB13C288"
+/* nickname=lucuma */
/* extrainfo=0 */
/* ===== */
,
-"176.107.176.31 orport=443 id=CFE937F5809DEE2C2916A6C54A59CCA5BC5D702A"
-" ipv6=[2a04:1741:0:12::]:9001"
-/* nickname=sandbox */
+"185.243.218.61 orport=9001 id=8E1CB2E2467989A9369284E09669AD0FD691075E"
+" ipv6=[2a03:94e0:24d4::2]:9001"
+/* nickname=4716 */
/* extrainfo=0 */
/* ===== */
,
-"65.21.50.48 orport=443 id=D71B18C42D71549C6066FE1AC5DF0FEC1F03696F"
-" ipv6=[2a01:4f9:c010:89f::1]:443"
-/* nickname=berlinwonderland */
+"185.220.102.253 orport=443 id=6B61EFE3AEDEB3351FD3C910443D95556316E01C"
+" ipv6=[2a0b:f4c1:2::253]:443"
+/* nickname=Digitalcourage4ip6a */
/* extrainfo=0 */
/* ===== */
,
-"144.217.4.166 orport=443 id=F6691E3EB7CAB3C876AAA885E6801B63DC998C39"
-/* nickname=anotherRelay */
+"185.220.100.254 orport=9000 id=E8C8667CAF3D5148E52ECF736A7B204982F78EAA"
+" ipv6=[2a0b:f4c0:16c:2::1]:9000"
+/* nickname=F3Netze */
/* extrainfo=0 */
/* ===== */
,
-"199.249.230.150 orport=443 id=30C55C496F5C7B9868E0BC6349A1CD5623F0B75F"
-" ipv6=[2620:7:6001::150]:80"
-/* nickname=Quintex61 */
+"91.126.217.153 orport=9001 id=F52611DA7E1EE1434C8B45368D0872C437A02958"
+/* nickname=elhackernet */
/* extrainfo=0 */
/* ===== */
,
-"199.249.230.105 orport=443 id=9F2856F6D2B89AD4EF6D5723FAB167DB5A53519A"
-" ipv6=[2620:7:6001::105]:80"
-/* nickname=Quintex15 */
+"131.203.32.146 orport=9001 id=979B2E677F6D94820CD8D645626ED776DCB1CB6C"
+/* nickname=Octogon */
/* extrainfo=0 */
/* ===== */
,
-"5.255.99.5 orport=9001 id=D698261BC1B4A80E24BD050909552C7FE9464CD2"
-" ipv6=[2a04:52c0:104:ad97::1]:9001"
-/* nickname=Unnamed */
+"195.15.242.99 orport=9001 id=00283B5564E3072DCDDAB31D6EF622DD49BF524F"
+" ipv6=[2001:1600:10:100::201]:9001"
+/* nickname=StarAppsMobley */
/* extrainfo=0 */
/* ===== */
,
-"185.232.70.209 orport=443 id=D36EFFB24481694E384787FAAB80F56AAA5CCD9A"
-" ipv6=[2a03:4000:4e:f48:54ac:99ff:fee4:b238]:443"
-/* nickname=08eRPfaL2Relay2 */
+"171.25.193.80 orport=80 id=491B4E55B4FD4FDEC63B229B0A3E59868FCA1F1F"
+" ipv6=[2001:67c:289c:4::79]:80"
+/* nickname=DFRI22 */
/* extrainfo=0 */
/* ===== */
,
-"176.9.98.108 orport=9001 id=EF25C1F9BEF8C4A3F2859493C7C8C5148725B4E7"
-/* nickname=0x90 */
+"31.164.230.171 orport=6969 id=AB40FD78D8A4DE530FB1E0355E74D80367784619"
+/* nickname=Eva */
/* extrainfo=0 */
/* ===== */
,
-"66.111.2.20 orport=9001 id=D317C7889162E9EC4A1DA1A1095C2A0F377536D9"
-" ipv6=[2610:1c0:0:5::20]:9001"
-/* nickname=NYCBUG0 */
+"137.74.119.109 orport=9001 id=88D6A3C0FC28EAE6B9AD0BA1082223C03C1B32FA"
+/* nickname=FreeHackCom */
/* extrainfo=0 */
/* ===== */
,
-"178.17.170.168 orport=443 id=33F221E3A9306FA08A857FE266EBE23720EB6026"
-" ipv6=[2a00:1dc0:caff:20::eda9]:443"
-/* nickname=h0mer */
+"193.135.10.219 orport=59999 id=05C621B44EF6833889AE7B7E2A0B476569C47E37"
+" ipv6=[2a0a:51c0:0:136::2]:59999"
+/* nickname=electroncash */
/* extrainfo=0 */
/* ===== */
,
-"107.189.1.160 orport=443 id=5AA6370205AA611CED967BDB4D8EBCB9D5DB57A9"
-" ipv6=[2605:6400:30:ef7a:391a:8c71:a2f1:9506]:443"
-/* nickname=AllTheWorldsAStage */
+"142.54.162.114 orport=443 id=16324C89132BE14F19E13FD6EB3226FC5AE3F059"
+/* nickname=BucketOfBits */
/* extrainfo=0 */
/* ===== */
,
-"185.100.85.132 orport=443 id=5F875CFB7E2ED0D24E85A5A8B8904A3650AB1ED8"
-/* nickname=vandergriff */
+"49.13.8.165 orport=9001 id=25280148FEF4E800FD179082D9E23276C7199E9D"
+" ipv6=[2a01:4f8:c012:f7e1::1]:9001"
+/* nickname=sb */
/* extrainfo=0 */
/* ===== */
,
-"152.69.198.49 orport=9001 id=CF762EF3C86B104C301511894547C72371F952A4"
-/* nickname=yudejp */
+"96.225.18.180 orport=8443 id=4690F84D4E2F21DA27399004470F72D216F5EF08"
+/* nickname=Sobit */
/* extrainfo=0 */
/* ===== */
,
-"77.83.198.213 orport=9001 id=4DE195FE0D5E96FD8AFDA25495785D276B36777B"
-/* nickname=rainboweuphoria */
+"108.181.56.183 orport=443 id=1E23A3E081E2C802ECE61190C214F0723A66971A"
+/* nickname=redbeans */
/* extrainfo=0 */
/* ===== */
,
-"193.108.118.218 orport=443 id=79D9E66BB2FDBF25E846B635D8248FE1194CFD26"
-" ipv6=[2604:86c0:f001:2:9baf:37c2:e99e:babe]:443"
-/* nickname=BeastieJoy65 */
+"107.189.12.101 orport=9001 id=AC9D89E7A99B7F95E115BE6D5D219D4196B09790"
+/* nickname=devvulLU */
/* extrainfo=0 */
/* ===== */
,
-"173.212.236.169 orport=9001 id=19173006B05B6119D966B73AE7677D71EF529CF6"
-" ipv6=[2a02:c207:3006:5899::1]:9001"
-/* nickname=gaunahTorRelay */
+"93.90.194.106 orport=9001 id=070673739A5470C6042A27CF44B02EF6A46B3D98"
+" ipv6=[2001:8d8:1800:208::1]:9001"
+/* nickname=addax */
/* extrainfo=0 */
/* ===== */
,
-"139.162.123.5 orport=443 id=0990E0F4F2C127BDDA9B6726400FAC077F6C83B0"
-" ipv6=[2400:8902::f03c:93ff:fef5:5412]:443"
-/* nickname=Anankke */
+"87.118.122.30 orport=444 id=1AA683E036EA10AA6E078D40498CC7234F6424B9"
+" ipv6=[2001:1b60:3:239:1003:103:0:1]:444"
+/* nickname=artikel5ev2b */
/* extrainfo=0 */
/* ===== */
,
-"83.255.155.80 orport=49001 id=A77F16A6B3131EADB5D51DE2F8D0914F702AD357"
-/* nickname=doboz */
+"78.45.83.195 orport=9001 id=58EC0CA73FABF6EB7CB41A0700834CD5E1AA1DF5"
+/* nickname=enbyfaggot */
/* extrainfo=0 */
/* ===== */
,
-"198.98.60.90 orport=444 id=E33CFFD6F03D53784993802B33DFAE2B178C60C9"
-" ipv6=[2605:6400:10:4ed:1:1:1:1]:444"
-/* nickname=SamicTor */
+"23.128.248.28 orport=443 id=531A6F7F364AAF47B4D4F717435F76154FC78797"
+" ipv6=[2602:fc05::28]:443"
+/* nickname=StormyCloud */
/* extrainfo=0 */
/* ===== */
,
-"185.181.60.181 orport=443 id=335E993222204F6B4817134506494A6441DEFB6B"
-" ipv6=[2a03:94e0:ffff:185:181:60:0:181]:443"
-/* nickname=DowntimePatrol */
+"108.61.189.136 orport=443 id=99348748C22EE093F22D32F1996507DC2E363872"
+/* nickname=vol1 */
/* extrainfo=0 */
/* ===== */
,
-"208.73.102.153 orport=443 id=4D1214B3EB6CF75B2DD0E01ACBD2676CD63233ED"
-/* nickname=Tetravoid */
+"94.23.150.210 orport=8080 id=60C24AFF465D2E7FB6E9375E243F894E2939DF27"
+/* nickname=Unnamed */
/* extrainfo=0 */
/* ===== */
,
-"155.248.213.203 orport=8888 id=94A8976E00C68ED23695D0668D87B3E7F126AF62"
-/* nickname=NothingToHide */
+"95.216.115.85 orport=8443 id=E3F98C86C9E01138DD8EA06B1E660A0CDB4B2782"
+/* nickname=Finisterre */
/* extrainfo=0 */
/* ===== */
,
-"147.135.64.217 orport=443 id=5889A54CCD68C319F6F8ACEFF81E063E6E84B9BE"
-/* nickname=trumpet */
+"91.65.99.32 orport=9001 id=3DAEB93223247937F7D488689F79B9203371E018"
+/* nickname=vjayDuckdnsOrg */
/* extrainfo=0 */
/* ===== */
,
-"37.187.23.232 orport=80 id=F4873B3EC3325B81DC36C7E38AD3A5ED12B2F339"
-" ipv6=[2001:41d0:a:17e8::1]:80"
-/* nickname=Islay */
+"5.252.178.224 orport=9001 id=0ABC1EBFF50C8A58279AD07FBD73E183F9E00B86"
+/* nickname=pinnacle */
/* extrainfo=0 */
/* ===== */
,
-"202.61.197.87 orport=9001 id=AD0FCFD83EA4899DB34735E599701592DEA13690"
-/* nickname=torbogen */
+"77.174.62.158 orport=43261 id=FD449127D30D8F5D124653D9EF736EDF4A12B4DC"
+" ipv6=[2a02:a468:8d92:1::baf]:43261"
+/* nickname=lw */
/* extrainfo=0 */
/* ===== */
,
-"185.82.217.49 orport=9001 id=9665A1A6EB9B98C57E446A483E75E05F0539B41B"
-/* nickname=Assange038bg */
+"84.243.23.54 orport=9001 id=F8C6CE08E91B09D7068F782F37DE756984237DBC"
+/* nickname=qREL */
/* extrainfo=0 */
/* ===== */
,
-"23.153.248.37 orport=443 id=E74FE1B23725E94540494339FBF4AC3DB8FB2631"
-" ipv6=[2602:2da:0:37::1]:443"
-/* nickname=0x7c0 */
+"91.135.7.214 orport=9100 id=49D13F9940F1548219C4094AEF263995D616C875"
+" ipv6=[2a02:390:9854:40:8c84:91ff:fe56:1a76]:9100"
+/* nickname=1337T0rN0d3 */
/* extrainfo=0 */
/* ===== */
,
-"72.198.121.59 orport=9001 id=58A22366C4EC4455D24B9856E6C5801B7AB556A6"
-/* nickname=TorrachoMejor */
+"46.226.107.215 orport=10400 id=17A1BA65F89657B35EAF718C46A2073E0A3AE03E"
+" ipv6=[2001:4b98:dc0:43:f816:3eff:fe93:b598]:10400"
+/* nickname=bereg */
/* extrainfo=0 */
/* ===== */
,
-"163.172.145.229 orport=443 id=D7BEA819F6FBE969AE608132991D4A42AEE40A39"
-" ipv6=[2001:bc8:634:101b::1]:443"
-/* nickname=loglessRelay2 */
+"94.247.42.173 orport=7890 id=901EF49AC6FD4976926974F8AF93C96EB5A9777C"
+/* nickname=pineapple */
/* extrainfo=0 */
/* ===== */
,
-"213.183.48.84 orport=9001 id=F80FDE27EFCB3F6A7B4E2CC517133DBFFA78BA2D"
-" ipv6=[2a06:f900:1:100::53a]:9001"
-/* nickname=TARS */
+"217.79.181.90 orport=443 id=0E4F190C4A6F7DDF7F8C9A7842B85B4BBCF5F44B"
+" ipv6=[2001:4ba0:ffff:58::2]:443"
+/* nickname=ForPrivacyNET */
/* extrainfo=0 */
/* ===== */
,
-"162.251.5.152 orport=9001 id=2C4E15CD40EE3D2D6F062F04ADFE9B85C8C3C52B"
-" ipv6=[2604:b480:3:6::2]:9001"
-/* nickname=Unzane */
+"91.208.75.3 orport=443 id=1EE6CA29D54A41E940C834B88F432A9CA931EBE2"
+/* nickname=nobuhide */
/* extrainfo=0 */
/* ===== */
,
-"185.100.87.61 orport=9001 id=B75123A66450D8622C5EED90D8EDEDF09825CC46"
-" ipv6=[2a06:1700:0:10::1]:9001"
-/* nickname=fffb */
+"194.233.75.85 orport=9001 id=A081D437124149D0645ACAA127BA4C608289B84D"
+/* nickname=Punggol */
/* extrainfo=0 */
/* ===== */
,
-"69.120.200.204 orport=9001 id=2FED5000F7FB781A54F96D1A5022DD9FCEEE4652"
-/* nickname=GrayBeard */
+"114.199.75.111 orport=9001 id=6F32594A7A1E6D43290CCF7FA2289FB5234B1810"
+/* nickname=toreeka */
/* extrainfo=0 */
/* ===== */
,
-"185.82.126.13 orport=443 id=60553CA7FB840C5CDA60950E33C71585DF774258"
-/* nickname=se4andersio */
+"46.38.242.228 orport=9001 id=DD0AA66DD9E4E71FFAFAB658DF8300F1CEEA0364"
+" ipv6=[2a03:4000:7:649:e8b3:63ff:fe9a:5e24]:9001"
+/* nickname=flowjob04 */
/* extrainfo=0 */
/* ===== */
,
-"185.220.100.247 orport=9100 id=B891CB6370CF7C51C6FB24D80947AFB7ED463D00"
-" ipv6=[2a0b:f4c0:16c:9::1]:9100"
-/* nickname=relayongrolantor */
+"74.208.104.100 orport=9001 id=347F981344919A2FDA662EA41CDC9B37FFE05549"
+/* nickname=RelayUli */
/* extrainfo=0 */
/* ===== */
,
-"162.248.160.122 orport=9000 id=9EBAABD8F4DD6EC621911158625FE9EC7F3FF8E5"
-" ipv6=[2607:8880::139:7a]:9000"
-/* nickname=GrmmlRelayFive */
+"80.67.167.81 orport=443 id=CD1FD2C1F330A3293DA6068E6A23866D063D6DCB"
+" ipv6=[2a0e:e701:1198::1]:443"
+/* nickname=arecoque1 */
/* extrainfo=0 */
/* ===== */
,
-"107.189.13.91 orport=9001 id=8B034F2AFBE2F2759CCAEE5855D0D91BB0A7036D"
-/* nickname=4862520897290463 */
+"159.2.191.175 orport=59001 id=F45334E75F3FABF5BDCF3463FF425FF5F2B71312"
+/* nickname=MyOwnDamnNodeRelay */
/* extrainfo=0 */
/* ===== */
,
-"185.220.101.43 orport=10043 id=829EC1AF85B89A4CD9E10C7271FEFF19A64C4A77"
-" ipv6=[2a0b:f4c2:2::43]:10043"
-/* nickname=ForPrivacyNET */
+"178.211.147.22 orport=6839 id=AAA083A03F9EAF563A5FAF08C5A54A1156677BD5"
+/* nickname=GTAOnline3 */
/* extrainfo=0 */
/* ===== */
,
-"70.50.61.97 orport=6700 id=0411EDB54F61F58F5EA8B96C3BBE0985B288069D"
-/* nickname=LunchBoxCanRelay */
+"79.141.174.124 orport=9001 id=1FB9CCBE02CF10978EAB16943973AC5C548FA243"
+/* nickname=PeachUnknown */
/* extrainfo=0 */
/* ===== */
,
-"104.37.251.124 orport=12800 id=4E41B00F930F3E72530F339EF4C911CE97D2AE9E"
-/* nickname=Tessa */
+"116.12.180.234 orport=443 id=98A6022D39DD25902D7728B65BE28E5557F5B914"
+/* nickname=maplefire */
/* extrainfo=0 */
/* ===== */
,
-"49.13.8.165 orport=9001 id=25280148FEF4E800FD179082D9E23276C7199E9D"
-" ipv6=[2a01:4f8:c012:f7e1::1]:9001"
-/* nickname=sb */
+"129.151.254.245 orport=443 id=D3F30647183C1A20DB58107ECFBAF1F77C1BEEBD"
+" ipv6=[2603:c026:c102:5ff:ae28:156d:4c5:518e]:443"
+/* nickname=Kurumi */
/* extrainfo=0 */
/* ===== */
,
-"199.249.230.116 orport=443 id=43209F6D50C657A56FE79AF01CA69F9EF19BD338"
-" ipv6=[2620:7:6001::116]:80"
-/* nickname=QuintexAirVPN5 */
+"160.119.249.240 orport=443 id=8428C02CCD1CF01715C91F1819BA507C1A79A931"
+/* nickname=dani */
/* extrainfo=0 */
/* ===== */
,
-"107.189.8.56 orport=9100 id=0CD666F9C9A40A8CFB1E6B9465597A51D3A1CBF8"
-" ipv6=[2605:6400:30:f0ed:9151:66ed:6366:5c74]:9100"
-/* nickname=Quetzalcoatl */
+"185.243.218.204 orport=443 id=2925365310A2487781BA7E743E155E4753C1D3EB"
+" ipv6=[2a03:94e0:ffff:185:243:218:0:204]:443"
+/* nickname=bauruine */
/* extrainfo=0 */
/* ===== */
,
-"213.144.135.22 orport=443 id=9ACD21680CCBE65A5D5A638D85A8388A85D6EE05"
-" ipv6=[2a02:168:6a16:1130::32:102]:443"
-/* nickname=YoYuD1N02NoExit */
+"90.155.5.6 orport=443 id=2D47F039F04EEC03EABE484CC017796A0AB48240"
+" ipv6=[2001:8b0:1628:a008::aa]:443"
+/* nickname=aanetuk */
/* extrainfo=0 */
/* ===== */
,
-"83.229.71.97 orport=443 id=AE337CE945D069964FD78A94E1D32AA94CD7DAC9"
-/* nickname=south */
+"79.117.25.40 orport=443 id=EC94F30532C7DBDB28DBFD615943E134D8D4FC79"
+/* nickname=LePotator */
/* extrainfo=0 */
/* ===== */
,
-"163.172.213.212 orport=10010 id=CB7DB13172E15D4AD7F9404667021DF7DF6E9A4A"
-/* nickname=noconname */
+"192.42.115.103 orport=9004 id=22EBCC0A15FA4850D0D8A9BC621CA42224338EF2"
+" ipv6=[2001:610:510:115:192:42:115:103]:9004"
+/* nickname=Gijsje */
/* extrainfo=0 */
/* ===== */
,
-"142.54.190.250 orport=8088 id=1B174B0FDAAAC50A78B12E64143D47ED7922C8EE"
-/* nickname=who7USicebeer05 */
+"199.170.132.80 orport=9001 id=CA52E423ECBF7D07BB8E1139A39B4D8668CFE2A4"
+/* nickname=NYCMesh1 */
/* extrainfo=0 */
/* ===== */
,
-"158.174.147.175 orport=9001 id=76FFB75E358D50868E5D5042AF77BDC38C39C45A"
-" ipv6=[2001:9b0:29d:cd00:215:5dff:fe02:5f1c]:9001"
-/* nickname=fter */
+"192.24.207.200 orport=9001 id=995362C04EAFB214BC96BE9D8F0F0B712D3BB763"
+/* nickname=bassblitzed */
/* extrainfo=0 */
/* ===== */
,
-"85.49.7.119 orport=9001 id=56377E958B14C1FBAB4461966F3B4CFE594513BF"
-/* nickname=papayaOwo */
+"74.91.23.139 orport=443 id=72511164C1216364123ACB5378132D21BEC24804"
+" ipv6=[2604:4300:a:4c:b19:b00b:babe:cafe]:443"
+/* nickname=TegridyFarms */
/* extrainfo=0 */
/* ===== */
,
-"199.249.230.185 orport=443 id=FAB96E0069596CACADCF1FCBA2407FCE505ED06D"
-" ipv6=[2620:7:6001::185]:80"
-/* nickname=Quintex96 */
+"77.68.30.104 orport=9201 id=A258D70F8B9DB43AE53609C0954D56249F466347"
+/* nickname=Assange007uk2 */
/* extrainfo=0 */
/* ===== */
,
-"144.24.181.175 orport=443 id=A6A361C0CC003103A943E3304B212035F5A38FD6"
-" ipv6=[2603:c020:800f:4500::8]:443"
-/* nickname=GermanCraft8 */
+"45.141.215.169 orport=9000 id=552C2E2AFDD1B740A38CA9768C51EC011B2AF701"
+/* nickname=Quetzalcoatl */
/* extrainfo=0 */
/* ===== */
,
-"69.164.205.192 orport=9001 id=472513311E04110A9EF6AF04E6ADB1AA1CDC33B9"
-" ipv6=[2600:3c00::f03c:92ff:fe25:5835]:9001"
-/* nickname=ElRelayoReturns */
+"185.100.87.174 orport=443 id=D82D18E8359EDFAD0B374887002ABDF1F29EA430"
+" ipv6=[2a06:1700:0:16::1]:443"
+/* nickname=flokinet1 */
/* extrainfo=0 */
/* ===== */
,
-"213.95.190.181 orport=9001 id=11ABDB4D0B944F186A898560CB82C70439957DCA"
-" ipv6=[2001:780:131:13::2]:9001"
-/* nickname=jonasBebe2 */
+"145.239.76.95 orport=6969 id=FCCCECDC44273C67FB374200138464F38DDF39AC"
+" ipv6=[2001:41d0:302:2200::390e]:6969"
+/* nickname=shrimpmaster */
/* extrainfo=0 */
/* ===== */
,
-"199.241.137.60 orport=9001 id=8D8DAD240CECFE9B48DC5F2C6EA20D042D5B8733"
-" ipv6=[2602:ff16:6:0:1:297:0:1]:9001"
-/* nickname=ac1dburn */
+"5.45.98.188 orport=443 id=C7735FB0369094ED6351130E81F3DFED25D67F8B"
+" ipv6=[2a03:4000:5:613:9872:48ff:fede:289d]:443"
+/* nickname=tembi */
/* extrainfo=0 */
/* ===== */
,
-"185.239.222.240 orport=443 id=49E5FB957045FDDC8C53255CEB6BA653E1E9AA5D"
-" ipv6=[2a09:2681:101:9001::1]:443"
-/* nickname=BM01 */
+"81.16.19.39 orport=9001 id=0711B720628A84B14D42107FB8C954EF699B3833"
+" ipv6=[2a03:4000:55:d46::3]:9001"
+/* nickname=Elenore */
/* extrainfo=0 */
/* ===== */
,
-"108.181.100.63 orport=443 id=BFF73A5F900E9749FBA2923AFC42DA803A24A7CA"
-/* nickname=ufer */
+"77.91.85.147 orport=443 id=C7A51E46740C15DEC0535AF5560A1919CE6E5758"
+" ipv6=[2a0e:d602:2:137::2]:443"
+/* nickname=cozybeardev */
/* extrainfo=0 */
/* ===== */
,
-"45.141.215.97 orport=8100 id=E0DBC376BB1E68BD55DADAB9A693D07BA70CFB69"
-/* nickname=Quetzalcoatl */
+"91.143.88.2 orport=443 id=ED7F2BE5D2AC7FCF821A909E2486FFFB95D65272"
+" ipv6=[2a02:180:6:1::2efd]:443"
+/* nickname=Planetclaire63 */
/* extrainfo=0 */
/* ===== */
,
-"107.189.7.144 orport=9100 id=4EFF3D0C9DE539CF1E27BFC5B3E23BC7CB2D41A9"
-" ipv6=[2605:6400:30:f1fa:f57f:d285:3ed9:ee27]:9100"
-/* nickname=Quetzalcoatl */
+"23.129.64.149 orport=443 id=8B9B72D9613E1B674A17DAA6A11FE336C3427191"
+" ipv6=[2620:18c:0:192::149]:443"
+/* nickname=LordNikon */
/* extrainfo=0 */
/* ===== */
,
-"167.86.85.117 orport=9001 id=C1154ABA79D89595B861C9C9794F88E68396D767"
-" ipv6=[2a02:c207:2025:1163::1]:9001"
-/* nickname=azbycx */
+"185.207.107.216 orport=9100 id=B6D8110B34BD401ADF85B7AD0725C445C55EB65B"
+" ipv6=[2a03:4000:1e:7d4:84fb:5fff:fef3:9d56]:9100"
+/* nickname=Quetzalcoatl */
/* extrainfo=0 */
/* ===== */
,
-"185.241.208.232 orport=143 id=393C3DB2EF81C469CC80A982CC31570423829099"
-/* nickname=Quetzalcoatl */
+"72.39.65.1 orport=9001 id=ECD18351D9BA04E1F4055084BA8C6DF19DAF339D"
+/* nickname=need4speed */
/* extrainfo=0 */
/* ===== */
,
-"185.220.101.61 orport=10061 id=5E224061F0E4721429027A130DB607F4FDD0DFE5"
-" ipv6=[2a0b:f4c2:2::61]:10061"
-/* nickname=ForPrivacyNET */
+"45.136.244.187 orport=443 id=01A6AB7119098BBEAD9F538187FFBB4E91F0904F"
+" ipv6=[2a00:b700::1:3ef]:443"
+/* nickname=bauruine */
/* extrainfo=0 */
/* ===== */
,
-"95.216.115.85 orport=8443 id=E3F98C86C9E01138DD8EA06B1E660A0CDB4B2782"
-/* nickname=Finisterre */
+"45.136.30.7 orport=443 id=FA4E158545E803244AB37586B3AE5B8C25A12FFA"
+" ipv6=[2a03:4000:49:687:24bc:e7ff:fe86:785e]:443"
+/* nickname=charon */
/* extrainfo=0 */
/* ===== */
,
-"23.111.189.202 orport=443 id=81AE230D4E2915CC562C0D202D19B3F0F385144A"
-/* nickname=Blastoise */
+"209.141.53.184 orport=9001 id=479524AEFDD60FA6911E5A9553FBDDCE3EF2E5AD"
+" ipv6=[2605:6400:20:1a15:e511:887f:23bd:a199]:9001"
+/* nickname=ToolHaven718 */
/* extrainfo=0 */
/* ===== */
,
-"162.251.116.50 orport=443 id=FCE5FFBFA528DE4BD8674ACFAA5AEE19DD9E0BAF"
-/* nickname=inthedark */
+"205.185.121.170 orport=9001 id=19C64AF24E40C2CE5E3CA5231509213230B46F70"
+/* nickname=c0wb0y */
/* extrainfo=0 */
/* ===== */
,
-"188.68.57.225 orport=8080 id=BE4D8E95F38F335840A650383271FA8A60CBA588"
-" ipv6=[2a03:4000:6:f832:38fc:feff:febb:5c26]:8080"
-/* nickname=ledgh53 */
+"185.241.208.236 orport=110 id=D7A43DD339748E93C4595434E3C18911178C4FFA"
+/* nickname=Quetzalcoatl */
/* extrainfo=0 */
/* ===== */
,
-"185.130.47.58 orport=443 id=FF37592F9AA7EB9380C5EF817DD1A5483A95D969"
-" ipv6=[2a07:e03:2a::bcde]:443"
-/* nickname=privexnl1exit */
+"139.162.63.125 orport=443 id=ACF7FD5B73681BC01BBE8176C63E4675B274111D"
+" ipv6=[2400:8901::f03c:91ff:feb1:8ece]:443"
+/* nickname=laukur3000 */
/* extrainfo=0 */
/* ===== */
,
-"37.228.129.24 orport=443 id=CB42772E3E8F368BF511C890E0051A8DF2A84C3F"
-" ipv6=[2a06:1700:1:1a::1]:443"
-/* nickname=flokinet3 */
+"104.0.0.175 orport=5564 id=52C8B217F594E96AED02D4BF3E212C2CB63127F4"
+/* nickname=openrelay */
/* extrainfo=0 */
/* ===== */
,
-"150.230.253.242 orport=23563 id=D7FEE7CF8D8246C3A74A598E48548142657FB7F1"
-" ipv6=[2603:c024:1:f088:34::]:15477"
-/* nickname=mrchau6 */
+"79.251.246.209 orport=24107 id=6B185DEEB249E4BA6182ECA077530C45E98A6C5F"
+/* nickname=Aykut */
/* extrainfo=0 */
/* ===== */
,
-"95.217.112.218 orport=80 id=485492A420AFDFFFBCCA05DFF317CDCA43052C11"
-" ipv6=[2a01:4f9:4a:2e4e::4]:80"
-/* nickname=arbitraryTessa5 */
+"65.21.249.220 orport=1312 id=5E4D1E6D31413DCCC148A8050224578CBBF12883"
+/* nickname=Unnamed */
/* extrainfo=0 */
/* ===== */
,
-"209.141.36.7 orport=443 id=FE26E025A61F61A0753B52CA19367E20A062E123"
-/* nickname=b1GdaDDyGL1Z */
+"23.153.248.38 orport=443 id=96E80699EEA339F33A9E9DD8892821B1CB4C88BC"
+" ipv6=[2602:2da:0:38::1]:443"
+/* nickname=0x7c0 */
/* extrainfo=0 */
/* ===== */
,
-"89.163.128.28 orport=9001 id=2CE96A8A1DA032664C90F574AFFBECE18A6E8DFC"
-" ipv6=[2001:4ba0:ffff:237::babe]:9001"
-/* nickname=Doedel24 */
+"178.254.20.38 orport=64789 id=408234F6CC9B176A11005E39758D8C2C02A25C33"
+/* nickname=LV233 */
/* extrainfo=0 */
/* ===== */
,
-"78.46.123.26 orport=8443 id=BFC4044119080D8BEE70218978EE83C3FC16AE7A"
-" ipv6=[2a01:4f8:190:62d9::2]:8443"
-/* nickname=antifaang */
+"86.145.227.46 orport=1298 id=2628A97232669B707100BE4046545077E291EDE3"
+/* nickname=UKP1B1S3 */
/* extrainfo=0 */
/* ===== */
,
-"23.128.248.12 orport=443 id=FD68811549AF27912C29FD63DA9FDD183D4536E8"
-" ipv6=[2602:fc05::12]:443"
-/* nickname=StormyCloud */
+"192.42.113.102 orport=9001 id=874D84382C892F3F61CC9E106BF08843DE0B865A"
+" ipv6=[2001:610:510:113:192:42:113:102]:9001"
+/* nickname=Spigen */
/* extrainfo=0 */
/* ===== */
,
-"90.155.5.6 orport=443 id=2D47F039F04EEC03EABE484CC017796A0AB48240"
-" ipv6=[2001:8b0:1628:a008::aa]:443"
-/* nickname=aanetuk */
+"193.35.18.96 orport=9100 id=CF62056A4754CBE657227FFE64F7CB18C1B92D20"
+" ipv6=[2a05:dfc7:40b9::1]:9100"
+/* nickname=prsv */
/* extrainfo=0 */
/* ===== */
,
-"174.162.181.9 orport=9001 id=0BEC860C45F69F047084DFEAFB7E7AD68A06278B"
-/* nickname=Dagoth */
+"108.181.100.63 orport=443 id=BFF73A5F900E9749FBA2923AFC42DA803A24A7CA"
+/* nickname=ufer */
/* extrainfo=0 */
/* ===== */
,
-"195.234.152.86 orport=443 id=868A253C330F40FBE435D9320849397F85823E86"
-/* nickname=dc6jgk4 */
+"140.78.100.38 orport=8443 id=8AC81A91A1196C2C1CBED71C96AA204F7B0FFE00"
+/* nickname=INSRelay38at8443 */
/* extrainfo=0 */
/* ===== */
,
-"60.241.48.194 orport=9002 id=833CEDD28CDB7F3A2EC3EC7398649F3C894FE1AE"
-" ipv6=[2001:470:1f2d:6e::8888]:9002"
-/* nickname=GentooLibre */
+"194.147.140.102 orport=443 id=3F6CEDCF8CA8F8AF550F6545A44738A343B65FBD"
+/* nickname=tor102IPConnectINFO */
/* extrainfo=0 */
/* ===== */
,
-"193.35.18.96 orport=9000 id=581EA58248AFF965440BAC693EA4CD6411F99A9C"
-" ipv6=[2a05:dfc7:40b9::1]:9000"
-/* nickname=prsv */
+"144.76.175.205 orport=443 id=B4C39AD461B21AA48DB4FB371B001D91A3043C0C"
+" ipv6=[2a01:4f8:200:53cc::2]:443"
+/* nickname=luraleen2 */
/* extrainfo=0 */
/* ===== */
,
-"137.22.114.29 orport=9001 id=87F24B0B9D45BF4886738FD587A2A76C077F388F"
-/* nickname=KittyBrand */
+"176.98.22.123 orport=55555 id=AD56555C3CCCE9EA49872967B0C90F169E7EB753"
+/* nickname=myNickName2 */
/* extrainfo=0 */
/* ===== */
,
-"92.60.36.153 orport=9001 id=2D418A89F79DB4A8E658BA549FBB974D1D22DD1A"
-" ipv6=[2a03:4000:33:6e3:1418:12ff:fe82:4abd]:9001"
-/* nickname=MyPalEdSnowden */
+"194.88.143.66 orport=443 id=2096BCFEBB95A1134F39FCF8CEB076FF41A2B48B"
+/* nickname=freja */
/* extrainfo=0 */
/* ===== */
,
-"164.215.1.110 orport=9001 id=AD0652EF631F9C99CE7CE21F1A156AD74F27ED56"
-/* nickname=Raphanus */
+"92.38.184.153 orport=443 id=8E1A82EDB2CFE72E765C98F1FE810539F8B8FC1A"
+/* nickname=sleipner */
/* extrainfo=0 */
/* ===== */
,
-"193.135.10.219 orport=59999 id=05C621B44EF6833889AE7B7E2A0B476569C47E37"
-" ipv6=[2a0a:51c0:0:136::2]:59999"
-/* nickname=electroncash */
+"185.241.208.105 orport=443 id=32C3C255D64BF056E5E2A2B8889B6CE4D8C27647"
+/* nickname=RDPdotSH */
/* extrainfo=0 */
/* ===== */
,
-"5.181.51.6 orport=9001 id=CE0C183AFA24DEDA9B217CB74F041774D8743EAF"
-/* nickname=torrelay */
+"31.179.4.18 orport=11001 id=69AF75BBE6AF4FA419A47689E1CC9B25B744B250"
+/* nickname=CoreRelay001 */
/* extrainfo=0 */
/* ===== */
,
-"137.74.119.109 orport=9001 id=88D6A3C0FC28EAE6B9AD0BA1082223C03C1B32FA"
-/* nickname=FreeHackCom */
+"23.154.177.18 orport=443 id=CCC3E229B4D7DD74BB40699B88615423D0F22DCA"
+/* nickname=UnredactedBasil */
/* extrainfo=0 */
/* ===== */
,
-"135.125.205.25 orport=9001 id=750E9CDFB4066039D01CC23695AD813A13DDEB20"
-" ipv6=[2001:41d0:701:1100::4f60]:9001"
-/* nickname=OnlineVrijheid */
+"135.148.52.231 orport=443 id=BA6E064596B86AF9F55F0603A82C90E958E86E7A"
+/* nickname=twoandtwoone */
/* extrainfo=0 */
/* ===== */
,
-"148.251.191.28 orport=9001 id=FA751944A6DADBB99496E5E06A8EA1C14D5A5C2D"
-/* nickname=fortherepublic */
+"44.242.33.87 orport=9001 id=40D13096BBD11AF198CE61DEE4EAECCE5472F2E7"
+" ipv6=[2600:1f13:775:d400:ceaf:7673:2ab9:a777]:9001"
+/* nickname=OhNoAnotherRelay02 */
/* extrainfo=0 */
/* ===== */
,
-"162.248.160.131 orport=9100 id=234701657300842363E09AEB6B4CDC88D4364FB1"
-" ipv6=[2607:8880::139:83]:9100"
-/* nickname=GrmmlRelayEight */
+"5.45.104.176 orport=9000 id=AA4644F0EC589EEA2F501BB867E32E599F8169DA"
+" ipv6=[2a03:4000:6:102b:c457:f3ff:feb0:a6d0]:9000"
+/* nickname=Quetzalcoatl */
/* extrainfo=0 */
/* ===== */
,
-"66.70.211.20 orport=9001 id=1841CB960128806151B61FC6D87AFBE9A98B99D7"
-/* nickname=SchulteTorRelay001 */
+"23.154.177.11 orport=443 id=66BAC488BEE20465F569E9343D441CB6195D7AC2"
+/* nickname=UnredactedcDc */
/* extrainfo=0 */
/* ===== */
,
-"94.16.113.89 orport=9003 id=2B8E642811FF6F610600F2703AB59E42FB9A00CB"
-/* nickname=torbogen3 */
+"167.235.112.134 orport=9003 id=55E1500DD1CC6A0C0419D4F3414F4FADE29FE50E"
+" ipv6=[2a01:4f8:2200:14dc:120::100]:9003"
+/* nickname=jhsseventhtorrelay */
/* extrainfo=0 */
/* ===== */
,
-"148.251.85.195 orport=9030 id=77A3ADC5D455778B53C2803761916DFB7DA0A790"
-" ipv6=[2a01:4f8:202:6096::2]:9030"
-/* nickname=redvader */
+"104.192.3.74 orport=444 id=6ABFC90631A8CDA0C2D43D266878DBF9DC5BA485"
+" ipv6=[2605:aa80:0:9::3]:444"
+/* nickname=OgresHaveLayers */
/* extrainfo=0 */
/* ===== */
,
-"23.129.64.134 orport=443 id=AC28D573C16BD0C7D42AA70976BF36984A1E4DE0"
-" ipv6=[2620:18c:0:192::134]:443"
-/* nickname=lattera */
+"45.8.144.90 orport=443 id=94EFE76920364D9ACFA8BA157C7C81484F0ACBF6"
+/* nickname=ThirdMusqeteer */
/* extrainfo=0 */
/* ===== */
,
-"45.141.215.200 orport=9000 id=EF194086B185178E1BF549A8F95DE8C03E2DEBF9"
-/* nickname=Quetzalcoatl */
+"188.26.52.167 orport=9001 id=9D958F3711F13AB4BED031EC12E907A9E95F6589"
+/* nickname=cshorerelay */
/* extrainfo=0 */
/* ===== */
,
-"132.145.245.6 orport=443 id=9C97E5840578697030ABFC7784442E32EFD8E91D"
-" ipv6=[2603:c020:8000:6a00:1::1]:443"
-/* nickname=protesilaus */
+"94.32.66.15 orport=9001 id=E43244684E0C924EC082B8ECC735FAF2F8CF1C45"
+/* nickname=punki */
/* extrainfo=0 */
/* ===== */
,
-"185.154.110.142 orport=9001 id=2E3CC55AD57D027FC64BE9C87563C7DD817D5817"
-/* nickname=ferrarizGonzalez */
+"185.241.208.232 orport=9000 id=D54DB93A10CE45B327CE6CFE6717A559CCBEF650"
+/* nickname=Quetzalcoatl */
/* extrainfo=0 */
/* ===== */
,
-"38.97.116.244 orport=9001 id=A0B5B5906EB13F213D7CA9AFEC91934BE3A5930F"
-/* nickname=RandomRecipes */
+"109.207.77.201 orport=443 id=01FC169CAF449D5E5EF67523F69346E7CB6A0572"
+/* nickname=island */
/* extrainfo=0 */
/* ===== */
,
-"135.148.139.41 orport=6968 id=13DC00AF2267554908CE0FCA82687B44968A701F"
-/* nickname=OkrRelay */
+"107.189.8.238 orport=9100 id=E0FC2B6033BCC1AD5CAC295A0B19CF6CF53EED11"
+" ipv6=[2605:6400:30:f330:61ea:72a8:8aea:fa1f]:9100"
+/* nickname=Quetzalcoatl */
/* extrainfo=0 */
/* ===== */
,
-"98.96.164.184 orport=9001 id=4BED68DF9EAF6C111D8778E19CC9AC7AFEC4FC02"
-" ipv6=[2a04:203:7e78:7b00:66b4:fed6:41ea:dd16]:9001"
-/* nickname=georgector */
+"5.199.162.155 orport=9001 id=6997013CB77B6F530540332626C23ACFE52C5096"
+/* nickname=QuakeSARGE */
/* extrainfo=0 */
/* ===== */
,
-"185.220.101.206 orport=443 id=EB9DD80E64DD829A5F7C7ACA5D5FEADFEBFDD847"
-" ipv6=[2a0b:f4c2:2:1::206]:443"
-/* nickname=ForPrivacyNET */
+"193.35.18.120 orport=9000 id=D3CC03CF98D62998E06431D31DA57615718650B4"
+" ipv6=[2a05:dfc7:4128::1]:9000"
+/* nickname=prsv */
/* extrainfo=0 */
/* ===== */
,
-"2.56.10.29 orport=9001 id=74574575E4C839AEF11AF6A944A855D425FB5280"
-/* nickname=mintyone9 */
+"140.78.100.19 orport=8443 id=885C7B6EB943068B762070E276E299319E5AB08C"
+/* nickname=INSRelay19at8443 */
/* extrainfo=0 */
/* ===== */
,
-"185.34.33.2 orport=31415 id=D71B1CA1C9DC7E8CA64158E106AD770A21160FEE"
-" ipv6=[2a00:99a0:0:1000::2]:31415"
-/* nickname=Unnamed */
+"143.47.179.12 orport=443 id=C7059B17CFC7ADC92EC1625139B0BCCDD5737242"
+" ipv6=[2603:c022:c004:c4ff:a1dc:af91:6b4f:994b]:443"
+/* nickname=BigSnowflake6048 */
/* extrainfo=0 */
/* ===== */
,
-"91.52.186.100 orport=420 id=97E7C23B208BE4EE66A663FD6AF01D08638F1877"
-/* nickname=ProPatte */
+"192.42.113.101 orport=9002 id=5C124A27FFD658CB76165718DABFFD4093F5C827"
+" ipv6=[2001:610:510:113:192:42:113:101]:9002"
+/* nickname=Teuntje */
/* extrainfo=0 */
/* ===== */
,
-"89.163.178.20 orport=443 id=C28B080086F6CF327F6AC3CD37633BB91E909213"
-/* nickname=gh0stNet */
+"85.239.34.24 orport=9001 id=04DAB3B5205C0EE19A702EBAFBBBC7AD21C24805"
+/* nickname=Spellbound */
/* extrainfo=0 */
/* ===== */
,
-"213.169.148.151 orport=443 id=42D58335381BC9BB8C9ED98D390109EB74DBCBC4"
-/* nickname=poussin */
+"51.158.230.172 orport=443 id=0D962170FBB3837E85E2314EEAAC49966A153F34"
+/* nickname=tirz */
/* extrainfo=0 */
/* ===== */
,
-"199.249.230.181 orport=443 id=D3A1B7DEF370CBC6055F3FC540A518C8576D7570"
-" ipv6=[2620:7:6001::181]:80"
-/* nickname=Quintex92 */
+"74.208.27.90 orport=9001 id=C60F0BE03DECFAEAEA0398362F985B39DAAF4A54"
+/* nickname=focalmohr */
/* extrainfo=0 */
/* ===== */
,
-"155.4.82.188 orport=9001 id=5CB30C264BB9EB17CF2FC6AEB611593B54C371C2"
-" ipv6=[2001:9b1:c395:9e4a:225:22ff:fefe:dbd8]:9001"
-/* nickname=torminator */
+"172.81.131.139 orport=443 id=D7F156D1A77B9E5CB59EFEB9CBBB6EC93734DBA1"
+/* nickname=anon1mous54 */
/* extrainfo=0 */
/* ===== */
,
-"73.54.200.51 orport=443 id=BC3B34DD0C9E54EF9E10F24317CA230E480E571F"
-/* nickname=ItachiUchiha */
+"192.87.28.82 orport=9001 id=844AE9CAD04325E955E2BE1521563B79FE7094B7"
+" ipv6=[2001:678:230:3028:192:87:28:82]:9001"
+/* nickname=Smeerboel */
/* extrainfo=0 */
/* ===== */
,
-"108.181.56.183 orport=443 id=1E23A3E081E2C802ECE61190C214F0723A66971A"
-/* nickname=redbeans */
+"109.122.221.11 orport=443 id=C476575CBDCD707299EEFDA1B46F130A36EBEB00"
+/* nickname=ano */
/* extrainfo=0 */
/* ===== */
,
-"198.58.107.53 orport=9001 id=2892073608985977DED33F98A9FA27A9C47C8B61"
-/* nickname=intothetylerzone */
+"23.129.64.227 orport=443 id=EEC43C685C0D0F7CF12D0F9E7481E09D03C6BE6C"
+" ipv6=[2620:18c:0:192::227]:443"
+/* nickname=EO */
/* extrainfo=0 */
/* ===== */
,
-"31.165.21.216 orport=9001 id=A170153BF63A9D2E2FBCA3FCD867286AC3B80CEA"
-" ipv6=[2001:1711:fa51:5d80:6099:d2ff:fe21:c2f0]:443"
-/* nickname=yournicerelay */
+"185.237.13.88 orport=443 id=EEF20BA0079A810A7BCE08E7ECABD3E9CC9FED4F"
+/* nickname=st */
/* extrainfo=0 */
/* ===== */
,
-"95.99.0.83 orport=13337 id=9C585AE38D855C0D5C64D4DA1CC6F61C6E7AF642"
-/* nickname=grshdw */
+"185.32.183.225 orport=9001 id=53136799CC1E2DFE0F5D279D79DDE4F51EE9AF0C"
+/* nickname=CzRelay2FuckCCP */
/* extrainfo=0 */
/* ===== */
,
-"23.129.64.211 orport=443 id=FDC2D887B604872DBD0C0BA3F79B911D951D943B"
-" ipv6=[2620:18c:0:192::211]:443"
-/* nickname=EO */
+"23.154.177.5 orport=443 id=A6FFD101B96E86D95B4CCF1DB99D231BF7CD16CB"
+/* nickname=UnredactedEllsberg */
/* extrainfo=0 */
/* ===== */
,
-"179.43.159.195 orport=9001 id=68A54E180F778AFE96C7906A528B1EFEDFD42A47"
-/* nickname=FreeExit */
+"37.120.186.122 orport=4711 id=D6D677014A583E6F783A03F523A6C5DC2F6347D1"
+" ipv6=[2a03:4000:f:992:98d8:54ff:fe3d:fc2b]:4711"
+/* nickname=mittelerde */
/* extrainfo=0 */
/* ===== */
,
-"185.225.210.87 orport=9002 id=54D59FEF67387E1EEE85D4D11685342D15582992"
-/* nickname=privy14me */
+"152.89.254.46 orport=9001 id=63830987301CFA28654FB789C743972AA60EE250"
+" ipv6=[2a0e:b107:dd0::3:7fa3:c010]:9001"
+/* nickname=deathstar */
/* extrainfo=0 */
/* ===== */
,
-"140.78.100.35 orport=8443 id=0FB07690D64CE5C22B5175183C0E59678CDF7EAB"
-/* nickname=INSRelay35at8443 */
+"109.248.147.172 orport=443 id=185F32DEE43CA46F12EDE06107C718DB00E9FDDA"
+/* nickname=CloseOmega */
/* extrainfo=0 */
/* ===== */
,
-"185.247.226.143 orport=443 id=34AA8E15FD8AFAB6C0F2D6ECB3188A656C615F3F"
-/* nickname=Tor1RsMe */
+"45.141.215.200 orport=9100 id=5E40E552910A561C92FEAA0427F3AF07296CE9E0"
+/* nickname=Quetzalcoatl */
/* extrainfo=0 */
/* ===== */
,
-"188.126.83.38 orport=443 id=E0A3471C24C9021CC58FBF774203046FD2BC893F"
-/* nickname=redsox */
+"144.76.200.80 orport=9001 id=2AA5F598F9A1812F01CD99E3B59BB87362ED7438"
+/* nickname=setsun */
/* extrainfo=0 */
/* ===== */
,
-"149.202.79.129 orport=9001 id=D7D5AD4675D33D9DCAAC61E07D5BA92A6908F91A"
-/* nickname=wokestaywokestay */
+"161.97.132.254 orport=9001 id=70D1EB563BBB10F1EE62E537BB9F3BD7419EE11E"
+/* nickname=ZenGarden */
/* extrainfo=0 */
/* ===== */
,
-"140.78.100.29 orport=8443 id=73F34CDC592584C0519988E443E6FDFBA72C790B"
-/* nickname=INSRelay29at8443 */
+"198.98.61.11 orport=9001 id=0011F7E36734D661E83ACD2D7653A3796A913D77"
+/* nickname=freedomrunner */
/* extrainfo=0 */
/* ===== */
,
diff --git a/src/app/config/or_options_st.h b/src/app/config/or_options_st.h
index 290a2bb9b4..36b00662b5 100644
--- a/src/app/config/or_options_st.h
+++ b/src/app/config/or_options_st.h
@@ -396,8 +396,6 @@ struct or_options_t {
/** List of suffixes for <b>AutomapHostsOnResolve</b>. The special value
* "." means "match everything." */
struct smartlist_t *AutomapHostsSuffixes;
- int RendPostPeriod; /**< How often do we post each rendezvous service
- * descriptor? Remember to publish them independently. */
int KeepalivePeriod; /**< How often do we send padding cells to keep
* connections alive? */
int SocksTimeout; /**< How long do we let a socks connection wait
@@ -725,6 +723,19 @@ struct or_options_t {
* accessing this value directly. */
int ClientPreferIPv6DirPort;
+ /** If true, always use the compiled hash implementation. If false, always
+ * the interpreter. Default of "auto" allows a dynamic fallback from
+ * copmiler to interpreter. */
+ int CompiledProofOfWorkHash;
+
+ /** If true, the tor client will use conflux for its general purpose
+ * circuits which excludes onion service traffic. */
+ int ConfluxEnabled;
+
+ /** Has the UX integer value that the client will request from the exit. */
+ char *ConfluxClientUX_option;
+ int ConfluxClientUX;
+
/** The length of time that we think a consensus should be fresh. */
int V3AuthVotingInterval;
/** The length of time we think it will take to distribute votes. */
diff --git a/src/app/config/resolve_addr.c b/src/app/config/resolve_addr.c
index 09d4b800f6..130998b7c8 100644
--- a/src/app/config/resolve_addr.c
+++ b/src/app/config/resolve_addr.c
@@ -810,7 +810,7 @@ find_my_address(const or_options_t *options, int family, int warn_severity,
* want to learn here if the address is considered to come from the
* Internet basically.
*
- * @param addr The address to test if local and also test against our resovled
+ * @param addr The address to test if local and also test against our resolved
* address.
*
* @return True iff address is considered local or else False.
diff --git a/src/app/config/testnet.inc b/src/app/config/testnet.inc
index 039454a0d0..2774a4c8ea 100644
--- a/src/app/config/testnet.inc
+++ b/src/app/config/testnet.inc
@@ -30,5 +30,4 @@
{ "TestingDirConnectionMaxStall", "30 seconds" },
{ "TestingEnableConnBwEvent", "1" },
{ "TestingEnableCellStatsEvent", "1" },
-{ "RendPostPeriod", "2 minutes" },
{ "___UsingTestNetworkDefaults", "1" },
diff --git a/src/app/main/main.c b/src/app/main/main.c
index 838e129d04..a50a0aad6f 100644
--- a/src/app/main/main.c
+++ b/src/app/main/main.c
@@ -1237,10 +1237,10 @@ run_tor_main_loop(void)
const time_t now = time(NULL);
directory_info_has_arrived(now, 1, 0);
- if (server_mode(get_options()) || dir_server_mode(get_options())) {
- /* launch cpuworkers. Need to do this *after* we've read the onion key. */
- cpu_init();
- }
+ /* launch cpuworkers. Need to do this *after* we've read the onion key. */
+ /* launch them always for all tors, now that clients can solve onion PoWs. */
+ cpuworker_init();
+
consdiffmgr_enable_background_compression();
/* Setup shared random protocol subsystem. */
diff --git a/src/app/main/shutdown.c b/src/app/main/shutdown.c
index a6065db5da..b3f1c6d058 100644
--- a/src/app/main/shutdown.c
+++ b/src/app/main/shutdown.c
@@ -23,6 +23,7 @@
#include "core/or/circuitlist.h"
#include "core/or/circuitmux_ewma.h"
#include "core/or/circuitpadding.h"
+#include "core/or/conflux_pool.h"
#include "core/or/connection_edge.h"
#include "core/or/dos.h"
#include "core/or/scheduler.h"
@@ -120,6 +121,7 @@ tor_free_all(int postfork)
rep_hist_free_all();
bwhist_free_all();
circuit_free_all();
+ conflux_pool_free_all();
circpad_machines_free();
entry_guards_free_all();
pt_free_all();
diff --git a/src/app/main/subsystem_list.c b/src/app/main/subsystem_list.c
index 0333077164..4a66e21a79 100644
--- a/src/app/main/subsystem_list.c
+++ b/src/app/main/subsystem_list.c
@@ -14,6 +14,7 @@
#include "lib/cc/torint.h"
#include "core/mainloop/mainloop_sys.h"
+#include "core/or/conflux_sys.h"
#include "core/or/dos_sys.h"
#include "core/or/or_sys.h"
#include "feature/control/btrack_sys.h"
@@ -64,6 +65,7 @@ const subsys_fns_t *tor_subsystems[] = {
&sys_process,
&sys_mainloop,
+ &sys_conflux,
&sys_or,
&sys_dos,
diff --git a/src/config/geoip b/src/config/geoip
index ea256a2318..2824ceffb6 100644
--- a/src/config/geoip
+++ b/src/config/geoip
@@ -10,7 +10,7 @@
#
# Location Database Export
#
-# Generated: Mon, 18 Sep 2023 04:43:32 GMT
+# Generated: Mon, 25 Sep 2023 04:43:56 GMT
# Vendor: IPFire Project
# License: CC BY-SA 4.0
#
@@ -400,8 +400,7 @@
37350656,37350911,GB
37350912,37351167,TR
37351168,37351423,NL
-37351424,37351679,TR
-37351680,37351935,NZ
+37351424,37351935,TR
37351936,37352191,IN
37352192,37352447,NZ
37352448,37353471,SE
@@ -433,7 +432,7 @@
37369856,37370879,NL
37370880,37371903,MD
37371904,37372415,AP
-37372416,37372927,US
+37372416,37372927,NL
37372928,37373951,RU
37373952,37374463,GB
37374464,37374719,AP
@@ -933,9 +932,7 @@
86497280,86499327,NL
86499328,86503423,FR
86503424,86505471,DE
-86505472,86505727,GB
-86505728,86505983,US
-86505984,86507519,GB
+86505472,86507519,GB
86507520,86573055,ES
86573056,86638591,SA
86638592,86656767,RU
@@ -1005,9 +1002,7 @@
86798336,86802431,CH
86802432,86804479,GE
86804480,86806527,DK
-86806528,86809087,TR
-86809088,86809343,NL
-86809344,86810623,TR
+86806528,86810623,TR
86810624,86812671,FR
86812672,86814719,RU
86814720,86816767,SE
@@ -1261,7 +1256,12 @@
87971840,87972863,IE
87972864,87973375,GI
87973376,87973887,GB
-87973888,87981823,DE
+87973888,87978239,DE
+87978240,87978495,GB
+87978496,87979519,US
+87979520,87979775,BR
+87979776,87980031,SG
+87980032,87981823,DE
87981824,87982079,GB
87982080,87988223,IQ
87988224,87990271,CA
@@ -1429,8 +1429,7 @@
90764288,90765055,US
90765056,90765311,IL
90765312,90767359,PL
-90767360,90767615,UA
-90767616,90767871,EE
+90767360,90767871,EE
90767872,90768127,DE
90768128,90768383,US
90768384,90768639,TR
@@ -1440,11 +1439,9 @@
90769408,90769919,GB
90769920,90770175,EE
90770176,90770431,GB
-90770432,90770687,EE
-90770688,90771199,NL
-90771200,90771711,EE
-90771712,90771967,CH
-90771968,90772223,EE
+90770432,90770943,EE
+90770944,90771199,NL
+90771200,90772223,EE
90772224,90772479,TR
90772480,90772735,NL
90772736,90772991,EE
@@ -1457,19 +1454,20 @@
90775296,90775551,CA
90775552,90775807,NL
90775808,90776063,EE
-90776064,90777087,NL
-90777088,90778367,EE
-90778368,90779135,NL
+90776064,90776319,NL
+90776320,90776575,EE
+90776576,90777087,NL
+90777088,90778623,EE
+90778624,90779135,NL
90779136,90779391,CA
90779392,90779647,NL
90779648,90779903,EE
90779904,90780159,NL
90780160,90780415,EE
-90780416,90781951,NL
-90781952,90782207,EE
-90782208,90782463,NL
+90780416,90780671,NL
+90780672,90782463,EE
90782464,90782719,GB
-90782720,90782975,NL
+90782720,90782975,EE
90782976,90783231,GB
90783232,90783487,EE
90783488,90783743,NL
@@ -1478,15 +1476,14 @@
90784512,90784767,GB
90784768,90785023,US
90785024,90785279,NL
-90785280,90785535,US
+90785280,90785535,EE
90785536,90785791,CA
90785792,90786047,NL
90786048,90786303,GB
90786304,90786559,EE
90786560,90786815,NL
90786816,90787327,DE
-90787328,90787583,US
-90787584,90787839,EE
+90787328,90787839,EE
90787840,90788095,CA
90788096,90788351,EE
90788352,90788607,TR
@@ -1494,29 +1491,25 @@
90788864,90789119,EE
90789120,90789375,IN
90789376,90790399,US
-90790400,90791423,GB
+90790400,90791423,EE
90791424,90791679,NL
90791680,90791935,US
-90791936,90792191,DE
-90792192,90792447,EE
+90791936,90792447,EE
90792448,90792703,CA
-90792704,90792959,US
-90792960,90793215,EE
-90793216,90793727,NL
+90792704,90793471,EE
+90793472,90793727,NL
90793728,90793983,EE
90793984,90794239,CA
90794240,90794751,EE
90794752,90795007,NL
-90795008,90795263,EE
-90795264,90795775,US
-90795776,90796543,NL
+90795008,90795519,EE
+90795520,90795775,US
+90795776,90796031,EE
+90796032,90796543,NL
90796544,90797055,US
-90797056,90797311,NL
-90797312,90797567,EE
-90797568,90798079,NL
-90798080,90798335,EE
-90798336,90798591,NL
-90798592,90799103,EE
+90797056,90797567,EE
+90797568,90797823,NL
+90797824,90799103,EE
90799104,90799359,NL
90799360,90799615,US
90799616,90799871,NL
@@ -1524,11 +1517,9 @@
90800128,90800639,US
90800640,90801151,EE
90801152,90801407,PE
-90801408,90801663,US
-90801664,90801919,EE
+90801408,90801919,EE
90801920,90802175,US
-90802176,90803199,EE
-90803200,90803455,US
+90802176,90803455,EE
90803456,90803711,PE
90803712,90803967,EE
90803968,90804223,NL
@@ -1537,29 +1528,24 @@
90807296,90807551,DE
90807552,90807807,EE
90807808,90808063,CA
-90808064,90808319,US
-90808320,90809343,NL
-90809344,90809599,EE
+90808064,90809599,EE
90809600,90810111,NL
-90810112,90810367,US
+90810112,90810367,EE
90810368,90810623,NL
-90810624,90811135,EE
-90811136,90811391,US
+90810624,90811391,EE
90811392,90811647,CA
-90811648,90812927,US
+90811648,90811903,EE
+90811904,90812927,US
90812928,90813183,EE
90813184,90813439,US
-90813440,90814463,EE
-90814464,90814719,GB
-90814720,90814975,EE
+90813440,90814975,EE
90814976,90815231,NL
90815232,90815487,EE
90815488,90815743,NL
90815744,90815999,US
-90816000,90816767,NL
+90816000,90816767,EE
90816768,90817023,US
-90817024,90817279,NL
-90817280,90817535,EE
+90817024,90817535,EE
90817536,90817791,US
90817792,90818047,EE
90818048,90818815,NL
@@ -1567,36 +1553,32 @@
90819072,90819327,NL
90819328,90819839,EE
90819840,90820095,TR
-90820096,90820351,US
-90820352,90820607,EE
+90820096,90820607,EE
90820608,90820863,US
-90820864,90821375,IN
-90821376,90821631,SG
-90821632,90821887,EE
-90821888,90822143,US
+90820864,90822143,EE
90822144,90822655,RU
90822656,90822911,NL
-90822912,90823167,US
-90823168,90824191,NL
-90824192,90825215,GB
-90825216,90825727,NL
-90825728,90825983,EE
+90822912,90823167,EE
+90823168,90823423,NL
+90823424,90823935,EE
+90823936,90824191,NL
+90824192,90825215,EE
+90825216,90825471,NL
+90825472,90825983,EE
90825984,90826239,NL
-90826240,90826495,IT
+90826240,90826495,EE
90826496,90828543,US
90828544,90829055,SK
-90829056,90829311,US
+90829056,90829311,BG
90829312,90829567,DE
-90829568,90829823,NZ
+90829568,90829823,EE
90829824,90830079,RO
90830080,90830335,HU
-90830336,90830591,NZ
+90830336,90830591,EE
90830592,90831359,US
-90831360,90831871,NL
+90831360,90831871,EE
90831872,90832127,US
-90832128,90832383,EE
-90832384,90832639,NL
-90832640,90832895,US
+90832128,90832895,EE
90832896,90898431,IR
90898432,90963967,AE
90963968,91226111,SA
@@ -1663,7 +1645,7 @@
92631808,92632063,PL
92632064,92633087,CA
92633088,92634111,UZ
-92634112,92635135,CH
+92634112,92635135,GB
92635136,92643327,BA
92643328,92643839,GE
92643840,92644095,NL
@@ -2038,7 +2020,7 @@
95702784,95703039,NL
95703040,95703551,DE
95703552,95703807,RO
-95703808,95704063,ID
+95703808,95704063,US
95704064,95705087,NL
95705088,95706111,DE
95706112,95707135,RU
@@ -2518,9 +2500,7 @@
96337920,96403455,IR
96403456,96468991,AZ
96468992,96731135,AE
-96731136,96780031,FR
-96780032,96780287,ES
-96780288,96795903,FR
+96731136,96795903,FR
96795904,96796159,ES
96796160,96796671,FR
96796672,96862207,AZ
@@ -3282,7 +3262,8 @@
266758912,266759679,US
266759680,266759935,CA
266759936,266760191,DE
-266760192,266764543,US
+266760192,266760447,IT
+266760448,266764543,US
266764544,266764799,JP
266764800,266765055,US
266765056,266765311,DE
@@ -3480,9 +3461,7 @@
387612416,387612671,NL
387612672,387619583,US
387619584,387619839,IN
-387619840,387620607,US
-387620608,387620863,NL
-387620864,387640063,US
+387619840,387640063,US
387640064,387640319,NL
387640320,387643391,US
387643392,387643647,TR
@@ -4653,15 +4632,25 @@
396484608,396484863,US
396486656,396486911,US
396488704,396488959,US
+396490752,396491007,CA
396492800,396493055,US
+396494848,396495103,US
396496896,396497151,US
+396498944,396499199,US
396500992,396501247,US
+396503040,396503295,US
396505088,396505343,US
+396507136,396507391,US
396509184,396509439,PR
+396511232,396511487,US
396513280,396513535,US
+396515328,396515583,US
396517376,396517631,US
+396519424,396519679,US
396521472,396521983,US
+396523520,396523775,US
396525568,396525823,US
+396527616,396527871,US
396529664,396529919,US
396533760,396534015,US
396537856,396538367,US
@@ -5173,7 +5162,9 @@
400999936,401000191,AP
401000192,401004031,US
401004032,401004287,AP
-401004288,401006335,US
+401004288,401005311,US
+401005312,401005567,AP
+401005568,401006335,US
401006336,401006591,DE
401006592,401007871,US
401007872,401008127,AP
@@ -6261,8 +6252,7 @@
522894336,522895103,NL
522895104,522911743,RU
522911744,522953727,UA
-522953728,522953983,HK
-522953984,522954495,US
+522953728,522954495,US
522954496,522954751,NL
522954752,522955775,UA
522955776,522956287,IS
@@ -6382,7 +6372,8 @@
528755712,528756735,SG
528756736,528757759,IT
528757760,528758783,US
-528758784,528759295,AE
+528758784,528759039,AE
+528759040,528759295,SE
528759296,528759551,DE
528759552,528759807,SE
528759808,528760831,US
@@ -6464,7 +6455,9 @@
529800704,529800959,KG
529800960,529805823,RU
529805824,529806335,UA
-529806336,529818367,CZ
+529806336,529807359,CZ
+529807360,529809407,RU
+529809408,529818367,CZ
529818368,529818623,RU
529818624,529819647,UZ
529819648,529825791,RU
@@ -6705,9 +6698,7 @@
532348672,532348927,DE
532348928,532365311,IE
532365312,532365567,NL
-532365568,532365823,DE
-532365824,532366079,US
-532366080,532366335,DE
+532365568,532366335,DE
532366336,532366591,ES
532366592,532366847,AP
532366848,532367359,DE
@@ -7744,8 +7735,8 @@
625508864,625509119,BG
625509120,625509375,RU
625509376,625509631,JP
-625509632,625509887,US
-625509888,625510655,NL
+625509632,625510143,US
+625510144,625510655,NL
625510656,625510911,FR
625510912,625511167,NL
625511168,625511679,RU
@@ -7821,7 +7812,7 @@
625840640,625840895,FR
625840896,625841151,FI
625841152,625841407,RU
-625841408,625841663,CZ
+625841408,625841663,IT
625841664,625841919,RU
625841920,625842175,US
625842176,625844223,PL
@@ -7886,7 +7877,9 @@
628097024,628230143,RU
628230144,628232191,IT
628232192,628236287,RU
-628236288,628243455,DE
+628236288,628236543,DE
+628236544,628236799,GB
+628236800,628243455,DE
628243456,628243711,NL
628243712,628244479,DE
628244480,628246527,FR
@@ -8020,7 +8013,7 @@
629202944,629207039,RO
629207040,629209087,AU
629209088,629209599,ID
-629209600,629210111,AU
+629209600,629210111,AE
629210112,629210623,TW
629210624,629211135,US
629211136,629276671,IR
@@ -8068,7 +8061,7 @@
629899264,629899519,TH
629899520,629899775,NL
629899776,629900031,IN
-629900032,629900287,TR
+629900032,629900287,BG
629900288,629901311,GB
629901312,629903359,NL
629903360,629905407,PL
@@ -8101,7 +8094,7 @@
629996544,629996799,NL
629996800,629997055,TR
629997056,629997311,NL
-629997312,629997567,US
+629997312,629997567,RU
629997568,630063103,SA
630063104,630128639,IL
630128640,630129663,GB
@@ -8650,8 +8643,8 @@
637927424,637965311,HK
637965312,637966335,US
637966336,637968639,HK
-637968640,637969407,US
-637969408,637971455,HK
+637968640,637969919,US
+637969920,637971455,HK
637971456,637976575,US
637976576,637978623,KR
637978624,637984767,HK
@@ -9503,9 +9496,7 @@
701459712,701460223,GB
701460224,701460479,KE
701460480,701460735,BI
-701460736,701461247,KE
-701461248,701461503,CD
-701461504,701464575,KE
+701460736,701464575,KE
701464576,701472767,MU
701472768,701480959,TG
701480960,701490175,CI
@@ -10143,7 +10134,10 @@
732909312,732909567,US
732909568,732909823,ID
732909824,732910079,SA
-732910080,732954623,SG
+732910080,732910335,SG
+732910336,732911615,ID
+732911616,732912639,VN
+732912640,732954623,SG
732954624,734396415,CN
734396416,734527487,HK
734527488,734789631,KR
@@ -10877,7 +10871,8 @@
737738752,737739519,SG
737739520,737739775,HK
737739776,737740799,CN
-737740800,737741311,AP
+737740800,737741055,HK
+737741056,737741311,AP
737741312,737741823,HK
737741824,737742079,SG
737742080,737742335,US
@@ -11400,7 +11395,8 @@
755544064,755544319,RU
755544320,755545087,NL
755545088,755546111,GB
-755546112,755547135,HK
+755546112,755546367,HU
+755546368,755547135,HK
755547136,755547903,US
755547904,755548159,TR
755548160,755549183,US
@@ -11993,7 +11989,7 @@
755990016,755991551,AM
755991552,755993599,ES
755993600,755994367,TR
-755994368,755994623,NL
+755994368,755994623,US
755994624,755995391,TR
755995392,755995647,AR
755995648,755996671,AM
@@ -12056,41 +12052,78 @@
757512704,757512959,AP
757512960,757514495,US
757514496,757514751,AP
-757514752,757526527,US
+757514752,757518079,US
+757518080,757518335,UA
+757518336,757522687,US
+757522688,757522943,UA
+757522944,757526527,US
757526528,757526783,AP
-757526784,757530367,US
+757526784,757527295,US
+757527296,757527551,UA
+757527552,757530367,US
757530368,757530623,AP
757530624,757538815,US
757538816,757539071,AP
757539072,757539327,US
757539328,757539839,AP
-757539840,757543423,US
+757539840,757540863,US
+757540864,757541375,UA
+757541376,757541631,US
+757541632,757541887,UA
+757541888,757543423,US
757543424,757543679,AP
757543680,757544703,US
757544704,757544959,AP
757544960,757546495,US
757546496,757546751,AP
-757546752,757549823,US
+757546752,757547007,UA
+757547008,757549823,US
757549824,757550079,AP
-757550080,757557503,US
+757550080,757554687,US
+757554688,757554943,UA
+757554944,757557503,US
757557504,757557759,AP
-757557760,757560575,US
+757557760,757558783,US
+757558784,757559295,UA
+757559296,757559551,US
+757559552,757559807,UA
+757559808,757560575,US
757560576,757560831,HK
-757560832,757562111,US
+757560832,757561087,US
+757561088,757561343,UA
+757561344,757562111,US
757562112,757562367,AP
757562368,757571583,US
757571584,757571839,AP
-757571840,757572607,US
+757571840,757572351,US
+757572352,757572607,UA
757572608,757573119,AP
-757573120,757578495,US
+757573120,757573631,UA
+757573632,757573887,US
+757573888,757574143,UA
+757574144,757576447,US
+757576448,757576703,AP
+757576704,757577215,US
+757577216,757577727,UA
+757577728,757578495,US
757578496,757578751,AP
-757578752,757580799,US
+757578752,757579775,US
+757579776,757580031,UA
+757580032,757580799,US
757580800,757581055,AP
-757581056,757583103,US
+757581056,757582079,US
+757582080,757582335,UA
+757582336,757583103,US
757583104,757583359,AP
-757583360,757586687,US
+757583360,757585919,US
+757585920,757586175,UA
+757586176,757586687,US
757586688,757586943,AU
-757586944,757590783,US
+757586944,757587711,US
+757587712,757587967,UA
+757587968,757589247,US
+757589248,757589503,UA
+757589504,757590783,US
757590784,757591039,AP
757591040,757592063,US
757592064,757592319,AP
@@ -12283,7 +12316,8 @@
759256064,759258111,DK
759258112,759259135,MX
759259136,759260159,GB
-759260160,759261183,IL
+759260160,759260415,DE
+759260416,759261183,IL
759261184,759263231,FR
759263232,759263999,GB
759264000,759264255,DE
@@ -12490,6 +12524,7 @@
759437312,759439615,CO
759439872,759440383,HN
759440384,759441407,CO
+759441408,759442431,DO
759562240,759564287,BR
759564288,759565311,AR
759565312,759566335,EC
@@ -12634,8 +12669,7 @@
760264704,760264959,US
760264960,760266751,DE
760266752,760267007,US
-760267008,760267263,DE
-760267264,760267775,GB
+760267008,760267775,GB
760267776,760268799,EC
760268800,760269823,PT
760269824,760270847,RU
@@ -12691,7 +12725,9 @@
760308736,760309759,TR
760309760,760310783,ES
760310784,760311807,HU
-760311808,760312831,UA
+760311808,760312319,UA
+760312320,760312575,EU
+760312576,760312831,UA
760312832,760313087,DE
760313088,760313343,IT
760313344,760313599,US
@@ -12836,7 +12872,8 @@
760418304,760419327,RU
760419328,760419839,PY
760419840,760421375,JP
-760421376,760421887,US
+760421376,760421631,US
+760421632,760421887,NL
760421888,760422399,BG
760422400,760423423,TR
760423424,760424447,GB
@@ -13107,7 +13144,8 @@
760624128,760625151,LT
760625152,760626175,RS
760626176,760627711,AU
-760627712,760628735,US
+760627712,760627967,GB
+760627968,760628735,US
760628736,760628991,AU
760628992,760629503,PH
760629504,760629759,GB
@@ -13121,7 +13159,7 @@
760633344,760634367,DE
760634368,760634879,BE
760634880,760635135,US
-760635136,760635391,BE
+760635136,760635391,JP
760635392,760637439,FR
760637440,760638463,SE
760638464,760639487,IT
@@ -13275,8 +13313,7 @@
760744448,760744959,HK
760744960,760745215,US
760745216,760745471,DE
-760745472,760745727,IN
-760745728,760745983,AE
+760745472,760745983,AE
760745984,760747007,NL
760747008,760747263,FR
760747264,760747519,GB
@@ -13303,7 +13340,7 @@
760761344,760762367,NL
760762368,760763391,GB
760763392,760764415,AU
-760764416,760764671,BG
+760764416,760764671,IN
760764672,760764927,TR
760764928,760765183,NL
760765184,760765439,TR
@@ -13329,7 +13366,7 @@
760775680,760776703,FR
760776704,760777215,TR
760777216,760777471,NL
-760777472,760777727,UA
+760777472,760777727,EU
760777728,760778751,FR
760778752,760779775,GB
760779776,760780799,RU
@@ -13385,8 +13422,10 @@
760813056,760813311,RU
760813312,760813567,CY
760813568,760814591,RU
-760814592,760815615,EU
-760815616,760816639,US
+760814592,760815103,EU
+760815104,760815359,BR
+760815360,760815615,EU
+760815616,760816639,NL
760816640,760816895,FR
760816896,760817151,GB
760817152,760817407,FR
@@ -13459,7 +13498,7 @@
760869888,760870143,AU
760870144,760870399,MD
760870400,760870655,TR
-760870656,760870911,BG
+760870656,760870911,GB
760870912,760871167,FR
760871168,760871423,IT
760871424,760872191,GB
@@ -13472,7 +13511,8 @@
760876032,760877055,NL
760877056,760877311,TR
760877312,760877567,UA
-760877568,760878079,GB
+760877568,760877823,GB
+760877824,760878079,US
760878080,760879103,IT
760879104,760880127,AT
760880128,760881151,US
@@ -13571,7 +13611,8 @@
760952576,760952831,FI
760952832,760953855,NL
760953856,760955135,DE
-760955136,760955903,RU
+760955136,760955647,RU
+760955648,760955903,KZ
760955904,760956927,NL
760956928,760957951,GB
760957952,760958463,DE
@@ -13678,9 +13719,7 @@
761027584,761028607,IR
761028608,761029631,AU
761029632,761030655,EE
-761030656,761031167,GB
-761031168,761031423,TR
-761031424,761031679,GB
+761030656,761031679,GB
761031680,761032703,FR
761032704,761033727,DE
761033728,761034751,IL
@@ -13698,9 +13737,7 @@
761043968,761044479,NL
761044480,761044991,HK
761044992,761045759,BD
-761045760,761046015,IN
-761046016,761046527,US
-761046528,761047039,IN
+761045760,761047039,IN
761047040,761048063,NL
761048064,761048319,RU
761048320,761048575,UZ
@@ -13790,7 +13827,8 @@
761110528,761111551,PL
761111552,761112063,BE
761112064,761112575,SC
-761112576,761113599,TR
+761112576,761112831,IR
+761112832,761113599,TR
761113600,761114623,GB
761114624,761115647,DE
761115648,761116671,ES
@@ -14416,7 +14454,8 @@
762882048,762883071,HK
762883072,762883839,PH
762883840,762884095,IN
-762884096,762885119,NL
+762884096,762884863,MD
+762884864,762885119,BE
762885120,762887167,HK
762887168,762888191,IN
762889216,762890239,PK
@@ -14468,7 +14507,8 @@
762952704,762953727,SG
762953728,762957823,HK
762957824,762958847,AU
-762958848,762959871,HK
+762958848,762959103,CN
+762959104,762959871,HK
762959872,762960895,ID
762960896,762964991,IN
762964992,762966015,KH
@@ -14934,9 +14974,7 @@
763517952,763518975,DE
763518976,763519999,PS
763520000,763521023,NL
-763521024,763521535,DE
-763521536,763521791,US
-763521792,763522047,DE
+763521024,763522047,DE
763522048,763523071,IT
763523072,763523327,RS
763523328,763523839,RU
@@ -15066,7 +15104,9 @@
763620352,763621375,IT
763621376,763622399,NL
763622400,763623423,LU
-763623424,763624447,US
+763623424,763623679,NL
+763623680,763623935,US
+763623936,763624447,NL
763624448,763625471,CH
763625472,763625727,FR
763625728,763625983,DE
@@ -15150,8 +15190,9 @@
763677696,763678463,RU
763678464,763678719,DE
763678720,763680767,IT
-763680768,763681023,US
-763681024,763681791,DE
+763680768,763681279,US
+763681280,763681535,HK
+763681536,763681791,DE
763681792,763682815,IT
763682816,763683327,AU
763683328,763683583,CH
@@ -15339,10 +15380,9 @@
763811840,763812863,UZ
763812864,763813375,SE
763813376,763813887,NL
-763813888,763814143,DE
+763813888,763814143,US
763814144,763814399,NL
-763814400,763814655,DE
-763814656,763814911,US
+763814400,763814911,DE
763814912,763815935,GB
763815936,763816959,DE
763816960,763817983,HU
@@ -15508,8 +15548,7 @@
763931648,763932671,NL
763932672,763933695,EU
763933696,763934719,RU
-763934720,763934975,KR
-763934976,763935743,VG
+763934720,763935743,VG
763935744,763936767,HR
763936768,763938047,ES
763938048,763938303,HK
@@ -15525,8 +15564,7 @@
763943424,763943679,FR
763943680,763943935,GB
763943936,763944959,DE
-763944960,763947007,NL
-763947008,763948031,US
+763944960,763948031,NL
763948032,763949055,TH
763949056,763949567,US
763949568,763949823,EU
@@ -15601,7 +15639,7 @@
764001280,764002047,RU
764002048,764002303,AE
764002304,764002559,US
-764002560,764002815,TR
+764002560,764002815,DE
764002816,764003071,US
764003072,764003327,DE
764003328,764004351,NL
@@ -15664,7 +15702,7 @@
764040960,764041215,RO
764041216,764042239,HU
764042240,764043263,IN
-764043264,764044287,DE
+764043264,764044287,RO
764044288,764044799,US
764044800,764045055,AU
764045056,764045311,CN
@@ -15827,7 +15865,9 @@
764155904,764156927,RU
764156928,764157951,IR
764157952,764158975,US
-764158976,764159999,DE
+764158976,764159487,DE
+764159488,764159743,CA
+764159744,764159999,HK
764160000,764160511,GR
764160512,764161023,GB
764161024,764162047,UA
@@ -15875,7 +15915,7 @@
764190720,764191743,ES
764191744,764192255,FR
764192256,764192511,ES
-764192512,764192767,NL
+764192512,764192767,GB
764192768,764193535,RU
764193536,764193791,BE
764193792,764194047,RU
@@ -16106,7 +16146,7 @@
764346368,764346623,AU
764346624,764347647,DE
764347648,764347903,AE
-764347904,764348159,GB
+764347904,764348159,US
764348160,764348415,AE
764348416,764349439,US
764349440,764350463,GB
@@ -16223,7 +16263,7 @@
764441600,764442623,SE
764442624,764443647,PL
764443648,764444671,IR
-764444672,764445695,US
+764444672,764445695,BE
764445696,764446719,DE
764446720,764447743,HK
764447744,764448767,IT
@@ -16345,7 +16385,10 @@
764535808,764536319,HK
764536320,764536831,AP
764536832,764537855,GB
-764537856,764539903,DE
+764537856,764539135,DE
+764539136,764539391,US
+764539392,764539647,DE
+764539648,764539903,US
764539904,764540927,ES
764540928,764541183,BR
764541184,764541439,FR
@@ -16410,17 +16453,13 @@
764586752,764587007,RU
764587008,764588031,DE
764588032,764589055,GB
-764589056,764590079,NL
-764590080,764590591,US
-764590592,764590847,NL
-764590848,764591103,US
+764589056,764591103,NL
764591104,764592127,ES
764592128,764592639,LT
764592640,764593151,LU
764593152,764594175,NL
764594176,764594687,TR
-764594688,764594943,US
-764594944,764595199,LT
+764594688,764595199,US
764595200,764596223,FR
764596224,764597247,NL
764597248,764598271,FR
@@ -16490,7 +16529,8 @@
764645376,764646399,RU
764646400,764647423,UA
764647424,764648447,LT
-764648448,764649727,NL
+764648448,764649471,HU
+764649472,764649727,NL
764649728,764649983,LU
764649984,764650495,RU
764650496,764650751,CA
@@ -16531,9 +16571,11 @@
764675328,764675583,DE
764675584,764675839,NL
764675840,764676095,CA
-764676096,764676607,US
+764676096,764676351,US
+764676352,764676607,RO
764676608,764676863,NL
-764676864,764678143,GB
+764676864,764677119,RO
+764677120,764678143,GB
764678144,764679167,SE
764679168,764680191,IT
764680192,764680447,PL
@@ -16547,7 +16589,8 @@
764685312,764686335,DE
764686336,764686591,CH
764686592,764686847,BE
-764686848,764687359,NL
+764686848,764687103,AU
+764687104,764687359,NL
764687360,764688383,DE
764688384,764689407,GB
764689408,764691455,NL
@@ -16573,7 +16616,7 @@
764708352,764708607,JP
764708608,764708863,US
764708864,764709887,DE
-764709888,764710143,TR
+764709888,764710143,HK
764710144,764710399,NL
764710400,764710655,IT
764710656,764710911,IN
@@ -16644,7 +16687,9 @@
764760832,764761087,FR
764761088,764762111,AE
764762112,764763135,NL
-764763136,764763903,SI
+764763136,764763391,DE
+764763392,764763647,ID
+764763648,764763903,SI
764763904,764764159,BR
764764160,764765183,BE
764765184,764765439,US
@@ -16713,8 +16758,7 @@
764806656,764807167,EU
764807168,764808191,RU
764808192,764809215,ES
-764809216,764809983,NL
-764809984,764810239,US
+764809216,764810239,NL
764810240,764810751,SI
764810752,764811007,GB
764811008,764811263,CA
@@ -16751,7 +16795,7 @@
764830720,764831743,DE
764831744,764832767,NL
764832768,764833023,IL
-764833024,764833279,US
+764833024,764833279,IT
764833280,764833535,UA
764833536,764833791,IT
764833792,764834047,DE
@@ -16777,7 +16821,8 @@
764852224,764853247,ES
764853248,764854271,NL
764854272,764855295,ES
-764855296,764856319,EU
+764855296,764855807,EU
+764855808,764856319,HK
764856320,764857343,IT
764857344,764858367,RU
764858368,764859391,AE
@@ -17075,7 +17120,8 @@
765092352,765092607,NL
765092608,765092863,FR
765092864,765093887,IE
-765093888,765094655,US
+765093888,765094399,US
+765094400,765094655,GB
765094656,765094911,AE
765094912,765095935,DE
765095936,765096959,FI
@@ -17209,7 +17255,7 @@
765191168,765192191,FR
765192192,765193215,GB
765193216,765194239,RU
-765194240,765195263,EU
+765194240,765195263,ES
765195264,765196287,AT
765196288,765196543,DE
765196544,765196799,NL
@@ -17337,8 +17383,7 @@
765294336,765294591,EU
765294592,765295615,NL
765295616,765296639,IN
-765296640,765297663,US
-765297664,765298943,NL
+765296640,765298943,NL
765298944,765299199,DE
765299200,765299711,NL
765299712,765299967,RU
@@ -17418,7 +17463,8 @@
765358080,765359103,NL
765359104,765360127,SE
765360128,765361151,IR
-765361152,765361919,GB
+765361152,765361663,GB
+765361664,765361919,US
765361920,765362175,TR
765362176,765363199,UA
765363200,765364223,GB
@@ -17761,8 +17807,8 @@
766040064,766043135,BR
766043136,766046207,MX
766046208,766059519,BR
-766059520,766060031,PE
-766060032,766060543,CO
+766059520,766059775,PE
+766059776,766060543,CO
766060544,766063615,BR
766063616,766064127,AR
766064128,766064639,CL
@@ -18121,7 +18167,8 @@
766757888,766768127,BR
766768128,766769151,CO
766769152,766770175,BR
-766770176,766771199,AR
+766770176,766770431,AR
+766770432,766771199,PY
766771200,766773247,BR
766773248,766774271,MX
766774272,766776831,BR
@@ -19555,9 +19602,7 @@
772304896,772305919,HK
772305920,772306431,PH
772306432,772306943,TW
-772306944,772307455,DE
-772307456,772307711,HK
-772307712,772308223,DE
+772306944,772308223,DE
772308224,772308479,HK
772308480,772308991,DE
772308992,772314367,RU
@@ -19691,7 +19736,8 @@
772954112,772958207,FR
772958208,772958463,AE
772958464,772958719,TR
-772958720,772959231,NL
+772958720,772958975,US
+772958976,772959231,NL
772959232,772959487,RO
772959488,772959743,IQ
772959744,772959999,DE
@@ -19768,8 +19814,8 @@
773088768,773089023,GR
773089024,773089279,RO
773089280,773090047,LB
-773090048,773090303,US
-773090304,773090559,LB
+773090048,773090303,TR
+773090304,773090559,GR
773090560,773090815,HK
773090816,773091071,GR
773091072,773091327,LB
@@ -19780,8 +19826,8 @@
773107712,773111807,RU
773111808,773115903,TJ
773115904,773116415,PS
-773116416,773116927,US
-773116928,773119999,EU
+773116416,773117951,US
+773117952,773119999,EU
773120000,773124095,GB
773124096,773128191,CH
773128192,773132287,DE
@@ -19870,8 +19916,8 @@
773591040,773593087,RU
773593088,773595135,IT
773595136,773597183,DE
-773597184,773598207,US
-773598208,773601279,GB
+773597184,773599231,US
+773599232,773601279,GB
773601280,773603327,LV
773603328,773605375,UA
773605376,773607423,IR
@@ -20050,8 +20096,7 @@
773993472,773993983,ES
773993984,773994239,TR
773994240,773994495,DE
-773994496,773995007,ES
-773995008,773995519,TR
+773994496,773995519,ES
773995520,773995775,US
773995776,773996031,NL
773996032,773996543,ES
@@ -20111,8 +20156,7 @@
774205952,774206207,TR
774206208,774206463,US
774206464,774206719,TR
-774206720,774207487,US
-774207488,774207999,GB
+774206720,774207999,US
774208000,774208255,EU
774208256,774208511,US
774208512,774208767,GB
@@ -20219,7 +20263,8 @@
778388480,778389503,DE
778389504,778395647,GB
778395648,778436607,DE
-778436608,778461183,RO
+778436608,778452991,RO
+778452992,778461183,IT
778461184,778462207,US
778462208,778462463,PL
778462464,778462719,US
@@ -20602,7 +20647,8 @@
783745024,783747071,RU
783747072,783749119,GB
783749120,783751167,GR
-783751168,783752191,US
+783751168,783751423,NL
+783751424,783752191,US
783752192,783752447,PA
783752448,783752703,SE
783752704,783752959,PA
@@ -21121,7 +21167,8 @@
788095232,788095487,US
788095488,788095999,AU
788096000,788097023,EU
-788097024,788099071,AU
+788097024,788098047,DE
+788098048,788099071,AU
788099072,788100095,GB
788100096,788101119,NL
788101120,788103167,IR
@@ -21171,7 +21218,9 @@
788271104,788275199,DE
788275200,788279295,AL
788279296,788283391,BG
-788283392,788291583,GB
+788283392,788287487,GB
+788287488,788287743,DE
+788287744,788291583,GB
788291584,788295679,TR
788295680,788299775,RU
788299776,788303871,DE
@@ -21803,8 +21852,7 @@
868462592,868463615,GB
868463616,868464383,FR
868464384,868464639,GB
-868464640,868464895,IE
-868464896,868465151,FR
+868464640,868465151,FR
868465152,868465407,GB
868465408,868465663,FR
868465664,868466687,GB
@@ -22782,7 +22830,7 @@
978593792,978594815,MY
978594816,978595839,KR
978595840,978596863,NZ
-978596864,978597887,EU
+978596864,978597887,HK
978597888,978599935,IN
978599936,978640895,AU
978640896,978644991,NZ
@@ -23878,7 +23926,9 @@
1044946944,1044947199,US
1044947200,1044948479,JO
1044948480,1044948991,DE
-1044948992,1044951807,JO
+1044948992,1044949759,JO
+1044949760,1044950015,HK
+1044950016,1044951807,JO
1044951808,1044952063,US
1044952064,1044952831,JO
1044952832,1044953087,US
@@ -24160,7 +24210,7 @@
1047535360,1047535615,BE
1047535616,1047551999,DE
1047552000,1047560191,RU
-1047560192,1047568383,CH
+1047560192,1047568383,US
1047568384,1047570943,NL
1047570944,1047571199,BE
1047571200,1047576575,NL
@@ -25458,9 +25508,7 @@
1055467264,1055467519,RU
1055467520,1055467775,LU
1055467776,1055468031,PT
-1055468032,1055468287,RU
-1055468288,1055468543,TR
-1055468544,1055468799,RU
+1055468032,1055468799,RU
1055468800,1055469055,NL
1055469056,1055469823,RU
1055469824,1055470079,NL
@@ -25604,7 +25652,9 @@
1073364224,1073364991,IL
1073364992,1073373183,US
1073373184,1073381375,CA
-1073381376,1074020351,US
+1073381376,1073444095,US
+1073444096,1073444351,SE
+1073444352,1074020351,US
1074020352,1074028543,CA
1074028544,1074118655,US
1074118656,1074135039,CA
@@ -25786,7 +25836,9 @@
1079861248,1079865343,CA
1079865344,1079924223,US
1079924224,1079924479,CA
-1079924480,1080033279,US
+1079924480,1080017919,US
+1080017920,1080018431,CA
+1080018432,1080033279,US
1080033280,1080066047,CA
1080066048,1080164351,US
1080164352,1080295423,CA
@@ -26278,7 +26330,9 @@
1109479424,1109481471,US
1109481472,1109483519,CA
1109483520,1109483775,US
-1109483776,1109491711,CA
+1109483776,1109484287,CA
+1109484288,1109484543,US
+1109484544,1109491711,CA
1109491712,1109681151,US
1109681152,1109682175,CA
1109682176,1109688319,US
@@ -26516,7 +26570,9 @@
1119032320,1119032831,CA
1119032832,1119048703,US
1119048704,1119048959,CA
-1119048960,1119110143,US
+1119048960,1119065599,US
+1119065600,1119065855,CA
+1119065856,1119110143,US
1119110144,1119111167,CA
1119111168,1119199231,US
1119199232,1119207423,MN
@@ -26649,27 +26705,16 @@
1123601408,1123602431,NL
1123602432,1123651583,US
1123651584,1123655679,JM
-1123655680,1123779071,US
-1123779072,1123779583,ZA
+1123655680,1123778559,US
+1123778560,1123779583,ZA
1123779584,1123780607,DE
1123780608,1123781631,ZA
1123781632,1123782655,DE
-1123782656,1123782911,US
-1123782912,1123783679,ZA
+1123782656,1123783679,ZA
1123783680,1123784191,DE
-1123784192,1123784447,US
-1123784448,1123785983,ZA
-1123785984,1123786239,US
-1123786240,1123788799,ZA
+1123784192,1123788799,ZA
1123788800,1123789823,DE
-1123789824,1123791871,US
-1123791872,1123792127,ZA
-1123792128,1123792383,US
-1123792384,1123792639,ZA
-1123792640,1123793151,US
-1123793152,1123793407,ZA
-1123793408,1123793919,US
-1123793920,1123794943,ZA
+1123789824,1123794943,ZA
1123794944,1123848191,US
1123848192,1123852287,CA
1123852288,1123950591,US
@@ -26936,9 +26981,7 @@
1159616768,1159617023,SE
1159617024,1159700479,US
1159700480,1159725055,CA
-1159725056,1159995391,US
-1159995392,1159999487,??
-1159999488,1160011775,US
+1159725056,1160011775,US
1160011776,1160019967,CA
1160019968,1160364031,US
1160364032,1160368127,CA
@@ -27110,9 +27153,7 @@
1170489344,1170497535,CA
1170497536,1170505727,US
1170505728,1170522111,CA
-1170522112,1170572543,US
-1170572544,1170572799,GB
-1170572800,1172750335,US
+1170522112,1172750335,US
1172750336,1172766719,CN
1172766720,1172799487,US
1172799488,1172815871,CN
@@ -27291,9 +27332,7 @@
1242562560,1244717055,US
1244717056,1244792063,CA
1244792064,1244792319,TR
-1244792320,1244796927,CA
-1244796928,1244797183,TR
-1244797184,1244798975,CA
+1244792320,1244798975,CA
1244798976,1244831743,US
1244831744,1244839935,CA
1244839936,1244844031,US
@@ -27626,9 +27665,7 @@
1294272768,1294273023,US
1294273024,1294277887,DE
1294277888,1294278143,IT
-1294278144,1294279679,DE
-1294279680,1294279935,NL
-1294279936,1294280447,DE
+1294278144,1294280447,DE
1294280448,1294280703,NL
1294280704,1294285311,DE
1294285312,1294285567,TR
@@ -27667,9 +27704,7 @@
1294962688,1294963711,UA
1294963712,1294964735,TR
1294964736,1294965759,UA
-1294965760,1294966015,US
-1294966016,1294966271,TR
-1294966272,1294966783,US
+1294965760,1294966783,US
1294966784,1294971391,UA
1294971392,1294971647,TR
1294971648,1294971903,BZ
@@ -28048,7 +28083,8 @@
1297185792,1297186815,GB
1297186816,1297188863,IR
1297188864,1297189119,AU
-1297189120,1297189631,RO
+1297189120,1297189375,RO
+1297189376,1297189631,NL
1297189632,1297189887,AU
1297189888,1297190143,RO
1297190144,1297190399,UA
@@ -28630,7 +28666,8 @@
1307312128,1307320319,PL
1307320320,1307336703,RU
1307336704,1307337215,DE
-1307337216,1307338751,FR
+1307337216,1307338495,FR
+1307338496,1307338751,EU
1307338752,1307342847,DE
1307342848,1307353087,SA
1307353088,1307361279,BG
@@ -28644,8 +28681,8 @@
1307418624,1307426815,IR
1307426816,1307435007,CH
1307435008,1307436031,DE
-1307436032,1307436543,US
-1307436544,1307441151,DE
+1307436032,1307436287,US
+1307436288,1307441151,DE
1307441152,1307442175,GB
1307442176,1307443199,DE
1307443200,1307451391,IT
@@ -28720,7 +28757,9 @@
1307742208,1307743743,HU
1307743744,1307743999,US
1307744000,1307745279,HU
-1307745280,1307746303,US
+1307745280,1307745535,US
+1307745536,1307745791,NL
+1307745792,1307746303,US
1307746304,1307750399,CH
1307750400,1307754495,IT
1307754496,1307755007,GB
@@ -29622,7 +29661,8 @@
1333776128,1333776383,CH
1333776384,1333776639,BR
1333776640,1333776895,CL
-1333776896,1333788671,GB
+1333776896,1333777407,DE
+1333777408,1333788671,GB
1333788672,1334050815,GR
1334050816,1334059007,BG
1334059008,1334067199,FR
@@ -29954,7 +29994,8 @@
1336852480,1336868863,FR
1336868864,1336885247,RU
1336885248,1336885759,RS
-1336885760,1336886271,US
+1336885760,1336886015,US
+1336886016,1336886271,ID
1336886272,1336893183,RS
1336893184,1336893695,US
1336893696,1336898815,RS
@@ -30145,7 +30186,7 @@
1346673664,1346673919,PL
1346673920,1346674175,LU
1346674176,1346674431,NL
-1346674432,1346674687,US
+1346674432,1346674687,CH
1346674688,1346678783,DE
1346678784,1346686975,IT
1346686976,1346691071,GB
@@ -30460,8 +30501,7 @@
1347620864,1347624959,LB
1347624960,1347633151,CH
1347633152,1347637247,CZ
-1347637248,1347639295,SE
-1347639296,1347639807,US
+1347637248,1347639807,US
1347639808,1347641343,SE
1347641344,1347649535,DE
1347649536,1347653631,GE
@@ -30709,7 +30749,8 @@
1348313088,1348317183,GB
1348317184,1348321279,RU
1348321280,1348322303,GB
-1348322304,1348322815,DE
+1348322304,1348322559,DE
+1348322560,1348322815,GB
1348322816,1348323327,US
1348323328,1348323583,GB
1348323584,1348323839,TR
@@ -30840,8 +30881,8 @@
1353308672,1353308927,GB
1353308928,1353309183,IE
1353309184,1353311231,GB
-1353311232,1353311743,IE
-1353311744,1353312255,GB
+1353311232,1353311487,IE
+1353311488,1353312255,GB
1353312256,1353312767,CH
1353312768,1353314303,GB
1353314304,1353314815,CH
@@ -31277,7 +31318,9 @@
1358356480,1358356991,SI
1358356992,1358357503,ES
1358357504,1358358527,SI
-1358358528,1358360575,US
+1358358528,1358359295,US
+1358359296,1358359551,NL
+1358359552,1358360575,US
1358360576,1358364671,RU
1358364672,1358368767,FR
1358368768,1358372863,GB
@@ -31536,7 +31579,7 @@
1359970304,1360003071,PL
1360003072,1360007167,AM
1360007168,1360009215,DE
-1360009216,1360010239,US
+1360009216,1360010239,AT
1360010240,1360011263,NL
1360011264,1360015359,AT
1360015360,1360019455,DE
@@ -31651,10 +31694,11 @@
1360318464,1360322559,FR
1360322560,1360326655,FI
1360326656,1360330751,PT
-1360330752,1360332799,JO
+1360330752,1360331775,JO
+1360331776,1360332543,NL
+1360332544,1360332799,US
1360332800,1360333311,GB
-1360333312,1360333567,KZ
-1360333568,1360334335,TR
+1360333312,1360334335,TR
1360334336,1360334847,US
1360334848,1360338943,IT
1360338944,1360343039,CY
@@ -31689,14 +31733,14 @@
1360412672,1360420863,CI
1360420864,1360424959,TR
1360424960,1360429055,SA
-1360429056,1360429823,UA
+1360429056,1360429311,UA
+1360429312,1360429823,ES
1360429824,1360430079,TR
1360430080,1360430335,US
1360430336,1360430591,UA
1360430592,1360430847,NL
1360430848,1360431103,PL
-1360431104,1360432127,NL
-1360432128,1360433151,US
+1360431104,1360433151,NL
1360433152,1360437247,RO
1360437248,1360441343,FI
1360441344,1360445439,HU
@@ -32661,7 +32705,7 @@
1383322624,1383322879,FR
1383322880,1383323135,IN
1383323136,1383323391,IL
-1383323392,1383323647,PT
+1383323392,1383323647,IN
1383323648,1383324671,EU
1383324672,1383324927,FI
1383324928,1383325183,RU
@@ -32689,7 +32733,13 @@
1383399424,1383407615,LI
1383407616,1383415807,NO
1383415808,1383419903,RU
-1383419904,1383421951,SG
+1383419904,1383420159,FI
+1383420160,1383420415,LT
+1383420416,1383420671,VN
+1383420672,1383420927,CO
+1383420928,1383421183,AU
+1383421184,1383421439,SE
+1383421440,1383421951,GB
1383421952,1383422207,MY
1383422208,1383422463,CA
1383422464,1383422719,VN
@@ -32947,7 +32997,9 @@
1385676800,1385684991,RU
1385684992,1385720831,GB
1385720832,1385721087,US
-1385721088,1385738239,GB
+1385721088,1385721599,GB
+1385721600,1385721855,LT
+1385721856,1385738239,GB
1385738240,1385738751,TR
1385738752,1385757183,GB
1385757184,1385757439,US
@@ -32965,11 +33017,16 @@
1385775360,1385775615,NL
1385775616,1385775871,GB
1385775872,1385776127,US
-1385776128,1385793535,GB
+1385776128,1385777407,GB
+1385777408,1385777663,LT
+1385777664,1385778687,GB
+1385778688,1385778943,LT
+1385778944,1385793535,GB
1385793536,1385793791,IT
-1385793792,1385794047,US
+1385793792,1385794047,LT
1385794048,1385794303,RO
-1385794304,1385794815,US
+1385794304,1385794559,LT
+1385794560,1385794815,US
1385794816,1385811967,GB
1385811968,1385812479,TR
1385812480,1385812735,GB
@@ -32985,7 +33042,9 @@
1385820160,1385820415,US
1385820416,1385820927,GB
1385820928,1385821183,NL
-1385821184,1385822207,GB
+1385821184,1385821439,GB
+1385821440,1385821695,US
+1385821696,1385822207,GB
1385822208,1385822975,US
1385822976,1385824255,GB
1385824256,1385955327,PT
@@ -33003,7 +33062,8 @@
1386427136,1386427391,IL
1386427392,1386429439,EU
1386429440,1386430463,US
-1386430464,1386432511,EU
+1386430464,1386431487,EU
+1386431488,1386432511,US
1386432512,1386437887,GB
1386437888,1386438143,NL
1386438144,1386438399,ES
@@ -33039,7 +33099,8 @@
1386469120,1386469375,GB
1386469376,1386469631,DE
1386469632,1386471423,GB
-1386471424,1386473471,EU
+1386471424,1386472447,US
+1386472448,1386473471,EU
1386473472,1386477567,GB
1386477568,1386477823,US
1386477824,1386478079,IL
@@ -33782,18 +33843,19 @@
1402077184,1402093567,GB
1402093568,1402109951,RU
1402109952,1402142719,FI
-1402142720,1402143743,US
-1402143744,1402144767,ES
+1402142720,1402144767,US
1402144768,1402146047,GB
1402146048,1402146303,DE
1402146304,1402146815,TR
1402146816,1402147839,ES
1402147840,1402149119,GB
1402149120,1402149375,TR
-1402149376,1402149887,GB
+1402149376,1402149887,ES
1402149888,1402150143,US
1402150144,1402150911,TR
-1402150912,1402157055,US
+1402150912,1402151935,US
+1402151936,1402152959,GB
+1402152960,1402157055,US
1402157056,1402158079,GB
1402158080,1402158335,NZ
1402158336,1402158847,US
@@ -33813,7 +33875,7 @@
1402200064,1402202111,SC
1402202112,1402203135,GR
1402203136,1402204159,RU
-1402204160,1402205183,GR
+1402204160,1402205183,US
1402205184,1402206207,PL
1402206208,1402208255,GR
1402208256,1402224639,CZ
@@ -33909,7 +33971,7 @@
1403535360,1403550207,PL
1403550208,1403550463,US
1403550464,1403550719,PA
-1403550720,1403550975,CN
+1403550720,1403550975,JP
1403550976,1403551231,PA
1403551232,1403551743,PL
1403551744,1403568127,SK
@@ -34172,7 +34234,7 @@
1407529984,1407531007,GB
1407531008,1407531519,IL
1407531520,1407532287,CA
-1407532288,1407532543,IT
+1407532288,1407532543,RO
1407532544,1407532799,TR
1407532800,1407533055,IL
1407533056,1407533311,AT
@@ -34461,15 +34523,14 @@
1411392256,1411393279,LT
1411393280,1411393791,US
1411393792,1411394047,GB
-1411394048,1411394303,ID
-1411394304,1411394559,US
+1411394048,1411394559,US
1411394560,1411395071,SG
1411395072,1411395583,US
1411395584,1411395839,NL
1411395840,1411396095,US
-1411396096,1411397631,TR
-1411397632,1411397887,ID
-1411397888,1411399167,TR
+1411396096,1411398399,TR
+1411398400,1411398655,EU
+1411398656,1411399167,TR
1411399168,1411399423,US
1411399424,1411400447,TR
1411400448,1411400703,US
@@ -34718,9 +34779,11 @@
1412835328,1412836351,NL
1412836352,1412837375,RU
1412837376,1412837631,DE
-1412837632,1412837887,TR
+1412837632,1412837887,BG
1412837888,1412838399,NL
-1412838400,1412839423,RU
+1412838400,1412838911,RU
+1412838912,1412839167,EU
+1412839168,1412839423,RU
1412839424,1412839935,CN
1412839936,1412840191,GB
1412840192,1412840447,RU
@@ -35015,7 +35078,14 @@
1425494272,1425495295,EU
1425495296,1425495551,RO
1425495552,1425496575,EU
-1425496576,1425506303,RO
+1425496576,1425497087,BO
+1425497088,1425497599,EC
+1425497600,1425498111,GT
+1425498112,1425498623,NP
+1425498624,1425499135,PE
+1425499136,1425499647,UY
+1425499648,1425500159,KR
+1425500160,1425506303,RO
1425506304,1425509887,NO
1425509888,1425510143,SE
1425510144,1425522687,NO
@@ -35098,7 +35168,8 @@
1425973504,1425973759,CI
1425973760,1425974015,LR
1425974016,1425974271,LS
-1425974272,1425974783,GB
+1425974272,1425974527,SG
+1425974528,1425974783,IT
1425974784,1425975039,LU
1425975040,1425975295,MG
1425975296,1425975551,MW
@@ -35584,7 +35655,19 @@
1434943488,1434976255,SK
1434976256,1435107327,ES
1435107328,1435238399,PT
-1435238400,1435500543,RU
+1435238400,1435418623,RU
+1435418624,1435422719,KZ
+1435422720,1435423743,RU
+1435423744,1435428351,KZ
+1435428352,1435430399,UZ
+1435430400,1435430911,KG
+1435430912,1435431679,KZ
+1435431680,1435431935,BY
+1435431936,1435445247,RU
+1435445248,1435447295,KZ
+1435447296,1435449087,RU
+1435449088,1435451391,BY
+1435451392,1435500543,RU
1435500544,1435959295,NL
1435959296,1436024831,DE
1436024832,1436090367,ES
@@ -35613,14 +35696,18 @@
1436106752,1436107007,TR
1436107008,1436109823,US
1436109824,1436110847,EE
-1436110848,1436114943,US
+1436110848,1436111615,US
+1436111616,1436111871,EE
+1436111872,1436114175,US
+1436114176,1436114431,EE
+1436114432,1436114943,US
1436114944,1436116991,EE
1436116992,1436119039,US
1436119040,1436119295,EE
1436119296,1436119551,US
1436119552,1436120575,EE
-1436120576,1436122879,US
-1436122880,1436123135,EE
+1436120576,1436122623,US
+1436122624,1436123135,EE
1436123136,1436155903,TR
1436155904,1436221439,OM
1436221440,1436286975,ES
@@ -36068,8 +36155,8 @@
1439705088,1439706111,IN
1439706112,1439707135,SE
1439707136,1439707391,DE
-1439707392,1439707903,US
-1439707904,1439708159,DE
+1439707392,1439707647,US
+1439707648,1439708159,DE
1439708160,1439709183,SA
1439709184,1439710207,HK
1439710208,1439710463,NL
@@ -36346,12 +36433,11 @@
1441628160,1441636351,SA
1441636352,1441646847,PL
1441646848,1441647615,US
-1441647616,1441647871,PL
+1441647616,1441647871,NL
1441647872,1441648127,AP
1441648128,1441651455,PL
1441651456,1441652223,US
-1441652224,1441652479,HK
-1441652480,1441652735,PL
+1441652224,1441652735,HK
1441652736,1441660927,SK
1441660928,1441669119,ES
1441669120,1441677311,GE
@@ -36413,9 +36499,7 @@
1442719744,1442719999,US
1442720000,1442720255,LV
1442720256,1442720767,US
-1442720768,1442721535,LV
-1442721536,1442721791,US
-1442721792,1442722559,LV
+1442720768,1442722559,LV
1442722560,1442722815,US
1442722816,1442724607,LV
1442724608,1442724863,CA
@@ -36569,7 +36653,9 @@
1445998592,1446003711,DK
1446003712,1446004735,NL
1446004736,1446019071,DK
-1446019072,1446042623,NL
+1446019072,1446041599,NL
+1446041600,1446041855,GB
+1446041856,1446042623,NL
1446042624,1446042879,FR
1446042880,1446043135,NL
1446043136,1446043391,ES
@@ -36701,7 +36787,9 @@
1449714944,1449715199,IT
1449715200,1449715711,RO
1449715712,1449719807,IR
-1449719808,1449720831,GB
+1449719808,1449720063,FR
+1449720064,1449720319,CH
+1449720320,1449720831,GB
1449720832,1449721343,FR
1449721344,1449721855,RO
1449721856,1449722111,GB
@@ -37001,7 +37089,9 @@
1451229184,1455423487,GB
1455423488,1459617791,FR
1459617792,1461714943,IT
-1461714944,1461766911,IE
+1461714944,1461765887,IE
+1461765888,1461766143,GB
+1461766144,1461766911,IE
1461766912,1461767167,GB
1461767168,1461787135,IE
1461787136,1461787391,GB
@@ -37035,15 +37125,17 @@
1462283520,1462283775,GB
1462283776,1462292991,IE
1462292992,1462293247,GB
-1462293248,1462374911,IE
+1462293248,1462361343,IE
+1462361344,1462361599,GB
+1462361600,1462374911,IE
1462374912,1462375167,GB
1462375168,1462394111,IE
1462394112,1462394367,GB
1462394368,1462427135,IE
1462427136,1462427391,GB
-1462427392,1462512639,IE
-1462512640,1462512895,GB
-1462512896,1462513919,IE
+1462427392,1462510079,IE
+1462510080,1462510335,GB
+1462510336,1462513919,IE
1462513920,1462514175,GB
1462514176,1462747135,IE
1462747136,1462747391,GB
@@ -37639,9 +37731,7 @@
1475904512,1475904767,DE
1475904768,1475905023,IR
1475905024,1475905791,EU
-1475905792,1475906047,IR
-1475906048,1475906303,US
-1475906304,1475907327,IR
+1475905792,1475907327,IR
1475907328,1475907583,IN
1475907584,1475908351,EU
1475908352,1475908607,IR
@@ -37737,7 +37827,8 @@
1476265984,1476266239,US
1476266240,1476266495,GB
1476266496,1476267007,EU
-1476267008,1476268031,GB
+1476267008,1476267519,US
+1476267520,1476268031,GB
1476268032,1476268287,EU
1476268288,1476268543,US
1476268544,1476268799,EU
@@ -37929,7 +38020,7 @@
1486225408,1486258175,DE
1486258176,1486292991,GB
1486292992,1486293247,RU
-1486293248,1486293503,CZ
+1486293248,1486293503,IT
1486293504,1486293759,LT
1486293760,1486294015,MX
1486294016,1486294271,UA
@@ -38143,7 +38234,7 @@
1490145280,1490145535,HU
1490145536,1490145791,EU
1490145792,1490147327,HU
-1490147328,1490147583,TR
+1490147328,1490147583,US
1490147584,1490147839,EU
1490147840,1490148095,HU
1490148096,1490148351,EU
@@ -38155,7 +38246,9 @@
1490150656,1490150911,TR
1490150912,1490151167,US
1490151168,1490151423,DE
-1490151424,1490155263,HU
+1490151424,1490154751,HU
+1490154752,1490155007,IN
+1490155008,1490155263,HU
1490155264,1490156031,TR
1490156032,1490156543,HU
1490156544,1490156799,TR
@@ -38205,8 +38298,7 @@
1490337792,1490354175,RU
1490354176,1490386943,SA
1490386944,1490403327,CH
-1490403328,1490411263,BG
-1490411264,1490411519,US
+1490403328,1490411519,BG
1490411520,1490419711,FR
1490419712,1490420735,FI
1490420736,1490421759,CH
@@ -38270,9 +38362,7 @@
1490562816,1490563071,TR
1490563072,1490565375,LT
1490565376,1490565631,EU
-1490565632,1490567935,LT
-1490567936,1490568191,DE
-1490568192,1490573823,LT
+1490565632,1490573823,LT
1490573824,1490574335,US
1490574336,1490575103,LT
1490575104,1490575615,TR
@@ -38515,13 +38605,14 @@
1494624256,1494626303,UA
1494626304,1494626559,CZ
1494626560,1494626815,RO
-1494626816,1494627071,GB
+1494626816,1494627071,LV
1494627072,1494627327,IE
1494627328,1494630399,RU
1494630400,1494638591,CZ
1494638592,1494646783,DE
1494646784,1494663167,RU
-1494663168,1494665215,RO
+1494663168,1494664191,RO
+1494664192,1494665215,GB
1494665216,1494667263,UA
1494667264,1494669311,PL
1494669312,1494671359,RU
@@ -39240,7 +39331,7 @@
1495756800,1495758847,MD
1495758848,1495759359,RO
1495759360,1495759615,TH
-1495759616,1495759871,RO
+1495759616,1495759871,DK
1495759872,1495760127,ES
1495760128,1495760383,NZ
1495760384,1495760895,RO
@@ -39739,7 +39830,7 @@
1496187392,1496188927,RO
1496188928,1496189183,US
1496189184,1496189695,GB
-1496189696,1496189951,LT
+1496189696,1496189951,US
1496189952,1496190975,RO
1496190976,1496193023,SE
1496193024,1496195071,RO
@@ -39925,8 +40016,7 @@
1500168192,1500170239,RU
1500170240,1500170495,NL
1500170496,1500170751,CH
-1500170752,1500171007,CO
-1500171008,1500171263,GB
+1500170752,1500171263,GB
1500171264,1500171519,NL
1500171520,1500171775,US
1500171776,1500172031,DE
@@ -40131,7 +40221,8 @@
1500838912,1500839423,US
1500839424,1500839679,LT
1500839680,1500839935,DE
-1500839936,1500840959,US
+1500839936,1500840191,GB
+1500840192,1500840959,US
1500840960,1500841215,LT
1500841216,1500841471,TR
1500841472,1500841983,BR
@@ -40644,6 +40735,10 @@
1506772992,1506775039,GB
1506775040,1506776063,AT
1506776064,1506777087,LT
+1506777088,1506777343,UA
+1506777344,1506777599,DE
+1506777600,1506777855,BE
+1506777856,1506778111,AE
1506779136,1506779903,GB
1506779904,1506780159,DK
1506780160,1506781183,US
@@ -40688,32 +40783,36 @@
1507132416,1507132671,GB
1507132672,1507132927,BR
1507132928,1507133439,PA
-1507133440,1507141631,GB
-1507141632,1507143167,US
+1507133440,1507142655,GB
+1507142656,1507143167,US
1507143168,1507164159,GB
1507164160,1507164415,US
1507164416,1507164671,FR
1507164672,1507164927,PA
1507164928,1507165439,GB
-1507165440,1507166975,FR
+1507165440,1507166975,LT
1507166976,1507167231,MT
-1507167232,1507168255,FR
+1507167232,1507167487,FR
+1507167488,1507167743,LT
+1507167744,1507168255,FR
1507168256,1507168511,GB
1507168512,1507169279,FR
1507169280,1507172351,US
-1507172352,1507172863,FR
+1507172352,1507172607,LT
+1507172608,1507172863,FR
1507172864,1507173119,US
-1507173120,1507174143,FR
+1507173120,1507173631,LT
+1507173632,1507174143,FR
1507174144,1507174399,RO
-1507174400,1507174655,FR
+1507174400,1507174655,LT
1507174656,1507174911,GB
-1507174912,1507175167,FR
+1507174912,1507175167,LT
1507175168,1507175423,GB
-1507175424,1507176447,FR
+1507175424,1507176447,SG
1507176448,1507178495,US
-1507178496,1507179007,FR
+1507178496,1507179007,LT
1507179008,1507179519,US
-1507179520,1507180031,FR
+1507179520,1507180031,LT
1507180032,1507180287,PA
1507180288,1507196927,GB
1507196928,1507262463,PT
@@ -41093,8 +41192,7 @@
1520231680,1520231935,RU
1520231936,1520232191,KZ
1520232192,1520232447,PL
-1520232448,1520234495,NL
-1520234496,1520271359,RU
+1520232448,1520271359,RU
1520271360,1520304127,SI
1520304128,1520435199,TR
1520435200,1521483775,ES
@@ -41265,7 +41363,9 @@
1533446144,1533448191,DE
1533448192,1533450239,KW
1533450240,1533452287,RU
-1533452288,1533454335,TR
+1533452288,1533453567,TR
+1533453568,1533453823,DE
+1533453824,1533454335,TR
1533454336,1533456383,RS
1533456384,1533457407,UA
1533457408,1533458431,US
@@ -41464,8 +41564,8 @@
1535387648,1535388671,NL
1535388672,1535389695,FR
1535389696,1535389951,AE
-1535389952,1535390207,NZ
-1535390208,1535390719,NL
+1535389952,1535390463,NZ
+1535390464,1535390719,NL
1535390720,1535391743,SE
1535391744,1535391999,HN
1535392000,1535392255,EU
@@ -41692,8 +41792,7 @@
1536552704,1536552959,US
1536552960,1536553471,NL
1536553472,1536553983,ES
-1536553984,1536555007,TR
-1536555008,1536556543,PL
+1536553984,1536556543,PL
1536556544,1536573439,FI
1536573440,1536579071,RS
1536579072,1536579327,CS
@@ -41865,7 +41964,7 @@
1539217408,1539217663,RU
1539217664,1539217919,UA
1539217920,1539218175,DE
-1539218176,1539218431,NO
+1539218176,1539218431,SE
1539218432,1539218687,RU
1539218688,1539218943,MT
1539218944,1539219199,RU
@@ -41879,9 +41978,9 @@
1539226112,1539226367,US
1539226368,1539226623,TR
1539226624,1539226879,GB
-1539226880,1539227135,US
+1539226880,1539227135,HU
1539227136,1539227391,HK
-1539227392,1539227647,US
+1539227392,1539227647,IN
1539227648,1539229695,FI
1539229696,1539231743,DE
1539231744,1539233791,BE
@@ -43609,9 +43708,10 @@
1540375040,1540375295,GB
1540375552,1540375807,DE
1540375808,1540376319,TR
-1540376320,1540376575,NO
+1540376320,1540376575,DK
1540376576,1540376831,PL
-1540376832,1540377343,DE
+1540376832,1540377087,HK
+1540377088,1540377343,DE
1540377344,1540377599,RO
1540377600,1540377855,AM
1540377856,1540378111,NL
@@ -44187,8 +44287,7 @@
1540634880,1540635135,RU
1540635136,1540635391,FR
1540635392,1540635647,RO
-1540635648,1540635903,RU
-1540635904,1540636159,GB
+1540635648,1540636159,RU
1540636160,1540636415,RO
1540636416,1540636671,LV
1540636672,1540637183,RU
@@ -44545,7 +44644,7 @@
1540736256,1540736511,IT
1540736512,1540736767,DE
1540736768,1540737023,GB
-1540737024,1540737279,AP
+1540737024,1540737279,HK
1540737280,1540737535,GB
1540737536,1540737791,AT
1540737792,1540738047,NO
@@ -45110,7 +45209,7 @@
1541010944,1541011199,CY
1541011200,1541011455,CH
1541011456,1541011711,FI
-1541011712,1541012223,US
+1541011712,1541012223,NL
1541012224,1541012479,DE
1541012480,1541012735,FI
1541012736,1541012991,NL
@@ -47436,7 +47535,7 @@
1542278912,1542279679,PL
1542279680,1542280191,RU
1542280192,1542280959,PL
-1542280960,1542281215,CZ
+1542280960,1542281215,IT
1542281216,1542281727,DE
1542281728,1542281983,SE
1542281984,1542282239,RO
@@ -47938,8 +48037,7 @@
1542522368,1542522879,NL
1542522880,1542523903,CZ
1542523904,1542524415,RU
-1542524416,1542524671,IT
-1542524672,1542524927,US
+1542524416,1542524927,IT
1542524928,1542525951,RU
1542525952,1542526463,IR
1542526464,1542526719,RU
@@ -48086,7 +48184,7 @@
1542684160,1542684671,IR
1542684672,1542692863,ES
1542692864,1542696959,IR
-1542696960,1542697215,ES
+1542696960,1542697215,IN
1542697216,1542697471,GB
1542697472,1542697727,AE
1542697728,1542697983,GB
@@ -48306,7 +48404,7 @@
1542962688,1542962943,RU
1542962944,1542963199,NL
1542963200,1542970623,RU
-1542970624,1542970879,UA
+1542970624,1542970879,US
1542970880,1542971391,RU
1542971392,1542972415,UA
1542972416,1542973439,NO
@@ -48616,8 +48714,7 @@
1547526400,1547526655,IN
1547526656,1547527679,HU
1547527680,1547527935,GB
-1547527936,1547528191,TR
-1547528192,1547534335,HU
+1547527936,1547534335,HU
1547534336,1547538431,FR
1547538432,1547542527,SE
1547542528,1547546623,FR
@@ -48718,7 +48815,7 @@
1550987264,1550988287,IR
1550988288,1550988543,RO
1550988544,1550988799,ES
-1550988800,1550989055,US
+1550988800,1550989055,NZ
1550989056,1550989311,GG
1550989312,1550990335,ES
1550990336,1550991359,US
@@ -48755,8 +48852,7 @@
1551244288,1551245311,GB
1551245312,1551246335,IE
1551246336,1551246591,BG
-1551246592,1551246847,US
-1551246848,1551248383,RO
+1551246592,1551248383,RO
1551248384,1551248895,US
1551248896,1551249151,GB
1551249152,1551249407,US
@@ -49340,7 +49436,10 @@
1562378240,1564999679,IT
1564999680,1565368319,UA
1565368320,1565376511,RU
-1565376512,1565523967,UA
+1565376512,1565392895,UA
+1565392896,1565425663,US
+1565425664,1565491199,UA
+1565491200,1565523967,US
1565523968,1565655039,RU
1565655040,1565786111,AT
1565786112,1565917183,BY
@@ -49387,7 +49486,7 @@
1566169856,1566170111,NL
1566170112,1566170623,EE
1566170624,1566170879,NL
-1566170880,1566171135,IN
+1566170880,1566171135,EE
1566171136,1566175231,TR
1566175232,1566179327,IE
1566179328,1566183423,DK
@@ -49429,9 +49528,8 @@
1566306304,1566310399,CZ
1566310400,1566312447,SE
1566312448,1566314495,IE
-1566314496,1566314751,BE
-1566314752,1566315007,US
-1566315008,1566315519,BE
+1566314496,1566314751,BG
+1566314752,1566315519,BE
1566315520,1566315775,JP
1566315776,1566316031,BE
1566316032,1566316543,US
@@ -50223,7 +50321,8 @@
1571482624,1571483647,BY
1571483648,1571484159,HR
1571484160,1571484671,NL
-1571484672,1571486719,RU
+1571484672,1571485695,RU
+1571485696,1571486719,EU
1571486720,1571486975,BY
1571486976,1571487231,UA
1571487232,1571487487,RU
@@ -50232,7 +50331,8 @@
1571488256,1571488767,RU
1571488768,1571489279,UA
1571489280,1571489535,BY
-1571489536,1571491071,RU
+1571489536,1571490815,RU
+1571490816,1571491071,EU
1571491072,1571491327,GB
1571491328,1571491839,RU
1571491840,1571495935,EU
@@ -50269,8 +50369,7 @@
1571532544,1571532799,BY
1571532800,1571533055,UA
1571533056,1571533311,RU
-1571533312,1571533823,UA
-1571533824,1571534079,EU
+1571533312,1571534079,EU
1571534080,1571535103,RU
1571535104,1571535359,UA
1571535360,1571535615,EU
@@ -50542,8 +50641,8 @@
1572564736,1572564991,NL
1572564992,1572567039,DE
1572567040,1572569087,RU
-1572569088,1572569599,HK
-1572569600,1572570111,AP
+1572569088,1572569855,HK
+1572569856,1572570111,AP
1572570112,1572571135,ES
1572571136,1572571391,BG
1572571392,1572573183,US
@@ -51362,7 +51461,7 @@
1586236416,1586236927,US
1586236928,1586237439,CY
1586237440,1586237695,US
-1586237696,1586237951,DK
+1586237696,1586237951,NO
1586237952,1586239487,US
1586239488,1586239743,DK
1586239744,1586239999,CZ
@@ -52048,7 +52147,7 @@
1592250368,1592251391,PT
1592251392,1592251647,RU
1592251648,1592251903,IE
-1592251904,1592252415,FR
+1592251904,1592252159,FR
1592252416,1592254463,RU
1592254464,1592258559,PL
1592258560,1592262655,NL
@@ -52602,8 +52701,9 @@
1602412800,1602413055,IR
1602413056,1602413311,MD
1602413312,1602413567,UZ
-1602413568,1602413823,NL
-1602413824,1602414591,RU
+1602413568,1602413823,US
+1602413824,1602414335,RU
+1602414336,1602414591,KG
1602414592,1602416639,NL
1602416640,1602418687,IR
1602418688,1602420735,DE
@@ -52861,9 +52961,11 @@
1604599296,1604599807,BE
1604599808,1604601087,UA
1604601088,1604601343,GI
-1604601344,1604601599,UA
+1604601344,1604601599,US
1604601600,1604601855,GI
-1604601856,1604604927,UA
+1604601856,1604603135,UA
+1604603136,1604603903,US
+1604603904,1604604927,UA
1604604928,1604605183,NO
1604605184,1604605439,DK
1604605440,1604605951,NL
@@ -52871,7 +52973,9 @@
1604606720,1604606975,LV
1604606976,1604607999,UA
1604608000,1604624383,US
-1604624384,1604627967,UA
+1604624384,1604626431,UA
+1604626432,1604626943,US
+1604626944,1604627967,UA
1604627968,1604628479,GI
1604628480,1604632575,GR
1604632576,1604634623,GI
@@ -52881,7 +52985,7 @@
1604642816,1604643839,ES
1604643840,1604646911,US
1604646912,1604647935,GI
-1604647936,1604648959,UA
+1604647936,1604648959,US
1604648960,1604714495,RU
1604714496,1604780031,DK
1604780032,1604845567,RU
@@ -53134,19 +53238,23 @@
1607625728,1607626495,ES
1607626496,1607627775,IT
1607627776,1607628543,FR
-1607628544,1607628799,IT
+1607628544,1607628799,BG
1607628800,1607630847,FR
1607630848,1607631103,CI
1607631104,1607631871,IT
1607631872,1607632127,FR
-1607632128,1607632895,IT
+1607632128,1607632639,IT
+1607632640,1607632895,HU
1607632896,1607633407,SN
1607633408,1607633919,TG
-1607633920,1607634431,ZM
-1607634432,1607634687,GB
+1607633920,1607634175,IT
+1607634176,1607634431,LY
+1607634432,1607634687,MA
1607634688,1607634943,IT
-1607634944,1607635455,CM
-1607635456,1607635967,KE
+1607634944,1607635199,RO
+1607635200,1607635455,HR
+1607635456,1607635711,GR
+1607635712,1607635967,IT
1607635968,1607636479,NG
1607636480,1607636991,ZA
1607636992,1607637503,TZ
@@ -53170,8 +53278,8 @@
1607863296,1607864319,UA
1607864320,1607865343,EU
1607865344,1607866367,JP
-1607866368,1607866879,NL
-1607866880,1607867135,VG
+1607866368,1607866623,NL
+1607866624,1607867135,VG
1607867136,1607867391,NL
1607867392,1607868415,BE
1607868416,1607869439,FR
@@ -57034,8 +57142,8 @@
1729675776,1729676287,JP
1729676288,1729677311,ID
1729677312,1729678335,IN
-1729678336,1729678591,HK
-1729678592,1729679359,AP
+1729678336,1729678847,HK
+1729678848,1729679359,AP
1729679360,1729680383,AU
1729680384,1729681663,ID
1729681664,1729682431,HK
@@ -57585,7 +57693,7 @@
1730392576,1730393087,CY
1730393088,1730394111,SG
1730394112,1730395135,HK
-1730395136,1730396159,JP
+1730395136,1730396159,NL
1730396160,1730398207,IN
1730398208,1730399231,AU
1730399232,1730399999,TW
@@ -58671,7 +58779,7 @@
1731629056,1731630079,IN
1731630080,1731631103,BD
1731631104,1731631359,SG
-1731631360,1731631615,TH
+1731631360,1731631615,AU
1731631616,1731632127,SG
1731632128,1731633151,JP
1731633152,1731635199,CN
@@ -58793,7 +58901,7 @@
1731734528,1731735551,HK
1731735552,1731736575,JP
1731736576,1731736831,HK
-1731736832,1731737087,SG
+1731736832,1731737087,AU
1731737088,1731737343,HK
1731737344,1731737599,JP
1731737600,1731739647,CN
@@ -59138,9 +59246,7 @@
1732128768,1732129023,SG
1732129024,1732129279,NZ
1732129280,1732129791,AU
-1732129792,1732130303,HK
-1732130304,1732130559,CN
-1732130560,1732130815,HK
+1732129792,1732130815,CN
1732130816,1732134911,IN
1732134912,1732140031,CN
1732140032,1732141055,IN
@@ -59749,7 +59855,8 @@
1732875264,1732877311,IN
1732877312,1732877823,US
1732877824,1732878335,ID
-1732878336,1732879359,AP
+1732878336,1732879103,AP
+1732879104,1732879359,HK
1732879360,1732880383,KH
1732880384,1732881407,CN
1732881408,1732882431,FR
@@ -59946,7 +60053,8 @@
1733065984,1733066751,AU
1733066752,1733067007,TR
1733067008,1733067263,ID
-1733067264,1733067775,NL
+1733067264,1733067519,NL
+1733067520,1733067775,US
1733067776,1733068799,ID
1733068800,1733070847,IN
1733070848,1733071871,NZ
@@ -60870,8 +60978,7 @@
1733956608,1733957631,AU
1733957632,1733958655,ID
1733958656,1733959679,JP
-1733959680,1733960703,IN
-1733960704,1733961727,AU
+1733959680,1733961727,IN
1733961728,1733962751,TH
1733962752,1733963775,IN
1733963776,1733964543,AU
@@ -60936,10 +61043,7 @@
1734030336,1734030847,BD
1734030848,1734031103,AU
1734031104,1734031359,ID
-1734031360,1734031615,IM
-1734031616,1734031871,US
-1734031872,1734032127,NL
-1734032128,1734032383,US
+1734031360,1734032383,NL
1734032384,1734033407,IN
1734033408,1734034431,MY
1734034432,1734039295,IN
@@ -61084,9 +61188,7 @@
1734183936,1734184447,BD
1734184448,1734184959,CN
1734184960,1734185983,NZ
-1734185984,1734186239,AU
-1734186240,1734186495,US
-1734186496,1734187007,AU
+1734185984,1734187007,AU
1734187008,1734188031,CN
1734188032,1734188543,AU
1734188544,1734190591,ID
@@ -61462,7 +61564,7 @@
1734552576,1734553599,AU
1734553600,1734554111,IN
1734554112,1734554623,SG
-1734554624,1734554879,US
+1734554624,1734554879,CN
1734554880,1734555135,NL
1734555136,1734556671,CN
1734556672,1734557183,HK
@@ -61493,7 +61595,7 @@
1734574080,1734575103,BD
1734575104,1734576127,PK
1734576128,1734576639,ID
-1734576640,1734578175,AU
+1734576640,1734578175,TW
1734578176,1734580223,IN
1734580224,1734581247,CN
1734581248,1734582271,IN
@@ -62190,8 +62292,7 @@
1735168000,1735169023,BD
1735169024,1735171071,IN
1735171072,1735172095,ID
-1735172096,1735173119,CN
-1735173120,1735174143,DE
+1735172096,1735174143,CN
1735174144,1735174399,NZ
1735174400,1735175167,AU
1735175168,1735175423,HK
@@ -62323,7 +62424,7 @@
1735287808,1735288319,ID
1735288320,1735288831,IN
1735288832,1735289087,KR
-1735289088,1735289343,GB
+1735289088,1735289343,AU
1735289344,1735289599,US
1735289600,1735289855,IN
1735289856,1735290111,AU
@@ -62670,7 +62771,8 @@
1735598336,1735598591,PH
1735598592,1735598847,SG
1735598848,1735600127,ID
-1735600128,1735602175,AP
+1735600128,1735601151,AP
+1735601152,1735602175,US
1735602176,1735603199,HK
1735603200,1735604223,CN
1735604224,1735605759,HK
@@ -62681,7 +62783,7 @@
1735609344,1735610367,SG
1735610368,1735610879,SB
1735610880,1735611391,BD
-1735611392,1735612415,AU
+1735611392,1735612415,JP
1735612416,1735612927,NP
1735612928,1735613439,AU
1735613440,1735614463,CN
@@ -62876,7 +62978,7 @@
1735751680,1735752703,HK
1735752704,1735753727,IN
1735753728,1735754751,SG
-1735754752,1735755775,AU
+1735754752,1735755775,TW
1735755776,1735756799,CN
1735756800,1735757055,PH
1735757056,1735757311,MY
@@ -63620,7 +63722,9 @@
1736425472,1736429567,VN
1736429568,1736430591,ID
1736430592,1736431615,KR
-1736431616,1736433663,AU
+1736431616,1736432639,TW
+1736432640,1736433151,ID
+1736433152,1736433663,BD
1736433664,1736434687,IN
1736434688,1736437759,TW
1736437760,1736438783,EU
@@ -63806,7 +63910,10 @@
1736668160,1736669183,ID
1736669184,1736670207,JP
1736670208,1736671231,TW
-1736671232,1736673279,AU
+1736671232,1736671743,IN
+1736671744,1736672255,SG
+1736672256,1736672767,JP
+1736672768,1736673279,MY
1736673280,1736673791,BD
1736673792,1736674303,CN
1736674304,1736675327,MY
@@ -64603,7 +64710,7 @@
1737254912,1737255423,ID
1737255424,1737255935,IN
1737255936,1737256447,ID
-1737256448,1737256959,AU
+1737256448,1737256959,IN
1737256960,1737257471,JP
1737257472,1737257983,US
1737257984,1737258495,BD
@@ -64838,7 +64945,7 @@
1737374208,1737374719,CN
1737374720,1737375487,ID
1737375488,1737376255,IN
-1737376256,1737376767,AU
+1737376256,1737376767,MY
1737376768,1737377791,BD
1737377792,1737378303,IN
1737378304,1737378815,AU
@@ -65628,7 +65735,8 @@
1737839616,1737840127,SG
1737840128,1737840639,VN
1737840640,1737841151,AU
-1737841152,1737842175,AP
+1737841152,1737841919,AP
+1737841920,1737842175,HK
1737842176,1737843199,IN
1737843200,1737843711,VN
1737843712,1737844223,PH
@@ -65902,7 +66010,8 @@
1737990656,1737991679,ID
1737991680,1737992191,IN
1737992192,1737993215,BD
-1737993216,1737994239,AU
+1737993216,1737993727,HK
+1737993728,1737994239,AU
1737994240,1737994495,SG
1737994496,1737994751,ID
1737994752,1737995263,CN
@@ -69600,7 +69709,9 @@
1740978176,1740979199,MY
1740979200,1740980223,NZ
1740980224,1740981247,AU
-1740981248,1740982271,EU
+1740981248,1740981759,HK
+1740981760,1740982015,EU
+1740982016,1740982271,HK
1740982272,1740985343,IN
1740985344,1740986367,PH
1740986368,1740986623,AU
@@ -69863,7 +69974,8 @@
1741413888,1741414143,JP
1741414144,1741414399,HK
1741414400,1741416447,IN
-1741416448,1741420543,AU
+1741416448,1741417215,ID
+1741417216,1741420543,AU
1741420544,1741421055,ID
1741421056,1741423103,IN
1741423104,1741423615,NZ
@@ -70128,7 +70240,9 @@
1741701376,1741701631,PH
1741701632,1741701887,MY
1741701888,1741702143,PH
-1741702144,1741706239,IN
+1741702144,1741703167,IN
+1741703168,1741704191,IT
+1741704192,1741706239,IN
1741706240,1741706495,GB
1741706496,1741707007,NZ
1741707008,1741707263,TW
@@ -70241,7 +70355,7 @@
1741806592,1741807615,IN
1741807616,1741808639,NZ
1741808640,1741809151,BD
-1741809152,1741809663,SC
+1741809152,1741809663,NL
1741809664,1741810687,HK
1741810688,1741811711,JP
1741811712,1741812223,IN
@@ -70312,7 +70426,9 @@
1741873152,1741873663,PK
1741873664,1741874175,SG
1741874176,1741875199,ID
-1741875200,1741877759,HK
+1741875200,1741875967,HK
+1741875968,1741876223,GB
+1741876224,1741877759,HK
1741877760,1741878015,JP
1741878016,1741879295,HK
1741879296,1741879807,AU
@@ -70592,8 +70708,8 @@
1742162432,1742162687,US
1742162688,1742162943,IN
1742162944,1742163455,HK
-1742163456,1742163967,AP
-1742163968,1742164991,HK
+1742163456,1742163711,AP
+1742163712,1742164991,HK
1742164992,1742166015,JP
1742166016,1742167039,AU
1742167040,1742167551,PG
@@ -70658,7 +70774,7 @@
1742234624,1742235135,HK
1742235136,1742235391,KR
1742235392,1742235647,HK
-1742235648,1742236671,AU
+1742235648,1742236671,ID
1742236672,1742237695,CN
1742237696,1742242815,VN
1742242816,1742243071,NZ
@@ -71074,8 +71190,7 @@
1742895104,1742895615,SG
1742895616,1742895871,BD
1742895872,1742896127,AU
-1742896128,1742896383,HK
-1742896384,1742896639,AP
+1742896128,1742896639,AP
1742896640,1742896895,MY
1742896896,1742897151,HK
1742897152,1742898175,AU
@@ -71422,7 +71537,9 @@
1743198208,1743198719,IN
1743198720,1743198975,SG
1743198976,1743199231,GB
-1743199232,1743200255,AP
+1743199232,1743199487,AP
+1743199488,1743199743,HK
+1743199744,1743200255,AP
1743200256,1743200767,IN
1743200768,1743201279,BD
1743201280,1743202303,PH
@@ -72100,8 +72217,7 @@
1743909376,1743910911,IN
1743910912,1743911935,VN
1743911936,1743912959,AU
-1743912960,1743913215,AP
-1743913216,1743913983,HK
+1743912960,1743913983,HK
1743913984,1743915007,JP
1743915008,1743915519,BD
1743915520,1743916031,ID
@@ -72601,7 +72717,7 @@
1744355328,1744356351,CN
1744356352,1744357375,ID
1744357376,1744357631,NZ
-1744357632,1744357887,AU
+1744357632,1744357887,SG
1744357888,1744358399,IN
1744358400,1744359423,BD
1744359424,1744360447,IN
@@ -72693,7 +72809,7 @@
1744438272,1744439295,AP
1744439296,1744439807,AU
1744439808,1744440319,SG
-1744440320,1744441343,AU
+1744440320,1744441343,ID
1744441344,1744442367,IN
1744442368,1744443391,AU
1744443392,1744444415,VN
@@ -73327,35 +73443,100 @@
1755443200,1755445247,AU
1755445248,1755512831,US
1755512832,1755578367,CA
-1755578368,1755588095,US
+1755578368,1755587839,US
+1755587840,1755588095,UA
1755588096,1755588351,HK
-1755588352,1755590143,US
+1755588352,1755588607,US
+1755588608,1755588863,UA
+1755588864,1755590143,US
1755590144,1755590399,AP
1755590400,1755608063,US
1755608064,1755608319,AP
-1755608320,1755625983,US
+1755608320,1755617279,US
+1755617280,1755617535,AP
+1755617536,1755625983,US
1755625984,1755626239,AU
-1755626240,1755662079,US
+1755626240,1755645439,US
+1755645440,1755645695,UA
+1755645696,1755647487,US
+1755647488,1755647743,UA
+1755647744,1755650559,US
+1755650560,1755650815,UA
+1755650816,1755661055,US
+1755661056,1755661311,UA
+1755661312,1755662079,US
1755662080,1755662335,AP
-1755662336,1755672575,US
+1755662336,1755662591,US
+1755662592,1755662847,UA
+1755662848,1755663871,US
+1755663872,1755664127,UA
+1755664128,1755664639,US
+1755664640,1755664895,UA
+1755664896,1755665151,US
+1755665152,1755665407,UA
+1755665408,1755666687,US
+1755666688,1755666943,UA
+1755666944,1755667199,US
+1755667200,1755667455,UA
+1755667456,1755667711,US
+1755667712,1755667967,UA
+1755667968,1755669503,US
+1755669504,1755669759,UA
+1755669760,1755671295,US
+1755671296,1755671551,UA
+1755671552,1755671807,US
+1755671808,1755672063,UA
+1755672064,1755672575,US
1755672576,1755672831,AP
-1755672832,1755674367,US
+1755672832,1755673343,UA
+1755673344,1755674367,US
1755674368,1755674623,AP
1755674624,1755675903,US
1755675904,1755676415,AP
-1755676416,1755681279,US
+1755676416,1755676927,US
+1755676928,1755677183,UA
+1755677184,1755677695,US
+1755677696,1755677951,UA
+1755677952,1755679231,US
+1755679232,1755679487,UA
+1755679488,1755680255,US
+1755680256,1755680511,UA
+1755680512,1755681023,US
+1755681024,1755681279,UA
1755681280,1755681535,AP
1755681536,1755682047,US
1755682048,1755682303,AP
1755682304,1755683071,US
1755683072,1755683583,AP
-1755683584,1755687935,US
+1755683584,1755684863,US
+1755684864,1755685119,UA
+1755685120,1755685375,US
+1755685376,1755685631,UA
+1755685632,1755685887,US
+1755685888,1755686143,UA
+1755686144,1755687679,US
+1755687680,1755687935,UA
1755687936,1755688191,AP
-1755688192,1755703039,US
+1755688192,1755688447,UA
+1755688448,1755689727,US
+1755689728,1755689983,UA
+1755689984,1755690239,US
+1755690240,1755690495,UA
+1755690496,1755695103,US
+1755695104,1755695359,UA
+1755695360,1755695615,US
+1755695616,1755695871,UA
+1755695872,1755696383,US
+1755696384,1755696639,UA
+1755696640,1755702783,US
+1755702784,1755703039,UA
1755703040,1755703295,AP
1755703296,1755705855,US
1755705856,1755706367,AP
-1755706368,1755708671,US
+1755706368,1755706623,UA
+1755706624,1755707135,US
+1755707136,1755707903,UA
+1755707904,1755708671,US
1755708672,1755708927,AP
1755708928,1755717631,US
1755717632,1755721727,BS
@@ -73557,7 +73738,9 @@
1760166144,1760166399,NL
1760166400,1760168447,CA
1760168448,1760168959,NL
-1760168960,1760177663,CA
+1760168960,1760171519,CA
+1760171520,1760171775,NL
+1760171776,1760177663,CA
1760177664,1760177919,NL
1760177920,1760180735,CA
1760180736,1760180991,US
@@ -73573,7 +73756,9 @@
1760201728,1760201983,US
1760201984,1760202495,CA
1760202496,1760202751,US
-1760202752,1760216063,CA
+1760202752,1760215551,CA
+1760215552,1760215807,US
+1760215808,1760216063,CA
1760216064,1760216319,NL
1760216320,1760219647,CA
1760219648,1760219903,US
@@ -73709,9 +73894,7 @@
1761047296,1761047551,IN
1761047552,1761050111,US
1761050112,1761050367,CA
-1761050368,1761057535,US
-1761057536,1761057791,TR
-1761057792,1761058815,US
+1761050368,1761058815,US
1761058816,1761067007,TR
1761067008,1761075199,US
1761075200,1761083391,CA
@@ -73749,9 +73932,108 @@
1761345792,1761346047,AP
1761346048,1761348607,US
1761348608,1761348863,AP
-1761348864,1761351423,US
+1761348864,1761349119,UA
+1761349120,1761351423,US
1761351424,1761351679,AP
-1761351680,1761478655,US
+1761351680,1761352191,US
+1761352192,1761352447,UA
+1761352448,1761360639,US
+1761360640,1761360895,UA
+1761360896,1761361407,US
+1761361408,1761361663,UA
+1761361664,1761364735,US
+1761364736,1761364991,UA
+1761364992,1761366271,US
+1761366272,1761366527,UA
+1761366528,1761370367,US
+1761370368,1761370623,UA
+1761370624,1761370879,US
+1761370880,1761371135,UA
+1761371136,1761373183,US
+1761373184,1761373439,UA
+1761373440,1761374719,US
+1761374720,1761374975,UA
+1761374976,1761375231,US
+1761375232,1761375487,UA
+1761375488,1761376255,US
+1761376256,1761376767,UA
+1761376768,1761378047,US
+1761378048,1761378303,UA
+1761378304,1761378559,US
+1761378560,1761378815,UA
+1761378816,1761381631,US
+1761381632,1761381887,UA
+1761381888,1761382399,US
+1761382400,1761382655,UA
+1761382656,1761382911,US
+1761382912,1761383167,UA
+1761383168,1761388031,US
+1761388032,1761388287,UA
+1761388288,1761388543,US
+1761388544,1761389311,UA
+1761389312,1761390591,US
+1761390592,1761390847,UA
+1761390848,1761392639,US
+1761392640,1761392895,UA
+1761392896,1761393663,US
+1761393664,1761393919,UA
+1761393920,1761403391,US
+1761403392,1761403647,UA
+1761403648,1761406463,US
+1761406464,1761406719,UA
+1761406720,1761408767,US
+1761408768,1761409023,UA
+1761409024,1761409535,US
+1761409536,1761409791,UA
+1761409792,1761412095,US
+1761412096,1761412351,UA
+1761412352,1761413887,US
+1761413888,1761414399,UA
+1761414400,1761414911,US
+1761414912,1761415167,UA
+1761415168,1761418495,US
+1761418496,1761419007,UA
+1761419008,1761420543,US
+1761420544,1761420799,UA
+1761420800,1761421055,US
+1761421056,1761421311,UA
+1761421312,1761423103,US
+1761423104,1761423359,UA
+1761423360,1761425663,US
+1761425664,1761426175,UA
+1761426176,1761427199,US
+1761427200,1761427455,UA
+1761427456,1761435647,US
+1761435648,1761435903,UA
+1761435904,1761438975,US
+1761438976,1761439231,UA
+1761439232,1761439487,US
+1761439488,1761439743,UA
+1761439744,1761446911,US
+1761446912,1761447423,UA
+1761447424,1761447679,US
+1761447680,1761447935,UA
+1761447936,1761448959,US
+1761448960,1761449215,UA
+1761449216,1761451775,US
+1761451776,1761452031,UA
+1761452032,1761453567,US
+1761453568,1761453823,UA
+1761453824,1761455615,US
+1761455616,1761455871,UA
+1761455872,1761456895,US
+1761456896,1761457151,UA
+1761457152,1761458943,US
+1761458944,1761459199,UA
+1761459200,1761463551,US
+1761463552,1761464063,UA
+1761464064,1761465599,US
+1761465600,1761465855,UA
+1761465856,1761466367,US
+1761466368,1761466623,UA
+1761466624,1761466879,US
+1761466880,1761467135,UA
+1761467136,1761478655,US
1761478656,1761479679,CA
1761479680,1761484799,US
1761484800,1761485823,CA
@@ -74012,8 +74294,8 @@
1804976128,1804976639,HK
1804976640,1804977151,US
1804977152,1804978175,HK
-1804978176,1804980479,US
-1804980480,1804980735,HK
+1804978176,1804980223,US
+1804980224,1804980735,HK
1804980736,1805010431,US
1805010432,1805010687,KR
1805010688,1805010943,GB
@@ -74063,9 +74345,13 @@
1805752832,1805753087,CA
1805753088,1805877247,US
1805877248,1805893631,HK
-1805893632,1805964287,US
+1805893632,1805932287,US
+1805932288,1805932543,UA
+1805932544,1805964287,US
1805964288,1805964543,DE
-1805964544,1806170111,US
+1805964544,1806035455,US
+1806035456,1806035711,UA
+1806035712,1806170111,US
1806170112,1806172159,CA
1806303232,1806401535,US
1806401536,1806434303,CA
@@ -74092,8 +74378,7 @@
1807093760,1807097855,CA
1807097856,1807118335,US
1807122432,1807122687,NL
-1807122688,1807123199,US
-1807123200,1807123455,NL
+1807122688,1807123455,US
1807124480,1807134719,US
1807134720,1807138815,CA
1807138816,1807155199,US
@@ -74202,7 +74487,10 @@
1833181184,1833183231,GB
1833183232,1833185279,UA
1833185280,1833189375,DE
-1833189376,1833191423,GB
+1833189376,1833190143,GB
+1833190144,1833190399,US
+1833190400,1833190911,GB
+1833190912,1833191423,IE
1833191424,1833193471,RU
1833193472,1833195519,ES
1833195520,1833197567,NO
@@ -74351,7 +74639,8 @@
1833455616,1833459711,NL
1833459712,1833463807,ME
1833463808,1833464319,NL
-1833464320,1833465087,US
+1833464320,1833464831,US
+1833464832,1833465087,ES
1833465088,1833465599,TR
1833465600,1833465855,US
1833465856,1833466111,KR
@@ -74634,8 +74923,7 @@
1835999232,1836003327,US
1836003328,1836004351,AU
1836004352,1836005375,TW
-1836005376,1836006399,US
-1836006400,1836007423,AU
+1836005376,1836007423,AU
1836007424,1836015615,RU
1836015616,1836023807,AD
1836023808,1836040191,RU
@@ -74679,13 +74967,11 @@
1836762624,1836762879,EU
1836762880,1836763135,IR
1836763136,1836763391,IN
-1836763392,1836763647,NL
-1836763648,1836765183,EU
+1836763392,1836765183,EU
1836765184,1836765439,NL
1836765440,1836765695,IR
1836765696,1836766207,EU
-1836766208,1836766463,US
-1836766464,1836766719,EU
+1836766208,1836766719,US
1836766720,1836766975,NL
1836766976,1836767231,EU
1836767232,1836767743,IR
@@ -74813,16 +75099,22 @@
1840185344,1840218111,BA
1840218112,1840232447,GB
1840232448,1840232703,NL
-1840232704,1840304639,GB
-1840304640,1840304895,CN
-1840304896,1840312319,GB
+1840232704,1840304127,GB
+1840304128,1840304383,HU
+1840304384,1840304639,LT
+1840304640,1840304895,JP
+1840304896,1840305151,LT
+1840305152,1840306175,GB
+1840306176,1840308223,LT
+1840308224,1840312319,GB
1840312320,1840312575,TR
-1840312576,1840312831,CN
+1840312576,1840312831,JP
1840312832,1840313599,US
-1840313600,1840313855,BH
+1840313600,1840313855,NL
1840313856,1840314111,TR
1840314112,1840314367,PA
-1840314368,1840315135,TR
+1840314368,1840314623,IN
+1840314624,1840315135,LT
1840315136,1840315391,PA
1840315392,1840315647,TR
1840315648,1840315903,GB
@@ -74942,8 +75234,8 @@
1842053120,1842061311,IR
1842061312,1842061567,US
1842061568,1842061823,RU
-1842061824,1842063359,US
-1842063360,1842069503,IR
+1842061824,1842065407,US
+1842065408,1842069503,IR
1842069504,1842077695,RU
1842077696,1842079743,FR
1842079744,1842085887,MQ
@@ -74968,7 +75260,7 @@
1842166784,1842167039,ES
1842167040,1842167295,SE
1842167296,1842167551,MX
-1842167552,1842167807,NL
+1842167552,1842167807,US
1842167808,1842169855,FR
1842169856,1842171903,CZ
1842171904,1842173951,RU
@@ -75028,9 +75320,7 @@
1842278912,1842279167,AU
1842279168,1842279423,FI
1842279424,1842279679,HK
-1842279680,1842279935,AP
-1842279936,1842280191,HK
-1842280192,1842280447,AP
+1842279680,1842280447,AP
1842280448,1842280959,US
1842280960,1842281471,GB
1842281472,1842282495,IR
@@ -75435,9 +75725,7 @@
1845166080,1845231615,UA
1845231616,1845297151,RU
1845297152,1845362687,IL
-1845362688,1845381119,RU
-1845381120,1845383167,UA
-1845383168,1845428223,RU
+1845362688,1845428223,RU
1845428224,1845493759,IE
1845493760,1845755903,JP
1845755904,1845764095,HK
@@ -76121,15 +76409,23 @@
1908932608,1909129215,CN
1909129216,1909161983,IR
1909161984,1909178367,ES
-1909178368,1909183231,PK
+1909178368,1909182463,PK
+1909182464,1909182719,US
+1909182720,1909183231,PK
1909183232,1909183487,TR
1909183488,1909185279,PK
1909185280,1909185535,TR
-1909185536,1909188863,PK
+1909185536,1909188351,PK
+1909188352,1909188607,US
+1909188608,1909188863,PK
1909188864,1909189119,TR
-1909189120,1909191935,PK
+1909189120,1909191423,PK
+1909191424,1909191679,FI
+1909191680,1909191935,PK
1909191936,1909192191,NL
-1909192192,1909194751,PK
+1909192192,1909193215,PK
+1909193216,1909193471,US
+1909193472,1909194751,PK
1909194752,1909456895,CN
1909456896,1909473279,JP
1909473280,1909473791,ID
@@ -76480,9 +76776,12 @@
1940295680,1940324351,JP
1940324352,1940326143,US
1940326144,1940326399,GB
-1940326400,1940332543,US
+1940326400,1940330495,US
+1940330496,1940331519,CA
+1940331520,1940332543,GB
1940332544,1940336639,SG
-1940336640,1940337151,US
+1940336640,1940336895,CA
+1940336896,1940337151,US
1940337152,1940337407,PK
1940337408,1940337663,GB
1940337664,1940338175,US
@@ -76824,7 +77123,8 @@
1959681024,1959681279,AP
1959681280,1959682047,JP
1959682048,1959683071,US
-1959683072,1959684095,EU
+1959683072,1959683839,HK
+1959683840,1959684095,EU
1959684096,1959684607,IN
1959684608,1959685119,HK
1959685120,1959686143,PH
@@ -77008,7 +77308,7 @@
1966589184,1966589439,LU
1966589440,1966589951,AF
1966589952,1966590463,SE
-1966590464,1966590975,AF
+1966590464,1966590975,NL
1966590976,1966591231,JP
1966591232,1966591999,SG
1966592000,1966596095,JP
@@ -78257,7 +78557,7 @@
2063392768,2063400959,IN
2063400960,2063466495,JP
2063466496,2063482879,TW
-2063482880,2063483135,HK
+2063482880,2063483135,KR
2063483136,2063484927,MN
2063484928,2063486975,US
2063486976,2063490047,MN
@@ -78310,18 +78610,11 @@
2067726336,2067791871,IN
2067791872,2070036479,CN
2070036480,2070037503,DE
-2070037504,2070038527,US
+2070037504,2070038527,CN
2070038528,2070039551,DE
-2070039552,2070042623,CN
-2070042624,2070043647,US
-2070043648,2070044671,CN
-2070044672,2070045695,US
+2070039552,2070045695,CN
2070045696,2070046719,DE
-2070046720,2070047743,CN
-2070047744,2070048767,US
-2070048768,2070050815,CN
-2070050816,2070051839,US
-2070051840,2070052863,CN
+2070046720,2070052863,CN
2070052864,2070056959,AU
2070056960,2070061055,JP
2070061056,2070077439,KR
@@ -78487,8 +78780,7 @@
2080201728,2080202751,PK
2080202752,2080203775,BD
2080203776,2080204799,HK
-2080204800,2080205055,US
-2080205056,2080205823,IM
+2080204800,2080205823,NL
2080205824,2080206591,JP
2080206592,2080207871,HK
2080207872,2080208895,AU
@@ -79076,7 +79368,8 @@
2160714752,2160716799,BR
2160716800,2160717823,AR
2160717824,2160721919,BR
-2160721920,2160852991,US
+2160721920,2160787455,US
+2160787456,2160852991,GB
2160852992,2160885759,RU
2160885760,2160893951,AT
2160893952,2160902143,RU
@@ -79475,9 +79768,7 @@
2193424384,2193489919,US
2193489920,2193555455,FR
2193555456,2193620991,US
-2193620992,2193686527,IT
-2193686528,2193686783,GB
-2193686784,2193687039,IT
+2193620992,2193687039,IT
2193687040,2193687295,GB
2193687296,2193687551,US
2193687552,2193688063,NL
@@ -79590,7 +79881,9 @@
2197480448,2197481471,CO
2197481472,2197487615,US
2197487616,2197553151,IT
-2197553152,2197700607,US
+2197553152,2197694463,US
+2197694464,2197695487,RO
+2197695488,2197700607,US
2197700608,2197708799,CA
2197708800,2197749759,US
2197749760,2197751807,IQ
@@ -80535,7 +80828,9 @@
2270494720,2270560255,GB
2270560256,2270822399,US
2270822400,2270887935,AU
-2270887936,2272526335,US
+2270887936,2272395263,US
+2272395264,2272460799,GB
+2272460800,2272526335,US
2272526336,2272591871,GB
2272591872,2273116159,US
2273116160,2273134847,FR
@@ -80551,30 +80846,25 @@
2273156864,2273158143,DE
2273158144,2273159167,FR
2273159168,2273159423,DE
-2273159424,2273159679,FR
-2273159680,2273159935,DE
-2273159936,2273160191,FI
-2273160192,2273160959,FR
+2273159424,2273160959,FR
2273160960,2273161215,DE
2273161216,2273162239,FR
-2273162240,2273163775,DE
-2273163776,2273164287,FR
+2273162240,2273163519,DE
+2273163520,2273164287,FR
2273164288,2273165311,DE
2273165312,2273166335,FR
2273166336,2273166591,DE
2273166592,2273167103,FR
2273167104,2273169407,DE
2273169408,2273171455,FR
-2273171456,2273173503,DE
-2273173504,2273174015,FR
+2273171456,2273172991,DE
+2273172992,2273174015,FR
2273174016,2273174271,DE
2273174272,2273175551,FR
2273175552,2273177599,DE
2273177600,2273178623,FR
2273178624,2273179647,DE
-2273179648,2273181183,FR
-2273181184,2273181439,DE
-2273181440,2273181695,FR
+2273179648,2273181695,FR
2273181696,2273435647,US
2273435648,2273439743,ES
2273439744,2273443839,US
@@ -80587,7 +80877,9 @@
2276786176,2276816895,FI
2276816896,2276817151,DE
2276817152,2276851711,FI
-2276851712,2277769215,US
+2276851712,2277048319,US
+2277048320,2277113855,GB
+2277113856,2277769215,US
2277769216,2277834751,GB
2277834752,2279604223,US
2279604224,2279800831,GB
@@ -80597,7 +80889,9 @@
2280128512,2280521727,GB
2280521728,2280652799,US
2280652800,2280718335,GB
-2280718336,2281751551,US
+2280718336,2281718015,US
+2281718016,2281718271,UA
+2281718272,2281751551,US
2281751552,2281751807,TR
2281751808,2282885631,US
2282885632,2282885887,DE
@@ -80697,7 +80991,9 @@
2294808576,2294874111,US
2294874112,2294939647,IE
2294939648,2295201791,US
-2295201792,2295209983,IE
+2295201792,2295205631,IE
+2295205632,2295205887,GB
+2295205888,2295209983,IE
2295209984,2295210239,GB
2295210240,2295267327,IE
2295267328,2296446975,US
@@ -80732,7 +81028,9 @@
2300837888,2301100031,US
2301100032,2301165567,JP
2301165568,2301296639,US
-2301296640,2301362175,IE
+2301296640,2301330431,IE
+2301330432,2301330687,GB
+2301330688,2301362175,IE
2301362176,2301427711,GB
2301427712,2301558783,US
2301558784,2301624319,NO
@@ -81762,7 +82060,7 @@
2333877248,2333878271,UA
2333878272,2333879295,PL
2333879296,2333880319,UZ
-2333880320,2333881343,US
+2333880320,2333881343,CH
2333881344,2333882367,RU
2333882368,2333883391,ES
2333883392,2333884415,DE
@@ -82060,8 +82358,10 @@
2344489984,2344493055,US
2344493056,2344494079,DE
2344494080,2344496127,US
-2344496128,2344497151,ES
-2344497152,2344501247,US
+2344496128,2344497151,GB
+2344497152,2344498175,US
+2344498176,2344499199,CA
+2344499200,2344501247,US
2344501248,2344509439,EU
2344509440,2344510463,US
2344510464,2344511487,TR
@@ -82069,7 +82369,8 @@
2344517632,2344534015,PS
2344534016,2344542207,EU
2344542208,2344544511,AU
-2344544512,2344545023,US
+2344544512,2344544767,US
+2344544768,2344545023,GB
2344545024,2344546303,PK
2344546304,2344550399,US
2344550400,2344615935,EU
@@ -82279,29 +82580,28 @@
2366334464,2366334719,HK
2366334720,2366335231,NL
2366335232,2366335487,FR
-2366335488,2366335743,BE
-2366335744,2366335999,NL
+2366335488,2366335999,NL
2366336000,2366336255,US
2366336256,2366336511,TR
2366336512,2366336767,FR
2366336768,2366337023,US
2366337024,2366339839,FR
-2366339840,2366340095,NL
-2366340096,2366340351,US
+2366339840,2366340351,NL
2366340352,2366340607,HK
2366340608,2366340863,FR
2366340864,2366341119,TR
-2366341120,2366342143,EU
-2366342144,2366343679,US
+2366341120,2366343167,EU
+2366343168,2366343679,US
2366343680,2366344191,JP
2366344192,2366345215,CY
2366345216,2366347263,EU
2366347264,2366347775,US
-2366347776,2366348287,EU
+2366347776,2366348287,DE
2366348288,2366349311,TH
2366349312,2366349823,US
2366349824,2366351359,FR
-2366351360,2366352383,US
+2366351360,2366351871,EU
+2366351872,2366352383,DE
2366352384,2366353407,GB
2366353408,2366353919,US
2366353920,2366354175,MD
@@ -82318,21 +82618,15 @@
2366357248,2366357503,FR
2366357504,2366358015,NL
2366358016,2366358527,KR
-2366358528,2366359551,EU
-2366359552,2366360575,US
-2366360576,2366361599,EU
+2366358528,2366361599,EU
2366361600,2366362623,US
2366362624,2366363135,NL
-2366363136,2366363647,EU
-2366363648,2366364159,FR
-2366364160,2366364671,EU
-2366364672,2366365695,US
+2366363136,2366365695,EU
2366365696,2366367231,NL
2366367232,2366367487,SG
-2366367488,2366369279,NL
-2366369280,2366369791,US
-2366369792,2366370303,TR
-2366370304,2366370559,US
+2366367488,2366368767,NL
+2366368768,2366369279,DE
+2366369280,2366370559,US
2366370560,2366370815,LB
2366370816,2366371327,ES
2366371328,2366371583,NL
@@ -82362,9 +82656,7 @@
2371770880,2371771135,DE
2371771136,2371780351,FR
2371780352,2371780607,BE
-2371780608,2371787519,FR
-2371787520,2371787775,DE
-2371787776,2371788031,FR
+2371780608,2371788031,FR
2371788032,2371788287,DE
2371788288,2371807999,FR
2371808000,2371808255,BE
@@ -83921,7 +84213,7 @@
2450782976,2450783231,AE
2450783232,2450783487,US
2450783488,2450783743,NL
-2450783744,2450783999,US
+2450783744,2450783999,FR
2450784000,2450784255,CZ
2450784256,2450849791,US
2450849792,2450915327,SE
@@ -84559,7 +84851,9 @@
2459847680,2459848191,RU
2459848192,2459848447,FR
2459848448,2459848703,KZ
-2459848704,2459860991,RU
+2459848704,2459852287,EU
+2459852288,2459852543,UZ
+2459852544,2459860991,RU
2459860992,2459893759,ES
2459893760,2459959295,CH
2459959296,2460024831,JP
@@ -84871,7 +85165,7 @@
2471393280,2471393535,ES
2471393536,2471393791,GB
2471393792,2471394047,FR
-2471394048,2471394303,GB
+2471394048,2471394303,EU
2471394304,2471395327,DE
2471395328,2471396351,AP
2471396352,2471396607,AE
@@ -85423,9 +85717,7 @@
2500182784,2500183039,IN
2500183040,2500270847,US
2500270848,2500271103,UA
-2500271104,2500984831,US
-2500984832,2500985087,TR
-2500985088,2500985599,US
+2500271104,2500985599,US
2500985600,2500985855,NL
2500985856,2500995327,US
2500995328,2500995583,NL
@@ -85448,7 +85740,11 @@
2501011968,2501012223,US
2501012224,2501012479,NL
2501012480,2501013503,GB
-2501013504,2501054463,US
+2501013504,2501014783,US
+2501014784,2501015039,FI
+2501015040,2501015295,US
+2501015296,2501015551,FI
+2501015552,2501054463,US
2501054464,2501058559,NZ
2501058560,2501074943,US
2501074944,2501076991,CA
@@ -85497,9 +85793,7 @@
2503545856,2503546367,TR
2503546368,2503548415,US
2503548416,2503548927,TR
-2503548928,2503549951,US
-2503549952,2503550207,TR
-2503550208,2503550463,US
+2503548928,2503550463,US
2503550464,2503550719,UA
2503550720,2503551999,US
2503552000,2503553023,NL
@@ -85509,12 +85803,14 @@
2503562496,2503562751,NL
2503562752,2503566335,US
2503566336,2503567359,GB
-2503567360,2503671807,US
+2503567360,2503570687,US
+2503570688,2503570943,FI
+2503570944,2503671807,US
2503671808,2503737343,NL
2503737344,2503868415,US
2503868416,2503876607,RU
2503876608,2503876863,IT
-2503876864,2503877119,MD
+2503876864,2503877119,AT
2503877120,2503877375,IE
2503877376,2503877631,AT
2503877632,2503877887,US
@@ -85549,7 +85845,9 @@
2505498624,2505499647,PL
2505499648,2505500671,US
2505500672,2505502719,FI
-2505502720,2505703423,US
+2505502720,2505588735,US
+2505588736,2505590783,AP
+2505590784,2505703423,US
2505703424,2505768959,PT
2505768960,2506293247,US
2506293248,2506358783,CA
@@ -85562,7 +85860,9 @@
2506530816,2506620927,US
2506620928,2506623487,HK
2506623488,2506623743,US
-2506623744,2506627583,HK
+2506623744,2506626559,HK
+2506626560,2506627071,US
+2506627072,2506627583,HK
2506627584,2506633215,US
2506633216,2506635263,HK
2506635264,2506655999,US
@@ -85907,9 +86207,7 @@
2525051904,2525053951,IN
2525053952,2525054975,MY
2525054976,2525055999,TW
-2525056000,2525057023,HK
-2525057024,2525057279,AP
-2525057280,2525058047,HK
+2525056000,2525058047,HK
2525058048,2525059071,AU
2525059072,2525060095,IN
2525060096,2525061119,US
@@ -86248,6 +86546,7 @@
2547154944,2547187711,NZ
2547187712,2547318783,GB
2547318784,2547515391,US
+2547523584,2547525631,NO
2547525632,2547526655,??
2547526656,2547526911,NL
2547548160,2547580927,??
@@ -86751,7 +87050,9 @@
2584112384,2584112639,NL
2584112640,2584113151,US
2584113152,2584114175,TR
-2584114176,2584116479,US
+2584114176,2584115455,US
+2584115456,2584115711,FI
+2584115712,2584116479,US
2584116480,2584116735,TR
2584116736,2584116991,NL
2584116992,2584117247,TR
@@ -86791,8 +87092,12 @@
2584477696,2584481791,US
2584481792,2584482303,AP
2584482304,2584482559,HK
-2584482560,2584485375,AP
-2584485376,2584485631,HK
+2584482560,2584483071,AP
+2584483072,2584483327,HK
+2584483328,2584484095,AP
+2584484096,2584484351,HK
+2584484352,2584485119,AP
+2584485120,2584485631,HK
2584485632,2584485887,AP
2584485888,2584486655,HK
2584486656,2584486911,US
@@ -86802,13 +87107,11 @@
2584488960,2584492031,US
2584492032,2584492799,HK
2584492800,2584498175,US
-2584498176,2584498687,AP
-2584498688,2584498943,HK
-2584498944,2584499199,AP
-2584499200,2584499455,HK
-2584499456,2584500223,AP
-2584500224,2584500479,HK
-2584500480,2584502271,AP
+2584498176,2584498431,AP
+2584498432,2584498687,HK
+2584498688,2584498943,AP
+2584498944,2584499711,HK
+2584499712,2584502271,AP
2584502272,2584544255,US
2584544256,2584545279,HK
2584545280,2584600575,US
@@ -86926,7 +87229,7 @@
2584763648,2584763903,ZA
2584763904,2584764159,DE
2584764160,2584764415,ZA
-2584764416,2584764671,MA
+2584764416,2584764671,US
2584764672,2584764927,ZA
2584764928,2584765183,US
2584765184,2584765439,ZA
@@ -87007,9 +87310,7 @@
2584852480,2584908799,US
2584908800,2584909823,MO
2584909824,2584952831,US
-2584952832,2584958207,AP
-2584958208,2584958463,US
-2584958464,2584960511,AP
+2584952832,2584960511,AP
2584960512,2584985599,US
2584985600,2584993791,HK
2584993792,2585001983,US
@@ -87017,7 +87318,9 @@
2585067520,2585157631,US
2585157632,2585158655,HK
2585158656,2585161215,US
-2585161216,2585165823,HK
+2585161216,2585161727,HK
+2585161728,2585161983,US
+2585161984,2585165823,HK
2585165824,2585174015,US
2585174016,2585227775,HK
2585227776,2585228031,US
@@ -87034,8 +87337,8 @@
2585234432,2585239551,HK
2585239552,2585243647,US
2585243648,2585246719,AP
-2585246720,2585246975,US
-2585246976,2585247743,AP
+2585246720,2585247231,US
+2585247232,2585247743,AP
2585247744,2585251839,US
2585251840,2585252351,HK
2585252352,2585252607,US
@@ -87101,8 +87404,8 @@
2586264576,2586264831,HK
2586264832,2586265087,US
2586265088,2586265343,HK
-2586265344,2586266367,US
-2586266368,2586267391,HK
+2586265344,2586266111,US
+2586266112,2586267391,HK
2586267392,2586268927,US
2586268928,2586269695,HK
2586269696,2586270207,US
@@ -87152,12 +87455,16 @@
2587472384,2587710207,US
2587710208,2587710463,NL
2587710464,2587885567,US
-2587885568,2587900927,HK
+2587885568,2587899903,HK
+2587899904,2587900415,US
+2587900416,2587900927,HK
2587900928,2587901439,US
-2587901440,2587918335,HK
+2587901440,2587901695,HK
+2587901696,2587901951,US
+2587901952,2587918335,HK
2587918336,2587934719,US
-2587934720,2587938815,HK
-2587938816,2587944191,US
+2587934720,2587937023,HK
+2587937024,2587944191,US
2587944192,2587944447,HK
2587944448,2587951103,US
2587951104,2587952127,ZA
@@ -87254,9 +87561,7 @@
2588424192,2588426239,ZA
2588426240,2588434431,TZ
2588434432,2588438527,ZA
-2588438528,2588439551,CG
-2588439552,2588440575,RW
-2588440576,2588442623,TG
+2588438528,2588442623,CI
2588442624,2588459007,CM
2588459008,2588467199,UG
2588467200,2588471295,TN
@@ -87700,18 +88005,10 @@
2596417024,2596417279,ZA
2596417280,2596418303,US
2596418304,2596418559,JP
-2596418560,2596418815,PL
-2596418816,2596419071,RU
+2596418560,2596419071,PL
2596419072,2596419327,US
-2596419328,2596421119,NL
-2596421120,2596421375,US
-2596421376,2596421631,NL
-2596421632,2596421887,US
-2596421888,2596422143,IN
-2596422144,2596422399,NL
-2596422400,2596422655,ZA
-2596422656,2596422911,NL
-2596422912,2596423167,TR
+2596419328,2596419583,NL
+2596419584,2596423167,US
2596423168,2596438015,DE
2596438016,2596454399,HK
2596454400,2596470783,PK
@@ -87747,32 +88044,25 @@
2596615680,2596615935,SA
2596615936,2596616191,US
2596616192,2596618239,HK
-2596618240,2596618495,IN
-2596618496,2596619007,ZA
+2596618240,2596619007,ZA
2596619008,2596619263,SG
-2596619264,2596620799,TR
-2596620800,2596621311,ZA
+2596619264,2596621311,ZA
2596621312,2596621823,GB
-2596621824,2596622079,TR
-2596622080,2596622335,IN
-2596622336,2596622591,ZA
-2596622592,2596622847,IN
+2596621824,2596622847,ZA
2596622848,2596623103,EG
-2596623104,2596623359,NL
-2596623360,2596623615,ZA
-2596623616,2596624127,NL
+2596623104,2596624127,ZA
2596624128,2596625151,TR
2596625152,2596625407,HK
-2596625408,2596626431,NL
+2596625408,2596626431,ZA
2596626432,2596626687,TR
-2596626688,2596626943,NL
+2596626688,2596626943,ZA
2596626944,2596627455,AP
2596627456,2596627711,ZA
2596627712,2596627967,TR
2596627968,2596628223,ZA
2596628224,2596628735,TR
2596628736,2596628991,IN
-2596628992,2596629247,ZA
+2596628992,2596629247,US
2596629248,2596629503,NZ
2596629504,2596632575,ZA
2596632576,2596633599,HK
@@ -87808,8 +88098,10 @@
2596874240,2596874751,FR
2596874752,2596877055,US
2596877056,2596878335,ES
-2596878336,2596880383,US
-2596880384,2596896767,ZA
+2596878336,2596884479,US
+2596884480,2596888575,ZA
+2596888576,2596890623,US
+2596890624,2596896767,ZA
2596896768,2596929535,HK
2596929536,2596929791,US
2596929792,2596930047,PH
@@ -87838,12 +88130,8 @@
2597066752,2597067263,AP
2597067264,2597067519,HK
2597067520,2597068799,AP
-2597068800,2597069311,HK
-2597069312,2597069567,US
-2597069568,2597069823,HK
-2597069824,2597070591,US
-2597070592,2597070847,HK
-2597070848,2597071103,US
+2597068800,2597069823,HK
+2597069824,2597071103,US
2597071104,2597071359,HK
2597071360,2597071615,US
2597071616,2597072895,HK
@@ -88723,7 +89011,7 @@
2632173568,2632177663,US
2632177664,2632178175,PH
2632178176,2632178431,LV
-2632178432,2632178687,GR
+2632178432,2632178687,MD
2632178688,2632179711,HK
2632179712,2632183807,ZA
2632183808,2632187903,HK
@@ -88849,7 +89137,9 @@
2632734464,2632734719,HK
2632734720,2632736767,PH
2632736768,2632744959,HK
-2632744960,2632778751,US
+2632744960,2632777983,US
+2632777984,2632778239,IN
+2632778240,2632778751,US
2632778752,2632779263,JP
2632779264,2632785919,US
2632785920,2632810495,ZA
@@ -88897,7 +89187,8 @@
2632974080,2632974335,US
2632974336,2632974591,AP
2632974592,2632989183,HK
-2632989184,2632989695,ZA
+2632989184,2632989439,ZA
+2632989440,2632989695,HK
2632989696,2632990207,SV
2632990208,2632990463,ID
2632990464,2632990719,HK
@@ -88914,9 +89205,7 @@
2633000960,2633003007,AP
2633003008,2633007103,HK
2633007104,2633023487,SG
-2633023488,2633023999,AP
-2633024000,2633024511,US
-2633024512,2633025535,AP
+2633023488,2633025535,AP
2633025536,2633025791,US
2633025792,2633026047,AP
2633026048,2633026303,US
@@ -88975,8 +89264,8 @@
2633306368,2633306623,MY
2633306624,2633309695,HK
2633309696,2633309951,MY
-2633309952,2633325567,HK
-2633325568,2633334783,US
+2633309952,2633326591,HK
+2633326592,2633334783,US
2633334784,2633372159,HK
2633372160,2633372927,SG
2633372928,2633385983,US
@@ -89527,7 +89816,9 @@
2650472448,2650537983,US
2650537984,2650603519,GB
2650603520,2650669055,CO
-2650669056,2650724351,US
+2650669056,2650709503,US
+2650709504,2650709759,IN
+2650709760,2650724351,US
2650724352,2650724607,NL
2650724608,2650734591,US
2650734592,2650800127,CN
@@ -89666,7 +89957,7 @@
2658664448,2658682879,US
2658682880,2658683391,GB
2658683392,2658685951,US
-2658685952,2658686975,NZ
+2658685952,2658686975,NL
2658686976,2658689023,US
2658689024,2658693119,GB
2658693120,2658721791,US
@@ -90489,9 +90780,16 @@
2692008960,2692009983,BR
2692009984,2692014079,ZA
2692014080,2692016127,BR
-2692016128,2692169727,ZA
-2692169728,2692173823,US
-2692173824,2692175871,ZA
+2692016128,2692170239,ZA
+2692170240,2692170495,US
+2692170496,2692170751,ZA
+2692170752,2692171007,SC
+2692171008,2692171263,US
+2692171264,2692171775,ZA
+2692171776,2692172031,US
+2692172032,2692173055,SC
+2692173056,2692173311,EG
+2692173312,2692175871,ZA
2692175872,2692177919,BF
2692177920,2692179967,ZA
2692180992,2692182015,GH
@@ -90529,7 +90827,7 @@
2694578176,2694840319,TN
2694840320,2696151039,MA
2696151040,2696216575,IT
-2696257536,2696265727,HK
+2696257536,2696265727,??
2696282112,2696413183,GM
2696478720,2696609791,JP
2696675328,2696871935,JP
@@ -90661,7 +90959,7 @@
2699983872,2699984895,UA
2699984896,2699986943,BR
2699986944,2699987967,BZ
-2699988992,2699995135,BR
+2699987968,2699995135,BR
2699995136,2699996159,AR
2699996160,2699999231,BR
2699999232,2700000255,PY
@@ -90926,9 +91224,7 @@
2709596672,2709596927,AP
2709596928,2709597439,US
2709597440,2709597695,KR
-2709597696,2709601279,US
-2709601280,2709601535,CA
-2709601536,2709602815,US
+2709597696,2709602815,US
2709602816,2709603327,NL
2709603328,2709610495,US
2709610496,2709620735,CA
@@ -91044,8 +91340,10 @@
2718826496,2718892031,CN
2718892032,2719154175,US
2719154176,2719156735,FR
-2719156736,2719157247,DE
-2719157248,2719187967,FR
+2719156736,2719156991,DE
+2719156992,2719186943,FR
+2719186944,2719187199,DE
+2719187200,2719187967,FR
2719187968,2719188223,DE
2719188224,2719188991,FR
2719188992,2719190015,DE
@@ -91606,7 +91904,8 @@
2735030528,2735030783,FR
2735030784,2735031039,US
2735031040,2735031807,FR
-2735031808,2735032575,US
+2735031808,2735032063,AP
+2735032064,2735032575,US
2735032576,2735032831,FR
2735032832,2735034111,US
2735034112,2735035391,FR
@@ -91708,8 +92007,8 @@
2735077632,2735077887,US
2735077888,2735078143,FR
2735078144,2735078399,US
-2735078400,2735079167,FR
-2735079168,2735144959,US
+2735078400,2735078911,FR
+2735078912,2735144959,US
2735144960,2735210495,NZ
2735210496,2735276031,AU
2735276032,2735341567,FR
@@ -92003,19 +92302,29 @@
2745923584,2745924607,TH
2745924608,2745925631,KR
2745925632,2745925887,DE
-2745925888,2745926143,GB
-2745926144,2745926399,KR
+2745925888,2745926399,GB
2745926400,2745926655,FR
-2745926656,2745929471,KR
+2745926656,2745926911,DE
+2745926912,2745927935,KR
+2745927936,2745928191,UA
+2745928192,2745928703,KR
+2745928704,2745928959,NL
+2745928960,2745929471,KR
2745929472,2745929727,BE
2745929728,2745929983,GB
2745929984,2745930239,NL
-2745930240,2745930751,KR
+2745930240,2745930495,GB
+2745930496,2745930751,KR
2745930752,2745931007,TH
2745931008,2745932031,KR
2745932032,2745932287,RU
2745932288,2745932543,PT
-2745932544,2745934591,KR
+2745932544,2745932799,KR
+2745932800,2745933055,DE
+2745933056,2745933823,KR
+2745933824,2745934079,NL
+2745934080,2745934335,GB
+2745934336,2745934591,KR
2745934592,2745934847,ID
2745934848,2745935103,KR
2745935104,2745935359,ID
@@ -92027,11 +92336,12 @@
2745937152,2745937407,SG
2745937408,2745937663,ES
2745937664,2745937919,BR
-2745937920,2745938431,KR
+2745937920,2745938175,ZA
+2745938176,2745938431,KR
2745938432,2745938687,AE
-2745938688,2745938943,KR
+2745938688,2745938943,OM
2745938944,2745939199,EG
-2745939200,2745939455,KR
+2745939200,2745939455,KW
2745939456,2745940223,PH
2745940224,2745940735,KR
2745940736,2745941503,TH
@@ -92055,8 +92365,8 @@
2745949184,2745949439,ID
2745949440,2745949695,KR
2745949696,2745949951,TW
-2745949952,2745950207,US
-2745950208,2745950463,TW
+2745949952,2745950207,ID
+2745950208,2745950463,GB
2745950464,2745950719,SG
2745950720,2745950975,US
2745950976,2745952767,KR
@@ -92103,7 +92413,8 @@
2747645952,2747646207,US
2747646208,2747646463,ZA
2747646464,2747650047,US
-2747650048,2747654143,HK
+2747650048,2747653631,HK
+2747653632,2747654143,ZA
2747654144,2747658239,US
2747658240,2747662335,HK
2747662336,2747687935,ZA
@@ -92285,9 +92596,7 @@
2757099520,2757230591,US
2757230592,2757257471,HK
2757257472,2757257727,AP
-2757257728,2757278719,HK
-2757278720,2757278975,ZA
-2757278976,2757296127,HK
+2757257728,2757296127,HK
2757296128,2757378047,US
2757378048,2757380095,HK
2757380096,2757380863,IN
@@ -92535,7 +92844,6 @@
2773024768,2773058559,ZA
2773058560,2773059583,SZ
2773059584,2773061631,ZA
-2773061632,2773065727,??
2773065728,2773073919,ZA
2773073920,2773082111,NG
2773082112,2773085183,ZA
@@ -92883,15 +93191,17 @@
2785021952,2785022207,NL
2785022208,2785032703,US
2785032704,2785032959,DE
-2785032960,2785057791,US
+2785032960,2785048063,US
+2785048064,2785048319,NL
+2785048320,2785049343,US
+2785049344,2785049599,NL
+2785049600,2785057791,US
2785057792,2785058047,DE
2785058048,2785059327,US
2785059328,2785059583,NL
2785059584,2785116415,US
2785116416,2785116671,DE
-2785116672,2785119231,US
-2785119232,2785119487,TR
-2785119488,2785123583,US
+2785116672,2785123583,US
2785123584,2785123839,DE
2785123840,2785124607,US
2785124608,2785124863,DE
@@ -93043,9 +93353,7 @@
2807608576,2807608831,CA
2807608832,2807610111,JP
2807610112,2807611391,CA
-2807611392,2807615487,US
-2807615488,2807619583,??
-2807619584,2807824383,US
+2807611392,2807824383,US
2807824384,2807889919,CA
2807889920,2807961599,US
2807961600,2807961855,IT
@@ -93884,7 +94192,7 @@
2833711104,2833776639,CL
2833776640,2833783807,BR
2833783808,2833784831,CR
-2833784832,2833785855,CL
+2833784832,2833785855,CO
2833785856,2833786879,SV
2833786880,2833788927,BR
2833788928,2833789951,SV
@@ -93895,8 +94203,7 @@
2833800192,2833801215,BR
2833801216,2833804287,AR
2833804288,2833805311,DO
-2833805312,2833807359,BR
-2833808384,2833812479,BR
+2833805312,2833812479,BR
2833812480,2833813503,AR
2833813504,2833814527,GY
2833814528,2833818623,BR
@@ -95019,8 +95326,8 @@
2870371840,2870372095,FR
2870372096,2870372351,DE
2870372352,2870373375,GB
-2870373376,2870374399,US
-2870374400,2870374655,BE
+2870373376,2870373631,US
+2870373632,2870374655,BE
2870374656,2870375167,CZ
2870375168,2870375423,US
2870375424,2870375935,CZ
@@ -95147,9 +95454,7 @@
2890996736,2890997759,CA
2890997760,2890998783,US
2890998784,2890999039,CA
-2890999040,2891016191,US
-2891016192,2891016447,CR
-2891016448,2891026431,US
+2890999040,2891026431,US
2891028480,2891034623,US
2891034624,2891036671,CA
2891036672,2891038719,US
@@ -95232,9 +95537,7 @@
2891858432,2891858687,CA
2891858688,2891862015,US
2891862016,2891862271,AU
-2891862272,2891862783,US
-2891862784,2891863039,IN
-2891863040,2891863295,US
+2891862272,2891863295,US
2891863296,2891863551,AU
2891863552,2891867391,US
2891867392,2891867647,AU
@@ -95387,7 +95690,9 @@
2901902848,2901904895,HK
2901904896,2901906943,US
2901906944,2901911039,HK
-2901911040,2902392831,US
+2901911040,2902255103,US
+2902255104,2902255359,UA
+2902255360,2902392831,US
2902392832,2902396927,NL
2902396928,2902405119,US
2902405120,2902409215,CA
@@ -95501,7 +95806,8 @@
2917797888,2917799935,GB
2917799936,2917810175,US
2917810176,2917811199,JP
-2917811200,2917820415,US
+2917811200,2917812223,NL
+2917812224,2917820415,US
2917820416,2917822463,AU
2917822464,2917826559,US
2917826560,2917828607,NL
@@ -95711,7 +96017,9 @@
2943238144,2943239167,TR
2943239168,2943244287,US
2943244288,2943245311,CA
-2943245312,2943247103,US
+2943245312,2943246335,US
+2943246336,2943246591,CA
+2943246592,2943247103,US
2943247104,2943247359,AP
2943247360,2943248383,CA
2943248384,2943249407,TR
@@ -96627,7 +96935,7 @@
2960531968,2960532479,NL
2960532480,2960532735,PL
2960532736,2960532991,RU
-2960532992,2960533247,CA
+2960532992,2960533247,FR
2960533248,2960533503,JO
2960533504,2960537599,UA
2960537600,2960539647,KZ
@@ -97109,8 +97417,7 @@
2974022144,2974022399,PE
2974022400,2974244863,BR
2974244864,2974245887,AR
-2974245888,2974384127,BR
-2974385152,2974390271,BR
+2974245888,2974390271,BR
2974390272,2974391295,CO
2974391296,2974392319,AR
2974392320,2974416383,BR
@@ -97137,8 +97444,8 @@
2975697920,2975698431,CW
2975698432,2975698687,BR
2975698688,2975698943,TM
-2975698944,2976498687,BR
-2976501760,2977715199,BR
+2975698944,2976499711,BR
+2976500736,2977715199,BR
2977715200,2977716223,MX
2977716224,2977794047,BR
2977794048,2977795071,MX
@@ -97340,7 +97647,7 @@
2987793152,2987793407,GE
2987793408,2987793663,IT
2987793664,2987793919,NL
-2987793920,2987794175,GB
+2987793920,2987794175,US
2987794176,2987794431,RU
2987794432,2987796479,IQ
2987796480,2987800575,RU
@@ -97653,8 +97960,7 @@
2996775936,2996776959,BY
2996776960,2996781055,RU
2996781056,2996785151,US
-2996785152,2996788479,RU
-2996788480,2996789247,SG
+2996785152,2996789247,RU
2996789248,2996790015,UA
2996790016,2996790527,US
2996790528,2996792063,UA
@@ -97911,7 +98217,7 @@
3000257536,3000257791,TR
3000257792,3000258047,US
3000258048,3000258303,RU
-3000258304,3000258559,NL
+3000258304,3000258559,US
3000258560,3000260607,RU
3000260608,3000260863,RS
3000260864,3000261887,DE
@@ -98620,7 +98926,9 @@
3006922752,3007053823,BO
3007053824,3007062015,AR
3007062016,3007066111,CO
-3007066112,3007070207,EC
+3007066112,3007067391,EC
+3007067392,3007067647,PA
+3007067648,3007070207,EC
3007070208,3007078399,CL
3007078400,3007082495,AR
3007082496,3007086591,BO
@@ -99020,7 +99328,9 @@
3031592960,3031595007,CN
3031595008,3031596031,AU
3031596032,3031597055,KH
-3031597056,3031601407,PK
+3031597056,3031600127,PK
+3031600128,3031600383,FI
+3031600384,3031601407,PK
3031601408,3031601663,CA
3031601664,3031601919,PK
3031601920,3031602175,TR
@@ -99236,7 +99546,8 @@
3039402496,3039402751,CR
3039402752,3039403007,VE
3039403008,3039404031,BO
-3039404032,3039412735,BR
+3039404032,3039412479,BR
+3039412480,3039412735,VN
3039412736,3039412991,NL
3039412992,3039413759,BR
3039413760,3039414015,SE
@@ -99450,8 +99761,7 @@
3049754624,3049762815,AR
3049762816,3049766911,HN
3049766912,3049771007,MX
-3049771008,3049771263,PA
-3049771264,3049771519,AR
+3049771008,3049771519,AR
3049771520,3049772031,GT
3049772032,3049775103,AR
3049775104,3049783295,GY
@@ -99567,7 +99877,8 @@
3050747136,3050747391,US
3050747392,3050747647,BR
3050747648,3050747903,SG
-3050747904,3050748415,US
+3050747904,3050748159,US
+3050748160,3050748415,HK
3050748416,3050748671,GB
3050748672,3050748927,SG
3050748928,3050749183,TH
@@ -100433,7 +100744,6 @@
3103901440,3103901695,PL
3103901696,3103901951,IS
3103901952,3103902207,DE
-3103902208,3103902463,TR
3103902464,3103902719,NL
3103902720,3103902975,NO
3103902976,3103903231,CH
@@ -101736,6 +102046,7 @@
3105096704,3105096959,NL
3105096960,3105097215,FR
3105097216,3105097471,TR
+3105097472,3105097727,DE
3105097728,3105098751,FR
3105098752,3105099775,SE
3105099776,3105100799,FR
@@ -102345,7 +102656,7 @@
3105648640,3105649663,GB
3105649664,3105649919,DE
3105649920,3105650431,ES
-3105650432,3105650687,PL
+3105650432,3105650687,NL
3105650688,3105651199,EE
3105651200,3105651455,PL
3105651456,3105651711,EE
@@ -102918,7 +103229,8 @@
3106193920,3106194431,HK
3106194432,3106195455,UA
3106195456,3106196479,AZ
-3106196480,3106197503,GB
+3106196480,3106196735,US
+3106196736,3106197503,GB
3106197504,3106198527,ES
3106198528,3106199551,NO
3106199552,3106200575,FR
@@ -103095,8 +103407,7 @@
3106345728,3106345983,RU
3106345984,3106347007,DE
3106347008,3106348031,IT
-3106348032,3106348287,UA
-3106348288,3106348543,PL
+3106348032,3106348543,UA
3106348544,3106348799,RO
3106348800,3106349055,US
3106349056,3106350079,CH
@@ -105518,8 +105829,7 @@
3108645888,3108646655,US
3108646656,3108646911,EU
3108646912,3108647935,DK
-3108647936,3108648447,GB
-3108648448,3108648959,US
+3108647936,3108648959,US
3108648960,3108649215,GB
3108649216,3108649983,IM
3108649984,3108651007,CZ
@@ -106008,7 +106318,7 @@
3109097472,3109098495,GB
3109098496,3109099519,HU
3109099520,3109100543,RU
-3109100544,3109101567,GB
+3109100544,3109101567,US
3109101568,3109102591,TR
3109102592,3109103615,DK
3109103616,3109104639,IR
@@ -108140,7 +108450,7 @@
3111009280,3111009535,BG
3111009536,3111009791,GB
3111009792,3111010047,US
-3111010048,3111010303,DE
+3111010048,3111010303,TR
3111010304,3111012351,ES
3111012352,3111013375,CH
3111013376,3111014399,ES
@@ -108323,7 +108633,8 @@
3111183360,3111184383,FR
3111184384,3111185407,IQ
3111185408,3111186431,RU
-3111186432,3111187455,NL
+3111186432,3111187199,HU
+3111187200,3111187455,NL
3111187456,3111188479,GB
3111188480,3111188735,MK
3111188736,3111188991,AE
@@ -108415,7 +108726,8 @@
3111271424,3111272447,GB
3111272448,3111273471,ES
3111273472,3111274495,SA
-3111274496,3111275263,SC
+3111274496,3111275007,SC
+3111275008,3111275263,MA
3111275264,3111275519,GE
3111275520,3111276031,US
3111276032,3111276287,SG
@@ -110009,7 +110321,7 @@
3112787456,3112787967,US
3112787968,3112788223,FR
3112788224,3112788479,DE
-3112788480,3112788735,GB
+3112788480,3112788735,TR
3112788736,3112788991,EE
3112788992,3112791039,ES
3112791040,3112792063,IR
@@ -110570,7 +110882,7 @@
3113303040,3113304063,NL
3113304064,3113306111,ES
3113306112,3113308159,FR
-3113308160,3113309183,US
+3113308160,3113309183,MD
3113309184,3113310207,IT
3113310208,3113311231,GB
3113311232,3113312255,SE
@@ -111861,7 +112173,7 @@
3114432512,3114433535,MC
3114433536,3114434559,IL
3114434560,3114434815,NL
-3114434816,3114435071,US
+3114434816,3114435071,RU
3114435072,3114435583,NL
3114435584,3114436607,MD
3114436608,3114437631,DK
@@ -111889,7 +112201,7 @@
3114459136,3114461183,GB
3114461184,3114461695,RU
3114461696,3114461951,KZ
-3114461952,3114462207,NL
+3114461952,3114462207,RU
3114462208,3114463231,GR
3114463232,3114464255,US
3114464256,3114465279,BE
@@ -112635,8 +112947,7 @@
3115087360,3115087615,CZ
3115087616,3115087871,PL
3115087872,3115088895,GB
-3115088896,3115089919,DE
-3115089920,3115090175,GB
+3115088896,3115090175,DE
3115090176,3115090431,US
3115090432,3115090943,DE
3115090944,3115091967,NL
@@ -113260,8 +113571,8 @@
3115630848,3115631103,JP
3115631104,3115631359,KR
3115631360,3115631615,HK
-3115631616,3115631871,NL
-3115631872,3115632383,US
+3115631616,3115632127,NL
+3115632128,3115632383,US
3115632384,3115633663,RU
3115633664,3115635711,PL
3115635712,3115636735,RU
@@ -113375,7 +113686,7 @@
3115738112,3115739135,UA
3115739136,3115739391,RU
3115739392,3115739647,TR
-3115739648,3115739903,CZ
+3115739648,3115739903,IT
3115739904,3115740159,FR
3115740160,3115741183,RU
3115741184,3115742207,LB
@@ -113830,7 +114141,7 @@
3116112896,3116113151,GB
3116113152,3116113407,TR
3116113408,3116113663,FI
-3116113664,3116113919,IR
+3116113664,3116113919,TR
3116113920,3116114943,DE
3116114944,3116115967,TR
3116115968,3116116223,GB
@@ -114328,7 +114639,9 @@
3116540928,3116541951,FR
3116541952,3116542975,GB
3116542976,3116543999,TR
-3116544000,3116545023,GB
+3116544000,3116544255,GB
+3116544256,3116544511,DE
+3116544512,3116545023,GB
3116545024,3116546047,CH
3116546048,3116546815,FR
3116546816,3116547071,BE
@@ -114784,7 +115097,7 @@
3116941056,3116941311,US
3116941312,3116942335,FR
3116942336,3116943359,RU
-3116943360,3116944383,??
+3116943360,3116944383,FR
3116944384,3116944895,IT
3116944896,3116945407,FR
3116945408,3116945919,JP
@@ -114914,7 +115227,7 @@
3117047808,3117048831,DE
3117048832,3117049087,US
3117049088,3117049343,KR
-3117049344,3117049599,US
+3117049344,3117049599,TW
3117049600,3117049855,JP
3117049856,3117050111,EU
3117050112,3117050367,RO
@@ -115064,7 +115377,8 @@
3117167872,3117168127,BG
3117168128,3117168639,NL
3117168640,3117169663,MK
-3117169664,3117171711,ES
+3117169664,3117170687,ES
+3117170688,3117171711,DE
3117171712,3117172735,UA
3117172736,3117173759,TR
3117173760,3117174783,GB
@@ -115454,7 +115768,8 @@
3117497344,3117498367,ES
3117498368,3117499391,DE
3117499392,3117500415,PL
-3117500416,3117500927,GB
+3117500416,3117500671,GB
+3117500672,3117500927,SG
3117500928,3117501183,TR
3117501184,3117501439,GB
3117501440,3117502463,ES
@@ -115587,8 +115902,9 @@
3117604864,3117605119,AT
3117605120,3117605887,ES
3117605888,3117606911,GB
-3117606912,3117607167,CN
-3117607168,3117607679,GB
+3117606912,3117607167,DE
+3117607168,3117607423,AU
+3117607424,3117607679,GB
3117607680,3117607935,HK
3117607936,3117608959,DK
3117608960,3117609983,RU
@@ -116053,7 +116369,8 @@
3117957120,3117958143,IT
3117958144,3117958399,NL
3117958400,3117958655,IQ
-3117958656,3117959167,NL
+3117958656,3117958911,VG
+3117958912,3117959167,NL
3117959168,3117959423,US
3117959424,3117959935,AP
3117959936,3117960191,DE
@@ -116098,8 +116415,8 @@
3117989888,3117990911,RU
3117990912,3117991935,SY
3117991936,3117992191,DE
-3117992192,3117992703,US
-3117992704,3117992959,DE
+3117992192,3117992447,US
+3117992448,3117992959,DE
3117992960,3117993983,RU
3117993984,3117995007,LT
3117995008,3117996031,DE
@@ -116182,7 +116499,7 @@
3118048768,3118049023,US
3118049024,3118049279,RU
3118049280,3118049535,AP
-3118049536,3118049791,US
+3118049536,3118049791,DE
3118049792,3118050303,AP
3118050304,3118051327,SY
3118051328,3118052351,DE
@@ -116239,8 +116556,7 @@
3118096384,3118097407,ES
3118097408,3118097663,GB
3118097664,3118097919,ES
-3118097920,3118098175,GB
-3118098176,3118098431,ES
+3118097920,3118098431,GB
3118098432,3118098687,IT
3118098688,3118098943,DK
3118098944,3118099199,PL
@@ -116450,8 +116766,8 @@
3118263808,3118264319,JP
3118264320,3118265343,ES
3118265344,3118266367,IT
-3118266368,3118266623,ES
-3118266624,3118267391,GB
+3118266368,3118266879,ES
+3118266880,3118267391,GB
3118267392,3118268415,AT
3118268416,3118269439,NO
3118269440,3118270463,GB
@@ -116554,7 +116870,8 @@
3118339840,3118340095,UA
3118340096,3118341119,GB
3118341120,3118341375,RO
-3118341376,3118342143,GB
+3118341376,3118341631,SG
+3118341632,3118342143,GB
3118342144,3118343167,NL
3118343168,3118344191,GB
3118344192,3118344447,SA
@@ -116707,7 +117024,6 @@
3118461952,3118462975,DE
3118462976,3118463999,GB
3118464000,3118465023,DE
-3118465024,3118466047,TR
3118466048,3118467071,HU
3118467072,3118468095,RU
3118468096,3118469119,GB
@@ -116778,7 +117094,7 @@
3118527488,3118528511,CH
3118528512,3118529535,RU
3118529536,3118530559,GB
-3118530560,3118530815,CN
+3118530560,3118530815,IT
3118530816,3118531071,US
3118531072,3118531327,GB
3118531328,3118531583,NL
@@ -116967,8 +117283,7 @@
3118679040,3118679295,FI
3118679296,3118679551,US
3118679552,3118679807,KR
-3118679808,3118680063,US
-3118680064,3118681087,NL
+3118679808,3118681087,NL
3118681088,3118682111,SE
3118682112,3118682879,NL
3118682880,3118683135,DE
@@ -117141,8 +117456,9 @@
3118827520,3118828543,BG
3118828544,3118829567,AT
3118829568,3118829823,DK
-3118829824,3118830079,US
-3118830080,3118832639,DK
+3118829824,3118830335,US
+3118830336,3118830591,EU
+3118830592,3118832639,DK
3118832640,3118833663,ES
3118833664,3118834687,FR
3118834688,3118835711,SA
@@ -117181,8 +117497,8 @@
3118859264,3118860287,BG
3118860288,3118861311,FR
3118861312,3118861567,NL
-3118861568,3118862079,DE
-3118862080,3118862591,TR
+3118861568,3118862335,DE
+3118862336,3118862591,TR
3118862592,3118862847,EG
3118862848,3118863103,RO
3118863104,3118863359,SA
@@ -117504,8 +117820,8 @@
3119098880,3119099903,NL
3119099904,3119100927,IE
3119100928,3119101951,AZ
-3119101952,3119102207,GB
-3119102208,3119102975,RU
+3119101952,3119102463,NL
+3119102464,3119102975,RU
3119102976,3119103999,DE
3119104000,3119105023,RU
3119105024,3119106047,DK
@@ -118270,7 +118586,8 @@
3119710464,3119710719,CH
3119710720,3119710975,GR
3119710976,3119711231,MC
-3119711232,3119712255,HK
+3119711232,3119711487,NL
+3119711488,3119712255,HK
3119712256,3119713535,DE
3119713536,3119713791,AE
3119713792,3119714303,DE
@@ -118396,7 +118713,8 @@
3119804416,3119805439,CH
3119805440,3119806463,TR
3119806464,3119807487,DE
-3119807488,3119808511,NL
+3119807488,3119807999,NL
+3119808000,3119808511,DE
3119808512,3119808767,BG
3119808768,3119809535,RO
3119809536,3119810559,KZ
@@ -118558,7 +118876,7 @@
3119932416,3119933439,ES
3119933440,3119934463,CH
3119934464,3119935487,NL
-3119935488,3119935743,GB
+3119935488,3119935743,SG
3119935744,3119935999,NL
3119936000,3119936255,MD
3119936256,3119936511,US
@@ -118731,7 +119049,7 @@
3120070656,3120071679,RU
3120071680,3120071935,CH
3120071936,3120072191,ES
-3120072192,3120072447,GB
+3120072192,3120072447,US
3120072448,3120072703,NL
3120072704,3120073727,RO
3120073728,3120074751,DE
@@ -119260,7 +119578,7 @@
3120494592,3120495615,SK
3120495616,3120496639,HR
3120496640,3120497663,NL
-3120497664,3120497919,US
+3120497664,3120497919,TR
3120497920,3120498431,UA
3120498432,3120498687,NZ
3120498688,3120498943,IN
@@ -120444,11 +120762,11 @@
3164899328,3164901375,RU
3164901376,3164903423,PL
3164903424,3164903679,PA
-3164903680,3164904191,AM
+3164903680,3164903935,AM
+3164903936,3164904191,CY
3164904192,3164904447,PA
3164904448,3164904703,NL
-3164904704,3164905215,AM
-3164905216,3164905471,IN
+3164904704,3164905471,AM
3164905472,3164913663,RU
3164913664,3164915711,ES
3164915712,3164917759,GR
@@ -120588,7 +120906,7 @@
3167784704,3167784959,IN
3167784960,3167797247,IR
3167797248,3167798271,MD
-3167798272,3167798783,SI
+3167798272,3167798783,NL
3167798784,3167799295,FR
3167799296,3167800319,IR
3167800320,3167801343,MD
@@ -120709,7 +121027,8 @@
3168049664,3168049919,GB
3168049920,3168050175,NL
3168050176,3168050431,RO
-3168050432,3168051199,NL
+3168050432,3168050943,NL
+3168050944,3168051199,IN
3168051200,3168059391,IR
3168059392,3168061439,RO
3168061440,3168073727,IR
@@ -120976,7 +121295,9 @@
3169845504,3169845759,CZ
3169845760,3169846271,RO
3169846272,3169847295,NL
-3169847296,3169848575,RO
+3169847296,3169847807,RO
+3169847808,3169848319,LA
+3169848320,3169848575,RO
3169848576,3169848831,NL
3169848832,3169849087,RO
3169849088,3169849343,NL
@@ -121140,8 +121461,7 @@
3169972736,3169972991,NL
3169972992,3169973247,UA
3169973248,3169973759,RO
-3169973760,3169974015,GB
-3169974016,3169974527,NL
+3169973760,3169974527,NL
3169974528,3169974783,US
3169974784,3169975039,EU
3169975040,3169975295,IT
@@ -121605,7 +121925,11 @@
3193776128,3193777151,AR
3193777152,3193778175,VE
3193778176,3193782271,AR
-3193782272,3193788671,BZ
+3193782272,3193785343,BZ
+3193785344,3193785855,US
+3193785856,3193786623,BZ
+3193786624,3193786879,US
+3193786880,3193788671,BZ
3193788672,3193788927,US
3193788928,3193789951,BZ
3193789952,3193790207,US
@@ -121647,7 +121971,9 @@
3194126848,3194128127,AR
3194128128,3194128383,BR
3194128384,3194129407,NI
-3194129408,3194133759,AR
+3194129408,3194130943,AR
+3194130944,3194131199,CN
+3194131200,3194133759,AR
3194133760,3194134015,US
3194134016,3194135551,AR
3194135552,3194136319,BR
@@ -122481,7 +122807,8 @@
3211091968,3211092223,PA
3211092224,3211092991,US
3211092992,3211093247,DE
-3211093248,3211094271,US
+3211093248,3211093503,GB
+3211093504,3211094271,US
3211094272,3211094527,AE
3211094528,3211096063,DE
3211096064,3211096575,NL
@@ -125299,17 +125626,13 @@
3230537728,3230538751,TR
3230538752,3230557183,US
3230557184,3230557695,GB
-3230557696,3230558207,US
-3230558208,3230558463,TR
-3230558464,3230558719,US
+3230557696,3230558719,US
3230558720,3230558975,TR
3230558976,3230559231,US
3230559232,3230560255,TR
3230560256,3230564863,US
3230564864,3230565119,TR
-3230565120,3230566143,US
-3230566144,3230566399,TR
-3230566400,3230567679,US
+3230565120,3230567679,US
3230567680,3230567935,TR
3230567936,3230580223,US
3230580224,3230580735,GB
@@ -126310,7 +126633,35 @@
3232832000,3232832255,DE
3232832256,3232844543,US
3232844544,3232844799,IN
-3232844800,3233288191,US
+3232844800,3232858111,US
+3232858112,3232858367,UA
+3232858368,3232858879,US
+3232858880,3232859135,UA
+3232859136,3232859391,US
+3232859392,3232859647,UA
+3232859648,3232859903,US
+3232859904,3232860927,UA
+3232860928,3232861439,US
+3232861440,3232861695,UA
+3232861696,3232862207,US
+3232862208,3232862463,UA
+3232862464,3232862975,US
+3232862976,3232863231,UA
+3232863232,3232863743,US
+3232863744,3232863999,UA
+3232864000,3232864511,US
+3232864512,3232864767,UA
+3232864768,3232866559,US
+3232866560,3232866815,UA
+3232866816,3232867327,US
+3232867328,3232867583,UA
+3232867584,3232868095,US
+3232868096,3232868351,UA
+3232868352,3232872191,US
+3232872192,3232872447,UA
+3232872448,3232873983,US
+3232873984,3232874239,UA
+3232874240,3233288191,US
3233288192,3233292287,CA
3233292288,3233431551,US
3233431552,3233464319,CA
@@ -127131,7 +127482,7 @@
3238203392,3238203647,US
3238203648,3238203903,GB
3238203904,3238204415,RU
-3238204416,3238204671,TW
+3238204416,3238204671,UA
3238204672,3238204927,FR
3238204928,3238205183,NL
3238205184,3238205439,RU
@@ -128039,7 +128390,7 @@
3239736064,3239736319,US
3239736320,3239737343,GB
3239737344,3239737599,DE
-3239737600,3239737855,FR
+3239737600,3239737855,NL
3239737856,3239738111,RU
3239738112,3239739391,DE
3239739392,3239739647,IT
@@ -128701,7 +129052,7 @@
3240218880,3240219135,DE
3240219136,3240219647,AT
3240219648,3240220159,CA
-3240220160,3240220671,NL
+3240220160,3240220671,DE
3240220672,3240221183,AT
3240221184,3240221695,SE
3240221696,3240221951,NL
@@ -128874,9 +129225,10 @@
3240354048,3240354303,LU
3240354304,3240354559,US
3240354560,3240354815,RU
-3240354816,3240355327,NL
+3240354816,3240355071,NL
+3240355072,3240355327,US
3240355328,3240355583,IR
-3240355584,3240355839,NL
+3240355584,3240355839,US
3240355840,3240361983,GB
3240361984,3240362239,TR
3240362240,3240362751,GB
@@ -128986,8 +129338,7 @@
3240438272,3240438527,TR
3240438528,3240438783,IT
3240438784,3240439039,TR
-3240439040,3240439551,BG
-3240439552,3240439807,SG
+3240439040,3240439807,BG
3240439808,3240440831,RU
3240440832,3240441855,RO
3240441856,3240442367,GB
@@ -129205,8 +129556,7 @@
3240704768,3240705023,GE
3240705024,3240706047,UA
3240706048,3240707071,BG
-3240707072,3240707327,NL
-3240707328,3240707583,TR
+3240707072,3240707583,NL
3240707584,3240707839,HU
3240707840,3240709119,FR
3240709120,3240710143,RU
@@ -129965,7 +130315,8 @@
3241837568,3241838591,DE
3241838592,3241840639,BE
3241840640,3241840895,US
-3241840896,3241841407,GB
+3241840896,3241841151,GB
+3241841152,3241841407,SG
3241841408,3241841663,US
3241841664,3241842175,BE
3241842176,3241843199,IL
@@ -130459,7 +130810,7 @@
3244864512,3244864767,RO
3244864768,3244865023,RU
3244865024,3244865279,UA
-3244865280,3244865535,NL
+3244865280,3244865535,US
3244865536,3244865791,PL
3244865792,3244866047,CH
3244866048,3244866303,NL
@@ -130539,6 +130890,7 @@
3244886784,3244887039,RU
3244887040,3244887295,NL
3244887296,3244887551,GB
+3244887552,3244887807,DE
3244887808,3244888063,FR
3244888064,3244888319,PL
3244888320,3244888575,DE
@@ -130918,7 +131270,8 @@
3245092352,3245092863,HK
3245092864,3245093887,UA
3245093888,3245094911,NL
-3245094912,3245095423,UA
+3245094912,3245095167,US
+3245095168,3245095423,UA
3245095424,3245095679,CA
3245095680,3245095935,UA
3245095936,3245096959,IT
@@ -131096,7 +131449,9 @@
3245193216,3245195519,US
3245195520,3245196031,PL
3245196032,3245196287,US
-3245196288,3245197311,PL
+3245196288,3245196543,PL
+3245196544,3245196799,HK
+3245196800,3245197311,PL
3245197312,3245199359,IT
3245199360,3245199615,LU
3245199616,3245199871,PL
@@ -131444,7 +131799,8 @@
3246129408,3246129663,ES
3246129664,3246129919,SK
3246129920,3246130175,EE
-3246130176,3246130687,NL
+3246130176,3246130431,CZ
+3246130432,3246130687,NL
3246130688,3246130943,EE
3246130944,3246131199,RU
3246131200,3246131455,GR
@@ -131453,7 +131809,7 @@
3246132736,3246132991,DE
3246132992,3246133247,US
3246133248,3246133503,DE
-3246133504,3246133759,RU
+3246133504,3246133759,US
3246133760,3246134015,HU
3246134016,3246134271,RU
3246134272,3246134783,DE
@@ -132308,7 +132664,7 @@
3248630784,3248631039,GB
3248631040,3248631295,AT
3248631296,3248631551,GB
-3248631552,3248631807,US
+3248631552,3248631807,CZ
3248631808,3248638463,DK
3248638464,3248638719,GB
3248638720,3248639487,DK
@@ -134052,7 +134408,7 @@
3252567552,3252567807,RU
3252567808,3252568063,RO
3252568064,3252576255,CH
-3252576256,3252576511,BG
+3252576256,3252576511,KP
3252576512,3252576767,TR
3252576768,3252577023,AE
3252577024,3252577279,TR
@@ -134300,7 +134656,7 @@
3253288960,3253291519,RU
3253291520,3253291775,NL
3253291776,3253293055,RU
-3253293056,3253293311,DE
+3253293056,3253293311,FI
3253293312,3253293567,RU
3253293568,3253294335,US
3253294336,3253295103,RU
@@ -134593,8 +134949,7 @@
3253713920,3253714431,AT
3253714432,3253715455,FR
3253715456,3253715967,RO
-3253715968,3253716223,GB
-3253716224,3253716479,US
+3253715968,3253716479,US
3253716480,3253716991,FR
3253716992,3253717503,CH
3253717504,3253717759,GB
@@ -135756,7 +136111,7 @@
3255778304,3255787519,DE
3255787520,3255787775,US
3255787776,3255788031,PL
-3255788032,3255788287,AZ
+3255788032,3255788287,DE
3255788288,3255788543,US
3255788544,3255789567,TR
3255789568,3255790591,RO
@@ -135878,7 +136233,7 @@
3256487936,3256488191,DE
3256488192,3256488447,RU
3256488448,3256488703,CZ
-3256488704,3256488959,GB
+3256488704,3256488959,IT
3256488960,3256489471,IR
3256489472,3256489983,GR
3256489984,3256490239,BE
@@ -137064,7 +137419,7 @@
3258104320,3258104575,PL
3258104576,3258104831,DE
3258104832,3258105343,MD
-3258105344,3258105599,US
+3258105344,3258105599,RU
3258105600,3258105855,DE
3258105856,3258106879,US
3258106880,3258107135,DE
@@ -137419,7 +137774,7 @@
3258701824,3258702847,NL
3258702848,3258703359,US
3258703360,3258703615,RU
-3258703616,3258703871,ES
+3258703616,3258703871,GB
3258703872,3258707967,DE
3258707968,3258708991,CZ
3258708992,3258709503,US
@@ -137934,7 +138289,7 @@
3260416000,3260481535,FI
3260481536,3260481791,RU
3260481792,3260482047,DE
-3260482048,3260482303,NL
+3260482048,3260482303,CZ
3260482304,3260482559,FR
3260482560,3260482815,DE
3260482816,3260483071,RU
@@ -137948,15 +138303,13 @@
3260485376,3260485631,RU
3260485632,3260485887,EE
3260485888,3260486143,CZ
-3260486144,3260486399,TR
+3260486144,3260486399,DE
3260486400,3260486655,RU
-3260486656,3260486911,CZ
-3260486912,3260487167,TR
-3260487168,3260487423,CZ
+3260486656,3260487423,CZ
3260487424,3260487679,RO
3260487680,3260487935,AE
3260487936,3260488191,FI
-3260488192,3260488703,DE
+3260488192,3260488703,TR
3260488704,3260488959,RU
3260488960,3260489215,US
3260489216,3260489727,NL
@@ -137966,19 +138319,18 @@
3260490496,3260490751,NL
3260490752,3260491007,FR
3260491008,3260491263,RU
-3260491264,3260491519,CN
+3260491264,3260491519,US
3260491520,3260491775,TR
3260491776,3260492031,DE
3260492032,3260492287,US
3260492288,3260492543,PL
3260492544,3260492799,RS
-3260492800,3260493055,NL
+3260492800,3260493055,CZ
3260493056,3260493311,ES
3260493312,3260493567,RU
3260493568,3260493823,IT
3260493824,3260494591,RU
-3260494592,3260494847,NL
-3260494848,3260495103,CZ
+3260494592,3260495103,CZ
3260495104,3260495359,SK
3260495360,3260495615,NL
3260495616,3260495871,CZ
@@ -138004,17 +138356,16 @@
3260502272,3260502527,CH
3260502528,3260502783,NL
3260502784,3260503039,DE
-3260503040,3260503295,NL
+3260503040,3260503295,CZ
3260503296,3260503551,HU
3260503552,3260503807,TR
-3260503808,3260504063,NL
-3260504064,3260504575,CZ
+3260503808,3260504575,CZ
3260504576,3260504831,US
3260504832,3260505087,TR
3260505088,3260506367,RU
3260506368,3260506623,CH
3260506624,3260508159,RU
-3260508160,3260508415,CZ
+3260508160,3260508415,DE
3260508416,3260508671,RO
3260508672,3260509183,RU
3260509184,3260509439,DE
@@ -138047,7 +138398,7 @@
3260517888,3260518399,NL
3260518400,3260519423,RU
3260519424,3260519679,DE
-3260519680,3260519935,TR
+3260519680,3260519935,CZ
3260519936,3260520191,FR
3260520192,3260520447,DE
3260520448,3260522495,RU
@@ -138072,14 +138423,17 @@
3260527872,3260528127,BE
3260528128,3260528383,MD
3260528384,3260528639,IL
-3260528640,3260529407,RU
-3260529408,3260529919,TR
+3260528640,3260528895,RU
+3260528896,3260529151,CZ
+3260529152,3260529407,RU
+3260529408,3260529663,CZ
+3260529664,3260529919,TR
3260529920,3260530175,UA
3260530176,3260530431,DE
3260530432,3260530687,NL
3260530688,3260531711,US
3260531712,3260532223,RU
-3260532224,3260532479,CZ
+3260532224,3260532479,FI
3260532480,3260532991,DE
3260532992,3260533247,NL
3260533248,3260533503,CZ
@@ -138100,11 +138454,12 @@
3260537856,3260538111,RU
3260538112,3260538367,NL
3260538368,3260538623,DE
-3260538624,3260539135,NL
+3260538624,3260538879,NL
+3260538880,3260539135,TR
3260539136,3260539391,US
3260539392,3260539647,CH
3260539648,3260539903,DE
-3260539904,3260540159,IN
+3260539904,3260540159,CZ
3260540160,3260540415,NL
3260540416,3260540671,GR
3260540672,3260540927,SK
@@ -138717,8 +139072,7 @@
3262192128,3262192639,US
3262192640,3262193663,ES
3262193664,3262193919,UA
-3262193920,3262194175,DE
-3262194176,3262194431,PL
+3262193920,3262194431,DE
3262194432,3262194687,US
3262194688,3262195711,JP
3262195712,3262196735,DE
@@ -139524,7 +139878,8 @@
3264410624,3264411647,NO
3264411648,3264413695,PL
3264413696,3264414719,FR
-3264414720,3264415743,GB
+3264414720,3264414975,SG
+3264414976,3264415743,GB
3264415744,3264416767,IT
3264416768,3264417791,CZ
3264417792,3264418047,GB
@@ -139709,7 +140064,7 @@
3264628736,3264628991,PT
3264628992,3264629759,UA
3264629760,3264630015,NL
-3264630016,3264630271,CZ
+3264630016,3264630271,IT
3264630272,3264630527,AL
3264630528,3264630783,NL
3264630784,3264631807,DE
@@ -139750,8 +140105,7 @@
3264662528,3264663039,US
3264663040,3264663551,PL
3264663552,3264664063,NL
-3264664064,3264664319,TR
-3264664320,3264664575,US
+3264664064,3264664575,US
3264664576,3264665087,NO
3264665088,3264665599,RU
3264665600,3264666111,RO
@@ -139900,7 +140254,7 @@
3265021952,3265022975,ES
3265022976,3265023231,UA
3265023232,3265023487,SC
-3265023488,3265023743,NL
+3265023488,3265023743,US
3265023744,3265023999,DE
3265024000,3265025023,HU
3265025024,3265026303,DE
@@ -140835,7 +141189,7 @@
3268742400,3268742655,DE
3268742656,3268742911,IT
3268742912,3268743167,DE
-3268743168,3268743423,UZ
+3268743168,3268743423,GB
3268743424,3268743679,DE
3268743680,3268743935,US
3268743936,3268744191,ES
@@ -141594,7 +141948,7 @@
3272264192,3272264447,NL
3272264448,3272264703,DE
3272264704,3272264959,LV
-3272264960,3272265215,ME
+3272264960,3272265215,DE
3272265216,3272265471,AT
3272265472,3272265727,DK
3272265728,3272265983,DE
@@ -142112,8 +142466,9 @@
3273840640,3273841663,PL
3273841664,3273842687,AT
3273842688,3273850879,RU
-3273850880,3273863167,DE
-3273863168,3273863679,LT
+3273850880,3273859071,DE
+3273859072,3273861119,US
+3273861120,3273863679,LT
3273863680,3273864191,GB
3273864192,3273864703,NL
3273864704,3273865215,ID
@@ -142614,7 +142969,7 @@
3275366912,3275367423,CZ
3275367424,3275367679,DE
3275367680,3275367935,RU
-3275367936,3275368191,NL
+3275367936,3275368191,CZ
3275368192,3275368447,DE
3275368448,3275371007,RU
3275371008,3275371263,NL
@@ -142630,7 +142985,7 @@
3275373568,3275373823,PS
3275373824,3275374079,US
3275374080,3275374335,FI
-3275374336,3275374591,NL
+3275374336,3275374591,CZ
3275374592,3275382783,GB
3275382784,3275390975,SE
3275390976,3275399167,GB
@@ -144146,8 +144501,8 @@
3278110720,3278115839,SE
3278115840,3278116351,ES
3278116352,3278117119,SE
-3278117120,3278117375,ES
-3278117376,3278125055,SE
+3278117120,3278117631,ES
+3278117632,3278125055,SE
3278125056,3278125567,NL
3278125568,3278176255,SE
3278176256,3278241791,FR
@@ -144570,7 +144925,7 @@
3280276992,3280277247,CH
3280277248,3280277503,SK
3280277504,3280278015,NL
-3280278016,3280278271,CZ
+3280278016,3280278271,TR
3280278272,3280278527,IL
3280278528,3280278783,NL
3280278784,3280279039,US
@@ -144725,6 +145080,8 @@
3280590336,3280590847,NL
3280590848,3280591359,DE
3280591360,3280591871,UA
+3280591872,3280592127,GB
+3280592128,3280592383,BG
3280592384,3280592895,TR
3280592896,3280593407,DE
3280593408,3280593919,UA
@@ -146020,7 +146377,9 @@
3285088768,3285089279,RU
3285089280,3285090303,PL
3285090304,3285098495,DE
-3285098496,3285114879,GB
+3285098496,3285099519,GB
+3285099520,3285099775,RO
+3285099776,3285114879,GB
3285114880,3285115903,RU
3285115904,3285116415,SI
3285116416,3285116671,GB
@@ -146255,8 +146614,8 @@
3285583360,3285599231,US
3285599232,3285599487,DE
3285599488,3285601535,US
-3285601536,3285602303,DE
-3285602304,3285606399,US
+3285601536,3285602047,DE
+3285602048,3285606399,US
3285606400,3285614591,GB
3285614592,3285630975,TR
3285630976,3285633023,UA
@@ -146883,7 +147242,7 @@
3287201792,3287202815,PL
3287202816,3287203839,UA
3287203840,3287212031,FI
-3287212032,3287212287,DE
+3287212032,3287212543,DE
3287212544,3287212799,FR
3287212800,3287213311,PL
3287213568,3287213823,RU
@@ -147912,10 +148271,13 @@
3291217920,3291230207,ZA
3291230208,3291234303,CI
3291234304,3291242495,ZA
-3291242496,3291248127,GH
+3291242496,3291242751,TR
+3291242752,3291247871,GH
+3291247872,3291248127,TR
3291248128,3291248383,VG
3291248384,3291248639,DE
-3291248640,3291250687,GH
+3291248640,3291250431,GH
+3291250432,3291250687,TR
3291250688,3291258879,NA
3291258880,3291262975,TZ
3291262976,3291267071,ZW
@@ -148593,7 +148955,9 @@
3304108800,3304109055,ZA
3304109056,3304109311,SE
3304109312,3304109567,ZA
-3304109568,3304111615,SE
+3304109568,3304110335,SE
+3304110336,3304110591,ZA
+3304110592,3304111615,SE
3304111616,3304111871,ZA
3304111872,3304112383,SE
3304112384,3304112639,ZA
@@ -148691,9 +149055,9 @@
3304428544,3304433151,ZA
3304433152,3304434687,SE
3304434688,3304435711,ZA
-3304435712,3304436991,SE
-3304436992,3304437247,ZA
-3304437248,3304442879,SE
+3304435712,3304436735,SE
+3304436736,3304437759,ZA
+3304437760,3304442879,SE
3304442880,3304443135,SC
3304443136,3304445951,SE
3304445952,3304447231,SC
@@ -148751,16 +149115,9 @@
3304685568,3304701951,ZA
3304701952,3304718335,AO
3304718336,3304734719,ZA
-3304734720,3304735743,RW
-3304735744,3304737791,CG
-3304737792,3304738815,RW
-3304738816,3304740863,TG
-3304740864,3304741887,RW
-3304741888,3304742911,TG
+3304734720,3304742911,CI
3304742912,3304747007,CD
-3304747008,3304748031,RW
-3304748032,3304749055,CG
-3304749056,3304751103,CI
+3304747008,3304751103,CI
3304751104,3304759295,ZA
3304759296,3304763391,MU
3304763392,3304767487,LR
@@ -148784,7 +149141,9 @@
3304841216,3304843263,NG
3304843264,3304845311,ZA
3304845312,3304846335,GQ
-3304846336,3304848383,ZA
+3304846336,3304847615,ZA
+3304847616,3304847871,US
+3304847872,3304848383,ZA
3304848384,3304849407,MU
3304849408,3305111551,ZA
3305111552,3307208703,TN
@@ -148959,7 +149318,9 @@
3319562240,3319570431,LS
3319570432,3319574527,GH
3319574528,3319574783,NG
-3319574784,3319578623,GH
+3319574784,3319577343,GH
+3319577344,3319577599,NG
+3319577600,3319578623,GH
3319578624,3319595007,MU
3319595008,3319611391,ZA
3319611392,3319619583,GH
@@ -149212,8 +149573,7 @@
3325035520,3325067263,US
3325067264,3325100287,CA
3325100288,3325100543,US
-3325100544,3325100799,AU
-3325100800,3325101055,NZ
+3325100544,3325101055,AU
3325101056,3325108223,US
3325108224,3325110271,AU
3325110272,3325122303,US
@@ -150211,9 +150571,7 @@
3341869056,3341869311,OM
3341869312,3341870079,US
3341870080,3341870591,CA
-3341870592,3341873919,US
-3341873920,3341874175,RU
-3341874176,3342139391,US
+3341870592,3342139391,US
3342139392,3342143487,CH
3342143488,3342143999,US
3342144000,3342144511,CH
@@ -152217,8 +152575,7 @@
3367804928,3367840767,BR
3367840768,3367841791,US
3367841792,3367846911,BR
-3367847936,3367848959,BR
-3367849984,3368052991,BR
+3367847936,3368052991,BR
3368052992,3368053247,PE
3368053248,3368053503,CO
3368053504,3368086527,BR
@@ -152304,7 +152661,7 @@
3377267200,3377267711,AR
3377267712,3377274879,BR
3377274880,3377278975,SG
-3377278976,3377279999,VE
+3377278976,3377279999,ES
3377280000,3377280511,PA
3377280512,3377281791,ES
3377281792,3377282047,MX
@@ -152958,8 +153315,7 @@
3389545984,3389546495,SG
3389546496,3389547519,ID
3389547520,3389548543,PH
-3389548544,3389548799,HK
-3389548800,3389549567,EU
+3389548544,3389549567,HK
3389549568,3389550591,SA
3389550592,3389552639,IN
3389552640,3389553663,CN
@@ -154896,7 +155252,10 @@
3395028992,3395031039,CN
3395031040,3395031551,PK
3395031552,3395031807,TR
-3395031808,3395035135,PK
+3395031808,3395032063,GB
+3395032064,3395032319,PK
+3395032320,3395032575,GB
+3395032576,3395035135,PK
3395035136,3395039231,AU
3395039232,3395043327,CN
3395043328,3395059711,AU
@@ -155194,7 +155553,8 @@
3397733376,3397734399,AU
3397734400,3397735423,MY
3397735424,3397736447,MM
-3397736448,3397738495,AU
+3397736448,3397737471,DE
+3397737472,3397738495,AU
3397738496,3397742591,MY
3397742592,3397746687,JP
3397746688,3397763071,TH
@@ -158685,12 +159045,12 @@
3415343104,3415425023,TH
3415425024,3415431167,NC
3415431168,3415432191,IN
-3415432192,3415435263,AU
-3415435264,3415436287,PH
-3415436288,3415436799,AU
+3415432192,3415436799,AU
3415436800,3415437311,HK
3415437312,3415441407,JP
-3415441408,3415474175,AU
+3415441408,3415467007,AU
+3415467008,3415467519,HK
+3415467520,3415474175,AU
3415474176,3415495679,CN
3415495680,3415496191,ID
3415496192,3415496703,CN
@@ -159459,7 +159819,9 @@
3423092736,3423093759,VI
3423093760,3423094783,US
3423094784,3423095807,CA
-3423095808,3423128575,US
+3423095808,3423096831,US
+3423096832,3423097855,NL
+3423097856,3423128575,US
3423128576,3423128831,AO
3423128832,3423129087,ZA
3423129088,3423129599,NG
@@ -160346,7 +160708,9 @@
3456163072,3456163327,US
3456163328,3456163583,PK
3456163584,3456270335,US
-3456270336,3456303103,HK
+3456270336,3456301055,HK
+3456301056,3456302335,US
+3456302336,3456303103,HK
3456303104,3456311295,JP
3456311296,3456892927,US
3456892928,3456958463,CA
@@ -161225,7 +161589,12 @@
3494787072,3494789119,CA
3494789120,3494803455,US
3494803456,3494805503,CA
-3494805504,3494813183,US
+3494805504,3494806015,US
+3494806016,3494806527,JP
+3494806528,3494807039,GB
+3494807040,3494807295,US
+3494807296,3494807551,GB
+3494807552,3494813183,US
3494813184,3494813439,CA
3494813440,3494842367,US
3494842368,3494843391,??
@@ -161696,7 +162065,9 @@
3514591488,3514592255,NI
3514592256,3514713855,US
3514713856,3514714111,PL
-3514714112,3514761215,US
+3514714112,3514715135,US
+3514715136,3514715391,CA
+3514715392,3514761215,US
3514761216,3514773759,CA
3514773760,3514774015,US
3514774016,3514777343,CA
@@ -161811,11 +162182,7 @@
3517718528,3517726719,CA
3517726720,3518062591,US
3518062592,3518066687,CA
-3518066688,3518391295,US
-3518391296,3518391551,NL
-3518391552,3518391807,US
-3518391808,3518392319,NL
-3518392320,3518422271,US
+3518066688,3518422271,US
3518422272,3518422527,CA
3518422528,3518424063,US
3518424064,3518425087,CA
@@ -162290,11 +162657,11 @@
3528415232,3528416255,DE
3528416256,3528418303,CN
3528418304,3528419327,DE
-3528419328,3528420351,US
-3528420352,3528421375,CN
+3528419328,3528421375,CN
3528421376,3528422399,DE
3528422400,3528424447,CN
-3528424448,3528425471,US
+3528424448,3528424703,US
+3528424704,3528425471,CN
3528425472,3528441855,AU
3528441856,3528445951,JP
3528445952,3528450047,ID
@@ -162518,11 +162885,7 @@
3547635712,3547639807,AU
3547639808,3547856895,KR
3547856896,3548905471,JP
-3548905472,3549766655,CN
-3549766656,3549767679,US
-3549767680,3549778943,CN
-3549778944,3549779967,US
-3549779968,3549986815,CN
+3548905472,3549986815,CN
3549986816,3549994239,SG
3549994240,3551002623,CN
3551002624,3551285247,KR
@@ -163232,7 +163595,9 @@
3559956480,3559964671,IT
3559964672,3559976959,RU
3559976960,3559981055,HU
-3559981056,3559989247,EE
+3559981056,3559988223,EE
+3559988224,3559988479,NL
+3559988480,3559989247,EE
3559989248,3559997439,PL
3559997440,3560005631,KE
3560005632,3560013823,RU
@@ -164369,7 +164734,9 @@
3565511680,3565511935,GB
3565511936,3565512191,CH
3565512192,3565512447,DE
-3565512448,3565518335,GB
+3565512448,3565517823,GB
+3565517824,3565518079,CZ
+3565518080,3565518335,GB
3565518336,3565518591,BE
3565518592,3565518847,GB
3565518848,3565551615,TR
@@ -164675,7 +165042,8 @@
3569353984,3569354239,CZ
3569354240,3569354495,AE
3569354496,3569354751,ES
-3569354752,3569355263,NL
+3569354752,3569355007,CZ
+3569355008,3569355263,NL
3569355264,3569355519,EE
3569355520,3569355775,CZ
3569355776,3569356031,HK
@@ -164702,12 +165070,13 @@
3569410048,3569414143,RU
3569414144,3569414399,NL
3569414400,3569414655,AT
-3569414656,3569415167,NL
+3569414656,3569414911,CZ
+3569414912,3569415167,NL
3569415168,3569415423,IN
3569415424,3569415679,NL
3569415680,3569415935,CZ
3569415936,3569416191,AT
-3569416192,3569416447,NL
+3569416192,3569416447,CZ
3569416448,3569416703,PH
3569416704,3569416959,DE
3569416960,3569417215,US
@@ -165038,8 +165407,7 @@
3573907456,3573907711,GR
3573907712,3573907967,CY
3573907968,3573908223,FR
-3573908224,3573908479,UA
-3573908480,3573908991,GB
+3573908224,3573908991,GB
3573909248,3573909503,RU
3573909504,3573913599,PL
3573913600,3573915647,CH
@@ -165697,7 +166065,8 @@
3580709888,3580710399,DE
3580710400,3580710911,RU
3580710912,3580715007,UA
-3580715008,3580719103,RU
+3580715008,3580717055,EU
+3580717056,3580719103,RU
3580719104,3580723199,NL
3580723200,3580727295,UA
3580727296,3580727551,DE
@@ -165722,8 +166091,7 @@
3580737536,3580738559,IT
3580738560,3580739583,RU
3580739584,3580739839,IT
-3580739840,3580740095,TR
-3580740096,3580740351,GB
+3580739840,3580740351,GB
3580740352,3580740607,NL
3580740608,3580740863,RO
3580740864,3580741119,AM
@@ -166915,7 +167283,8 @@
3587772416,3587773439,GE
3587773440,3587774463,SA
3587774464,3587775743,ES
-3587775744,3587776255,DE
+3587775744,3587775999,IT
+3587776000,3587776255,DE
3587776256,3587776511,TR
3587776512,3587784703,IR
3587784704,3587801087,DE
@@ -167443,7 +167812,9 @@
3625467648,3625467903,CA
3625467904,3625496575,US
3625496576,3625500671,CA
-3625500672,3625517055,US
+3625500672,3625507839,US
+3625507840,3625508095,NL
+3625508096,3625517055,US
3625517056,3625529343,CA
3625529344,3625533439,US
3625533440,3625541631,CA
@@ -168495,7 +168866,7 @@
3642515456,3642519551,DE
3642519552,3642523647,IT
3642523648,3642524159,GB
-3642524160,3642524415,IN
+3642524160,3642524415,US
3642524416,3642524671,PL
3642524672,3642524927,RU
3642524928,3642525183,IE
@@ -168860,7 +169231,8 @@
3645693952,3645698047,BE
3645698048,3645702143,ES
3645702144,3645706239,GB
-3645706240,3645710335,EU
+3645706240,3645708287,US
+3645708288,3645710335,EU
3645710336,3645714431,NO
3645714432,3645718527,RU
3645718528,3645722623,GA
diff --git a/src/config/geoip6 b/src/config/geoip6
index 533ebb9925..9633ce173c 100644
--- a/src/config/geoip6
+++ b/src/config/geoip6
@@ -10,7 +10,7 @@
#
# Location Database Export
#
-# Generated: Mon, 18 Sep 2023 04:43:32 GMT
+# Generated: Mon, 25 Sep 2023 04:43:56 GMT
# Vendor: IPFire Project
# License: CC BY-SA 4.0
#
@@ -1685,13 +1685,9 @@
2001:678:96c::,2001:678:96c:ffff:ffff:ffff:ffff:ffff,PL
2001:678:96d::,2001:678:96f:ffff:ffff:ffff:ffff:ffff,EU
2001:678:970::,2001:678:970:ffff:ffff:ffff:ffff:ffff,DE
-2001:678:971::,2001:678:973:ffff:ffff:ffff:ffff:ffff,EU
-2001:678:974::,2001:678:974:ffff:ffff:ffff:ffff:ffff,DE
-2001:678:975::,2001:678:977:ffff:ffff:ffff:ffff:ffff,EU
+2001:678:971::,2001:678:977:ffff:ffff:ffff:ffff:ffff,EU
2001:678:978::,2001:678:978:ffff:ffff:ffff:ffff:ffff,DE
-2001:678:979::,2001:678:97b:ffff:ffff:ffff:ffff:ffff,EU
-2001:678:97c::,2001:678:97c:ffff:ffff:ffff:ffff:ffff,DE
-2001:678:97d::,2001:678:97f:ffff:ffff:ffff:ffff:ffff,EU
+2001:678:979::,2001:678:97f:ffff:ffff:ffff:ffff:ffff,EU
2001:678:980::,2001:678:980:ffff:ffff:ffff:ffff:ffff,DE
2001:678:981::,2001:678:983:ffff:ffff:ffff:ffff:ffff,EU
2001:678:984::,2001:678:984:ffff:ffff:ffff:ffff:ffff,FR
@@ -4097,7 +4093,15 @@
2001:67c:d24::,2001:67c:d24:ffff:ffff:ffff:ffff:ffff,RU
2001:67c:d25::,2001:67c:d27:ffff:ffff:ffff:ffff:ffff,EU
2001:67c:d28::,2001:67c:d28:ffff:ffff:ffff:ffff:ffff,DE
-2001:67c:d29::,2001:67c:fff:ffff:ffff:ffff:ffff:ffff,EU
+2001:67c:d29::,2001:67c:d2b:ffff:ffff:ffff:ffff:ffff,EU
+2001:67c:d2c::,2001:67c:d2c:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:d2d::,2001:67c:d2f:ffff:ffff:ffff:ffff:ffff,EU
+2001:67c:d30::,2001:67c:d30:ffff:ffff:ffff:ffff:ffff,RU
+2001:67c:d31::,2001:67c:d33:ffff:ffff:ffff:ffff:ffff,EU
+2001:67c:d34::,2001:67c:d34:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:d35::,2001:67c:d37:ffff:ffff:ffff:ffff:ffff,EU
+2001:67c:d38::,2001:67c:d38:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:d39::,2001:67c:fff:ffff:ffff:ffff:ffff:ffff,EU
2001:67c:1000::,2001:67c:1001:ffff:ffff:ffff:ffff:ffff,SE
2001:67c:1002::,2001:67c:1007:ffff:ffff:ffff:ffff:ffff,EU
2001:67c:1008::,2001:67c:1009:ffff:ffff:ffff:ffff:ffff,RU
@@ -4345,9 +4349,7 @@
2001:67c:1248::,2001:67c:1248:ffff:ffff:ffff:ffff:ffff,RO
2001:67c:1249::,2001:67c:124b:ffff:ffff:ffff:ffff:ffff,EU
2001:67c:124c::,2001:67c:124c:ffff:ffff:ffff:ffff:ffff,SE
-2001:67c:124d::,2001:67c:124f:ffff:ffff:ffff:ffff:ffff,EU
-2001:67c:1250::,2001:67c:1250:ffff:ffff:ffff:ffff:ffff,DE
-2001:67c:1251::,2001:67c:1253:ffff:ffff:ffff:ffff:ffff,EU
+2001:67c:124d::,2001:67c:1253:ffff:ffff:ffff:ffff:ffff,EU
2001:67c:1254::,2001:67c:1254:ffff:ffff:ffff:ffff:ffff,FR
2001:67c:1255::,2001:67c:1257:ffff:ffff:ffff:ffff:ffff,EU
2001:67c:1258::,2001:67c:1258:ffff:ffff:ffff:ffff:ffff,RU
@@ -6216,9 +6218,7 @@
2001:67c:27b8::,2001:67c:27b8:ffff:ffff:ffff:ffff:ffff,SA
2001:67c:27b9::,2001:67c:27bb:ffff:ffff:ffff:ffff:ffff,EU
2001:67c:27bc::,2001:67c:27bc:ffff:ffff:ffff:ffff:ffff,DE
-2001:67c:27bd::,2001:67c:27bf:ffff:ffff:ffff:ffff:ffff,EU
-2001:67c:27c0::,2001:67c:27c0:ffff:ffff:ffff:ffff:ffff,GB
-2001:67c:27c1::,2001:67c:27c3:ffff:ffff:ffff:ffff:ffff,EU
+2001:67c:27bd::,2001:67c:27c3:ffff:ffff:ffff:ffff:ffff,EU
2001:67c:27c4::,2001:67c:27c4:ffff:ffff:ffff:ffff:ffff,GB
2001:67c:27c5::,2001:67c:27c7:ffff:ffff:ffff:ffff:ffff,EU
2001:67c:27c8::,2001:67c:27c8:ffff:ffff:ffff:ffff:ffff,RU
@@ -7676,7 +7676,7 @@
2001:7f8:10b::,2001:7f8:10b:ffff:ffff:ffff:ffff:ffff,PL
2001:7f8:10c::,2001:7f8:10c:ffff:ffff:ffff:ffff:ffff,IS
2001:7f8:10d::,2001:7f8:10d:ffff:ffff:ffff:ffff:ffff,DE
-2001:7f8:10e::,2001:7f8:10e:ffff:ffff:ffff:ffff:ffff,TR
+2001:7f8:10e::,2001:7f8:10e:ffff:ffff:ffff:ffff:ffff,EU
2001:7f8:10f::,2001:7f8:10f:ffff:ffff:ffff:ffff:ffff,NL
2001:7f8:110::,2001:7f8:110:ffff:ffff:ffff:ffff:ffff,UZ
2001:7f8:111::,2001:7f8:111:ffff:ffff:ffff:ffff:ffff,CH
@@ -8224,7 +8224,9 @@
2001:b18:1019::,2001:b18:ffff:ffff:ffff:ffff:ffff:ffff,US
2001:b19::,2001:b1f:ffff:ffff:ffff:ffff:ffff:ffff,EU
2001:b20::,2001:b27:ffff:ffff:ffff:ffff:ffff:ffff,LU
-2001:b28::,2001:b28:f23a:ffff:ffff:ffff:ffff:ffff,RU
+2001:b28::,2001:b28:3:ffff:ffff:ffff:ffff:ffff,RU
+2001:b28:4::,2001:b28:4:ffff:ffff:ffff:ffff:ffff,UA
+2001:b28:5::,2001:b28:f23a:ffff:ffff:ffff:ffff:ffff,RU
2001:b28:f23b::,2001:b28:f23b:ffff:ffff:ffff:ffff:ffff,IN
2001:b28:f23c::,2001:b28:f23c:ffff:ffff:ffff:ffff:ffff,AZ
2001:b28:f23d::,2001:b28:f23d:ffff:ffff:ffff:ffff:ffff,US
@@ -8375,7 +8377,9 @@
2001:d80:1000::,2001:d80:1000:ffff:ffff:ffff:ffff:ffff,SG
2001:d80:1001::,2001:d80:103f:ffff:ffff:ffff:ffff:ffff,JP
2001:d80:1040::,2001:d80:1040:ffff:ffff:ffff:ffff:ffff,AU
-2001:d80:1041::,2001:d80:1240:ffff:ffff:ffff:ffff:ffff,JP
+2001:d80:1041::,2001:d80:1180:ffff:ffff:ffff:ffff:ffff,JP
+2001:d80:1181::,2001:d80:1181:ffff:ffff:ffff:ffff:ffff,CN
+2001:d80:1182::,2001:d80:1240:ffff:ffff:ffff:ffff:ffff,JP
2001:d80:1241::,2001:d80:1241:ffff:ffff:ffff:ffff:ffff,IN
2001:d80:1242::,2001:d80:ffff:ffff:ffff:ffff:ffff:ffff,JP
2001:d81::,2001:d87:ffff:ffff:ffff:ffff:ffff:ffff,AU
@@ -10921,9 +10925,7 @@
2001:df1:4040::,2001:df1:4040:ffff:ffff:ffff:ffff:ffff,PK
2001:df1:4041::,2001:df1:407f:ffff:ffff:ffff:ffff:ffff,AU
2001:df1:4080::,2001:df1:4080:ffff:ffff:ffff:ffff:ffff,IN
-2001:df1:4081::,2001:df1:40bf:ffff:ffff:ffff:ffff:ffff,AU
-2001:df1:40c0::,2001:df1:40c0:ffff:ffff:ffff:ffff:ffff,PH
-2001:df1:40c1::,2001:df1:413f:ffff:ffff:ffff:ffff:ffff,AU
+2001:df1:4081::,2001:df1:413f:ffff:ffff:ffff:ffff:ffff,AU
2001:df1:4140::,2001:df1:4140:ffff:ffff:ffff:ffff:ffff,ID
2001:df1:4141::,2001:df1:41ff:ffff:ffff:ffff:ffff:ffff,AU
2001:df1:4200::,2001:df1:4200:ffff:ffff:ffff:ffff:ffff,MY
@@ -13913,11 +13915,25 @@
2001:df2:f100::,2001:df2:f100:ffff:ffff:ffff:ffff:ffff,ID
2001:df2:f101::,2001:df2:f13f:ffff:ffff:ffff:ffff:ffff,AU
2001:df2:f140::,2001:df2:f140:ffff:ffff:ffff:ffff:ffff,ID
-2001:df2:f141::,2001:df2:f27f:ffff:ffff:ffff:ffff:ffff,AU
+2001:df2:f141::,2001:df2:f1bf:ffff:ffff:ffff:ffff:ffff,AU
+2001:df2:f1c0::,2001:df2:f1c0:ffff:ffff:ffff:ffff:ffff,IN
+2001:df2:f1c1::,2001:df2:f23f:ffff:ffff:ffff:ffff:ffff,AU
+2001:df2:f240::,2001:df2:f240:ffff:ffff:ffff:ffff:ffff,ID
+2001:df2:f241::,2001:df2:f27f:ffff:ffff:ffff:ffff:ffff,AU
2001:df2:f280::,2001:df2:f280:ffff:ffff:ffff:ffff:ffff,PH
-2001:df2:f281::,2001:df2:f2ff:ffff:ffff:ffff:ffff:ffff,AU
+2001:df2:f281::,2001:df2:f2bf:ffff:ffff:ffff:ffff:ffff,AU
+2001:df2:f2c0::,2001:df2:f2c0:ffff:ffff:ffff:ffff:ffff,ID
+2001:df2:f2c1::,2001:df2:f2ff:ffff:ffff:ffff:ffff:ffff,AU
2001:df2:f300::,2001:df2:f300:ffff:ffff:ffff:ffff:ffff,IN
-2001:df2:f301::,2001:df2:f57f:ffff:ffff:ffff:ffff:ffff,AU
+2001:df2:f301::,2001:df2:f33f:ffff:ffff:ffff:ffff:ffff,AU
+2001:df2:f340::,2001:df2:f340:ffff:ffff:ffff:ffff:ffff,ID
+2001:df2:f341::,2001:df2:f3bf:ffff:ffff:ffff:ffff:ffff,AU
+2001:df2:f3c0::,2001:df2:f3c0:ffff:ffff:ffff:ffff:ffff,PH
+2001:df2:f3c1::,2001:df2:f43f:ffff:ffff:ffff:ffff:ffff,AU
+2001:df2:f440::,2001:df2:f440:ffff:ffff:ffff:ffff:ffff,MY
+2001:df2:f441::,2001:df2:f4bf:ffff:ffff:ffff:ffff:ffff,AU
+2001:df2:f4c0::,2001:df2:f4c0:ffff:ffff:ffff:ffff:ffff,ID
+2001:df2:f4c1::,2001:df2:f57f:ffff:ffff:ffff:ffff:ffff,AU
2001:df2:f580::,2001:df2:f580:ffff:ffff:ffff:ffff:ffff,ID
2001:df2:f581::,2001:df2:f5ff:ffff:ffff:ffff:ffff:ffff,AU
2001:df2:f600::,2001:df2:f600:ffff:ffff:ffff:ffff:ffff,ID
@@ -14595,7 +14611,9 @@
2001:df3:cc80::,2001:df3:cc80:ffff:ffff:ffff:ffff:ffff,BD
2001:df3:cc81::,2001:df3:ccff:ffff:ffff:ffff:ffff:ffff,AU
2001:df3:cd00::,2001:df3:cd00:ffff:ffff:ffff:ffff:ffff,HK
-2001:df3:cd01::,2001:df3:cdff:ffff:ffff:ffff:ffff:ffff,AU
+2001:df3:cd01::,2001:df3:cd7f:ffff:ffff:ffff:ffff:ffff,AU
+2001:df3:cd80::,2001:df3:cd80:ffff:ffff:ffff:ffff:ffff,HK
+2001:df3:cd81::,2001:df3:cdff:ffff:ffff:ffff:ffff:ffff,AU
2001:df3:ce00::,2001:df3:ce00:ffff:ffff:ffff:ffff:ffff,MM
2001:df3:ce01::,2001:df3:ceff:ffff:ffff:ffff:ffff:ffff,AU
2001:df3:cf00::,2001:df3:cf00:ffff:ffff:ffff:ffff:ffff,ID
@@ -18538,8 +18556,7 @@
2001:19f8::,2001:19f8:ffff:ffff:ffff:ffff:ffff:ffff,US
2001:19f9::,2001:19ff:ffff:ffff:ffff:ffff:ffff:ffff,??
2001:1a00::,2001:1a07:ffff:ffff:ffff:ffff:ffff:ffff,EU
-2001:1a08::,2001:1a08:ffff:ffff:ffff:ffff:ffff:ffff,GB
-2001:1a09::,2001:1a0f:ffff:ffff:ffff:ffff:ffff:ffff,EU
+2001:1a08::,2001:1a0f:ffff:ffff:ffff:ffff:ffff:ffff,GB
2001:1a10::,2001:1a17:ffff:ffff:ffff:ffff:ffff:ffff,QA
2001:1a18::,2001:1a1f:ffff:ffff:ffff:ffff:ffff:ffff,CY
2001:1a20::,2001:1a20:ffff:ffff:ffff:ffff:ffff:ffff,GB
@@ -20003,7 +20020,9 @@
2001:4d40:8407::,2001:4d40:840c:ffff:ffff:ffff:ffff:ffff,GB
2001:4d40:840d::,2001:4d40:840d:ffff:ffff:ffff:ffff:ffff,EU
2001:4d40:840e::,2001:4d40:840e:ffff:ffff:ffff:ffff:ffff,GB
-2001:4d40:840f::,2001:4d40:fffe:ffff:ffff:ffff:ffff:ffff,EU
+2001:4d40:840f::,2001:4d40:8410:ffff:ffff:ffff:ffff:ffff,EU
+2001:4d40:8411::,2001:4d40:8411:ffff:ffff:ffff:ffff:ffff,GB
+2001:4d40:8412::,2001:4d40:fffe:ffff:ffff:ffff:ffff:ffff,EU
2001:4d40:ffff::,2001:4d40:ffff:ffff:ffff:ffff:ffff:ffff,GB
2001:4d41::,2001:4d47:ffff:ffff:ffff:ffff:ffff:ffff,EU
2001:4d48::,2001:4d4f:ffff:ffff:ffff:ffff:ffff:ffff,GB
@@ -23368,9 +23387,7 @@
2401:280::,2401:280:ffff:ffff:ffff:ffff:ffff:ffff,HK
2401:281::,2401:29f:ffff:ffff:ffff:ffff:ffff:ffff,AU
2401:2a0::,2401:2a0:ffff:ffff:ffff:ffff:ffff:ffff,JP
-2401:2a1::,2401:2bf:ffff:ffff:ffff:ffff:ffff:ffff,AU
-2401:2c0::,2401:2c0:ffff:ffff:ffff:ffff:ffff:ffff,US
-2401:2c1::,2401:2ff:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2401:2a1::,2401:2ff:ffff:ffff:ffff:ffff:ffff:ffff,AU
2401:300::,2401:300:ffff:ffff:ffff:ffff:ffff:ffff,HK
2401:301::,2401:31f:ffff:ffff:ffff:ffff:ffff:ffff,AU
2401:320::,2401:320:ffff:ffff:ffff:ffff:ffff:ffff,IN
@@ -24132,21 +24149,43 @@
2401:38a0::,2401:38a0:ffff:ffff:ffff:ffff:ffff:ffff,VN
2401:38a1::,2401:38df:ffff:ffff:ffff:ffff:ffff:ffff,AU
2401:38e0::,2401:38e0:ffff:ffff:ffff:ffff:ffff:ffff,MY
-2401:38e1::,2401:397f:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2401:38e1::,2401:391f:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2401:3920::,2401:3920:ffff:ffff:ffff:ffff:ffff:ffff,TW
+2401:3921::,2401:395f:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2401:3960::,2401:3960:ffff:ffff:ffff:ffff:ffff:ffff,TW
+2401:3961::,2401:397f:ffff:ffff:ffff:ffff:ffff:ffff,AU
2401:3980::,2401:3980:ffff:ffff:ffff:ffff:ffff:ffff,CN
-2401:3981::,2401:39bf:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2401:3981::,2401:399f:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2401:39a0::,2401:39a0:ffff:ffff:ffff:ffff:ffff:ffff,TW
+2401:39a1::,2401:39bf:ffff:ffff:ffff:ffff:ffff:ffff,AU
2401:39c0::,2401:39c0:ffff:ffff:ffff:ffff:ffff:ffff,HK
-2401:39c1::,2401:39ff:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2401:39c1::,2401:39df:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2401:39e0::,2401:39e0:ffff:ffff:ffff:ffff:ffff:ffff,TW
+2401:39e1::,2401:39ff:ffff:ffff:ffff:ffff:ffff:ffff,AU
2401:3a00::,2401:3a00:ffff:ffff:ffff:ffff:ffff:ffff,CN
-2401:3a01::,2401:3a7f:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2401:3a01::,2401:3a1f:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2401:3a20::,2401:3a20:ffff:ffff:ffff:ffff:ffff:ffff,TW
+2401:3a21::,2401:3a5f:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2401:3a60::,2401:3a60:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2401:3a61::,2401:3a7f:ffff:ffff:ffff:ffff:ffff:ffff,AU
2401:3a80::,2401:3a80:ffff:ffff:ffff:ffff:ffff:ffff,CN
-2401:3a81::,2401:3aff:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2401:3a81::,2401:3a9f:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2401:3aa0::,2401:3aa0:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2401:3aa1::,2401:3adf:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2401:3ae0::,2401:3ae0:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2401:3ae1::,2401:3aff:ffff:ffff:ffff:ffff:ffff:ffff,AU
2401:3b00::,2401:3b00:ffff:ffff:ffff:ffff:ffff:ffff,JP
-2401:3b01::,2401:3b3f:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2401:3b01::,2401:3b1f:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2401:3b20::,2401:3b20:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2401:3b21::,2401:3b3f:ffff:ffff:ffff:ffff:ffff:ffff,AU
2401:3b40::,2401:3b40:ffff:ffff:ffff:ffff:ffff:ffff,BD
-2401:3b41::,2401:3b7f:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2401:3b41::,2401:3b5f:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2401:3b60::,2401:3b60:ffff:ffff:ffff:ffff:ffff:ffff,TW
+2401:3b61::,2401:3b7f:ffff:ffff:ffff:ffff:ffff:ffff,AU
2401:3b80::,2401:3b80:ffff:ffff:ffff:ffff:ffff:ffff,CN
-2401:3b81::,2401:3bbf:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2401:3b81::,2401:3b9f:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2401:3ba0::,2401:3ba0:ffff:ffff:ffff:ffff:ffff:ffff,TW
+2401:3ba1::,2401:3bbf:ffff:ffff:ffff:ffff:ffff:ffff,AU
2401:3bc0::,2401:3bc0:9:ffff:ffff:ffff:ffff:ffff,NZ
2401:3bc0:a::,2401:3bc0:e:ffff:ffff:ffff:ffff:ffff,AU
2401:3bc0:f::,2401:3bc0:3ff:ffff:ffff:ffff:ffff:ffff,NZ
@@ -24169,9 +24208,13 @@
2401:3bc0:1013::,2401:3bc0:1015:ffff:ffff:ffff:ffff:ffff,US
2401:3bc0:1016::,2401:3bc0:1016:ffff:ffff:ffff:ffff:ffff,HK
2401:3bc0:1017::,2401:3bc0:ffff:ffff:ffff:ffff:ffff:ffff,NZ
-2401:3bc1::,2401:3bff:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2401:3bc1::,2401:3bdf:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2401:3be0::,2401:3be0:ffff:ffff:ffff:ffff:ffff:ffff,PH
+2401:3be1::,2401:3bff:ffff:ffff:ffff:ffff:ffff:ffff,AU
2401:3c00::,2401:3c00:ffff:ffff:ffff:ffff:ffff:ffff,MY
-2401:3c01::,2401:3c7f:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2401:3c01::,2401:3c1f:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2401:3c20::,2401:3c20:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2401:3c21::,2401:3c7f:ffff:ffff:ffff:ffff:ffff:ffff,AU
2401:3c80::,2401:3c80:ffff:ffff:ffff:ffff:ffff:ffff,CN
2401:3c81::,2401:3cbf:ffff:ffff:ffff:ffff:ffff:ffff,AU
2401:3cc0::,2401:3cc0:2:ffff:ffff:ffff:ffff:ffff,HK
@@ -26710,7 +26753,8 @@
2402:d041::,2402:d07f:ffff:ffff:ffff:ffff:ffff:ffff,AU
2402:d080::,2402:d080:ffff:ffff:ffff:ffff:ffff:ffff,TL
2402:d081::,2402:d0bf:ffff:ffff:ffff:ffff:ffff:ffff,AU
-2402:d0c0::,2402:d0c0:6:ffff:ffff:ffff:ffff:ffff,US
+2402:d0c0::,2402:d0c0:3:ffff:ffff:ffff:ffff:ffff,SG
+2402:d0c0:4::,2402:d0c0:6:ffff:ffff:ffff:ffff:ffff,US
2402:d0c0:7::,2402:d0c0:ffff:ffff:ffff:ffff:ffff:ffff,SG
2402:d0c1::,2402:d13f:ffff:ffff:ffff:ffff:ffff:ffff,AU
2402:d140::,2402:d140:ff:ffff:ffff:ffff:ffff:ffff,CN
@@ -34243,8 +34287,8 @@
2406:da12:1000::,2406:da12:ffff:ffff:ffff:ffff:ffff:ffff,US
2406:da13::,2406:da13:fff:ffff:ffff:ffff:ffff:ffff,JP
2406:da13:1000::,2406:da13:ffff:ffff:ffff:ffff:ffff:ffff,US
-2406:da14::,2406:da14:fff:ffff:ffff:ffff:ffff:ffff,JP
-2406:da14:1000::,2406:da14:ffff:ffff:ffff:ffff:ffff:ffff,US
+2406:da14::,2406:da14:1fff:ffff:ffff:ffff:ffff:ffff,JP
+2406:da14:2000::,2406:da14:ffff:ffff:ffff:ffff:ffff:ffff,US
2406:da15::,2406:da15:fff:ffff:ffff:ffff:ffff:ffff,KR
2406:da15:1000::,2406:da15:ffff:ffff:ffff:ffff:ffff:ffff,US
2406:da16::,2406:da16:fff:ffff:ffff:ffff:ffff:ffff,JP
@@ -35659,7 +35703,7 @@
2407:74c1::,2407:753f:ffff:ffff:ffff:ffff:ffff:ffff,AU
2407:7540::,2407:7540:ffff:ffff:ffff:ffff:ffff:ffff,ID
2407:7541::,2407:757f:ffff:ffff:ffff:ffff:ffff:ffff,AU
-2407:7580::,2407:7580:ffff:ffff:ffff:ffff:ffff:ffff,AP
+2407:7580::,2407:7580:ffff:ffff:ffff:ffff:ffff:ffff,SG
2407:7581::,2407:75bf:ffff:ffff:ffff:ffff:ffff:ffff,AU
2407:75c0::,2407:75c0:ffff:ffff:ffff:ffff:ffff:ffff,ID
2407:75c1::,2407:75ff:ffff:ffff:ffff:ffff:ffff:ffff,AU
@@ -36453,7 +36497,9 @@
2407:e841::,2407:e87f:ffff:ffff:ffff:ffff:ffff:ffff,AU
2407:e880::,2407:e880:ffff:ffff:ffff:ffff:ffff:ffff,IN
2407:e881::,2407:e8bf:ffff:ffff:ffff:ffff:ffff:ffff,AU
-2407:e8c0::,2407:e8c0:ffff:ffff:ffff:ffff:ffff:ffff,PA
+2407:e8c0::,2407:e8c0:0:ffff:ffff:ffff:ffff:ffff,PA
+2407:e8c0:1::,2407:e8c0:1:ffff:ffff:ffff:ffff:ffff,DE
+2407:e8c0:2::,2407:e8c0:ffff:ffff:ffff:ffff:ffff:ffff,PA
2407:e8c1::,2407:e93f:ffff:ffff:ffff:ffff:ffff:ffff,AU
2407:e940::,2407:e940:ffff:ffff:ffff:ffff:ffff:ffff,VN
2407:e941::,2407:e9bf:ffff:ffff:ffff:ffff:ffff:ffff,AU
@@ -37022,7 +37068,7 @@
2602:210::,2602:210:ffff:ffff:ffff:ffff:ffff:ffff,CA
2602:220::,2602:220:ffff:ffff:ffff:ffff:ffff:ffff,CA
2602:230::,2602:231:ffff:ffff:ffff:ffff:ffff:ffff,US
-2602:233::,2602:233:ffff:ffff:ffff:ffff:ffff:ffff,US
+2602:233::,2602:234:ffff:ffff:ffff:ffff:ffff:ffff,US
2602:240::,2602:260:ffff:ffff:ffff:ffff:ffff:ffff,US
2602:270::,2602:270:fff:ffff:ffff:ffff:ffff:ffff,US
2602:271::,2602:271:fff:ffff:ffff:ffff:ffff:ffff,US
@@ -37450,6 +37496,13 @@
2602:815:f000::,2602:815:f00f:ffff:ffff:ffff:ffff:ffff,US
2602:816::,2602:816:f:ffff:ffff:ffff:ffff:ffff,US
2602:816:1000::,2602:816:100f:ffff:ffff:ffff:ffff:ffff,US
+2602:fa16::,2602:fa16:ff:ffff:ffff:ffff:ffff:ffff,US
+2602:fa17::,2602:fa17:ff:ffff:ffff:ffff:ffff:ffff,US
+2602:fa18::,2602:fa18:fff:ffff:ffff:ffff:ffff:ffff,US
+2602:fa19::,2602:fa19:ff:ffff:ffff:ffff:ffff:ffff,US
+2602:fa1a::,2602:fa1a:fff:ffff:ffff:ffff:ffff:ffff,US
+2602:fa1b::,2602:fa1b:ff:ffff:ffff:ffff:ffff:ffff,US
+2602:fa1c::,2602:fa1c:fff:ffff:ffff:ffff:ffff:ffff,US
2602:fa1d::,2602:fa1d:fff:ffff:ffff:ffff:ffff:ffff,US
2602:fa1e::,2602:fa1e:fff:ffff:ffff:ffff:ffff:ffff,US
2602:fa1f::,2602:fa1f:ff:ffff:ffff:ffff:ffff:ffff,US
@@ -37594,7 +37647,7 @@
2602:faa9::,2602:faa9:ff:ffff:ffff:ffff:ffff:ffff,US
2602:faaa::,2602:faaa:fff:ffff:ffff:ffff:ffff:ffff,US
2602:faab::,2602:faab:fff:ffff:ffff:ffff:ffff:ffff,US
-2602:faac::,2602:faac:ff:ffff:ffff:ffff:ffff:ffff,US
+2602:faac::,2602:faac:fff:ffff:ffff:ffff:ffff:ffff,US
2602:faad::,2602:faad:ff:ffff:ffff:ffff:ffff:ffff,GB
2602:faae::,2602:faae:ff:ffff:ffff:ffff:ffff:ffff,US
2602:faaf::,2602:faaf:ff:ffff:ffff:ffff:ffff:ffff,US
@@ -37840,7 +37893,6 @@
2602:fbbb::,2602:fbbb:fff:ffff:ffff:ffff:ffff:ffff,US
2602:fbbc::,2602:fbbc:ff:ffff:ffff:ffff:ffff:ffff,US
2602:fbbd::,2602:fbbd:fff:ffff:ffff:ffff:ffff:ffff,US
-2602:fbbe::,2602:fbbe:ff:ffff:ffff:ffff:ffff:ffff,US
2602:fbbf::,2602:fbbf:fff:ffff:ffff:ffff:ffff:ffff,US
2602:fbc0::,2602:fbc0:ff:ffff:ffff:ffff:ffff:ffff,US
2602:fbc1::,2602:fbc1:fff:ffff:ffff:ffff:ffff:ffff,US
@@ -39736,7 +39788,6 @@
2605:140::,2605:140:ffff:ffff:ffff:ffff:ffff:ffff,US
2605:240::,2605:240:ffff:ffff:ffff:ffff:ffff:ffff,US
2605:280::,2605:280:ffff:ffff:ffff:ffff:ffff:ffff,US
-2605:2c0::,2605:2c0:ffff:ffff:ffff:ffff:ffff:ffff,US
2605:300::,2605:300:ffff:ffff:ffff:ffff:ffff:ffff,US
2605:340::,2605:340:ffff:ffff:ffff:ffff:ffff:ffff,US
2605:380::,2605:380:ffff:ffff:ffff:ffff:ffff:ffff,US
@@ -40914,7 +40965,8 @@
2606:3e80::,2606:3e80:ffff:ffff:ffff:ffff:ffff:ffff,US
2606:3ec0::,2606:3ec0:ffff:ffff:ffff:ffff:ffff:ffff,US
2606:3f00::,2606:3f00:ffff:ffff:ffff:ffff:ffff:ffff,US
-2606:3f40::,2606:3f40:2:ffff:ffff:ffff:ffff:ffff,NL
+2606:3f40::,2606:3f40:1:ffff:ffff:ffff:ffff:ffff,US
+2606:3f40:2::,2606:3f40:2:ffff:ffff:ffff:ffff:ffff,NL
2606:3f40:3::,2606:3f40:ffff:ffff:ffff:ffff:ffff:ffff,US
2606:3f80::,2606:3f80:ffff:ffff:ffff:ffff:ffff:ffff,US
2606:3fc0::,2606:3fc0:ffff:ffff:ffff:ffff:ffff:ffff,US
@@ -42074,7 +42126,9 @@
2607:6b80:32::,2607:6b80:ffff:ffff:ffff:ffff:ffff:ffff,US
2607:6bc0::,2607:6bc0:ffff:ffff:ffff:ffff:ffff:ffff,US
2607:6c00::,2607:6c00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:6c40::,2607:6c40:ffff:ffff:ffff:ffff:ffff:ffff,US
2607:6c80::,2607:6c80:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:6cc0::,2607:6cc0:ffff:ffff:ffff:ffff:ffff:ffff,US
2607:6d00::,2607:6d00:ffff:ffff:ffff:ffff:ffff:ffff,US
2607:6d80::,2607:6d80:ffff:ffff:ffff:ffff:ffff:ffff,US
2607:6e00::,2607:6e00:ffff:ffff:ffff:ffff:ffff:ffff,US
@@ -45928,6 +45982,7 @@
2801:11:a000::,2801:11:a000:ffff:ffff:ffff:ffff:ffff,VE
2801:11:a800::,2801:11:a800:ffff:ffff:ffff:ffff:ffff,BO
2801:11:b000::,2801:11:b000:ffff:ffff:ffff:ffff:ffff,AR
+2801:11:b800::,2801:11:b800:ffff:ffff:ffff:ffff:ffff,CL
2801:11:c000::,2801:11:c000:ffff:ffff:ffff:ffff:ffff,AR
2801:11:c800::,2801:11:c800:ffff:ffff:ffff:ffff:ffff,CO
2801:11:d000::,2801:11:d000:ffff:ffff:ffff:ffff:ffff,AR
@@ -46146,6 +46201,7 @@
2801:19:a000::,2801:19:a000:ffff:ffff:ffff:ffff:ffff,BO
2801:19:a800::,2801:19:a800:ffff:ffff:ffff:ffff:ffff,CO
2801:19:b000::,2801:19:b000:ffff:ffff:ffff:ffff:ffff,AR
+2801:19:b800::,2801:19:b800:ffff:ffff:ffff:ffff:ffff,DO
2801:19:c000::,2801:19:c000:ffff:ffff:ffff:ffff:ffff,AR
2801:19:c800::,2801:19:c800:ffff:ffff:ffff:ffff:ffff,CO
2801:19:d000::,2801:19:d000:ffff:ffff:ffff:ffff:ffff,BO
@@ -46283,6 +46339,7 @@
2801:1e:a000::,2801:1e:a000:ffff:ffff:ffff:ffff:ffff,AR
2801:1e:a800::,2801:1e:a800:ffff:ffff:ffff:ffff:ffff,AR
2801:1e:b000::,2801:1e:b000:ffff:ffff:ffff:ffff:ffff,AR
+2801:1e:b800::,2801:1e:b800:ffff:ffff:ffff:ffff:ffff,CO
2801:1e:c800::,2801:1e:c800:ffff:ffff:ffff:ffff:ffff,CO
2801:1e:d000::,2801:1e:d000:ffff:ffff:ffff:ffff:ffff,CO
2801:1e:d800::,2801:1e:d800:ffff:ffff:ffff:ffff:ffff,CO
@@ -46870,11 +46927,9 @@
2801:c4:a7::,2801:c4:a8:ffff:ffff:ffff:ffff:ffff,MX
2801:c4:aa::,2801:c4:aa:ffff:ffff:ffff:ffff:ffff,MX
2801:c4:ac::,2801:c4:ac:ffff:ffff:ffff:ffff:ffff,MX
-2801:c4:ae::,2801:c4:ae:ffff:ffff:ffff:ffff:ffff,MX
-2801:c4:b0::,2801:c4:b4:ffff:ffff:ffff:ffff:ffff,MX
+2801:c4:ae::,2801:c4:b4:ffff:ffff:ffff:ffff:ffff,MX
2801:c4:b8::,2801:c4:20f:ffff:ffff:ffff:ffff:ffff,MX
-2801:c4:217::,2801:c4:217:ffff:ffff:ffff:ffff:ffff,MX
-2801:c4:220::,2801:c4:22f:ffff:ffff:ffff:ffff:ffff,MX
+2801:c4:217::,2801:c4:22f:ffff:ffff:ffff:ffff:ffff,MX
2801:c4:240::,2801:c4:250:ffff:ffff:ffff:ffff:ffff,MX
2801:c4:259::,2801:c4:259:ffff:ffff:ffff:ffff:ffff,MX
2801:c4:278::,2801:c4:278:ffff:ffff:ffff:ffff:ffff,MX
@@ -47031,7 +47086,7 @@
2801:1e1::,2801:1e1:f:ffff:ffff:ffff:ffff:ffff,CO
2801:1e2::,2801:1e2:f:ffff:ffff:ffff:ffff:ffff,CO
2801:1e4::,2801:1e4:3f:ffff:ffff:ffff:ffff:ffff,CO
-2801:1e5::,2801:1e5:f:ffff:ffff:ffff:ffff:ffff,CO
+2801:1e5::,2801:1e5:ff:ffff:ffff:ffff:ffff:ffff,CO
2801:1e6::,2801:1e6:f:ffff:ffff:ffff:ffff:ffff,CO
2801:1e8::,2801:1e8:ff:ffff:ffff:ffff:ffff:ffff,AR
2801:1e9::,2801:1e9:f:ffff:ffff:ffff:ffff:ffff,CO
@@ -47658,6 +47713,7 @@
2803:3f40::,2803:3f40:ffff:ffff:ffff:ffff:ffff:ffff,AR
2803:3f60::,2803:3f60:ffff:ffff:ffff:ffff:ffff:ffff,EC
2803:3f80::,2803:3f80:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2803:3f90::,2803:3f90:ffff:ffff:ffff:ffff:ffff:ffff,PE
2803:3fa0::,2803:3fa0:ffff:ffff:ffff:ffff:ffff:ffff,AR
2803:3fc0::,2803:3fc0:ffff:ffff:ffff:ffff:ffff:ffff,AR
2803:3fe0::,2803:3fe0:ffff:ffff:ffff:ffff:ffff:ffff,CO
@@ -47992,6 +48048,7 @@
2803:5f40::,2803:5f40:ffff:ffff:ffff:ffff:ffff:ffff,AR
2803:5f60::,2803:5f60:ffff:ffff:ffff:ffff:ffff:ffff,AR
2803:5f80::,2803:5f80:ffff:ffff:ffff:ffff:ffff:ffff,EC
+2803:5f90::,2803:5f90:ffff:ffff:ffff:ffff:ffff:ffff,PE
2803:5fa0::,2803:5fa0:ffff:ffff:ffff:ffff:ffff:ffff,CO
2803:5fc0::,2803:5fc0:ffff:ffff:ffff:ffff:ffff:ffff,AR
2803:5fe0::,2803:5fe0:ffff:ffff:ffff:ffff:ffff:ffff,EC
@@ -48304,6 +48361,7 @@
2803:7f20::,2803:7f20:ffff:ffff:ffff:ffff:ffff:ffff,BZ
2803:7f60::,2803:7f60:ffff:ffff:ffff:ffff:ffff:ffff,CR
2803:7f80::,2803:7f80:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2803:7f90::,2803:7f90:ffff:ffff:ffff:ffff:ffff:ffff,PE
2803:7fa0::,2803:7fa0:ffff:ffff:ffff:ffff:ffff:ffff,AR
2803:7fc0::,2803:7fc0:ffff:ffff:ffff:ffff:ffff:ffff,HN
2803:7fe0::,2803:7fe0:ffff:ffff:ffff:ffff:ffff:ffff,AR
@@ -48934,6 +48992,7 @@
2803:bf20::,2803:bf20:ffff:ffff:ffff:ffff:ffff:ffff,EC
2803:bf40::,2803:bf40:ffff:ffff:ffff:ffff:ffff:ffff,GT
2803:bf60::,2803:bf60:ffff:ffff:ffff:ffff:ffff:ffff,GT
+2803:bf90::,2803:bf90:ffff:ffff:ffff:ffff:ffff:ffff,PE
2803:bfa0::,2803:bfa0:ffff:ffff:ffff:ffff:ffff:ffff,CO
2803:bfc0::,2803:bfc0:ffff:ffff:ffff:ffff:ffff:ffff,EC
2803:bfe0::,2803:bfe0:ffff:ffff:ffff:ffff:ffff:ffff,VE
@@ -49243,6 +49302,7 @@
2803:df20::,2803:df20:ffff:ffff:ffff:ffff:ffff:ffff,AR
2803:df60::,2803:df60:ffff:ffff:ffff:ffff:ffff:ffff,AR
2803:df80::,2803:df80:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2803:df90::,2803:df90:ffff:ffff:ffff:ffff:ffff:ffff,CO
2803:dfa0::,2803:dfa0:ffff:ffff:ffff:ffff:ffff:ffff,NI
2803:dfe0::,2803:dfe0:ffff:ffff:ffff:ffff:ffff:ffff,CL
2803:e000::,2803:e000:ffff:ffff:ffff:ffff:ffff:ffff,CO
@@ -49538,6 +49598,7 @@
2803:ff40::,2803:ff40:ffff:ffff:ffff:ffff:ffff:ffff,SR
2803:ff60::,2803:ff60:ffff:ffff:ffff:ffff:ffff:ffff,EC
2803:ff80::,2803:ff80:ffff:ffff:ffff:ffff:ffff:ffff,CO
+2803:ff90::,2803:ff90:ffff:ffff:ffff:ffff:ffff:ffff,AR
2803:ffa0::,2803:ffa0:ffff:ffff:ffff:ffff:ffff:ffff,AR
2803:ffc0::,2803:ffc0:ffff:ffff:ffff:ffff:ffff:ffff,CL
2803:ffe0::,2803:ffe0:ffff:ffff:ffff:ffff:ffff:ffff,CO
@@ -51846,7 +51907,6 @@
2804:2a44::,2804:2a44:ffff:ffff:ffff:ffff:ffff:ffff,BR
2804:2a48::,2804:2a48:ffff:ffff:ffff:ffff:ffff:ffff,BR
2804:2a4c::,2804:2a4c:ffff:ffff:ffff:ffff:ffff:ffff,BR
-2804:2a50::,2804:2a50:ffff:ffff:ffff:ffff:ffff:ffff,??
2804:2a54::,2804:2a54:ffff:ffff:ffff:ffff:ffff:ffff,BR
2804:2a58::,2804:2a58:ffff:ffff:ffff:ffff:ffff:ffff,BR
2804:2a5c::,2804:2a5c:ffff:ffff:ffff:ffff:ffff:ffff,BR
@@ -54238,7 +54298,6 @@
2804:5360::,2804:5360:ffff:ffff:ffff:ffff:ffff:ffff,BR
2804:5364::,2804:5364:ffff:ffff:ffff:ffff:ffff:ffff,BR
2804:5368::,2804:5368:ffff:ffff:ffff:ffff:ffff:ffff,BR
-2804:536c::,2804:536c:ffff:ffff:ffff:ffff:ffff:ffff,BR
2804:5370::,2804:5370:ffff:ffff:ffff:ffff:ffff:ffff,BR
2804:5374::,2804:5374:ffff:ffff:ffff:ffff:ffff:ffff,BR
2804:5378::,2804:5378:ffff:ffff:ffff:ffff:ffff:ffff,BR
@@ -54822,7 +54881,7 @@
2804:5d28::,2804:5d28:ffff:ffff:ffff:ffff:ffff:ffff,BR
2804:5d2c::,2804:5d2c:ffff:ffff:ffff:ffff:ffff:ffff,BR
2804:5d30::,2804:5d30:ffff:ffff:ffff:ffff:ffff:ffff,BR
-2804:5d34::,2804:5d34:ffff:ffff:ffff:ffff:ffff:ffff,BR
+2804:5d34::,2804:5d34:ffff:ffff:ffff:ffff:ffff:ffff,??
2804:5d38::,2804:5d38:ffff:ffff:ffff:ffff:ffff:ffff,BR
2804:5d3c::,2804:5d3c:ffff:ffff:ffff:ffff:ffff:ffff,BR
2804:5d40::,2804:5d40:ffff:ffff:ffff:ffff:ffff:ffff,BR
@@ -55530,7 +55589,6 @@
2804:68d8::,2804:68d8:ffff:ffff:ffff:ffff:ffff:ffff,BR
2804:68dc::,2804:68dc:ffff:ffff:ffff:ffff:ffff:ffff,BR
2804:68e0::,2804:68e0:ffff:ffff:ffff:ffff:ffff:ffff,BR
-2804:68e4::,2804:68e4:ffff:ffff:ffff:ffff:ffff:ffff,BR
2804:68e8::,2804:68e8:ffff:ffff:ffff:ffff:ffff:ffff,BR
2804:68ec::,2804:68ec:ffff:ffff:ffff:ffff:ffff:ffff,BR
2804:68f0::,2804:68f0:ffff:ffff:ffff:ffff:ffff:ffff,BR
@@ -56035,7 +56093,6 @@
2804:7128::,2804:7128:ffff:ffff:ffff:ffff:ffff:ffff,BR
2804:712c::,2804:712c:ffff:ffff:ffff:ffff:ffff:ffff,BR
2804:7130::,2804:7130:ffff:ffff:ffff:ffff:ffff:ffff,BR
-2804:7134::,2804:7134:ffff:ffff:ffff:ffff:ffff:ffff,??
2804:7138::,2804:7138:ffff:ffff:ffff:ffff:ffff:ffff,BR
2804:713c::,2804:713c:ffff:ffff:ffff:ffff:ffff:ffff,BR
2804:7140::,2804:7140:ffff:ffff:ffff:ffff:ffff:ffff,BR
@@ -57223,7 +57280,7 @@
2804:84d4::,2804:84d4:ffff:ffff:ffff:ffff:ffff:ffff,BR
2804:84d8::,2804:84d8:ffff:ffff:ffff:ffff:ffff:ffff,BR
2804:84dc::,2804:84dc:ffff:ffff:ffff:ffff:ffff:ffff,BR
-2804:84e0::,2804:84e0:ffff:ffff:ffff:ffff:ffff:ffff,BR
+2804:84e0::,2804:84e0:fff:ffff:ffff:ffff:ffff:ffff,??
2804:84e4::,2804:84e4:ffff:ffff:ffff:ffff:ffff:ffff,BR
2804:84ec::,2804:84ec:ffff:ffff:ffff:ffff:ffff:ffff,BR
2804:84f0::,2804:84f0:ffff:ffff:ffff:ffff:ffff:ffff,BR
@@ -57747,6 +57804,13 @@
2804:8d2c::,2804:8d2c:ffff:ffff:ffff:ffff:ffff:ffff,BR
2804:8d30::,2804:8d30:ffff:ffff:ffff:ffff:ffff:ffff,BR
2804:8d34::,2804:8d34:ffff:ffff:ffff:ffff:ffff:ffff,BR
+2804:8d38::,2804:8d38:ffff:ffff:ffff:ffff:ffff:ffff,BR
+2804:8d3c::,2804:8d3c:ffff:ffff:ffff:ffff:ffff:ffff,BR
+2804:8d40::,2804:8d40:ffff:ffff:ffff:ffff:ffff:ffff,BR
+2804:8d44::,2804:8d44:ffff:ffff:ffff:ffff:ffff:ffff,BR
+2804:8d48::,2804:8d48:ffff:ffff:ffff:ffff:ffff:ffff,BR
+2804:8d4c::,2804:8d4c:ffff:ffff:ffff:ffff:ffff:ffff,BR
+2804:8d50::,2804:8d50:ffff:ffff:ffff:ffff:ffff:ffff,BR
2805:f10:f12::,2805:f10:f14:ffff:ffff:ffff:ffff:ffff,??
2806::,2806:f:ffff:ffff:ffff:ffff:ffff:ffff,MX
2806:200::,2806:200:ffff:ffff:ffff:ffff:ffff:ffff,MX
@@ -59323,8 +59387,8 @@
2a00:5540:2::,2a00:5540:2:ffff:ffff:ffff:ffff:ffff,CA
2a00:5540:3::,2a00:5540:384:ffff:ffff:ffff:ffff:ffff,GB
2a00:5540:385::,2a00:5540:388:ffff:ffff:ffff:ffff:ffff,SI
-2a00:5540:389::,2a00:5540:ffff:ffff:ffff:ffff:ffff:ffff,GB
-2a00:5541::,2a00:555f:ffff:ffff:ffff:ffff:ffff:ffff,EU
+2a00:5540:389::,2a00:5547:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:5548::,2a00:555f:ffff:ffff:ffff:ffff:ffff:ffff,EU
2a00:5560::,2a00:5560:ffff:ffff:ffff:ffff:ffff:ffff,DE
2a00:5561::,2a00:557f:ffff:ffff:ffff:ffff:ffff:ffff,EU
2a00:5580::,2a00:5587:ffff:ffff:ffff:ffff:ffff:ffff,GB
@@ -70356,7 +70420,11 @@
2a03:5f61::,2a03:5f7f:ffff:ffff:ffff:ffff:ffff:ffff,EU
2a03:5f80::,2a03:5f80:3:ffff:ffff:ffff:ffff:ffff,RU
2a03:5f80:4::,2a03:5f80:4:ffff:ffff:ffff:ffff:ffff,NL
-2a03:5f80:5::,2a03:5f80:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a03:5f80:5::,2a03:5f80:7:ffff:ffff:ffff:ffff:ffff,RU
+2a03:5f80:8::,2a03:5f80:8:ffff:ffff:ffff:ffff:ffff,UA
+2a03:5f80:9::,2a03:5f80:9:ffff:ffff:ffff:ffff:ffff,RU
+2a03:5f80:a::,2a03:5f80:a:ffff:ffff:ffff:ffff:ffff,UA
+2a03:5f80:b::,2a03:5f80:ffff:ffff:ffff:ffff:ffff:ffff,RU
2a03:5f81::,2a03:5fbf:ffff:ffff:ffff:ffff:ffff:ffff,EU
2a03:5fc0::,2a03:5fc0:ffff:ffff:ffff:ffff:ffff:ffff,FI
2a03:5fc1::,2a03:5fdf:ffff:ffff:ffff:ffff:ffff:ffff,EU
@@ -70531,8 +70599,8 @@
2a03:6948::,2a03:695f:ffff:ffff:ffff:ffff:ffff:ffff,EU
2a03:6960::,2a03:6960:ffff:ffff:ffff:ffff:ffff:ffff,DK
2a03:6961::,2a03:697f:ffff:ffff:ffff:ffff:ffff:ffff,EU
-2a03:6980::,2a03:6980:ffff:ffff:ffff:ffff:ffff:ffff,NL
-2a03:6981::,2a03:69bf:ffff:ffff:ffff:ffff:ffff:ffff,EU
+2a03:6980::,2a03:6987:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a03:6988::,2a03:69bf:ffff:ffff:ffff:ffff:ffff:ffff,EU
2a03:69c0::,2a03:69c0:ff:ffff:ffff:ffff:ffff:ffff,FR
2a03:69c0:100::,2a03:69c0:1ff:ffff:ffff:ffff:ffff:ffff,NL
2a03:69c0:200::,2a03:69c0:ffff:ffff:ffff:ffff:ffff:ffff,FR
@@ -75330,9 +75398,7 @@
2a05:4140:1100::,2a05:4140:111f:ffff:ffff:ffff:ffff:ffff,DE
2a05:4140:1120::,2a05:4140:11ff:ffff:ffff:ffff:ffff:ffff,FR
2a05:4140:1200::,2a05:4140:121f:ffff:ffff:ffff:ffff:ffff,DE
-2a05:4140:1220::,2a05:4140:1f5f:ffff:ffff:ffff:ffff:ffff,FR
-2a05:4140:1f60::,2a05:4140:1f7f:ffff:ffff:ffff:ffff:ffff,CH
-2a05:4140:1f80::,2a05:4140:1fff:ffff:ffff:ffff:ffff:ffff,FR
+2a05:4140:1220::,2a05:4140:1fff:ffff:ffff:ffff:ffff:ffff,FR
2a05:4140:2000::,2a05:4147:ffff:ffff:ffff:ffff:ffff:ffff,IT
2a05:4148::,2a05:417f:ffff:ffff:ffff:ffff:ffff:ffff,EU
2a05:4180::,2a05:4187:ffff:ffff:ffff:ffff:ffff:ffff,CH
@@ -77295,11 +77361,9 @@
2a05:dfc1:146e::,2a05:dfc1:14ce:ffff:ffff:ffff:ffff:ffff,US
2a05:dfc1:14cf::,2a05:dfc1:14cf:ffff:ffff:ffff:ffff:ffff,AQ
2a05:dfc1:14d0::,2a05:dfc1:15ff:ffff:ffff:ffff:ffff:ffff,US
-2a05:dfc1:1600::,2a05:dfc1:1600:ffff:ffff:ffff:ffff:ffff,CN
-2a05:dfc1:1601::,2a05:dfc1:1603:ffff:ffff:ffff:ffff:ffff,HK
+2a05:dfc1:1600::,2a05:dfc1:1603:ffff:ffff:ffff:ffff:ffff,HK
2a05:dfc1:1604::,2a05:dfc1:1604:ffff:ffff:ffff:ffff:ffff,US
-2a05:dfc1:1605::,2a05:dfc1:16fe:ffff:ffff:ffff:ffff:ffff,HK
-2a05:dfc1:16ff::,2a05:dfc1:16ff:ffff:ffff:ffff:ffff:ffff,CN
+2a05:dfc1:1605::,2a05:dfc1:16ff:ffff:ffff:ffff:ffff:ffff,HK
2a05:dfc1:1700::,2a05:dfc1:170f:ffff:ffff:ffff:ffff:ffff,US
2a05:dfc1:1710::,2a05:dfc1:171f:ffff:ffff:ffff:ffff:ffff,JP
2a05:dfc1:1720::,2a05:dfc1:172f:ffff:ffff:ffff:ffff:ffff,NL
@@ -77637,9 +77701,13 @@
2a05:dfc1:5aff::,2a05:dfc1:5aff:ffff:ffff:ffff:ffff:ffff,YT
2a05:dfc1:5b00::,2a05:dfc1:5b0f:ffff:ffff:ffff:ffff:ffff,GB
2a05:dfc1:5b10::,2a05:dfc1:5b1f:ffff:ffff:ffff:ffff:ffff,NL
-2a05:dfc1:5b20::,2a05:dfc1:5edf:ffff:ffff:ffff:ffff:ffff,US
+2a05:dfc1:5b20::,2a05:dfc1:5e0f:ffff:ffff:ffff:ffff:ffff,US
+2a05:dfc1:5e10::,2a05:dfc1:5e1f:ffff:ffff:ffff:ffff:ffff,TW
+2a05:dfc1:5e20::,2a05:dfc1:5edf:ffff:ffff:ffff:ffff:ffff,US
2a05:dfc1:5ee0::,2a05:dfc1:5eef:ffff:ffff:ffff:ffff:ffff,TW
-2a05:dfc1:5ef0::,2a05:dfc1:5efe:ffff:ffff:ffff:ffff:ffff,US
+2a05:dfc1:5ef0::,2a05:dfc1:5efa:ffff:ffff:ffff:ffff:ffff,US
+2a05:dfc1:5efb::,2a05:dfc1:5efb:ffff:ffff:ffff:ffff:ffff,TW
+2a05:dfc1:5efc::,2a05:dfc1:5efe:ffff:ffff:ffff:ffff:ffff,US
2a05:dfc1:5eff::,2a05:dfc1:5eff:ffff:ffff:ffff:ffff:ffff,TW
2a05:dfc1:5f00::,2a05:dfc1:5f0f:ffff:ffff:ffff:ffff:ffff,HK
2a05:dfc1:5f10::,2a05:dfc1:5f10:ffff:ffff:ffff:ffff:ffff,US
@@ -77806,8 +77874,12 @@
2a05:dfc1:8e70::,2a05:dfc1:8e7f:ffff:ffff:ffff:ffff:ffff,JP
2a05:dfc1:8e80::,2a05:dfc1:8ecf:ffff:ffff:ffff:ffff:ffff,SG
2a05:dfc1:8ed0::,2a05:dfc1:8f0f:ffff:ffff:ffff:ffff:ffff,US
-2a05:dfc1:8f10::,2a05:dfc1:8f2f:ffff:ffff:ffff:ffff:ffff,EU
-2a05:dfc1:8f30::,2a05:dfc1:8f7f:ffff:ffff:ffff:ffff:ffff,US
+2a05:dfc1:8f10::,2a05:dfc1:8f21:ffff:ffff:ffff:ffff:ffff,EU
+2a05:dfc1:8f22::,2a05:dfc1:8f22:ffff:ffff:ffff:ffff:ffff,CH
+2a05:dfc1:8f23::,2a05:dfc1:8f2f:ffff:ffff:ffff:ffff:ffff,EU
+2a05:dfc1:8f30::,2a05:dfc1:8f53:ffff:ffff:ffff:ffff:ffff,US
+2a05:dfc1:8f54::,2a05:dfc1:8f54:ffff:ffff:ffff:ffff:ffff,CA
+2a05:dfc1:8f55::,2a05:dfc1:8f7f:ffff:ffff:ffff:ffff:ffff,US
2a05:dfc1:8f80::,2a05:dfc1:8f81:ffff:ffff:ffff:ffff:ffff,SG
2a05:dfc1:8f82::,2a05:dfc1:8f82:ffff:ffff:ffff:ffff:ffff,AU
2a05:dfc1:8f83::,2a05:dfc1:8f83:ffff:ffff:ffff:ffff:ffff,SG
@@ -77821,12 +77893,11 @@
2a05:dfc1:8fd0::,2a05:dfc1:8fdf:ffff:ffff:ffff:ffff:ffff,CA
2a05:dfc1:8fe0::,2a05:dfc1:8fff:ffff:ffff:ffff:ffff:ffff,US
2a05:dfc1:9000::,2a05:dfc1:90ff:ffff:ffff:ffff:ffff:ffff,FR
-2a05:dfc1:9100::,2a05:dfc1:92fd:ffff:ffff:ffff:ffff:ffff,GB
-2a05:dfc1:92fe::,2a05:dfc1:92fe:ffff:ffff:ffff:ffff:ffff,LU
-2a05:dfc1:92ff::,2a05:dfc1:92ff:ffff:ffff:ffff:ffff:ffff,NL
+2a05:dfc1:9100::,2a05:dfc1:92ff:ffff:ffff:ffff:ffff:ffff,GB
2a05:dfc1:9300::,2a05:dfc1:94ff:ffff:ffff:ffff:ffff:ffff,US
2a05:dfc1:9500::,2a05:dfc1:95ff:ffff:ffff:ffff:ffff:ffff,IQ
-2a05:dfc1:9600::,2a05:dfc1:b00a:ffff:ffff:ffff:ffff:ffff,US
+2a05:dfc1:9600::,2a05:dfc1:96ff:ffff:ffff:ffff:ffff:ffff,NL
+2a05:dfc1:9700::,2a05:dfc1:b00a:ffff:ffff:ffff:ffff:ffff,US
2a05:dfc1:b00b::,2a05:dfc1:b00b:ffff:ffff:ffff:ffff:ffff,GB
2a05:dfc1:b00c::,2a05:dfc1:b00e:ffff:ffff:ffff:ffff:ffff,US
2a05:dfc1:b00f::,2a05:dfc1:b00f:ffff:ffff:ffff:ffff:ffff,EU
@@ -77931,12 +78002,14 @@
2a05:dfc4:1113::,2a05:dfc4:1113:ffff:ffff:ffff:ffff:ffff,AU
2a05:dfc4:1114::,2a05:dfc4:1213:ffff:ffff:ffff:ffff:ffff,GB
2a05:dfc4:1214::,2a05:dfc4:1214:ffff:ffff:ffff:ffff:ffff,CH
-2a05:dfc4:1215::,2a05:dfc4:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a05:dfc4:1215::,2a05:dfc4:1414:ffff:ffff:ffff:ffff:ffff,GB
+2a05:dfc4:1415::,2a05:dfc4:1415:ffff:ffff:ffff:ffff:ffff,PK
+2a05:dfc4:1416::,2a05:dfc4:ffff:ffff:ffff:ffff:ffff:ffff,GB
2a05:dfc5::,2a05:dfc5:ffff:ffff:ffff:ffff:ffff:ffff,US
2a05:dfc6::,2a05:dfc6:8fff:ffff:ffff:ffff:ffff:ffff,GB
2a05:dfc6:9000::,2a05:dfc6:900f:ffff:ffff:ffff:ffff:ffff,US
-2a05:dfc6:9010::,2a05:dfc6:901f:ffff:ffff:ffff:ffff:ffff,TW
-2a05:dfc6:9020::,2a05:dfc6:90ef:ffff:ffff:ffff:ffff:ffff,US
+2a05:dfc6:9010::,2a05:dfc6:902f:ffff:ffff:ffff:ffff:ffff,TW
+2a05:dfc6:9030::,2a05:dfc6:90ef:ffff:ffff:ffff:ffff:ffff,US
2a05:dfc6:90f0::,2a05:dfc6:90ff:ffff:ffff:ffff:ffff:ffff,EU
2a05:dfc6:9100::,2a05:dfc6:ffff:ffff:ffff:ffff:ffff:ffff,GB
2a05:dfc7::,2a05:dfc7:2:ffff:ffff:ffff:ffff:ffff,BA
@@ -77995,11 +78068,7 @@
2a05:dfc7:1300::,2a05:dfc7:13ff:ffff:ffff:ffff:ffff:ffff,FR
2a05:dfc7:1400::,2a05:dfc7:14ff:ffff:ffff:ffff:ffff:ffff,US
2a05:dfc7:1500::,2a05:dfc7:15ff:ffff:ffff:ffff:ffff:ffff,SA
-2a05:dfc7:1600::,2a05:dfc7:165f:ffff:ffff:ffff:ffff:ffff,AU
-2a05:dfc7:1660::,2a05:dfc7:1660:ffff:ffff:ffff:ffff:ffff,US
-2a05:dfc7:1661::,2a05:dfc7:166f:ffff:ffff:ffff:ffff:ffff,AU
-2a05:dfc7:1670::,2a05:dfc7:1671:ffff:ffff:ffff:ffff:ffff,GB
-2a05:dfc7:1672::,2a05:dfc7:16ff:ffff:ffff:ffff:ffff:ffff,AU
+2a05:dfc7:1600::,2a05:dfc7:16ff:ffff:ffff:ffff:ffff:ffff,AU
2a05:dfc7:1700::,2a05:dfc7:17ff:ffff:ffff:ffff:ffff:ffff,GB
2a05:dfc7:1800::,2a05:dfc7:18ff:ffff:ffff:ffff:ffff:ffff,BA
2a05:dfc7:1900::,2a05:dfc7:19ff:ffff:ffff:ffff:ffff:ffff,UA
@@ -78107,7 +78176,9 @@
2a05:dfc7:a200::,2a05:dfc7:a3ff:ffff:ffff:ffff:ffff:ffff,NL
2a05:dfc7:a400::,2a05:dfc7:afff:ffff:ffff:ffff:ffff:ffff,AT
2a05:dfc7:b000::,2a05:dfc7:b1ff:ffff:ffff:ffff:ffff:ffff,BA
-2a05:dfc7:b200::,2a05:dfc7:b9ff:ffff:ffff:ffff:ffff:ffff,DE
+2a05:dfc7:b200::,2a05:dfc7:b200:ffff:ffff:ffff:ffff:ffff,DE
+2a05:dfc7:b201::,2a05:dfc7:b201:ffff:ffff:ffff:ffff:ffff,NL
+2a05:dfc7:b202::,2a05:dfc7:b9ff:ffff:ffff:ffff:ffff:ffff,DE
2a05:dfc7:ba00::,2a05:dfc7:bbff:ffff:ffff:ffff:ffff:ffff,SI
2a05:dfc7:bc00::,2a05:dfc7:bfff:ffff:ffff:ffff:ffff:ffff,ID
2a05:dfc7:c000::,2a05:dfc7:c1ff:ffff:ffff:ffff:ffff:ffff,SK
@@ -78623,7 +78694,9 @@
2a06:1287:320::,2a06:1287:320:ffff:ffff:ffff:ffff:ffff,HK
2a06:1287:321::,2a06:1287:32f:ffff:ffff:ffff:ffff:ffff,TW
2a06:1287:330::,2a06:1287:330:ffff:ffff:ffff:ffff:ffff,US
-2a06:1287:331::,2a06:1287:3ff:ffff:ffff:ffff:ffff:ffff,TW
+2a06:1287:331::,2a06:1287:3a9:ffff:ffff:ffff:ffff:ffff,TW
+2a06:1287:3aa::,2a06:1287:3aa:ffff:ffff:ffff:ffff:ffff,CN
+2a06:1287:3ab::,2a06:1287:3ff:ffff:ffff:ffff:ffff:ffff,TW
2a06:1287:400::,2a06:1287:41f:ffff:ffff:ffff:ffff:ffff,SY
2a06:1287:420::,2a06:1287:4ff:ffff:ffff:ffff:ffff:ffff,AL
2a06:1287:500::,2a06:1287:5ff:ffff:ffff:ffff:ffff:ffff,US
@@ -78771,7 +78844,8 @@
2a06:1287:8040::,2a06:1287:807f:ffff:ffff:ffff:ffff:ffff,HK
2a06:1287:8080::,2a06:1287:81ff:ffff:ffff:ffff:ffff:ffff,GB
2a06:1287:8200::,2a06:1287:83ff:ffff:ffff:ffff:ffff:ffff,US
-2a06:1287:8400::,2a06:1287:85ff:ffff:ffff:ffff:ffff:ffff,NL
+2a06:1287:8400::,2a06:1287:84ff:ffff:ffff:ffff:ffff:ffff,GB
+2a06:1287:8500::,2a06:1287:85ff:ffff:ffff:ffff:ffff:ffff,US
2a06:1287:8600::,2a06:1287:87ff:ffff:ffff:ffff:ffff:ffff,EG
2a06:1287:8800::,2a06:1287:89ff:ffff:ffff:ffff:ffff:ffff,ID
2a06:1287:8a00::,2a06:1287:8fff:ffff:ffff:ffff:ffff:ffff,AL
@@ -79173,7 +79247,8 @@
2a06:3548::,2a06:357f:ffff:ffff:ffff:ffff:ffff:ffff,EU
2a06:3580::,2a06:3587:ffff:ffff:ffff:ffff:ffff:ffff,SE
2a06:3588::,2a06:35bf:ffff:ffff:ffff:ffff:ffff:ffff,EU
-2a06:35c0::,2a06:35c7:ffff:ffff:ffff:ffff:ffff:ffff,US
+2a06:35c0::,2a06:35c3:ffff:ffff:ffff:ffff:ffff:ffff,US
+2a06:35c4::,2a06:35c7:ffff:ffff:ffff:ffff:ffff:ffff,CA
2a06:35c8::,2a06:35ff:ffff:ffff:ffff:ffff:ffff:ffff,EU
2a06:3600::,2a06:3607:ffff:ffff:ffff:ffff:ffff:ffff,US
2a06:3608::,2a06:363f:ffff:ffff:ffff:ffff:ffff:ffff,EU
@@ -80410,7 +80485,7 @@
2a06:a005:2d4::,2a06:a005:2d4:ffff:ffff:ffff:ffff:ffff,FI
2a06:a005:2d5::,2a06:a005:2d5:ffff:ffff:ffff:ffff:ffff,DK
2a06:a005:2d6::,2a06:a005:2d6:ffff:ffff:ffff:ffff:ffff,RS
-2a06:a005:2d7::,2a06:a005:2d7:ffff:ffff:ffff:ffff:ffff,FR
+2a06:a005:2d7::,2a06:a005:2d7:ffff:ffff:ffff:ffff:ffff,DE
2a06:a005:2d8::,2a06:a005:2d8:ffff:ffff:ffff:ffff:ffff,US
2a06:a005:2d9::,2a06:a005:2da:ffff:ffff:ffff:ffff:ffff,DE
2a06:a005:2db::,2a06:a005:2db:ffff:ffff:ffff:ffff:ffff,US
@@ -80683,8 +80758,7 @@
2a06:a005:b6d::,2a06:a005:b6d:ffff:ffff:ffff:ffff:ffff,NZ
2a06:a005:b6e::,2a06:a005:b6e:ffff:ffff:ffff:ffff:ffff,EE
2a06:a005:b6f::,2a06:a005:b6f:ffff:ffff:ffff:ffff:ffff,CA
-2a06:a005:b70::,2a06:a005:b8f:ffff:ffff:ffff:ffff:ffff,AU
-2a06:a005:b90::,2a06:a005:b9f:ffff:ffff:ffff:ffff:ffff,US
+2a06:a005:b70::,2a06:a005:b9f:ffff:ffff:ffff:ffff:ffff,AU
2a06:a005:ba0::,2a06:a005:ba0:ffff:ffff:ffff:ffff:ffff,CH
2a06:a005:ba1::,2a06:a005:ba1:ffff:ffff:ffff:ffff:ffff,RU
2a06:a005:ba2::,2a06:a005:ba2:ffff:ffff:ffff:ffff:ffff,DO
@@ -80700,9 +80774,7 @@
2a06:a005:baf::,2a06:a005:baf:ffff:ffff:ffff:ffff:ffff,DE
2a06:a005:bb0::,2a06:a005:bbf:ffff:ffff:ffff:ffff:ffff,NZ
2a06:a005:bc0::,2a06:a005:bcf:ffff:ffff:ffff:ffff:ffff,IE
-2a06:a005:bd0::,2a06:a005:bdf:ffff:ffff:ffff:ffff:ffff,SG
-2a06:a005:be0::,2a06:a005:bef:ffff:ffff:ffff:ffff:ffff,DE
-2a06:a005:bf0::,2a06:a005:bff:ffff:ffff:ffff:ffff:ffff,GB
+2a06:a005:bd0::,2a06:a005:bff:ffff:ffff:ffff:ffff:ffff,AU
2a06:a005:c00::,2a06:a005:c1f:ffff:ffff:ffff:ffff:ffff,BG
2a06:a005:c20::,2a06:a005:c2f:ffff:ffff:ffff:ffff:ffff,HK
2a06:a005:c30::,2a06:a005:c3f:ffff:ffff:ffff:ffff:ffff,CN
@@ -80770,7 +80842,7 @@
2a06:a005:f80::,2a06:a005:f8f:ffff:ffff:ffff:ffff:ffff,AU
2a06:a005:f90::,2a06:a005:f9f:ffff:ffff:ffff:ffff:ffff,CA
2a06:a005:fa0::,2a06:a005:faf:ffff:ffff:ffff:ffff:ffff,BR
-2a06:a005:fb0::,2a06:a005:fbf:ffff:ffff:ffff:ffff:ffff,FR
+2a06:a005:fb0::,2a06:a005:fbf:ffff:ffff:ffff:ffff:ffff,DE
2a06:a005:fc0::,2a06:a005:fcf:ffff:ffff:ffff:ffff:ffff,PK
2a06:a005:fd0::,2a06:a005:fdf:ffff:ffff:ffff:ffff:ffff,CN
2a06:a005:fe0::,2a06:a005:fef:ffff:ffff:ffff:ffff:ffff,SG
@@ -80812,7 +80884,7 @@
2a06:a005:1167::,2a06:a005:1167:ffff:ffff:ffff:ffff:ffff,DE
2a06:a005:1168::,2a06:a005:1168:ffff:ffff:ffff:ffff:ffff,HK
2a06:a005:1169::,2a06:a005:1169:ffff:ffff:ffff:ffff:ffff,DE
-2a06:a005:116a::,2a06:a005:116a:ffff:ffff:ffff:ffff:ffff,NL
+2a06:a005:116a::,2a06:a005:116a:ffff:ffff:ffff:ffff:ffff,GB
2a06:a005:116b::,2a06:a005:116c:ffff:ffff:ffff:ffff:ffff,US
2a06:a005:116d::,2a06:a005:116d:ffff:ffff:ffff:ffff:ffff,UA
2a06:a005:116e::,2a06:a005:116e:ffff:ffff:ffff:ffff:ffff,RU
@@ -80899,7 +80971,8 @@
2a06:a005:15da::,2a06:a005:15da:ffff:ffff:ffff:ffff:ffff,CA
2a06:a005:15db::,2a06:a005:15db:ffff:ffff:ffff:ffff:ffff,EU
2a06:a005:15dc::,2a06:a005:15dc:ffff:ffff:ffff:ffff:ffff,FI
-2a06:a005:15dd::,2a06:a005:15de:ffff:ffff:ffff:ffff:ffff,NL
+2a06:a005:15dd::,2a06:a005:15dd:ffff:ffff:ffff:ffff:ffff,US
+2a06:a005:15de::,2a06:a005:15de:ffff:ffff:ffff:ffff:ffff,GB
2a06:a005:15df::,2a06:a005:15df:ffff:ffff:ffff:ffff:ffff,CH
2a06:a005:15e0::,2a06:a005:15ff:ffff:ffff:ffff:ffff:ffff,EU
2a06:a005:1600::,2a06:a005:160f:ffff:ffff:ffff:ffff:ffff,ID
@@ -80973,8 +81046,7 @@
2a06:a005:1930::,2a06:a005:193f:ffff:ffff:ffff:ffff:ffff,EU
2a06:a005:1940::,2a06:a005:1940:ffff:ffff:ffff:ffff:ffff,NL
2a06:a005:1941::,2a06:a005:1941:ffff:ffff:ffff:ffff:ffff,DE
-2a06:a005:1942::,2a06:a005:1942:ffff:ffff:ffff:ffff:ffff,NL
-2a06:a005:1943::,2a06:a005:1943:ffff:ffff:ffff:ffff:ffff,EU
+2a06:a005:1942::,2a06:a005:1943:ffff:ffff:ffff:ffff:ffff,EU
2a06:a005:1944::,2a06:a005:1944:ffff:ffff:ffff:ffff:ffff,TR
2a06:a005:1945::,2a06:a005:1945:ffff:ffff:ffff:ffff:ffff,US
2a06:a005:1946::,2a06:a005:1947:ffff:ffff:ffff:ffff:ffff,KR
@@ -80989,7 +81061,7 @@
2a06:a005:1a20::,2a06:a005:1a5f:ffff:ffff:ffff:ffff:ffff,SG
2a06:a005:1a60::,2a06:a005:1a6f:ffff:ffff:ffff:ffff:ffff,LU
2a06:a005:1a70::,2a06:a005:1acf:ffff:ffff:ffff:ffff:ffff,US
-2a06:a005:1ad0::,2a06:a005:1aef:ffff:ffff:ffff:ffff:ffff,FR
+2a06:a005:1ad0::,2a06:a005:1aef:ffff:ffff:ffff:ffff:ffff,EU
2a06:a005:1af0::,2a06:a005:1b4f:ffff:ffff:ffff:ffff:ffff,US
2a06:a005:1b50::,2a06:a005:1b5f:ffff:ffff:ffff:ffff:ffff,FR
2a06:a005:1b60::,2a06:a005:1b7f:ffff:ffff:ffff:ffff:ffff,US
@@ -80997,7 +81069,7 @@
2a06:a005:1b90::,2a06:a005:1b9f:ffff:ffff:ffff:ffff:ffff,EU
2a06:a005:1ba0::,2a06:a005:1baf:ffff:ffff:ffff:ffff:ffff,US
2a06:a005:1bb0::,2a06:a005:1bbf:ffff:ffff:ffff:ffff:ffff,GB
-2a06:a005:1bc0::,2a06:a005:1bcf:ffff:ffff:ffff:ffff:ffff,FR
+2a06:a005:1bc0::,2a06:a005:1bcf:ffff:ffff:ffff:ffff:ffff,EU
2a06:a005:1bd0::,2a06:a005:1bef:ffff:ffff:ffff:ffff:ffff,TW
2a06:a005:1bf0::,2a06:a005:1bff:ffff:ffff:ffff:ffff:ffff,SG
2a06:a005:1c00::,2a06:a005:1c0f:ffff:ffff:ffff:ffff:ffff,KR
@@ -81038,8 +81110,7 @@
2a06:a005:1d57::,2a06:a005:1d57:ffff:ffff:ffff:ffff:ffff,KP
2a06:a005:1d58::,2a06:a005:1d58:ffff:ffff:ffff:ffff:ffff,NL
2a06:a005:1d59::,2a06:a005:1d59:ffff:ffff:ffff:ffff:ffff,PT
-2a06:a005:1d5a::,2a06:a005:1d5a:ffff:ffff:ffff:ffff:ffff,NL
-2a06:a005:1d5b::,2a06:a005:1d5b:ffff:ffff:ffff:ffff:ffff,US
+2a06:a005:1d5a::,2a06:a005:1d5b:ffff:ffff:ffff:ffff:ffff,US
2a06:a005:1d5c::,2a06:a005:1d5f:ffff:ffff:ffff:ffff:ffff,EU
2a06:a005:1d60::,2a06:a005:1d6f:ffff:ffff:ffff:ffff:ffff,GB
2a06:a005:1d70::,2a06:a005:1d7f:ffff:ffff:ffff:ffff:ffff,AQ
@@ -81166,7 +81237,7 @@
2a06:a005:26ce::,2a06:a005:26cf:ffff:ffff:ffff:ffff:ffff,EU
2a06:a005:26d0::,2a06:a005:26df:ffff:ffff:ffff:ffff:ffff,CN
2a06:a005:26e0::,2a06:a005:271f:ffff:ffff:ffff:ffff:ffff,PH
-2a06:a005:2720::,2a06:a005:272f:ffff:ffff:ffff:ffff:ffff,CA
+2a06:a005:2720::,2a06:a005:272f:ffff:ffff:ffff:ffff:ffff,AQ
2a06:a005:2730::,2a06:a005:273f:ffff:ffff:ffff:ffff:ffff,LV
2a06:a005:2740::,2a06:a005:27cf:ffff:ffff:ffff:ffff:ffff,GB
2a06:a005:27d0::,2a06:a005:27df:ffff:ffff:ffff:ffff:ffff,US
@@ -83161,7 +83232,14 @@
2a07:54c1:3403::,2a07:54c1:35ff:ffff:ffff:ffff:ffff:ffff,US
2a07:54c1:3600::,2a07:54c1:36ff:ffff:ffff:ffff:ffff:ffff,NL
2a07:54c1:3700::,2a07:54c1:37ff:ffff:ffff:ffff:ffff:ffff,NO
-2a07:54c1:3800::,2a07:54c1:38ff:ffff:ffff:ffff:ffff:ffff,GB
+2a07:54c1:3800::,2a07:54c1:3800:ffff:ffff:ffff:ffff:ffff,GB
+2a07:54c1:3801::,2a07:54c1:3801:ffff:ffff:ffff:ffff:ffff,CA
+2a07:54c1:3802::,2a07:54c1:3802:ffff:ffff:ffff:ffff:ffff,GB
+2a07:54c1:3803::,2a07:54c1:3803:ffff:ffff:ffff:ffff:ffff,LU
+2a07:54c1:3804::,2a07:54c1:3804:ffff:ffff:ffff:ffff:ffff,GB
+2a07:54c1:3805::,2a07:54c1:3805:ffff:ffff:ffff:ffff:ffff,CA
+2a07:54c1:3806::,2a07:54c1:3806:ffff:ffff:ffff:ffff:ffff,DE
+2a07:54c1:3807::,2a07:54c1:38ff:ffff:ffff:ffff:ffff:ffff,GB
2a07:54c1:3900::,2a07:54c1:39ff:ffff:ffff:ffff:ffff:ffff,CZ
2a07:54c1:3a00::,2a07:54c1:3fff:ffff:ffff:ffff:ffff:ffff,NL
2a07:54c1:4000::,2a07:54c1:40ff:ffff:ffff:ffff:ffff:ffff,US
@@ -83169,12 +83247,7 @@
2a07:54c1:4200::,2a07:54c1:42ff:ffff:ffff:ffff:ffff:ffff,US
2a07:54c1:4300::,2a07:54c1:4fff:ffff:ffff:ffff:ffff:ffff,EU
2a07:54c1:5000::,2a07:54c1:5fff:ffff:ffff:ffff:ffff:ffff,GB
-2a07:54c1:6000::,2a07:54c1:61ff:ffff:ffff:ffff:ffff:ffff,AU
-2a07:54c1:6200::,2a07:54c1:63ff:ffff:ffff:ffff:ffff:ffff,CA
-2a07:54c1:6400::,2a07:54c1:64ff:ffff:ffff:ffff:ffff:ffff,AU
-2a07:54c1:6500::,2a07:54c1:67ff:ffff:ffff:ffff:ffff:ffff,US
-2a07:54c1:6800::,2a07:54c1:68ff:ffff:ffff:ffff:ffff:ffff,NL
-2a07:54c1:6900::,2a07:54c1:6fff:ffff:ffff:ffff:ffff:ffff,AU
+2a07:54c1:6000::,2a07:54c1:6fff:ffff:ffff:ffff:ffff:ffff,AU
2a07:54c1:7000::,2a07:54c1:7fff:ffff:ffff:ffff:ffff:ffff,US
2a07:54c1:8000::,2a07:54c1:81ff:ffff:ffff:ffff:ffff:ffff,CA
2a07:54c1:8200::,2a07:54c1:82ff:ffff:ffff:ffff:ffff:ffff,US
@@ -83223,7 +83296,7 @@
2a07:54c4:2::,2a07:54c4:2:ffff:ffff:ffff:ffff:ffff,FI
2a07:54c4:3::,2a07:54c4:3:ffff:ffff:ffff:ffff:ffff,EE
2a07:54c4:4::,2a07:54c4:4:ffff:ffff:ffff:ffff:ffff,GL
-2a07:54c4:5::,2a07:54c4:5:ffff:ffff:ffff:ffff:ffff,IE
+2a07:54c4:5::,2a07:54c4:5:ffff:ffff:ffff:ffff:ffff,DE
2a07:54c4:6::,2a07:54c4:6:ffff:ffff:ffff:ffff:ffff,GB
2a07:54c4:7::,2a07:54c4:7:ffff:ffff:ffff:ffff:ffff,EE
2a07:54c4:8::,2a07:54c4:8:ffff:ffff:ffff:ffff:ffff,IS
@@ -83263,16 +83336,23 @@
2a07:54c5:1600::,2a07:54c5:16ff:ffff:ffff:ffff:ffff:ffff,EU
2a07:54c5:1700::,2a07:54c5:17ff:ffff:ffff:ffff:ffff:ffff,AQ
2a07:54c5:1800::,2a07:54c5:19ff:ffff:ffff:ffff:ffff:ffff,GB
-2a07:54c5:1a00::,2a07:54c5:9fff:ffff:ffff:ffff:ffff:ffff,IS
+2a07:54c5:1a00::,2a07:54c5:54c4:ffff:ffff:ffff:ffff:ffff,IS
+2a07:54c5:54c5::,2a07:54c5:54c5:ffff:ffff:ffff:ffff:ffff,GB
+2a07:54c5:54c6::,2a07:54c5:9fff:ffff:ffff:ffff:ffff:ffff,IS
2a07:54c5:a000::,2a07:54c5:a000:ffff:ffff:ffff:ffff:ffff,CA
2a07:54c5:a001::,2a07:54c5:a006:ffff:ffff:ffff:ffff:ffff,IS
-2a07:54c5:a007::,2a07:54c5:a009:ffff:ffff:ffff:ffff:ffff,GB
+2a07:54c5:a007::,2a07:54c5:a007:ffff:ffff:ffff:ffff:ffff,US
+2a07:54c5:a008::,2a07:54c5:a009:ffff:ffff:ffff:ffff:ffff,GB
2a07:54c5:a00a::,2a07:54c5:b009:ffff:ffff:ffff:ffff:ffff,IS
2a07:54c5:b00a::,2a07:54c5:b00a:ffff:ffff:ffff:ffff:ffff,GB
2a07:54c5:b00b::,2a07:54c5:beee:ffff:ffff:ffff:ffff:ffff,IS
2a07:54c5:beef::,2a07:54c5:beef:ffff:ffff:ffff:ffff:ffff,GB
2a07:54c5:bef0::,2a07:54c5:ffff:ffff:ffff:ffff:ffff:ffff,IS
-2a07:54c6::,2a07:54c6:ffff:ffff:ffff:ffff:ffff:ffff,EE
+2a07:54c6::,2a07:54c6:f:ffff:ffff:ffff:ffff:ffff,EU
+2a07:54c6:10::,2a07:54c6:1f:ffff:ffff:ffff:ffff:ffff,GB
+2a07:54c6:20::,2a07:54c6:2f:ffff:ffff:ffff:ffff:ffff,NL
+2a07:54c6:30::,2a07:54c6:3f:ffff:ffff:ffff:ffff:ffff,CA
+2a07:54c6:40::,2a07:54c6:ffff:ffff:ffff:ffff:ffff:ffff,EU
2a07:54c7::,2a07:54c7:fff:ffff:ffff:ffff:ffff:ffff,NO
2a07:54c7:1000::,2a07:54c7:2fff:ffff:ffff:ffff:ffff:ffff,DE
2a07:54c7:3000::,2a07:54ff:ffff:ffff:ffff:ffff:ffff:ffff,EU
@@ -83381,7 +83461,9 @@
2a07:6140::,2a07:6147:ffff:ffff:ffff:ffff:ffff:ffff,NO
2a07:6148::,2a07:617f:ffff:ffff:ffff:ffff:ffff:ffff,EU
2a07:6180::,2a07:6187:ffff:ffff:ffff:ffff:ffff:ffff,GB
-2a07:6188::,2a07:61ff:ffff:ffff:ffff:ffff:ffff:ffff,EU
+2a07:6188::,2a07:61bf:ffff:ffff:ffff:ffff:ffff:ffff,EU
+2a07:61c0::,2a07:61c7:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a07:61c8::,2a07:61ff:ffff:ffff:ffff:ffff:ffff:ffff,EU
2a07:6200::,2a07:6207:ffff:ffff:ffff:ffff:ffff:ffff,FR
2a07:6208::,2a07:623f:ffff:ffff:ffff:ffff:ffff:ffff,EU
2a07:6240::,2a07:6247:ffff:ffff:ffff:ffff:ffff:ffff,CH
@@ -84615,7 +84697,9 @@
2a07:f600:4033::,2a07:f600:4033:ffff:ffff:ffff:ffff:ffff,RU
2a07:f600:4034::,2a07:f600:4057:ffff:ffff:ffff:ffff:ffff,GB
2a07:f600:4058::,2a07:f600:4058:ffff:ffff:ffff:ffff:ffff,RU
-2a07:f600:4059::,2a07:f600:4443:ffff:ffff:ffff:ffff:ffff,GB
+2a07:f600:4059::,2a07:f600:4085:ffff:ffff:ffff:ffff:ffff,GB
+2a07:f600:4086::,2a07:f600:4086:ffff:ffff:ffff:ffff:ffff,GE
+2a07:f600:4087::,2a07:f600:4443:ffff:ffff:ffff:ffff:ffff,GB
2a07:f600:4444::,2a07:f600:4444:ffff:ffff:ffff:ffff:ffff,EU
2a07:f600:4445::,2a07:f607:ffff:ffff:ffff:ffff:ffff:ffff,GB
2a07:f608::,2a07:f63f:ffff:ffff:ffff:ffff:ffff:ffff,EU
@@ -85154,7 +85238,7 @@
2a09:fc8::,2a09:fff:ffff:ffff:ffff:ffff:ffff:ffff,EU
2a09:1000::,2a09:1007:ffff:ffff:ffff:ffff:ffff:ffff,DE
2a09:1008::,2a09:103f:ffff:ffff:ffff:ffff:ffff:ffff,EU
-2a09:1040::,2a09:1047:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a09:1040::,2a09:1047:ffff:ffff:ffff:ffff:ffff:ffff,FR
2a09:1048::,2a09:107f:ffff:ffff:ffff:ffff:ffff:ffff,EU
2a09:1080::,2a09:1087:ffff:ffff:ffff:ffff:ffff:ffff,GB
2a09:1088::,2a09:10bf:ffff:ffff:ffff:ffff:ffff:ffff,EU
@@ -87313,7 +87397,9 @@
2a09:fec8::,2a09:feff:ffff:ffff:ffff:ffff:ffff:ffff,EU
2a09:ff00::,2a09:ff00:ff:ffff:ffff:ffff:ffff:ffff,DE
2a09:ff00:100::,2a09:ff00:100:ffff:ffff:ffff:ffff:ffff,GB
-2a09:ff00:101::,2a09:ff07:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a09:ff00:101::,2a09:ff00:1ff:ffff:ffff:ffff:ffff:ffff,DE
+2a09:ff00:200::,2a09:ff00:20f:ffff:ffff:ffff:ffff:ffff,VN
+2a09:ff00:210::,2a09:ff07:ffff:ffff:ffff:ffff:ffff:ffff,DE
2a09:ff08::,2a09:ff3f:ffff:ffff:ffff:ffff:ffff:ffff,EU
2a09:ff40::,2a09:ff40:ffff:ffff:ffff:ffff:ffff:ffff,FR
2a09:ff41::,2a09:ff7f:ffff:ffff:ffff:ffff:ffff:ffff,EU
@@ -87346,7 +87432,55 @@
2a0a:280:1300::,2a0a:280:137f:ffff:ffff:ffff:ffff:ffff,US
2a0a:280:1380::,2a0a:280:1380:ffff:ffff:ffff:ffff:ffff,AL
2a0a:280:1381::,2a0a:280:1381:ffff:ffff:ffff:ffff:ffff,AD
-2a0a:280:1382::,2a0a:280:13ff:ffff:ffff:ffff:ffff:ffff,US
+2a0a:280:1382::,2a0a:280:1382:ffff:ffff:ffff:ffff:ffff,AM
+2a0a:280:1383::,2a0a:280:1383:ffff:ffff:ffff:ffff:ffff,AT
+2a0a:280:1384::,2a0a:280:1384:ffff:ffff:ffff:ffff:ffff,AZ
+2a0a:280:1385::,2a0a:280:1385:ffff:ffff:ffff:ffff:ffff,BY
+2a0a:280:1386::,2a0a:280:1386:ffff:ffff:ffff:ffff:ffff,BE
+2a0a:280:1387::,2a0a:280:1387:ffff:ffff:ffff:ffff:ffff,BA
+2a0a:280:1388::,2a0a:280:1388:ffff:ffff:ffff:ffff:ffff,BG
+2a0a:280:1389::,2a0a:280:1389:ffff:ffff:ffff:ffff:ffff,HR
+2a0a:280:138a::,2a0a:280:138a:ffff:ffff:ffff:ffff:ffff,CY
+2a0a:280:138b::,2a0a:280:138b:ffff:ffff:ffff:ffff:ffff,CZ
+2a0a:280:138c::,2a0a:280:138c:ffff:ffff:ffff:ffff:ffff,DK
+2a0a:280:138d::,2a0a:280:138d:ffff:ffff:ffff:ffff:ffff,EE
+2a0a:280:138e::,2a0a:280:138e:ffff:ffff:ffff:ffff:ffff,FO
+2a0a:280:138f::,2a0a:280:138f:ffff:ffff:ffff:ffff:ffff,FI
+2a0a:280:1390::,2a0a:280:1390:ffff:ffff:ffff:ffff:ffff,FR
+2a0a:280:1391::,2a0a:280:1391:ffff:ffff:ffff:ffff:ffff,GE
+2a0a:280:1392::,2a0a:280:1392:ffff:ffff:ffff:ffff:ffff,DE
+2a0a:280:1393::,2a0a:280:1393:ffff:ffff:ffff:ffff:ffff,GR
+2a0a:280:1394::,2a0a:280:1394:ffff:ffff:ffff:ffff:ffff,HU
+2a0a:280:1395::,2a0a:280:1395:ffff:ffff:ffff:ffff:ffff,IS
+2a0a:280:1396::,2a0a:280:1396:ffff:ffff:ffff:ffff:ffff,IE
+2a0a:280:1397::,2a0a:280:1397:ffff:ffff:ffff:ffff:ffff,IT
+2a0a:280:1398::,2a0a:280:1398:ffff:ffff:ffff:ffff:ffff,US
+2a0a:280:1399::,2a0a:280:1399:ffff:ffff:ffff:ffff:ffff,LV
+2a0a:280:139a::,2a0a:280:139a:ffff:ffff:ffff:ffff:ffff,LI
+2a0a:280:139b::,2a0a:280:139b:ffff:ffff:ffff:ffff:ffff,LT
+2a0a:280:139c::,2a0a:280:139c:ffff:ffff:ffff:ffff:ffff,LU
+2a0a:280:139d::,2a0a:280:139d:ffff:ffff:ffff:ffff:ffff,MK
+2a0a:280:139e::,2a0a:280:139e:ffff:ffff:ffff:ffff:ffff,MT
+2a0a:280:139f::,2a0a:280:139f:ffff:ffff:ffff:ffff:ffff,MD
+2a0a:280:13a0::,2a0a:280:13a0:ffff:ffff:ffff:ffff:ffff,MC
+2a0a:280:13a1::,2a0a:280:13a1:ffff:ffff:ffff:ffff:ffff,ME
+2a0a:280:13a2::,2a0a:280:13a2:ffff:ffff:ffff:ffff:ffff,NL
+2a0a:280:13a3::,2a0a:280:13a3:ffff:ffff:ffff:ffff:ffff,NO
+2a0a:280:13a4::,2a0a:280:13a4:ffff:ffff:ffff:ffff:ffff,PL
+2a0a:280:13a5::,2a0a:280:13a5:ffff:ffff:ffff:ffff:ffff,PT
+2a0a:280:13a6::,2a0a:280:13a6:ffff:ffff:ffff:ffff:ffff,RO
+2a0a:280:13a7::,2a0a:280:13a7:ffff:ffff:ffff:ffff:ffff,RU
+2a0a:280:13a8::,2a0a:280:13a8:ffff:ffff:ffff:ffff:ffff,SM
+2a0a:280:13a9::,2a0a:280:13a9:ffff:ffff:ffff:ffff:ffff,RS
+2a0a:280:13aa::,2a0a:280:13aa:ffff:ffff:ffff:ffff:ffff,SK
+2a0a:280:13ab::,2a0a:280:13ab:ffff:ffff:ffff:ffff:ffff,SI
+2a0a:280:13ac::,2a0a:280:13ac:ffff:ffff:ffff:ffff:ffff,ES
+2a0a:280:13ad::,2a0a:280:13ad:ffff:ffff:ffff:ffff:ffff,SE
+2a0a:280:13ae::,2a0a:280:13ae:ffff:ffff:ffff:ffff:ffff,CH
+2a0a:280:13af::,2a0a:280:13af:ffff:ffff:ffff:ffff:ffff,UA
+2a0a:280:13b0::,2a0a:280:13b0:ffff:ffff:ffff:ffff:ffff,GB
+2a0a:280:13b1::,2a0a:280:13b1:ffff:ffff:ffff:ffff:ffff,VA
+2a0a:280:13b2::,2a0a:280:13ff:ffff:ffff:ffff:ffff:ffff,US
2a0a:280:1400::,2a0a:280:14ff:ffff:ffff:ffff:ffff:ffff,EU
2a0a:280:1500::,2a0a:280:1500:ffff:ffff:ffff:ffff:ffff,TR
2a0a:280:1501::,2a0a:280:1501:ffff:ffff:ffff:ffff:ffff,AR
@@ -88595,7 +88729,9 @@
2a0a:6040:b1f7::,2a0a:6040:b1f7:ffff:ffff:ffff:ffff:ffff,FI
2a0a:6040:b1f8::,2a0a:6040:b1f8:ffff:ffff:ffff:ffff:ffff,AQ
2a0a:6040:b1f9::,2a0a:6040:b1ff:ffff:ffff:ffff:ffff:ffff,LV
-2a0a:6040:b200::,2a0a:6040:b205:ffff:ffff:ffff:ffff:ffff,NL
+2a0a:6040:b200::,2a0a:6040:b202:ffff:ffff:ffff:ffff:ffff,NL
+2a0a:6040:b203::,2a0a:6040:b203:ffff:ffff:ffff:ffff:ffff,EU
+2a0a:6040:b204::,2a0a:6040:b205:ffff:ffff:ffff:ffff:ffff,NL
2a0a:6040:b206::,2a0a:6040:b206:ffff:ffff:ffff:ffff:ffff,GB
2a0a:6040:b207::,2a0a:6040:b207:ffff:ffff:ffff:ffff:ffff,NL
2a0a:6040:b208::,2a0a:6040:b2ab:ffff:ffff:ffff:ffff:ffff,GB
@@ -91500,9 +91636,7 @@
2a0b:66c0::,2a0b:66c0:ffff:ffff:ffff:ffff:ffff:ffff,RU
2a0b:66c1::,2a0b:66ff:ffff:ffff:ffff:ffff:ffff:ffff,EU
2a0b:6700::,2a0b:6700:ffff:ffff:ffff:ffff:ffff:ffff,CZ
-2a0b:6701::,2a0b:673f:ffff:ffff:ffff:ffff:ffff:ffff,EU
-2a0b:6740::,2a0b:6747:ffff:ffff:ffff:ffff:ffff:ffff,GB
-2a0b:6748::,2a0b:677f:ffff:ffff:ffff:ffff:ffff:ffff,EU
+2a0b:6701::,2a0b:677f:ffff:ffff:ffff:ffff:ffff:ffff,EU
2a0b:6780::,2a0b:6787:ffff:ffff:ffff:ffff:ffff:ffff,TR
2a0b:6788::,2a0b:67bf:ffff:ffff:ffff:ffff:ffff:ffff,EU
2a0b:67c0::,2a0b:67c7:ffff:ffff:ffff:ffff:ffff:ffff,GB
@@ -93136,9 +93270,7 @@
2a0c:2180::,2a0c:2187:ffff:ffff:ffff:ffff:ffff:ffff,DE
2a0c:2188::,2a0c:21bf:ffff:ffff:ffff:ffff:ffff:ffff,EU
2a0c:21c0::,2a0c:21c7:ffff:ffff:ffff:ffff:ffff:ffff,ES
-2a0c:21c8::,2a0c:21ff:ffff:ffff:ffff:ffff:ffff:ffff,EU
-2a0c:2200::,2a0c:2207:ffff:ffff:ffff:ffff:ffff:ffff,TR
-2a0c:2208::,2a0c:223f:ffff:ffff:ffff:ffff:ffff:ffff,EU
+2a0c:21c8::,2a0c:223f:ffff:ffff:ffff:ffff:ffff:ffff,EU
2a0c:2240::,2a0c:2247:ffff:ffff:ffff:ffff:ffff:ffff,CH
2a0c:2248::,2a0c:227f:ffff:ffff:ffff:ffff:ffff:ffff,EU
2a0c:2280::,2a0c:2287:ffff:ffff:ffff:ffff:ffff:ffff,NO
@@ -93601,9 +93733,10 @@
2a0c:5705:5000::,2a0c:5705:5fff:ffff:ffff:ffff:ffff:ffff,DE
2a0c:5705:6000::,2a0c:5705:ffff:ffff:ffff:ffff:ffff:ffff,US
2a0c:5706::,2a0c:5707:feff:ffff:ffff:ffff:ffff:ffff,SE
-2a0c:5707:ff00::,2a0c:5707:ff02:ffff:ffff:ffff:ffff:ffff,NL
+2a0c:5707:ff00::,2a0c:5707:ff01:ffff:ffff:ffff:ffff:ffff,GB
+2a0c:5707:ff02::,2a0c:5707:ff02:ffff:ffff:ffff:ffff:ffff,US
2a0c:5707:ff03::,2a0c:5707:ff03:ffff:ffff:ffff:ffff:ffff,GB
-2a0c:5707:ff04::,2a0c:5707:ff04:ffff:ffff:ffff:ffff:ffff,NL
+2a0c:5707:ff04::,2a0c:5707:ff04:ffff:ffff:ffff:ffff:ffff,US
2a0c:5707:ff05::,2a0c:5707:ffff:ffff:ffff:ffff:ffff:ffff,GB
2a0c:5708::,2a0c:573f:ffff:ffff:ffff:ffff:ffff:ffff,EU
2a0c:5740::,2a0c:5747:ffff:ffff:ffff:ffff:ffff:ffff,FI
@@ -94403,7 +94536,8 @@
2a0c:9a40:8ce1::,2a0c:9a40:8dff:ffff:ffff:ffff:ffff:ffff,CH
2a0c:9a40:8e00::,2a0c:9a40:8eff:ffff:ffff:ffff:ffff:ffff,EU
2a0c:9a40:8f00::,2a0c:9a40:90ff:ffff:ffff:ffff:ffff:ffff,CH
-2a0c:9a40:9100::,2a0c:9a40:92ff:ffff:ffff:ffff:ffff:ffff,FR
+2a0c:9a40:9100::,2a0c:9a40:91ff:ffff:ffff:ffff:ffff:ffff,FR
+2a0c:9a40:9200::,2a0c:9a40:92ff:ffff:ffff:ffff:ffff:ffff,CH
2a0c:9a40:9300::,2a0c:9a40:93ff:ffff:ffff:ffff:ffff:ffff,TW
2a0c:9a40:9400::,2a0c:9a40:94ff:ffff:ffff:ffff:ffff:ffff,CH
2a0c:9a40:9500::,2a0c:9a40:9594:ffff:ffff:ffff:ffff:ffff,CA
@@ -94483,7 +94617,7 @@
2a0c:9a40:9fc0::,2a0c:9a40:9fcf:ffff:ffff:ffff:ffff:ffff,MY
2a0c:9a40:9fd0::,2a0c:9a40:9fdf:ffff:ffff:ffff:ffff:ffff,DE
2a0c:9a40:9fe0::,2a0c:9a40:9fef:ffff:ffff:ffff:ffff:ffff,FR
-2a0c:9a40:9ff0::,2a0c:9a40:9fff:ffff:ffff:ffff:ffff:ffff,US
+2a0c:9a40:9ff0::,2a0c:9a40:9fff:ffff:ffff:ffff:ffff:ffff,MO
2a0c:9a40:a000::,2a0c:9a40:b00a:ffff:ffff:ffff:ffff:ffff,CH
2a0c:9a40:b00b::,2a0c:9a40:b00b:ffff:ffff:ffff:ffff:ffff,EU
2a0c:9a40:b00c::,2a0c:9a40:bfff:ffff:ffff:ffff:ffff:ffff,CH
@@ -94815,7 +94949,7 @@
2a0c:b641:361::,2a0c:b641:36f:ffff:ffff:ffff:ffff:ffff,US
2a0c:b641:370::,2a0c:b641:37f:ffff:ffff:ffff:ffff:ffff,ES
2a0c:b641:380::,2a0c:b641:38f:ffff:ffff:ffff:ffff:ffff,GB
-2a0c:b641:390::,2a0c:b641:39f:ffff:ffff:ffff:ffff:ffff,FR
+2a0c:b641:390::,2a0c:b641:39f:ffff:ffff:ffff:ffff:ffff,BE
2a0c:b641:3a0::,2a0c:b641:3af:ffff:ffff:ffff:ffff:ffff,MD
2a0c:b641:3b0::,2a0c:b641:3bf:ffff:ffff:ffff:ffff:ffff,DE
2a0c:b641:3c0::,2a0c:b641:3cf:ffff:ffff:ffff:ffff:ffff,BO
@@ -95035,8 +95169,8 @@
2a0c:b642:2fff::,2a0c:b642:2fff:ffff:ffff:ffff:ffff:ffff,DE
2a0c:b642:3000::,2a0c:b642:3fff:ffff:ffff:ffff:ffff:ffff,BE
2a0c:b642:4000::,2a0c:b642:4000:ffff:ffff:ffff:ffff:ffff,CN
-2a0c:b642:4001::,2a0c:b642:4001:ffff:ffff:ffff:ffff:ffff,US
-2a0c:b642:4002::,2a0c:b642:4fff:ffff:ffff:ffff:ffff:ffff,CN
+2a0c:b642:4001::,2a0c:b642:4002:ffff:ffff:ffff:ffff:ffff,US
+2a0c:b642:4003::,2a0c:b642:4fff:ffff:ffff:ffff:ffff:ffff,CN
2a0c:b642:5000::,2a0c:b647:ffff:ffff:ffff:ffff:ffff:ffff,BE
2a0c:b648::,2a0c:b67f:ffff:ffff:ffff:ffff:ffff:ffff,EU
2a0c:b680::,2a0c:b687:ffff:ffff:ffff:ffff:ffff:ffff,NO
@@ -97408,7 +97542,7 @@
2a0d:8ac8::,2a0d:8aff:ffff:ffff:ffff:ffff:ffff:ffff,EU
2a0d:8b00::,2a0d:8b07:ffff:ffff:ffff:ffff:ffff:ffff,RU
2a0d:8b08::,2a0d:8b3f:ffff:ffff:ffff:ffff:ffff:ffff,EU
-2a0d:8b40::,2a0d:8b47:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a0d:8b40::,2a0d:8b47:ffff:ffff:ffff:ffff:ffff:ffff,MD
2a0d:8b48::,2a0d:8b7f:ffff:ffff:ffff:ffff:ffff:ffff,EU
2a0d:8b80::,2a0d:8b87:ffff:ffff:ffff:ffff:ffff:ffff,SY
2a0d:8b88::,2a0d:8bbf:ffff:ffff:ffff:ffff:ffff:ffff,EU
@@ -98171,7 +98305,8 @@
2a0d:e501::,2a0d:e53f:ffff:ffff:ffff:ffff:ffff:ffff,EU
2a0d:e540::,2a0d:e547:ffff:ffff:ffff:ffff:ffff:ffff,IT
2a0d:e548::,2a0d:e57f:ffff:ffff:ffff:ffff:ffff:ffff,EU
-2a0d:e580::,2a0d:e587:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a0d:e580::,2a0d:e582:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a0d:e583::,2a0d:e587:ffff:ffff:ffff:ffff:ffff:ffff,UA
2a0d:e588::,2a0d:e5bf:ffff:ffff:ffff:ffff:ffff:ffff,EU
2a0d:e5c0::,2a0d:e5c7:ffff:ffff:ffff:ffff:ffff:ffff,NL
2a0d:e5c8::,2a0d:e5ff:ffff:ffff:ffff:ffff:ffff:ffff,EU
@@ -98537,7 +98672,8 @@
2a0e:e01::,2a0e:e3f:ffff:ffff:ffff:ffff:ffff:ffff,EU
2a0e:e40::,2a0e:e40:ffff:ffff:ffff:ffff:ffff:ffff,GB
2a0e:e41::,2a0e:e42:ffff:ffff:ffff:ffff:ffff:ffff,US
-2a0e:e43::,2a0e:e47:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a0e:e43::,2a0e:e43:ffff:ffff:ffff:ffff:ffff:ffff,ZA
+2a0e:e44::,2a0e:e47:ffff:ffff:ffff:ffff:ffff:ffff,GB
2a0e:e48::,2a0e:e7f:ffff:ffff:ffff:ffff:ffff:ffff,EU
2a0e:e80::,2a0e:e87:ffff:ffff:ffff:ffff:ffff:ffff,DE
2a0e:e88::,2a0e:ebf:ffff:ffff:ffff:ffff:ffff:ffff,EU
@@ -99153,11 +99289,9 @@
2a0e:46c4:1810::,2a0e:46c4:181f:ffff:ffff:ffff:ffff:ffff,US
2a0e:46c4:1820::,2a0e:46c4:20ff:ffff:ffff:ffff:ffff:ffff,EU
2a0e:46c4:2100::,2a0e:46c4:21ff:ffff:ffff:ffff:ffff:ffff,EG
-2a0e:46c4:2200::,2a0e:46c4:229f:ffff:ffff:ffff:ffff:ffff,GB
-2a0e:46c4:22a0::,2a0e:46c4:22a0:ffff:ffff:ffff:ffff:ffff,US
-2a0e:46c4:22a1::,2a0e:46c4:22a1:ffff:ffff:ffff:ffff:ffff,GB
+2a0e:46c4:2200::,2a0e:46c4:22a1:ffff:ffff:ffff:ffff:ffff,GB
2a0e:46c4:22a2::,2a0e:46c4:22a2:ffff:ffff:ffff:ffff:ffff,NL
-2a0e:46c4:22a3::,2a0e:46c4:22a3:ffff:ffff:ffff:ffff:ffff,NO
+2a0e:46c4:22a3::,2a0e:46c4:22a3:ffff:ffff:ffff:ffff:ffff,ES
2a0e:46c4:22a4::,2a0e:46c4:22a5:ffff:ffff:ffff:ffff:ffff,DE
2a0e:46c4:22a6::,2a0e:46c4:22a6:ffff:ffff:ffff:ffff:ffff,SG
2a0e:46c4:22a7::,2a0e:46c4:22a7:ffff:ffff:ffff:ffff:ffff,CN
@@ -99715,7 +99849,13 @@
2a0e:7d44:f100::,2a0e:7d45:ffff:ffff:ffff:ffff:ffff:ffff,CH
2a0e:7d46::,2a0e:7d46:0:ffff:ffff:ffff:ffff:ffff,US
2a0e:7d46:1::,2a0e:7d46:ff:ffff:ffff:ffff:ffff:ffff,EU
-2a0e:7d46:100::,2a0e:7d46:fdff:ffff:ffff:ffff:ffff:ffff,NL
+2a0e:7d46:100::,2a0e:7d46:17ff:ffff:ffff:ffff:ffff:ffff,NL
+2a0e:7d46:1800::,2a0e:7d46:19ff:ffff:ffff:ffff:ffff:ffff,US
+2a0e:7d46:1a00::,2a0e:7d46:1dff:ffff:ffff:ffff:ffff:ffff,NL
+2a0e:7d46:1e00::,2a0e:7d46:1e3f:ffff:ffff:ffff:ffff:ffff,EU
+2a0e:7d46:1e40::,2a0e:7d46:1ec1:ffff:ffff:ffff:ffff:ffff,NL
+2a0e:7d46:1ec2::,2a0e:7d46:1ec2:ffff:ffff:ffff:ffff:ffff,DE
+2a0e:7d46:1ec3::,2a0e:7d46:fdff:ffff:ffff:ffff:ffff:ffff,NL
2a0e:7d46:fe00::,2a0e:7d46:fffe:ffff:ffff:ffff:ffff:ffff,EU
2a0e:7d46:ffff::,2a0e:7d46:ffff:ffff:ffff:ffff:ffff:ffff,US
2a0e:7d47::,2a0e:7d47:ffff:ffff:ffff:ffff:ffff:ffff,CH
@@ -99977,10 +100117,9 @@
2a0e:8f02:2222::,2a0e:8f02:222f:ffff:ffff:ffff:ffff:ffff,FR
2a0e:8f02:2230::,2a0e:8f02:223f:ffff:ffff:ffff:ffff:ffff,DE
2a0e:8f02:2240::,2a0e:8f02:225f:ffff:ffff:ffff:ffff:ffff,DK
-2a0e:8f02:2260::,2a0e:8f02:2260:ffff:ffff:ffff:ffff:ffff,GB
+2a0e:8f02:2260::,2a0e:8f02:2260:ffff:ffff:ffff:ffff:ffff,EU
2a0e:8f02:2261::,2a0e:8f02:2262:ffff:ffff:ffff:ffff:ffff,DE
-2a0e:8f02:2263::,2a0e:8f02:226f:ffff:ffff:ffff:ffff:ffff,GB
-2a0e:8f02:2270::,2a0e:8f02:efff:ffff:ffff:ffff:ffff:ffff,EU
+2a0e:8f02:2263::,2a0e:8f02:efff:ffff:ffff:ffff:ffff:ffff,EU
2a0e:8f02:f000::,2a0e:8f02:f000:ffff:ffff:ffff:ffff:ffff,DE
2a0e:8f02:f001::,2a0e:8f02:f001:ffff:ffff:ffff:ffff:ffff,CH
2a0e:8f02:f002::,2a0e:8f02:f002:ffff:ffff:ffff:ffff:ffff,EU
@@ -100652,8 +100791,7 @@
2a0e:97c0:4bfa::,2a0e:97c0:4bfa:ffff:ffff:ffff:ffff:ffff,ZW
2a0e:97c0:4bfb::,2a0e:97c0:4bfe:ffff:ffff:ffff:ffff:ffff,EU
2a0e:97c0:4bff::,2a0e:97c0:4bff:ffff:ffff:ffff:ffff:ffff,LI
-2a0e:97c0:4c00::,2a0e:97c1:ff:ffff:ffff:ffff:ffff:ffff,EU
-2a0e:97c1:100::,2a0e:97c1:10f:ffff:ffff:ffff:ffff:ffff,IT
+2a0e:97c0:4c00::,2a0e:97c1:10f:ffff:ffff:ffff:ffff:ffff,EU
2a0e:97c1:110::,2a0e:97c1:11f:ffff:ffff:ffff:ffff:ffff,DE
2a0e:97c1:120::,2a0e:97c1:12f:ffff:ffff:ffff:ffff:ffff,IS
2a0e:97c1:130::,2a0e:97c1:13f:ffff:ffff:ffff:ffff:ffff,IT
@@ -101002,8 +101140,14 @@
2a0e:aa07:e130::,2a0e:aa07:e13f:ffff:ffff:ffff:ffff:ffff,GB
2a0e:aa07:e140::,2a0e:aa07:e140:ffff:ffff:ffff:ffff:ffff,LU
2a0e:aa07:e141::,2a0e:aa07:e141:ffff:ffff:ffff:ffff:ffff,US
-2a0e:aa07:e142::,2a0e:aa07:e14f:ffff:ffff:ffff:ffff:ffff,GB
-2a0e:aa07:e150::,2a0e:aa07:e1ff:ffff:ffff:ffff:ffff:ffff,US
+2a0e:aa07:e142::,2a0e:aa07:e143:ffff:ffff:ffff:ffff:ffff,HK
+2a0e:aa07:e144::,2a0e:aa07:e14f:ffff:ffff:ffff:ffff:ffff,GB
+2a0e:aa07:e150::,2a0e:aa07:e150:ffff:ffff:ffff:ffff:ffff,TW
+2a0e:aa07:e151::,2a0e:aa07:e151:ffff:ffff:ffff:ffff:ffff,CN
+2a0e:aa07:e152::,2a0e:aa07:e152:ffff:ffff:ffff:ffff:ffff,HK
+2a0e:aa07:e153::,2a0e:aa07:e153:ffff:ffff:ffff:ffff:ffff,US
+2a0e:aa07:e154::,2a0e:aa07:e15f:ffff:ffff:ffff:ffff:ffff,TW
+2a0e:aa07:e160::,2a0e:aa07:e1ff:ffff:ffff:ffff:ffff:ffff,US
2a0e:aa07:e200::,2a0e:aa07:e200:ffff:ffff:ffff:ffff:ffff,GB
2a0e:aa07:e201::,2a0e:aa07:e201:ffff:ffff:ffff:ffff:ffff,CN
2a0e:aa07:e202::,2a0e:aa07:e202:ffff:ffff:ffff:ffff:ffff,NO
@@ -101043,14 +101187,14 @@
2a0e:aa07:f090::,2a0e:aa07:f09f:ffff:ffff:ffff:ffff:ffff,US
2a0e:aa07:f0a0::,2a0e:aa07:f0af:ffff:ffff:ffff:ffff:ffff,EU
2a0e:aa07:f0b0::,2a0e:aa07:f0bf:ffff:ffff:ffff:ffff:ffff,US
-2a0e:aa07:f0c0::,2a0e:aa07:f0d0:ffff:ffff:ffff:ffff:ffff,DE
+2a0e:aa07:f0c0::,2a0e:aa07:f0cf:ffff:ffff:ffff:ffff:ffff,DE
+2a0e:aa07:f0d0::,2a0e:aa07:f0d0:ffff:ffff:ffff:ffff:ffff,CN
2a0e:aa07:f0d1::,2a0e:aa07:f0d1:ffff:ffff:ffff:ffff:ffff,HK
2a0e:aa07:f0d2::,2a0e:aa07:f0d2:ffff:ffff:ffff:ffff:ffff,JP
2a0e:aa07:f0d3::,2a0e:aa07:f0d3:ffff:ffff:ffff:ffff:ffff,CN
-2a0e:aa07:f0d4::,2a0e:aa07:f0d4:ffff:ffff:ffff:ffff:ffff,EU
+2a0e:aa07:f0d4::,2a0e:aa07:f0d4:ffff:ffff:ffff:ffff:ffff,DE
2a0e:aa07:f0d5::,2a0e:aa07:f0d5:ffff:ffff:ffff:ffff:ffff,US
-2a0e:aa07:f0d6::,2a0e:aa07:f0df:ffff:ffff:ffff:ffff:ffff,CN
-2a0e:aa07:f0e0::,2a0e:aa07:f0ef:ffff:ffff:ffff:ffff:ffff,DE
+2a0e:aa07:f0d6::,2a0e:aa07:f0ef:ffff:ffff:ffff:ffff:ffff,DE
2a0e:aa07:f0f0::,2a0e:aa07:f0ff:ffff:ffff:ffff:ffff:ffff,US
2a0e:aa07:f100::,2a0e:aa3f:ffff:ffff:ffff:ffff:ffff:ffff,EU
2a0e:aa40::,2a0e:aa47:ffff:ffff:ffff:ffff:ffff:ffff,HU
@@ -102407,16 +102551,18 @@
2a0e:b107:27b8::,2a0e:b107:27bf:ffff:ffff:ffff:ffff:ffff,BR
2a0e:b107:27c0::,2a0e:b107:27c7:ffff:ffff:ffff:ffff:ffff,AT
2a0e:b107:27c8::,2a0e:b107:27d7:ffff:ffff:ffff:ffff:ffff,NL
-2a0e:b107:27d8::,2a0e:b107:27df:ffff:ffff:ffff:ffff:ffff,US
+2a0e:b107:27d8::,2a0e:b107:27dd:ffff:ffff:ffff:ffff:ffff,US
+2a0e:b107:27de::,2a0e:b107:27de:ffff:ffff:ffff:ffff:ffff,PL
+2a0e:b107:27df::,2a0e:b107:27df:ffff:ffff:ffff:ffff:ffff,US
2a0e:b107:27e0::,2a0e:b107:27e7:ffff:ffff:ffff:ffff:ffff,EU
-2a0e:b107:27e8::,2a0e:b107:27e8:ffff:ffff:ffff:ffff:ffff,ID
-2a0e:b107:27e9::,2a0e:b107:27e9:ffff:ffff:ffff:ffff:ffff,JP
+2a0e:b107:27e8::,2a0e:b107:27e9:ffff:ffff:ffff:ffff:ffff,JP
2a0e:b107:27ea::,2a0e:b107:27ea:ffff:ffff:ffff:ffff:ffff,NL
2a0e:b107:27eb::,2a0e:b107:27eb:ffff:ffff:ffff:ffff:ffff,SG
2a0e:b107:27ec::,2a0e:b107:27ec:ffff:ffff:ffff:ffff:ffff,JP
2a0e:b107:27ed::,2a0e:b107:27ef:ffff:ffff:ffff:ffff:ffff,ID
2a0e:b107:27f0::,2a0e:b107:27f7:ffff:ffff:ffff:ffff:ffff,NL
-2a0e:b107:27f8::,2a0e:b107:b106:ffff:ffff:ffff:ffff:ffff,EU
+2a0e:b107:27f8::,2a0e:b107:2807:ffff:ffff:ffff:ffff:ffff,DE
+2a0e:b107:2808::,2a0e:b107:b106:ffff:ffff:ffff:ffff:ffff,EU
2a0e:b107:b107::,2a0e:b107:b107:ffff:ffff:ffff:ffff:ffff,NL
2a0e:b107:b108::,2a0e:b13f:ffff:ffff:ffff:ffff:ffff:ffff,EU
2a0e:b140::,2a0e:b147:ffff:ffff:ffff:ffff:ffff:ffff,RU
@@ -102514,7 +102660,9 @@
2a0e:bb08::,2a0e:bb3f:ffff:ffff:ffff:ffff:ffff:ffff,EU
2a0e:bb40::,2a0e:bb47:ffff:ffff:ffff:ffff:ffff:ffff,SK
2a0e:bb48::,2a0e:bb7f:ffff:ffff:ffff:ffff:ffff:ffff,EU
-2a0e:bb80::,2a0e:bb87:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a0e:bb80::,2a0e:bb80:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a0e:bb81::,2a0e:bb81:0:ffff:ffff:ffff:ffff:ffff,EU
+2a0e:bb81:1::,2a0e:bb87:ffff:ffff:ffff:ffff:ffff:ffff,SE
2a0e:bb88::,2a0e:bbbf:ffff:ffff:ffff:ffff:ffff:ffff,EU
2a0e:bbc0::,2a0e:bbc0:7fff:ffff:ffff:ffff:ffff:ffff,GB
2a0e:bbc0:8000::,2a0e:bbc0:80ff:ffff:ffff:ffff:ffff:ffff,EU
@@ -102745,9 +102893,7 @@
2a0e:d602:3::,2a0e:d602:3:ffff:ffff:ffff:ffff:ffff,FI
2a0e:d602:4::,2a0e:d602:4:ffff:ffff:ffff:ffff:ffff,RU
2a0e:d602:5::,2a0e:d602:ffff:ffff:ffff:ffff:ffff:ffff,SC
-2a0e:d603::,2a0e:d603:f:ffff:ffff:ffff:ffff:ffff,RU
-2a0e:d603:10::,2a0e:d603:ffff:ffff:ffff:ffff:ffff:ffff,SC
-2a0e:d604::,2a0e:d604:0:ffff:ffff:ffff:ffff:ffff,RU
+2a0e:d603::,2a0e:d604:0:ffff:ffff:ffff:ffff:ffff,RU
2a0e:d604:1::,2a0e:d605:ffff:ffff:ffff:ffff:ffff:ffff,SC
2a0e:d606::,2a0e:d606:0:ffff:ffff:ffff:ffff:ffff,RU
2a0e:d606:1::,2a0e:d606:ffff:ffff:ffff:ffff:ffff:ffff,SC
@@ -102792,8 +102938,7 @@
2a0e:da00::,2a0e:da07:ffff:ffff:ffff:ffff:ffff:ffff,AE
2a0e:da08::,2a0e:da3f:ffff:ffff:ffff:ffff:ffff:ffff,EU
2a0e:da40::,2a0e:da40:0:ffff:ffff:ffff:ffff:ffff,FI
-2a0e:da40:1::,2a0e:da40:1:ffff:ffff:ffff:ffff:ffff,SG
-2a0e:da40:2::,2a0e:da40:ff:ffff:ffff:ffff:ffff:ffff,GB
+2a0e:da40:1::,2a0e:da40:ff:ffff:ffff:ffff:ffff:ffff,GB
2a0e:da40:100::,2a0e:da40:13f:ffff:ffff:ffff:ffff:ffff,US
2a0e:da40:140::,2a0e:da40:14f:ffff:ffff:ffff:ffff:ffff,HK
2a0e:da40:150::,2a0e:da40:1ff:ffff:ffff:ffff:ffff:ffff,US
@@ -103271,7 +103416,9 @@
2a0e:fd45:2d70::,2a0e:fd45:2d70:ffff:ffff:ffff:ffff:ffff,GB
2a0e:fd45:2d71::,2a0e:fd45:2d7f:ffff:ffff:ffff:ffff:ffff,EU
2a0e:fd45:2d80::,2a0e:fd45:2d80:ffff:ffff:ffff:ffff:ffff,NL
-2a0e:fd45:2d81::,2a0e:fd45:3fff:ffff:ffff:ffff:ffff:ffff,EU
+2a0e:fd45:2d81::,2a0e:fd45:2d8f:ffff:ffff:ffff:ffff:ffff,EU
+2a0e:fd45:2d90::,2a0e:fd45:2d90:ffff:ffff:ffff:ffff:ffff,NL
+2a0e:fd45:2d91::,2a0e:fd45:3fff:ffff:ffff:ffff:ffff:ffff,EU
2a0e:fd45:4000::,2a0e:fd45:40f1:ffff:ffff:ffff:ffff:ffff,FR
2a0e:fd45:40f2::,2a0e:fd45:40f2:ffff:ffff:ffff:ffff:ffff,DE
2a0e:fd45:40f3::,2a0e:fd45:40f7:ffff:ffff:ffff:ffff:ffff,FR
@@ -104450,7 +104597,12 @@
2a0f:7788::,2a0f:77bf:ffff:ffff:ffff:ffff:ffff:ffff,EU
2a0f:77c0::,2a0f:77c7:ffff:ffff:ffff:ffff:ffff:ffff,DE
2a0f:77c8::,2a0f:77ff:ffff:ffff:ffff:ffff:ffff:ffff,EU
-2a0f:7800::,2a0f:7800:5ff:ffff:ffff:ffff:ffff:ffff,GB
+2a0f:7800::,2a0f:7800:101:ffff:ffff:ffff:ffff:ffff,GB
+2a0f:7800:102::,2a0f:7800:102:ffff:ffff:ffff:ffff:ffff,FR
+2a0f:7800:103::,2a0f:7800:103:ffff:ffff:ffff:ffff:ffff,GB
+2a0f:7800:104::,2a0f:7800:104:ffff:ffff:ffff:ffff:ffff,DE
+2a0f:7800:105::,2a0f:7800:105:ffff:ffff:ffff:ffff:ffff,NL
+2a0f:7800:106::,2a0f:7800:5ff:ffff:ffff:ffff:ffff:ffff,GB
2a0f:7800:600::,2a0f:7800:6ff:ffff:ffff:ffff:ffff:ffff,KR
2a0f:7800:700::,2a0f:7800:701:ffff:ffff:ffff:ffff:ffff,US
2a0f:7800:702::,2a0f:7800:702:ffff:ffff:ffff:ffff:ffff,JP
@@ -104459,7 +104611,8 @@
2a0f:7800:705::,2a0f:7800:705:ffff:ffff:ffff:ffff:ffff,IN
2a0f:7800:706::,2a0f:7800:8ff:ffff:ffff:ffff:ffff:ffff,US
2a0f:7800:900::,2a0f:7800:9ff:ffff:ffff:ffff:ffff:ffff,JP
-2a0f:7800:a00::,2a0f:7800:ff4f:ffff:ffff:ffff:ffff:ffff,GB
+2a0f:7800:a00::,2a0f:7800:aff:ffff:ffff:ffff:ffff:ffff,US
+2a0f:7800:b00::,2a0f:7800:ff4f:ffff:ffff:ffff:ffff:ffff,GB
2a0f:7800:ff50::,2a0f:7800:ff5f:ffff:ffff:ffff:ffff:ffff,AQ
2a0f:7800:ff60::,2a0f:7800:ff6f:ffff:ffff:ffff:ffff:ffff,KP
2a0f:7800:ff70::,2a0f:7800:fffe:ffff:ffff:ffff:ffff:ffff,GB
@@ -104473,13 +104626,16 @@
2a0f:7803::,2a0f:7803:fbff:ffff:ffff:ffff:ffff:ffff,GB
2a0f:7803:fc00::,2a0f:7803:fc00:ffff:ffff:ffff:ffff:ffff,AG
2a0f:7803:fc01::,2a0f:7803:fcff:ffff:ffff:ffff:ffff:ffff,GB
-2a0f:7803:fd00::,2a0f:7803:fddc:ffff:ffff:ffff:ffff:ffff,HK
-2a0f:7803:fddd::,2a0f:7803:fddd:ffff:ffff:ffff:ffff:ffff,AQ
-2a0f:7803:fdde::,2a0f:7803:fdff:ffff:ffff:ffff:ffff:ffff,HK
+2a0f:7803:fd00::,2a0f:7803:fd00:ffff:ffff:ffff:ffff:ffff,AQ
+2a0f:7803:fd01::,2a0f:7803:fdff:ffff:ffff:ffff:ffff:ffff,HK
2a0f:7803:fe00::,2a0f:7803:febf:ffff:ffff:ffff:ffff:ffff,GB
2a0f:7803:fec0::,2a0f:7803:fec1:ffff:ffff:ffff:ffff:ffff,JP
2a0f:7803:fec2::,2a0f:7803:fec2:ffff:ffff:ffff:ffff:ffff,TW
-2a0f:7803:fec3::,2a0f:7803:fed0:ffff:ffff:ffff:ffff:ffff,GB
+2a0f:7803:fec3::,2a0f:7803:fec3:ffff:ffff:ffff:ffff:ffff,KP
+2a0f:7803:fec4::,2a0f:7803:fec4:ffff:ffff:ffff:ffff:ffff,AQ
+2a0f:7803:fec5::,2a0f:7803:fec5:ffff:ffff:ffff:ffff:ffff,SY
+2a0f:7803:fec6::,2a0f:7803:fec6:ffff:ffff:ffff:ffff:ffff,IS
+2a0f:7803:fec7::,2a0f:7803:fed0:ffff:ffff:ffff:ffff:ffff,GB
2a0f:7803:fed1::,2a0f:7803:fed1:ffff:ffff:ffff:ffff:ffff,HK
2a0f:7803:fed2::,2a0f:7803:fed2:ffff:ffff:ffff:ffff:ffff,TW
2a0f:7803:fed3::,2a0f:7803:fed3:ffff:ffff:ffff:ffff:ffff,SG
@@ -105039,7 +105195,8 @@
2a0f:9400:6907::,2a0f:9400:6907:ffff:ffff:ffff:ffff:ffff,US
2a0f:9400:6908::,2a0f:9400:690f:ffff:ffff:ffff:ffff:ffff,GB
2a0f:9400:6910::,2a0f:9400:691f:ffff:ffff:ffff:ffff:ffff,HK
-2a0f:9400:6920::,2a0f:9400:6aff:ffff:ffff:ffff:ffff:ffff,GB
+2a0f:9400:6920::,2a0f:9400:69ff:ffff:ffff:ffff:ffff:ffff,GB
+2a0f:9400:6a00::,2a0f:9400:6aff:ffff:ffff:ffff:ffff:ffff,US
2a0f:9400:6b00::,2a0f:9400:6b3f:ffff:ffff:ffff:ffff:ffff,AQ
2a0f:9400:6b40::,2a0f:9400:6bff:ffff:ffff:ffff:ffff:ffff,GB
2a0f:9400:6c00::,2a0f:9400:6cff:ffff:ffff:ffff:ffff:ffff,CN
@@ -109235,7 +109392,7 @@
2a11:1ac8::,2a11:1aff:ffff:ffff:ffff:ffff:ffff:ffff,EU
2a11:1b00::,2a11:1b07:ffff:ffff:ffff:ffff:ffff:ffff,DE
2a11:1b08::,2a11:1b3f:ffff:ffff:ffff:ffff:ffff:ffff,EU
-2a11:1b40::,2a11:1b47:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a11:1b40::,2a11:1b47:ffff:ffff:ffff:ffff:ffff:ffff,US
2a11:1b48::,2a11:1b7f:ffff:ffff:ffff:ffff:ffff:ffff,EU
2a11:1b80::,2a11:1b87:ffff:ffff:ffff:ffff:ffff:ffff,GB
2a11:1b88::,2a11:1bbf:ffff:ffff:ffff:ffff:ffff:ffff,EU
@@ -109243,7 +109400,7 @@
2a11:1bc8::,2a11:1bff:ffff:ffff:ffff:ffff:ffff:ffff,EU
2a11:1c00::,2a11:1c07:ffff:ffff:ffff:ffff:ffff:ffff,RU
2a11:1c08::,2a11:1c3f:ffff:ffff:ffff:ffff:ffff:ffff,EU
-2a11:1c40::,2a11:1c47:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a11:1c40::,2a11:1c47:ffff:ffff:ffff:ffff:ffff:ffff,US
2a11:1c48::,2a11:1c7f:ffff:ffff:ffff:ffff:ffff:ffff,EU
2a11:1c80::,2a11:1c87:ffff:ffff:ffff:ffff:ffff:ffff,RU
2a11:1c88::,2a11:1cbf:ffff:ffff:ffff:ffff:ffff:ffff,EU
@@ -109281,7 +109438,7 @@
2a11:2048::,2a11:207f:ffff:ffff:ffff:ffff:ffff:ffff,EU
2a11:2080::,2a11:2087:ffff:ffff:ffff:ffff:ffff:ffff,MX
2a11:2088::,2a11:20bf:ffff:ffff:ffff:ffff:ffff:ffff,EU
-2a11:20c0::,2a11:20c7:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a11:20c0::,2a11:20c7:ffff:ffff:ffff:ffff:ffff:ffff,FR
2a11:20c8::,2a11:20ff:ffff:ffff:ffff:ffff:ffff:ffff,EU
2a11:2100::,2a11:2107:ffff:ffff:ffff:ffff:ffff:ffff,GB
2a11:2108::,2a11:213f:ffff:ffff:ffff:ffff:ffff:ffff,EU
@@ -109340,7 +109497,7 @@
2a11:2648::,2a11:267f:ffff:ffff:ffff:ffff:ffff:ffff,EU
2a11:2680::,2a11:2687:ffff:ffff:ffff:ffff:ffff:ffff,RU
2a11:2688::,2a11:26bf:ffff:ffff:ffff:ffff:ffff:ffff,EU
-2a11:26c0::,2a11:26c7:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a11:26c0::,2a11:26c7:ffff:ffff:ffff:ffff:ffff:ffff,MD
2a11:26c8::,2a11:26ff:ffff:ffff:ffff:ffff:ffff:ffff,EU
2a11:2700::,2a11:2707:ffff:ffff:ffff:ffff:ffff:ffff,RU
2a11:2708::,2a11:273f:ffff:ffff:ffff:ffff:ffff:ffff,EU
@@ -109369,7 +109526,9 @@
2a11:29c0:6::,2a11:29c0:c:ffff:ffff:ffff:ffff:ffff,GB
2a11:29c0:d::,2a11:29c0:d:ffff:ffff:ffff:ffff:ffff,DE
2a11:29c0:e::,2a11:29c0:e:ffff:ffff:ffff:ffff:ffff,CA
-2a11:29c0:f::,2a11:29c0:3def:ffff:ffff:ffff:ffff:ffff,GB
+2a11:29c0:f::,2a11:29c0:3dcf:ffff:ffff:ffff:ffff:ffff,GB
+2a11:29c0:3dd0::,2a11:29c0:3ddf:ffff:ffff:ffff:ffff:ffff,NL
+2a11:29c0:3de0::,2a11:29c0:3def:ffff:ffff:ffff:ffff:ffff,GB
2a11:29c0:3df0::,2a11:29c0:3dff:ffff:ffff:ffff:ffff:ffff,FR
2a11:29c0:3e00::,2a11:29c7:ffff:ffff:ffff:ffff:ffff:ffff,GB
2a11:29c8::,2a11:29ff:ffff:ffff:ffff:ffff:ffff:ffff,EU
@@ -109400,7 +109559,7 @@
2a11:2cc8::,2a11:2cff:ffff:ffff:ffff:ffff:ffff:ffff,EU
2a11:2d00::,2a11:2d07:ffff:ffff:ffff:ffff:ffff:ffff,RU
2a11:2d08::,2a11:2d3f:ffff:ffff:ffff:ffff:ffff:ffff,EU
-2a11:2d40::,2a11:2d47:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a11:2d40::,2a11:2d47:ffff:ffff:ffff:ffff:ffff:ffff,US
2a11:2d48::,2a11:2d7f:ffff:ffff:ffff:ffff:ffff:ffff,EU
2a11:2d80::,2a11:2d87:ffff:ffff:ffff:ffff:ffff:ffff,KZ
2a11:2d88::,2a11:2dbf:ffff:ffff:ffff:ffff:ffff:ffff,EU
@@ -110156,7 +110315,7 @@
2a11:8688::,2a11:86bf:ffff:ffff:ffff:ffff:ffff:ffff,EU
2a11:86c0::,2a11:86c7:ffff:ffff:ffff:ffff:ffff:ffff,RU
2a11:86c8::,2a11:86ff:ffff:ffff:ffff:ffff:ffff:ffff,EU
-2a11:8700::,2a11:8707:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a11:8700::,2a11:8707:ffff:ffff:ffff:ffff:ffff:ffff,US
2a11:8708::,2a11:873f:ffff:ffff:ffff:ffff:ffff:ffff,EU
2a11:8740::,2a11:8747:ffff:ffff:ffff:ffff:ffff:ffff,RU
2a11:8748::,2a11:877f:ffff:ffff:ffff:ffff:ffff:ffff,EU
@@ -110218,7 +110377,7 @@
2a11:8e08::,2a11:8e3f:ffff:ffff:ffff:ffff:ffff:ffff,EU
2a11:8e40::,2a11:8e47:ffff:ffff:ffff:ffff:ffff:ffff,UA
2a11:8e48::,2a11:8e7f:ffff:ffff:ffff:ffff:ffff:ffff,EU
-2a11:8e80::,2a11:8e87:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a11:8e80::,2a11:8e87:ffff:ffff:ffff:ffff:ffff:ffff,US
2a11:8e88::,2a11:8ebf:ffff:ffff:ffff:ffff:ffff:ffff,EU
2a11:8ec0::,2a11:8ec7:ffff:ffff:ffff:ffff:ffff:ffff,GB
2a11:8ec8::,2a11:8eff:ffff:ffff:ffff:ffff:ffff:ffff,EU
@@ -110288,7 +110447,7 @@
2a11:9701::,2a11:973f:ffff:ffff:ffff:ffff:ffff:ffff,EU
2a11:9740::,2a11:9747:ffff:ffff:ffff:ffff:ffff:ffff,LT
2a11:9748::,2a11:977f:ffff:ffff:ffff:ffff:ffff:ffff,EU
-2a11:9780::,2a11:9787:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a11:9780::,2a11:9787:ffff:ffff:ffff:ffff:ffff:ffff,US
2a11:9788::,2a11:97bf:ffff:ffff:ffff:ffff:ffff:ffff,EU
2a11:97c0::,2a11:97c7:ffff:ffff:ffff:ffff:ffff:ffff,NL
2a11:97c8::,2a11:97ff:ffff:ffff:ffff:ffff:ffff:ffff,EU
@@ -110511,7 +110670,7 @@
2a11:b1c1::,2a11:b1c1:ffff:ffff:ffff:ffff:ffff:ffff,US
2a11:b1c2::,2a11:b1c7:ffff:ffff:ffff:ffff:ffff:ffff,RU
2a11:b1c8::,2a11:b1ff:ffff:ffff:ffff:ffff:ffff:ffff,EU
-2a11:b200::,2a11:b207:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a11:b200::,2a11:b207:ffff:ffff:ffff:ffff:ffff:ffff,US
2a11:b208::,2a11:b23f:ffff:ffff:ffff:ffff:ffff:ffff,EU
2a11:b240::,2a11:b247:ffff:ffff:ffff:ffff:ffff:ffff,NL
2a11:b248::,2a11:b27f:ffff:ffff:ffff:ffff:ffff:ffff,EU
@@ -110630,7 +110789,7 @@
2a11:c008::,2a11:c03f:ffff:ffff:ffff:ffff:ffff:ffff,EU
2a11:c040::,2a11:c047:ffff:ffff:ffff:ffff:ffff:ffff,ES
2a11:c048::,2a11:c07f:ffff:ffff:ffff:ffff:ffff:ffff,EU
-2a11:c080::,2a11:c087:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a11:c080::,2a11:c087:ffff:ffff:ffff:ffff:ffff:ffff,MD
2a11:c088::,2a11:c0bf:ffff:ffff:ffff:ffff:ffff:ffff,EU
2a11:c0c0::,2a11:c0c7:ffff:ffff:ffff:ffff:ffff:ffff,RU
2a11:c0c8::,2a11:c0ff:ffff:ffff:ffff:ffff:ffff:ffff,EU
@@ -110758,7 +110917,7 @@
2a11:d008::,2a11:d03f:ffff:ffff:ffff:ffff:ffff:ffff,EU
2a11:d040::,2a11:d047:ffff:ffff:ffff:ffff:ffff:ffff,US
2a11:d048::,2a11:d07f:ffff:ffff:ffff:ffff:ffff:ffff,EU
-2a11:d080::,2a11:d087:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a11:d080::,2a11:d087:ffff:ffff:ffff:ffff:ffff:ffff,FR
2a11:d088::,2a11:d0bf:ffff:ffff:ffff:ffff:ffff:ffff,EU
2a11:d0c0::,2a11:d0c7:ffff:ffff:ffff:ffff:ffff:ffff,GB
2a11:d0c8::,2a11:d0ff:ffff:ffff:ffff:ffff:ffff:ffff,EU
@@ -110937,7 +111096,7 @@
2a11:e508::,2a11:e53f:ffff:ffff:ffff:ffff:ffff:ffff,EU
2a11:e540::,2a11:e547:ffff:ffff:ffff:ffff:ffff:ffff,RU
2a11:e548::,2a11:e57f:ffff:ffff:ffff:ffff:ffff:ffff,EU
-2a11:e580::,2a11:e587:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a11:e580::,2a11:e587:ffff:ffff:ffff:ffff:ffff:ffff,US
2a11:e588::,2a11:e5bf:ffff:ffff:ffff:ffff:ffff:ffff,EU
2a11:e5c0::,2a11:e5c7:ffff:ffff:ffff:ffff:ffff:ffff,TR
2a11:e5c8::,2a11:e5ff:ffff:ffff:ffff:ffff:ffff:ffff,EU
@@ -110985,7 +111144,7 @@
2a11:eb08::,2a11:eb3f:ffff:ffff:ffff:ffff:ffff:ffff,EU
2a11:eb40::,2a11:eb47:ffff:ffff:ffff:ffff:ffff:ffff,US
2a11:eb48::,2a11:eb7f:ffff:ffff:ffff:ffff:ffff:ffff,EU
-2a11:eb80::,2a11:eb87:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a11:eb80::,2a11:eb87:ffff:ffff:ffff:ffff:ffff:ffff,US
2a11:eb88::,2a11:ebbf:ffff:ffff:ffff:ffff:ffff:ffff,EU
2a11:ebc0::,2a11:ebc7:ffff:ffff:ffff:ffff:ffff:ffff,RU
2a11:ebc8::,2a11:ebff:ffff:ffff:ffff:ffff:ffff:ffff,EU
@@ -111313,7 +111472,7 @@
2a12:1208::,2a12:123f:ffff:ffff:ffff:ffff:ffff:ffff,EU
2a12:1240::,2a12:1247:ffff:ffff:ffff:ffff:ffff:ffff,RU
2a12:1248::,2a12:127f:ffff:ffff:ffff:ffff:ffff:ffff,EU
-2a12:1280::,2a12:1287:ffff:ffff:ffff:ffff:ffff:ffff,US
+2a12:1280::,2a12:1287:ffff:ffff:ffff:ffff:ffff:ffff,RU
2a12:1288::,2a12:12bf:ffff:ffff:ffff:ffff:ffff:ffff,EU
2a12:12c0::,2a12:12c7:ffff:ffff:ffff:ffff:ffff:ffff,RU
2a12:12c8::,2a12:12ff:ffff:ffff:ffff:ffff:ffff:ffff,EU
@@ -111443,7 +111602,9 @@
2a12:2188::,2a12:21bf:ffff:ffff:ffff:ffff:ffff:ffff,EU
2a12:21c0::,2a12:21c7:ffff:ffff:ffff:ffff:ffff:ffff,BG
2a12:21c8::,2a12:21ff:ffff:ffff:ffff:ffff:ffff:ffff,EU
-2a12:2200::,2a12:2207:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a12:2200::,2a12:2200:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a12:2201::,2a12:2201:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a12:2202::,2a12:2207:ffff:ffff:ffff:ffff:ffff:ffff,RU
2a12:2208::,2a12:223f:ffff:ffff:ffff:ffff:ffff:ffff,EU
2a12:2240::,2a12:2247:ffff:ffff:ffff:ffff:ffff:ffff,DE
2a12:2248::,2a12:227f:ffff:ffff:ffff:ffff:ffff:ffff,EU
@@ -112457,7 +112618,7 @@
2a12:88c8::,2a12:88ff:ffff:ffff:ffff:ffff:ffff:ffff,EU
2a12:8900::,2a12:8907:ffff:ffff:ffff:ffff:ffff:ffff,DK
2a12:8908::,2a12:893f:ffff:ffff:ffff:ffff:ffff:ffff,EU
-2a12:8940::,2a12:8947:ffff:ffff:ffff:ffff:ffff:ffff,US
+2a12:8940::,2a12:8947:ffff:ffff:ffff:ffff:ffff:ffff,NL
2a12:8948::,2a12:897f:ffff:ffff:ffff:ffff:ffff:ffff,EU
2a12:8980::,2a12:8987:ffff:ffff:ffff:ffff:ffff:ffff,DE
2a12:8988::,2a12:89bf:ffff:ffff:ffff:ffff:ffff:ffff,EU
@@ -113094,9 +113255,18 @@
2a12:bec0:430::,2a12:bec0:43f:ffff:ffff:ffff:ffff:ffff,IT
2a12:bec0:440::,2a12:bec0:44f:ffff:ffff:ffff:ffff:ffff,GB
2a12:bec0:450::,2a12:bec0:45f:ffff:ffff:ffff:ffff:ffff,AQ
-2a12:bec0:460::,2a12:bec0:4ff:ffff:ffff:ffff:ffff:ffff,GB
-2a12:bec0:500::,2a12:bec0:50f:ffff:ffff:ffff:ffff:ffff,EE
-2a12:bec0:510::,2a12:bec0:dea:ffff:ffff:ffff:ffff:ffff,GB
+2a12:bec0:460::,2a12:bec0:46f:ffff:ffff:ffff:ffff:ffff,SE
+2a12:bec0:470::,2a12:bec0:47f:ffff:ffff:ffff:ffff:ffff,GB
+2a12:bec0:480::,2a12:bec0:48f:ffff:ffff:ffff:ffff:ffff,NL
+2a12:bec0:490::,2a12:bec0:49f:ffff:ffff:ffff:ffff:ffff,DE
+2a12:bec0:4a0::,2a12:bec0:4ff:ffff:ffff:ffff:ffff:ffff,GB
+2a12:bec0:500::,2a12:bec0:500:ffff:ffff:ffff:ffff:ffff,FI
+2a12:bec0:501::,2a12:bec0:501:ffff:ffff:ffff:ffff:ffff,SE
+2a12:bec0:502::,2a12:bec0:508:ffff:ffff:ffff:ffff:ffff,EE
+2a12:bec0:509::,2a12:bec0:509:ffff:ffff:ffff:ffff:ffff,SE
+2a12:bec0:50a::,2a12:bec0:50f:ffff:ffff:ffff:ffff:ffff,EE
+2a12:bec0:510::,2a12:bec0:51f:ffff:ffff:ffff:ffff:ffff,DE
+2a12:bec0:520::,2a12:bec0:dea:ffff:ffff:ffff:ffff:ffff,GB
2a12:bec0:deb::,2a12:bec0:deb:ffff:ffff:ffff:ffff:ffff,NO
2a12:bec0:dec::,2a12:bec0:ded:ffff:ffff:ffff:ffff:ffff,GB
2a12:bec0:dee::,2a12:bec0:dee:ffff:ffff:ffff:ffff:ffff,DE
@@ -113111,7 +113281,8 @@
2a12:bec0:1000::,2a12:bec0:7002:ffff:ffff:ffff:ffff:ffff,GB
2a12:bec0:7003::,2a12:bec0:7003:ffff:ffff:ffff:ffff:ffff,NO
2a12:bec0:7004::,2a12:bec0:7004:ffff:ffff:ffff:ffff:ffff,GB
-2a12:bec0:7005::,2a12:bec0:7fff:ffff:ffff:ffff:ffff:ffff,EU
+2a12:bec0:7005::,2a12:bec0:7005:ffff:ffff:ffff:ffff:ffff,US
+2a12:bec0:7006::,2a12:bec0:7fff:ffff:ffff:ffff:ffff:ffff,EU
2a12:bec0:8000::,2a12:bec0:b00a:ffff:ffff:ffff:ffff:ffff,GB
2a12:bec0:b00b::,2a12:bec0:b00b:ffff:ffff:ffff:ffff:ffff,NO
2a12:bec0:b00c::,2a12:bec7:ffff:ffff:ffff:ffff:ffff:ffff,GB
@@ -113396,7 +113567,7 @@
2a12:dd47:201::,2a12:dd47:201:ffff:ffff:ffff:ffff:ffff,TW
2a12:dd47:202::,2a12:dd47:202:ffff:ffff:ffff:ffff:ffff,JP
2a12:dd47:203::,2a12:dd47:204:ffff:ffff:ffff:ffff:ffff,GB
-2a12:dd47:205::,2a12:dd47:205:ffff:ffff:ffff:ffff:ffff,FR
+2a12:dd47:205::,2a12:dd47:205:ffff:ffff:ffff:ffff:ffff,CA
2a12:dd47:206::,2a12:dd47:207:ffff:ffff:ffff:ffff:ffff,HK
2a12:dd47:208::,2a12:dd47:20f:ffff:ffff:ffff:ffff:ffff,US
2a12:dd47:210::,2a12:dd47:21f:ffff:ffff:ffff:ffff:ffff,CA
@@ -113418,7 +113589,9 @@
2a12:dd47:3005::,2a12:dd47:3005:ffff:ffff:ffff:ffff:ffff,AG
2a12:dd47:3006::,2a12:dd47:3006:ffff:ffff:ffff:ffff:ffff,TW
2a12:dd47:3007::,2a12:dd47:3007:ffff:ffff:ffff:ffff:ffff,KP
-2a12:dd47:3008::,2a12:dd47:31ff:ffff:ffff:ffff:ffff:ffff,TW
+2a12:dd47:3008::,2a12:dd47:3008:ffff:ffff:ffff:ffff:ffff,TR
+2a12:dd47:3009::,2a12:dd47:3009:ffff:ffff:ffff:ffff:ffff,RU
+2a12:dd47:300a::,2a12:dd47:31ff:ffff:ffff:ffff:ffff:ffff,TW
2a12:dd47:3200::,2a12:dd47:32ff:ffff:ffff:ffff:ffff:ffff,US
2a12:dd47:3300::,2a12:dd47:33ff:ffff:ffff:ffff:ffff:ffff,AT
2a12:dd47:3400::,2a12:dd47:38ff:ffff:ffff:ffff:ffff:ffff,US
@@ -114388,7 +114561,9 @@
2a13:1c8::,2a13:1ff:ffff:ffff:ffff:ffff:ffff:ffff,EU
2a13:200::,2a13:207:ffff:ffff:ffff:ffff:ffff:ffff,DE
2a13:208::,2a13:23f:ffff:ffff:ffff:ffff:ffff:ffff,EU
-2a13:240::,2a13:247:ffff:ffff:ffff:ffff:ffff:ffff,IS
+2a13:240::,2a13:240:0:ffff:ffff:ffff:ffff:ffff,IS
+2a13:240:1::,2a13:240:1:ffff:ffff:ffff:ffff:ffff,NO
+2a13:240:2::,2a13:247:ffff:ffff:ffff:ffff:ffff:ffff,IS
2a13:248::,2a13:27f:ffff:ffff:ffff:ffff:ffff:ffff,EU
2a13:280::,2a13:287:ffff:ffff:ffff:ffff:ffff:ffff,LB
2a13:288::,2a13:2bf:ffff:ffff:ffff:ffff:ffff:ffff,EU
@@ -114595,8 +114770,8 @@
2a13:18c0::,2a13:18c0:0:ffff:ffff:ffff:ffff:ffff,SC
2a13:18c0:1::,2a13:18c0:2:ffff:ffff:ffff:ffff:ffff,US
2a13:18c0:3::,2a13:18c0:ffff:ffff:ffff:ffff:ffff:ffff,SC
-2a13:18c1::,2a13:18c1:ffff:ffff:ffff:ffff:ffff:ffff,US
-2a13:18c2::,2a13:18c7:ffff:ffff:ffff:ffff:ffff:ffff,SC
+2a13:18c1::,2a13:18c2:ffff:ffff:ffff:ffff:ffff:ffff,US
+2a13:18c3::,2a13:18c7:ffff:ffff:ffff:ffff:ffff:ffff,SC
2a13:18c8::,2a13:18ff:ffff:ffff:ffff:ffff:ffff:ffff,EU
2a13:1900::,2a13:1907:ffff:ffff:ffff:ffff:ffff:ffff,TR
2a13:1908::,2a13:193f:ffff:ffff:ffff:ffff:ffff:ffff,EU
@@ -114703,7 +114878,7 @@
2a13:23c8::,2a13:23ff:ffff:ffff:ffff:ffff:ffff:ffff,EU
2a13:2400::,2a13:2407:ffff:ffff:ffff:ffff:ffff:ffff,SA
2a13:2408::,2a13:243f:ffff:ffff:ffff:ffff:ffff:ffff,EU
-2a13:2440::,2a13:2447:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a13:2440::,2a13:2447:ffff:ffff:ffff:ffff:ffff:ffff,BG
2a13:2448::,2a13:247f:ffff:ffff:ffff:ffff:ffff:ffff,EU
2a13:2480::,2a13:2487:ffff:ffff:ffff:ffff:ffff:ffff,GB
2a13:2488::,2a13:24bf:ffff:ffff:ffff:ffff:ffff:ffff,EU
@@ -114877,8 +115052,8 @@
2a13:3608::,2a13:363f:ffff:ffff:ffff:ffff:ffff:ffff,EU
2a13:3640::,2a13:3647:ffff:ffff:ffff:ffff:ffff:ffff,DE
2a13:3648::,2a13:367f:ffff:ffff:ffff:ffff:ffff:ffff,EU
-2a13:3680::,2a13:3680:ffff:ffff:ffff:ffff:ffff:ffff,IQ
-2a13:3681::,2a13:36bf:ffff:ffff:ffff:ffff:ffff:ffff,EU
+2a13:3680::,2a13:3687:ffff:ffff:ffff:ffff:ffff:ffff,IQ
+2a13:3688::,2a13:36bf:ffff:ffff:ffff:ffff:ffff:ffff,EU
2a13:36c0::,2a13:36c0:ffff:ffff:ffff:ffff:ffff:ffff,NL
2a13:36c1::,2a13:36ff:ffff:ffff:ffff:ffff:ffff:ffff,EU
2a13:3700::,2a13:3700:f:ffff:ffff:ffff:ffff:ffff,GB
@@ -115035,7 +115210,7 @@
2a13:4948::,2a13:497f:ffff:ffff:ffff:ffff:ffff:ffff,EU
2a13:4980::,2a13:4987:ffff:ffff:ffff:ffff:ffff:ffff,AE
2a13:4988::,2a13:49bf:ffff:ffff:ffff:ffff:ffff:ffff,EU
-2a13:49c0::,2a13:49c7:ffff:ffff:ffff:ffff:ffff:ffff,US
+2a13:49c0::,2a13:49c7:ffff:ffff:ffff:ffff:ffff:ffff,RU
2a13:49c8::,2a13:49ff:ffff:ffff:ffff:ffff:ffff:ffff,EU
2a13:4a00::,2a13:4a07:ffff:ffff:ffff:ffff:ffff:ffff,CH
2a13:4a08::,2a13:4a3f:ffff:ffff:ffff:ffff:ffff:ffff,EU
@@ -115163,7 +115338,8 @@
2a13:5941::,2a13:5941:0:ffff:ffff:ffff:ffff:ffff,US
2a13:5941:1::,2a13:5941:1:ffff:ffff:ffff:ffff:ffff,KR
2a13:5941:2::,2a13:5941:4:ffff:ffff:ffff:ffff:ffff,DE
-2a13:5941:5::,2a13:5947:ffff:ffff:ffff:ffff:ffff:ffff,FI
+2a13:5941:5::,2a13:5941:5:ffff:ffff:ffff:ffff:ffff,US
+2a13:5941:6::,2a13:5947:ffff:ffff:ffff:ffff:ffff:ffff,FI
2a13:5948::,2a13:597f:ffff:ffff:ffff:ffff:ffff:ffff,EU
2a13:5980::,2a13:5987:ffff:ffff:ffff:ffff:ffff:ffff,RU
2a13:5988::,2a13:59bf:ffff:ffff:ffff:ffff:ffff:ffff,EU
@@ -115642,7 +115818,7 @@
2a13:9188::,2a13:91bf:ffff:ffff:ffff:ffff:ffff:ffff,EU
2a13:91c0::,2a13:91c7:ffff:ffff:ffff:ffff:ffff:ffff,UA
2a13:91c8::,2a13:91ff:ffff:ffff:ffff:ffff:ffff:ffff,EU
-2a13:9200::,2a13:9207:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a13:9200::,2a13:9207:ffff:ffff:ffff:ffff:ffff:ffff,CY
2a13:9208::,2a13:923f:ffff:ffff:ffff:ffff:ffff:ffff,EU
2a13:9240::,2a13:9247:ffff:ffff:ffff:ffff:ffff:ffff,RU
2a13:9248::,2a13:927f:ffff:ffff:ffff:ffff:ffff:ffff,EU
@@ -115811,9 +115987,16 @@
2a13:a5c0::,2a13:a5c0:ffff:ffff:ffff:ffff:ffff:ffff,CN
2a13:a5c1::,2a13:a5c4:ffff:ffff:ffff:ffff:ffff:ffff,GB
2a13:a5c5::,2a13:a5c5:0:ffff:ffff:ffff:ffff:ffff,AQ
-2a13:a5c5:1::,2a13:a5c5:5357:ffff:ffff:ffff:ffff:ffff,US
+2a13:a5c5:1::,2a13:a5c5:1fff:ffff:ffff:ffff:ffff:ffff,US
+2a13:a5c5:2000::,2a13:a5c5:2fff:ffff:ffff:ffff:ffff:ffff,SG
+2a13:a5c5:3000::,2a13:a5c5:30ff:ffff:ffff:ffff:ffff:ffff,DE
+2a13:a5c5:3100::,2a13:a5c5:3fff:ffff:ffff:ffff:ffff:ffff,EU
+2a13:a5c5:4000::,2a13:a5c5:4fff:ffff:ffff:ffff:ffff:ffff,BR
+2a13:a5c5:5000::,2a13:a5c5:5357:ffff:ffff:ffff:ffff:ffff,ZA
2a13:a5c5:5358::,2a13:a5c5:5358:ffff:ffff:ffff:ffff:ffff,JP
-2a13:a5c5:5359::,2a13:a5c6:fff:ffff:ffff:ffff:ffff:ffff,US
+2a13:a5c5:5359::,2a13:a5c5:5fff:ffff:ffff:ffff:ffff:ffff,ZA
+2a13:a5c5:6000::,2a13:a5c5:6fff:ffff:ffff:ffff:ffff:ffff,AU
+2a13:a5c5:7000::,2a13:a5c6:fff:ffff:ffff:ffff:ffff:ffff,US
2a13:a5c6:1000::,2a13:a5c6:1fff:ffff:ffff:ffff:ffff:ffff,HK
2a13:a5c6:2000::,2a13:a5c6:2fff:ffff:ffff:ffff:ffff:ffff,JP
2a13:a5c6:3000::,2a13:a5c6:3fff:ffff:ffff:ffff:ffff:ffff,SG
@@ -116102,7 +116285,7 @@
2a13:bac8::,2a13:baff:ffff:ffff:ffff:ffff:ffff:ffff,EU
2a13:bb00::,2a13:bb07:ffff:ffff:ffff:ffff:ffff:ffff,GB
2a13:bb08::,2a13:bb3f:ffff:ffff:ffff:ffff:ffff:ffff,EU
-2a13:bb40::,2a13:bb47:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2a13:bb40::,2a13:bb47:ffff:ffff:ffff:ffff:ffff:ffff,US
2a13:bb48::,2a13:bb7f:ffff:ffff:ffff:ffff:ffff:ffff,EU
2a13:bb80::,2a13:bb87:ffff:ffff:ffff:ffff:ffff:ffff,GB
2a13:bb88::,2a13:bbbf:ffff:ffff:ffff:ffff:ffff:ffff,EU
@@ -116246,7 +116429,14 @@
2a13:c888::,2a13:c8bf:ffff:ffff:ffff:ffff:ffff:ffff,EU
2a13:c8c0::,2a13:c8c7:ffff:ffff:ffff:ffff:ffff:ffff,FR
2a13:c8c8::,2a13:c8ff:ffff:ffff:ffff:ffff:ffff:ffff,EU
-2a13:c900::,2a13:c907:ffff:ffff:ffff:ffff:ffff:ffff,SC
+2a13:c900::,2a13:c900:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a13:c901::,2a13:c901:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a13:c902::,2a13:c902:ffff:ffff:ffff:ffff:ffff:ffff,LU
+2a13:c903::,2a13:c903:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2a13:c904::,2a13:c904:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2a13:c905::,2a13:c905:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2a13:c906::,2a13:c906:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a13:c907::,2a13:c907:ffff:ffff:ffff:ffff:ffff:ffff,ZA
2a13:c908::,2a13:c93f:ffff:ffff:ffff:ffff:ffff:ffff,EU
2a13:c940::,2a13:c947:ffff:ffff:ffff:ffff:ffff:ffff,IR
2a13:c948::,2a13:c97f:ffff:ffff:ffff:ffff:ffff:ffff,EU
@@ -116375,7 +116565,9 @@
2a13:d848::,2a13:d87f:ffff:ffff:ffff:ffff:ffff:ffff,EU
2a13:d880::,2a13:d887:ffff:ffff:ffff:ffff:ffff:ffff,BG
2a13:d888::,2a13:d8bf:ffff:ffff:ffff:ffff:ffff:ffff,EU
-2a13:d8c0::,2a13:d8c7:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a13:d8c0::,2a13:d8c4:3f:ffff:ffff:ffff:ffff:ffff,DE
+2a13:d8c4:40::,2a13:d8c4:4f:ffff:ffff:ffff:ffff:ffff,EE
+2a13:d8c4:50::,2a13:d8c7:ffff:ffff:ffff:ffff:ffff:ffff,DE
2a13:d8c8::,2a13:d8ff:ffff:ffff:ffff:ffff:ffff:ffff,EU
2a13:d900::,2a13:d900:ffff:ffff:ffff:ffff:ffff:ffff,SK
2a13:d901::,2a13:d901:ffff:ffff:ffff:ffff:ffff:ffff,SI
@@ -116392,7 +116584,7 @@
2a13:d988::,2a13:d9bf:ffff:ffff:ffff:ffff:ffff:ffff,EU
2a13:d9c0::,2a13:d9c7:ffff:ffff:ffff:ffff:ffff:ffff,IS
2a13:d9c8::,2a13:d9ff:ffff:ffff:ffff:ffff:ffff:ffff,EU
-2a13:da00::,2a13:da07:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a13:da00::,2a13:da07:ffff:ffff:ffff:ffff:ffff:ffff,CY
2a13:da08::,2a13:da3f:ffff:ffff:ffff:ffff:ffff:ffff,EU
2a13:da40::,2a13:da47:ffff:ffff:ffff:ffff:ffff:ffff,NL
2a13:da48::,2a13:da7f:ffff:ffff:ffff:ffff:ffff:ffff,EU
@@ -116473,8 +116665,8 @@
2a13:df80:ccd::,2a13:df80:cff:ffff:ffff:ffff:ffff:ffff,CA
2a13:df80:d00::,2a13:df80:dff:ffff:ffff:ffff:ffff:ffff,DE
2a13:df80:e00::,2a13:df80:fff:ffff:ffff:ffff:ffff:ffff,UA
-2a13:df80:1000::,2a13:df80:11ff:ffff:ffff:ffff:ffff:ffff,EU
-2a13:df80:1200::,2a13:df80:130f:ffff:ffff:ffff:ffff:ffff,DE
+2a13:df80:1000::,2a13:df80:10ff:ffff:ffff:ffff:ffff:ffff,EU
+2a13:df80:1100::,2a13:df80:130f:ffff:ffff:ffff:ffff:ffff,DE
2a13:df80:1310::,2a13:df80:131f:ffff:ffff:ffff:ffff:ffff,NL
2a13:df80:1320::,2a13:df80:13f8:ffff:ffff:ffff:ffff:ffff,EU
2a13:df80:13f9::,2a13:df80:13f9:ffff:ffff:ffff:ffff:ffff,DE
@@ -116501,7 +116693,13 @@
2a13:df80:3817::,2a13:df80:381c:ffff:ffff:ffff:ffff:ffff,EU
2a13:df80:381d::,2a13:df80:381d:ffff:ffff:ffff:ffff:ffff,GB
2a13:df80:381e::,2a13:df80:3820:ffff:ffff:ffff:ffff:ffff,EU
-2a13:df80:3821::,2a13:df80:6804:ffff:ffff:ffff:ffff:ffff,GB
+2a13:df80:3821::,2a13:df80:56ff:ffff:ffff:ffff:ffff:ffff,GB
+2a13:df80:5700::,2a13:df80:5700:ffff:ffff:ffff:ffff:ffff,ES
+2a13:df80:5701::,2a13:df80:67ff:ffff:ffff:ffff:ffff:ffff,GB
+2a13:df80:6800::,2a13:df80:6800:ffff:ffff:ffff:ffff:ffff,US
+2a13:df80:6801::,2a13:df80:6801:ffff:ffff:ffff:ffff:ffff,GB
+2a13:df80:6802::,2a13:df80:6802:ffff:ffff:ffff:ffff:ffff,CY
+2a13:df80:6803::,2a13:df80:6804:ffff:ffff:ffff:ffff:ffff,GB
2a13:df80:6805::,2a13:df80:6805:ffff:ffff:ffff:ffff:ffff,LU
2a13:df80:6806::,2a13:df80:6808:ffff:ffff:ffff:ffff:ffff,DE
2a13:df80:6809::,2a13:df80:69ff:ffff:ffff:ffff:ffff:ffff,GB
@@ -116519,31 +116717,25 @@
2a13:df80:8400::,2a13:df80:840f:ffff:ffff:ffff:ffff:ffff,DE
2a13:df80:8410::,2a13:df80:87ff:ffff:ffff:ffff:ffff:ffff,GB
2a13:df80:8800::,2a13:df80:880f:ffff:ffff:ffff:ffff:ffff,ID
-2a13:df80:8810::,2a13:df80:dcfe:ffff:ffff:ffff:ffff:ffff,GB
-2a13:df80:dcff::,2a13:df80:dcff:ffff:ffff:ffff:ffff:ffff,NL
-2a13:df80:dd00::,2a13:df80:efff:ffff:ffff:ffff:ffff:ffff,GB
+2a13:df80:8810::,2a13:df80:efff:ffff:ffff:ffff:ffff:ffff,GB
2a13:df80:f000::,2a13:df80:f000:ffff:ffff:ffff:ffff:ffff,IN
2a13:df80:f001::,2a13:df80:ffff:ffff:ffff:ffff:ffff:ffff,GB
2a13:df81::,2a13:df81:ffff:ffff:ffff:ffff:ffff:ffff,SI
-2a13:df82::,2a13:df82:feff:ffff:ffff:ffff:ffff:ffff,IS
-2a13:df82:ff00::,2a13:df85:ffff:ffff:ffff:ffff:ffff:ffff,GB
-2a13:df86::,2a13:df86:ff:ffff:ffff:ffff:ffff:ffff,EU
-2a13:df86:100::,2a13:df86:1ff:ffff:ffff:ffff:ffff:ffff,DE
-2a13:df86:200::,2a13:df86:411f:ffff:ffff:ffff:ffff:ffff,EU
-2a13:df86:4120::,2a13:df86:412f:ffff:ffff:ffff:ffff:ffff,US
-2a13:df86:4130::,2a13:df86:929f:ffff:ffff:ffff:ffff:ffff,EU
-2a13:df86:92a0::,2a13:df86:92af:ffff:ffff:ffff:ffff:ffff,FR
-2a13:df86:92b0::,2a13:df86:9acf:ffff:ffff:ffff:ffff:ffff,EU
-2a13:df86:9ad0::,2a13:df86:9adf:ffff:ffff:ffff:ffff:ffff,US
-2a13:df86:9ae0::,2a13:df86:b00a:ffff:ffff:ffff:ffff:ffff,EU
-2a13:df86:b00b::,2a13:df86:b00b:ffff:ffff:ffff:ffff:ffff,IS
-2a13:df86:b00c::,2a13:df86:b92f:ffff:ffff:ffff:ffff:ffff,EU
-2a13:df86:b930::,2a13:df86:b93f:ffff:ffff:ffff:ffff:ffff,DE
-2a13:df86:b940::,2a13:df87:fff:ffff:ffff:ffff:ffff:ffff,EU
-2a13:df87:1000::,2a13:df87:1fff:ffff:ffff:ffff:ffff:ffff,US
-2a13:df87:2000::,2a13:df87:2fff:ffff:ffff:ffff:ffff:ffff,EU
-2a13:df87:3000::,2a13:df87:3fff:ffff:ffff:ffff:ffff:ffff,DE
-2a13:df87:4000::,2a13:df87:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a13:df82::,2a13:df82:7fff:ffff:ffff:ffff:ffff:ffff,IE
+2a13:df82:8000::,2a13:df82:91ff:ffff:ffff:ffff:ffff:ffff,IS
+2a13:df82:9200::,2a13:df82:92ff:ffff:ffff:ffff:ffff:ffff,US
+2a13:df82:9300::,2a13:df82:feff:ffff:ffff:ffff:ffff:ffff,IS
+2a13:df82:ff00::,2a13:df84:1fff:ffff:ffff:ffff:ffff:ffff,GB
+2a13:df84:2000::,2a13:df84:2fff:ffff:ffff:ffff:ffff:ffff,US
+2a13:df84:3000::,2a13:df84:6fff:ffff:ffff:ffff:ffff:ffff,GB
+2a13:df84:7000::,2a13:df84:7fff:ffff:ffff:ffff:ffff:ffff,US
+2a13:df84:8000::,2a13:df84:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a13:df85::,2a13:df85:ffff:ffff:ffff:ffff:ffff:ffff,JE
+2a13:df86::,2a13:df86:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a13:df87::,2a13:df87:fff:ffff:ffff:ffff:ffff:ffff,EU
+2a13:df87:1000::,2a13:df87:7fff:ffff:ffff:ffff:ffff:ffff,DE
+2a13:df87:8000::,2a13:df87:bfff:ffff:ffff:ffff:ffff:ffff,GG
+2a13:df87:c000::,2a13:df87:ffff:ffff:ffff:ffff:ffff:ffff,DE
2a13:df88::,2a13:dfbf:ffff:ffff:ffff:ffff:ffff:ffff,EU
2a13:dfc0::,2a13:dfc7:ffff:ffff:ffff:ffff:ffff:ffff,AU
2a13:dfc8::,2a13:dfff:ffff:ffff:ffff:ffff:ffff:ffff,EU
@@ -116562,53 +116754,101 @@
2a13:e140::,2a13:e147:ffff:ffff:ffff:ffff:ffff:ffff,DE
2a13:e148::,2a13:e17f:ffff:ffff:ffff:ffff:ffff:ffff,EU
2a13:e180::,2a13:e187:ffff:ffff:ffff:ffff:ffff:ffff,IR
-2a13:e188::,2a13:e1ff:ffff:ffff:ffff:ffff:ffff:ffff,EU
-2a13:e200::,2a13:e207:ffff:ffff:ffff:ffff:ffff:ffff,GB
-2a13:e208::,2a13:e27f:ffff:ffff:ffff:ffff:ffff:ffff,EU
+2a13:e188::,2a13:e1bf:ffff:ffff:ffff:ffff:ffff:ffff,EU
+2a13:e1c0::,2a13:e1c7:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a13:e1c8::,2a13:e1ff:ffff:ffff:ffff:ffff:ffff:ffff,EU
+2a13:e200::,2a13:e207:ffff:ffff:ffff:ffff:ffff:ffff,CY
+2a13:e208::,2a13:e23f:ffff:ffff:ffff:ffff:ffff:ffff,EU
+2a13:e240::,2a13:e247:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2a13:e248::,2a13:e27f:ffff:ffff:ffff:ffff:ffff:ffff,EU
2a13:e280::,2a13:e287:ffff:ffff:ffff:ffff:ffff:ffff,GB
-2a13:e288::,2a13:e2ff:ffff:ffff:ffff:ffff:ffff:ffff,EU
+2a13:e288::,2a13:e2bf:ffff:ffff:ffff:ffff:ffff:ffff,EU
+2a13:e2c0::,2a13:e2c7:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a13:e2c8::,2a13:e2ff:ffff:ffff:ffff:ffff:ffff:ffff,EU
2a13:e300::,2a13:e307:ffff:ffff:ffff:ffff:ffff:ffff,TR
-2a13:e308::,2a13:e37f:ffff:ffff:ffff:ffff:ffff:ffff,EU
+2a13:e308::,2a13:e33f:ffff:ffff:ffff:ffff:ffff:ffff,EU
+2a13:e340::,2a13:e347:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a13:e348::,2a13:e37f:ffff:ffff:ffff:ffff:ffff:ffff,EU
2a13:e380::,2a13:e387:ffff:ffff:ffff:ffff:ffff:ffff,FR
-2a13:e388::,2a13:e3ff:ffff:ffff:ffff:ffff:ffff:ffff,EU
+2a13:e388::,2a13:e3bf:ffff:ffff:ffff:ffff:ffff:ffff,EU
+2a13:e3c0::,2a13:e3c7:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a13:e3c8::,2a13:e3ff:ffff:ffff:ffff:ffff:ffff:ffff,EU
2a13:e400::,2a13:e407:ffff:ffff:ffff:ffff:ffff:ffff,CY
-2a13:e408::,2a13:e47f:ffff:ffff:ffff:ffff:ffff:ffff,EU
+2a13:e408::,2a13:e43f:ffff:ffff:ffff:ffff:ffff:ffff,EU
+2a13:e440::,2a13:e447:ffff:ffff:ffff:ffff:ffff:ffff,BG
+2a13:e448::,2a13:e47f:ffff:ffff:ffff:ffff:ffff:ffff,EU
2a13:e480::,2a13:e487:ffff:ffff:ffff:ffff:ffff:ffff,AT
-2a13:e488::,2a13:e4ff:ffff:ffff:ffff:ffff:ffff:ffff,EU
+2a13:e488::,2a13:e4bf:ffff:ffff:ffff:ffff:ffff:ffff,EU
+2a13:e4c0::,2a13:e4c7:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a13:e4c8::,2a13:e4ff:ffff:ffff:ffff:ffff:ffff:ffff,EU
2a13:e500::,2a13:e507:ffff:ffff:ffff:ffff:ffff:ffff,UA
-2a13:e508::,2a13:e57f:ffff:ffff:ffff:ffff:ffff:ffff,EU
+2a13:e508::,2a13:e53f:ffff:ffff:ffff:ffff:ffff:ffff,EU
+2a13:e540::,2a13:e547:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a13:e548::,2a13:e57f:ffff:ffff:ffff:ffff:ffff:ffff,EU
2a13:e580::,2a13:e587:ffff:ffff:ffff:ffff:ffff:ffff,NO
-2a13:e588::,2a13:e5ff:ffff:ffff:ffff:ffff:ffff:ffff,EU
+2a13:e588::,2a13:e5bf:ffff:ffff:ffff:ffff:ffff:ffff,EU
+2a13:e5c0::,2a13:e5c0:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a13:e5c1::,2a13:e5ff:ffff:ffff:ffff:ffff:ffff:ffff,EU
2a13:e600::,2a13:e607:ffff:ffff:ffff:ffff:ffff:ffff,UA
-2a13:e608::,2a13:e67f:ffff:ffff:ffff:ffff:ffff:ffff,EU
+2a13:e608::,2a13:e63f:ffff:ffff:ffff:ffff:ffff:ffff,EU
+2a13:e640::,2a13:e647:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a13:e648::,2a13:e67f:ffff:ffff:ffff:ffff:ffff:ffff,EU
2a13:e680::,2a13:e687:ffff:ffff:ffff:ffff:ffff:ffff,GB
-2a13:e688::,2a13:e6ff:ffff:ffff:ffff:ffff:ffff:ffff,EU
+2a13:e688::,2a13:e6bf:ffff:ffff:ffff:ffff:ffff:ffff,EU
+2a13:e6c0::,2a13:e6c7:ffff:ffff:ffff:ffff:ffff:ffff,FI
+2a13:e6c8::,2a13:e6ff:ffff:ffff:ffff:ffff:ffff:ffff,EU
2a13:e700::,2a13:e707:ffff:ffff:ffff:ffff:ffff:ffff,DE
-2a13:e708::,2a13:e77f:ffff:ffff:ffff:ffff:ffff:ffff,EU
+2a13:e708::,2a13:e73f:ffff:ffff:ffff:ffff:ffff:ffff,EU
+2a13:e740::,2a13:e747:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2a13:e748::,2a13:e77f:ffff:ffff:ffff:ffff:ffff:ffff,EU
2a13:e780::,2a13:e787:ffff:ffff:ffff:ffff:ffff:ffff,UA
-2a13:e788::,2a13:e7ff:ffff:ffff:ffff:ffff:ffff:ffff,EU
+2a13:e788::,2a13:e7bf:ffff:ffff:ffff:ffff:ffff:ffff,EU
+2a13:e7c0::,2a13:e7c7:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a13:e7c8::,2a13:e7ff:ffff:ffff:ffff:ffff:ffff:ffff,EU
2a13:e800::,2a13:e807:ffff:ffff:ffff:ffff:ffff:ffff,FR
-2a13:e808::,2a13:e87f:ffff:ffff:ffff:ffff:ffff:ffff,EU
+2a13:e808::,2a13:e83f:ffff:ffff:ffff:ffff:ffff:ffff,EU
+2a13:e840::,2a13:e847:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a13:e848::,2a13:e87f:ffff:ffff:ffff:ffff:ffff:ffff,EU
2a13:e880::,2a13:e887:ffff:ffff:ffff:ffff:ffff:ffff,TR
-2a13:e888::,2a13:e8ff:ffff:ffff:ffff:ffff:ffff:ffff,EU
+2a13:e888::,2a13:e8bf:ffff:ffff:ffff:ffff:ffff:ffff,EU
+2a13:e8c0::,2a13:e8c7:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a13:e8c8::,2a13:e8ff:ffff:ffff:ffff:ffff:ffff:ffff,EU
2a13:e900::,2a13:e907:ffff:ffff:ffff:ffff:ffff:ffff,CZ
-2a13:e908::,2a13:e97f:ffff:ffff:ffff:ffff:ffff:ffff,EU
+2a13:e908::,2a13:e93f:ffff:ffff:ffff:ffff:ffff:ffff,EU
+2a13:e940::,2a13:e947:ffff:ffff:ffff:ffff:ffff:ffff,TR
+2a13:e948::,2a13:e97f:ffff:ffff:ffff:ffff:ffff:ffff,EU
2a13:e980::,2a13:e987:ffff:ffff:ffff:ffff:ffff:ffff,IT
-2a13:e988::,2a13:e9ff:ffff:ffff:ffff:ffff:ffff:ffff,EU
+2a13:e988::,2a13:e9bf:ffff:ffff:ffff:ffff:ffff:ffff,EU
+2a13:e9c0::,2a13:e9c7:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a13:e9c8::,2a13:e9ff:ffff:ffff:ffff:ffff:ffff:ffff,EU
2a13:ea00::,2a13:ea00:ffff:ffff:ffff:ffff:ffff:ffff,RO
-2a13:ea01::,2a13:ea7f:ffff:ffff:ffff:ffff:ffff:ffff,EU
+2a13:ea01::,2a13:ea3f:ffff:ffff:ffff:ffff:ffff:ffff,EU
+2a13:ea40::,2a13:ea47:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a13:ea48::,2a13:ea7f:ffff:ffff:ffff:ffff:ffff:ffff,EU
2a13:ea80::,2a13:ea80:ffff:ffff:ffff:ffff:ffff:ffff,NL
-2a13:ea81::,2a13:eaff:ffff:ffff:ffff:ffff:ffff:ffff,EU
+2a13:ea81::,2a13:eabf:ffff:ffff:ffff:ffff:ffff:ffff,EU
+2a13:eac0::,2a13:eac7:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a13:eac8::,2a13:eaff:ffff:ffff:ffff:ffff:ffff:ffff,EU
2a13:eb00::,2a13:eb07:ffff:ffff:ffff:ffff:ffff:ffff,GR
-2a13:eb08::,2a13:eb7f:ffff:ffff:ffff:ffff:ffff:ffff,EU
+2a13:eb08::,2a13:eb3f:ffff:ffff:ffff:ffff:ffff:ffff,EU
+2a13:eb40::,2a13:eb47:ffff:ffff:ffff:ffff:ffff:ffff,LB
+2a13:eb48::,2a13:eb7f:ffff:ffff:ffff:ffff:ffff:ffff,EU
2a13:eb80::,2a13:eb87:ffff:ffff:ffff:ffff:ffff:ffff,FR
-2a13:eb88::,2a13:ebff:ffff:ffff:ffff:ffff:ffff:ffff,EU
+2a13:eb88::,2a13:ebbf:ffff:ffff:ffff:ffff:ffff:ffff,EU
+2a13:ebc0::,2a13:ebc7:ffff:ffff:ffff:ffff:ffff:ffff,GR
+2a13:ebc8::,2a13:ebff:ffff:ffff:ffff:ffff:ffff:ffff,EU
2a13:ec00::,2a13:ec07:ffff:ffff:ffff:ffff:ffff:ffff,FR
-2a13:ec08::,2a13:ec7f:ffff:ffff:ffff:ffff:ffff:ffff,EU
+2a13:ec08::,2a13:ec3f:ffff:ffff:ffff:ffff:ffff:ffff,EU
+2a13:ec40::,2a13:ec47:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a13:ec48::,2a13:ec7f:ffff:ffff:ffff:ffff:ffff:ffff,EU
2a13:ec80::,2a13:ec87:ffff:ffff:ffff:ffff:ffff:ffff,DK
-2a13:ec88::,2a13:ecff:ffff:ffff:ffff:ffff:ffff:ffff,EU
+2a13:ec88::,2a13:ecbf:ffff:ffff:ffff:ffff:ffff:ffff,EU
+2a13:ecc0::,2a13:ecc7:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a13:ecc8::,2a13:ecff:ffff:ffff:ffff:ffff:ffff:ffff,EU
2a13:ed00::,2a13:ed07:ffff:ffff:ffff:ffff:ffff:ffff,SE
-2a13:ed08::,2a13:ed7f:ffff:ffff:ffff:ffff:ffff:ffff,EU
+2a13:ed08::,2a13:ed3f:ffff:ffff:ffff:ffff:ffff:ffff,EU
+2a13:ed40::,2a13:ed47:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a13:ed48::,2a13:ed7f:ffff:ffff:ffff:ffff:ffff:ffff,EU
2a13:ed80::,2a13:ed87:ffff:ffff:ffff:ffff:ffff:ffff,IR
2a13:ed88::,2a13:edff:ffff:ffff:ffff:ffff:ffff:ffff,EU
2a13:ee00::,2a13:ee07:ffff:ffff:ffff:ffff:ffff:ffff,IT
@@ -116660,8 +116900,8 @@
2a13:f888::,2a13:f8ff:ffff:ffff:ffff:ffff:ffff:ffff,EU
2a13:f900::,2a13:f907:ffff:ffff:ffff:ffff:ffff:ffff,SC
2a13:f908::,2a13:f97f:ffff:ffff:ffff:ffff:ffff:ffff,EU
-2a13:f980::,2a13:f980:ffff:ffff:ffff:ffff:ffff:ffff,NL
-2a13:f981::,2a13:f987:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a13:f980::,2a13:f983:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a13:f984::,2a13:f987:ffff:ffff:ffff:ffff:ffff:ffff,GB
2a13:f988::,2a13:f9ff:ffff:ffff:ffff:ffff:ffff:ffff,EU
2a13:fa00::,2a13:fa07:ffff:ffff:ffff:ffff:ffff:ffff,US
2a13:fa08::,2a13:fa7f:ffff:ffff:ffff:ffff:ffff:ffff,EU
diff --git a/src/config/include.am b/src/config/include.am
index ee38934938..351f32f575 100644
--- a/src/config/include.am
+++ b/src/config/include.am
@@ -12,9 +12,3 @@ EXTRA_DIST+= \
conf_DATA = src/config/torrc.sample
tordata_DATA = src/config/geoip src/config/geoip6
-# fallback_consensus
-
-# If we don't have it, fake it.
-src_config_fallback-consensus:
- touch src/config/fallback-consensus
-
diff --git a/src/config/torrc.sample.in b/src/config/torrc.sample.in
index edc30d043c..639d7c4d68 100644
--- a/src/config/torrc.sample.in
+++ b/src/config/torrc.sample.in
@@ -10,7 +10,7 @@
## for more options you can use in this file.
##
## Tor will look for this file in various places based on your platform:
-## https://www.torproject.org/docs/faq#torrc
+## https://support.torproject.org/tbb/tbb-editing-torrc/
## Tor opens a SOCKS proxy on port 9050 by default -- even if you don't
## configure one below. Set "SOCKSPort 0" if you plan to run Tor only
@@ -78,7 +78,7 @@
################ This section is just for relays #####################
#
-## See https://www.torproject.org/docs/tor-doc-relay for details.
+## See https://community.torproject.org/relay for details.
## Required: what port to advertise for incoming Tor connections.
#ORPort 9001
@@ -166,7 +166,7 @@
## key fingerprint of each Tor relay you control, even if they're on
## different networks. You declare it here so Tor clients can avoid
## using more than one of your relays in a single circuit. See
-## https://www.torproject.org/docs/faq#MultipleRelays
+## https://support.torproject.org/relay-operators/multiple-relays/
## However, you should never include a bridge's fingerprint here, as it would
## break its concealability and potentially reveal its IP/TCP address.
##
@@ -204,9 +204,9 @@
## reject *:* or an accept *:*. Otherwise, you're _augmenting_ (prepending to)
## the default exit policy. Leave commented to just use the default, which is
## described in the man page or at
-## https://www.torproject.org/documentation.html
+## https://support.torproject.org/relay-operators
##
-## Look at https://www.torproject.org/faq-abuse.html#TypicalAbuses
+## Look at https://support.torproject.org/abuse/exit-relay-expectations/
## for issues you might encounter if you use the default exit policy.
##
## If certain IPs and ports are blocked externally, e.g. by your firewall,
@@ -242,11 +242,11 @@
#BridgeDistribution none
## Configuration options can be imported from files or folders using the %include
-## option with the value being a path. This path can have wildcards. Wildcards are
-## expanded first, using lexical order. Then, for each matching file or folder, the following
-## rules are followed: if the path is a file, the options from the file will be parsed as if
-## they were written where the %include option is. If the path is a folder, all files on that
-## folder will be parsed following lexical order. Files starting with a dot are ignored. Files
+## option with the value being a path. This path can have wildcards. Wildcards are
+## expanded first, using lexical order. Then, for each matching file or folder, the following
+## rules are followed: if the path is a file, the options from the file will be parsed as if
+## they were written where the %include option is. If the path is a folder, all files on that
+## folder will be parsed following lexical order. Files starting with a dot are ignored. Files
## on subfolders are ignored.
## The %include option can be used recursively.
#%include /etc/torrc.d/*.conf
diff --git a/src/core/crypto/onion_crypto.c b/src/core/crypto/onion_crypto.c
index 81e4e1b078..0839d8903f 100644
--- a/src/core/crypto/onion_crypto.c
+++ b/src/core/crypto/onion_crypto.c
@@ -64,6 +64,9 @@ static const size_t NTOR3_CIRC_VERIFICATION_LEN = 14;
server_onion_keys_t *
server_onion_keys_new(void)
{
+ if (!get_master_identity_key())
+ return NULL;
+
server_onion_keys_t *keys = tor_malloc_zero(sizeof(server_onion_keys_t));
memcpy(keys->my_identity, router_get_my_id_digest(), DIGEST_LEN);
ed25519_pubkey_copy(&keys->my_ed_identity, get_master_identity_key());
diff --git a/src/core/include.am b/src/core/include.am
index 7752a7974b..d24e5d5137 100644
--- a/src/core/include.am
+++ b/src/core/include.am
@@ -17,6 +17,7 @@ if UNITTESTS_ENABLED
LIBTOR_APP_TESTING_A_SOURCES += $(MODULE_RELAY_SOURCES)
LIBTOR_APP_TESTING_A_SOURCES += $(MODULE_DIRCACHE_SOURCES)
LIBTOR_APP_TESTING_A_SOURCES += $(MODULE_DIRAUTH_SOURCES)
+LIBTOR_APP_TESTING_A_SOURCES += $(MODULE_POW_SOURCES)
src_core_libtor_app_testing_a_SOURCES = $(LIBTOR_APP_TESTING_A_SOURCES)
else
diff --git a/src/core/mainloop/connection.c b/src/core/mainloop/connection.c
index cf25213cb1..5a769f38be 100644
--- a/src/core/mainloop/connection.c
+++ b/src/core/mainloop/connection.c
@@ -187,7 +187,6 @@ static int connection_reached_eof(connection_t *conn);
static int connection_buf_read_from_socket(connection_t *conn,
ssize_t *max_to_read,
int *socket_error);
-static int connection_process_inbuf(connection_t *conn, int package_partial);
static void client_check_address_changed(tor_socket_t sock);
static void set_constrained_socket_buffers(tor_socket_t sock, int size);
@@ -1284,6 +1283,17 @@ socket_failed_from_fd_exhaustion(void)
warn_about_resource_exhaution();
}
+/**
+ * A socket failed from TCP port exhaustion.
+ *
+ * Note down TCP port exhaustion and log a warning. */
+static inline void
+socket_failed_from_tcp_port_exhaustion(void)
+{
+ rep_hist_note_tcp_exhaustion();
+ warn_about_resource_exhaution();
+}
+
#ifdef HAVE_SYS_UN_H
#define UNIX_SOCKET_PURPOSE_CONTROL_SOCKET 0
@@ -2222,13 +2232,6 @@ connection_connect_sockaddr,(connection_t *conn,
tor_socket_strerror(errno));
}
- /*
- * We've got the socket open; give the OOS handler a chance to check
- * against configured maximum socket number, but tell it no exhaustion
- * failure.
- */
- connection_check_oos(get_n_open_sockets(), 0);
-
/* From ip(7): Inform the kernel to not reserve an ephemeral port when using
* bind(2) with a port number of 0. The port will later be automatically
* chosen at connect(2) time, in a way that allows sharing a source port as
@@ -2255,12 +2258,25 @@ connection_connect_sockaddr,(connection_t *conn,
if (bindaddr && bind(s, bindaddr, bindaddr_len) < 0) {
*socket_error = tor_socket_errno(s);
- log_warn(LD_NET,"Error binding network socket: %s",
- tor_socket_strerror(*socket_error));
+ if (ERRNO_IS_EADDRINUSE(*socket_error)) {
+ socket_failed_from_tcp_port_exhaustion();
+ connection_check_oos(get_n_open_sockets(), 1);
+ } else {
+ log_warn(LD_NET,"Error binding network socket: %s",
+ tor_socket_strerror(*socket_error));
+ connection_check_oos(get_n_open_sockets(), 0);
+ }
tor_close_socket(s);
return -1;
}
+ /*
+ * We've got the socket open and bound; give the OOS handler a chance to
+ * check against configured maximum socket number, but tell it no exhaustion
+ * failure.
+ */
+ connection_check_oos(get_n_open_sockets(), 0);
+
tor_assert(options);
if (options->ConstrainedSockets)
set_constrained_socket_buffers(s, (int)options->ConstrainedSockSize);
@@ -3727,9 +3743,16 @@ void
connection_read_bw_exhausted(connection_t *conn, bool is_global_bw)
{
(void)is_global_bw;
- conn->read_blocked_on_bw = 1;
- connection_stop_reading(conn);
- reenable_blocked_connection_schedule();
+ // Double-calls to stop-reading are correlated with stalling for
+ // ssh uploads. Might as well prevent this from happening,
+ // especially the read_blocked_on_bw flag. That was clearly getting
+ // set when it should not be, during an already-blocked XOFF
+ // condition.
+ if (!CONN_IS_EDGE(conn) || !TO_EDGE_CONN(conn)->xoff_received) {
+ conn->read_blocked_on_bw = 1;
+ connection_stop_reading(conn);
+ reenable_blocked_connection_schedule();
+ }
}
/**
@@ -3906,10 +3929,17 @@ reenable_blocked_connections_cb(mainloop_event_t *ev, void *arg)
(void)ev;
(void)arg;
SMARTLIST_FOREACH_BEGIN(get_connection_array(), connection_t *, conn) {
- if (conn->read_blocked_on_bw == 1) {
+ /* For conflux, we noticed logs of connection_start_reading() called
+ * multiple times while we were blocked from a previous XOFF, and this
+ * was log was correlated with stalls during ssh uploads. So we added
+ * this additional check, to avoid connection_start_reading() without
+ * getting an XON. The most important piece is always allowing
+ * the read_blocked_on_bw to get cleared, either way. */
+ if (conn->read_blocked_on_bw == 1 &&
+ (!CONN_IS_EDGE(conn) || !TO_EDGE_CONN(conn)->xoff_received)) {
connection_start_reading(conn);
- conn->read_blocked_on_bw = 0;
}
+ conn->read_blocked_on_bw = 0;
if (conn->write_blocked_on_bw == 1) {
connection_start_writing(conn);
conn->write_blocked_on_bw = 0;
@@ -5181,7 +5211,7 @@ set_constrained_socket_buffers(tor_socket_t sock, int size)
* connection_*_process_inbuf() function. It also passes in
* package_partial if wanted.
*/
-static int
+int
connection_process_inbuf(connection_t *conn, int package_partial)
{
tor_assert(conn);
diff --git a/src/core/mainloop/connection.h b/src/core/mainloop/connection.h
index 8b378b15a4..88bf47a497 100644
--- a/src/core/mainloop/connection.h
+++ b/src/core/mainloop/connection.h
@@ -256,6 +256,7 @@ int connection_wants_to_flush(struct connection_t *conn);
int connection_outbuf_too_full(struct connection_t *conn);
int connection_handle_write(struct connection_t *conn, int force);
int connection_flush(struct connection_t *conn);
+int connection_process_inbuf(struct connection_t *conn, int package_partial);
MOCK_DECL(void, connection_write_to_buf_impl_,
(const char *string, size_t len, struct connection_t *conn,
diff --git a/src/core/mainloop/cpuworker.c b/src/core/mainloop/cpuworker.c
index 39d4899075..a42dbb528d 100644
--- a/src/core/mainloop/cpuworker.c
+++ b/src/core/mainloop/cpuworker.c
@@ -14,7 +14,8 @@
* Right now, we use this infrastructure
* <ul><li>for processing onionskins in onion.c
* <li>for compressing consensuses in consdiffmgr.c,
- * <li>and for calculating diffs and compressing them in consdiffmgr.c.
+ * <li>for calculating diffs and compressing them in consdiffmgr.c.
+ * <li>and for solving onion service PoW challenges in pow.c.
* </ul>
**/
#include "core/or/or.h"
@@ -117,7 +118,7 @@ cpuworker_consensus_has_changed(const networkstatus_t *ns)
* during Tor's lifetime.
*/
void
-cpu_init(void)
+cpuworker_init(void)
{
if (!replyqueue) {
replyqueue = replyqueue_new(0);
@@ -129,7 +130,7 @@ cpu_init(void)
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;
+ const int n_threads = MAX(get_num_cpus(get_options()), 2);
threadpool = threadpool_new(n_threads,
replyqueue,
worker_state_new,
diff --git a/src/core/mainloop/cpuworker.h b/src/core/mainloop/cpuworker.h
index 9eee287c1f..7821f5612f 100644
--- a/src/core/mainloop/cpuworker.h
+++ b/src/core/mainloop/cpuworker.h
@@ -12,9 +12,7 @@
#ifndef TOR_CPUWORKER_H
#define TOR_CPUWORKER_H
-#include "feature/nodelist/networkstatus_st.h"
-
-void cpu_init(void);
+void cpuworker_init(void);
void cpuworkers_rotate_keyinfo(void);
void cpuworker_consensus_has_changed(const networkstatus_t *ns);
diff --git a/src/core/mainloop/mainloop.c b/src/core/mainloop/mainloop.c
index 526f8c37af..658b4b47ee 100644
--- a/src/core/mainloop/mainloop.c
+++ b/src/core/mainloop/mainloop.c
@@ -21,7 +21,7 @@
* <li>signal_callback(), which handles incoming signals.
* </ul>
* 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 @@ connection_add_impl(connection_t *conn, int is_connecting)
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 @@ connection_watch_events(connection_t *conn, watchable_events_t events)
/** Return true iff <b>conn</b> 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 @@ connection_start_reading,(connection_t *conn))
"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 @@ run_connection_housekeeping(int i, time_t now)
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)) {
diff --git a/src/core/mainloop/mainloop.h b/src/core/mainloop/mainloop.h
index 98d0b3a058..64782c1318 100644
--- a/src/core/mainloop/mainloop.h
+++ b/src/core/mainloop/mainloop.h
@@ -38,7 +38,7 @@ typedef enum watchable_events {
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 --git a/src/core/or/channel.c b/src/core/or/channel.c
index c46fa93e58..b5b3f4c4f0 100644
--- a/src/core/or/channel.c
+++ b/src/core/or/channel.c
@@ -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 @@ channel_check_for_duplicates(void)
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);
}
}
@@ -1860,7 +1865,6 @@ channel_do_open_actions(channel_t *chan)
{
tor_addr_t remote_addr;
int started_here;
- time_t now = time(NULL);
int close_origin_circuits = 0;
tor_assert(chan);
@@ -1871,22 +1875,25 @@ channel_do_open_actions(channel_t *chan)
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 */
}
diff --git a/src/core/or/channeltls.c b/src/core/or/channeltls.c
index 9db8e2392d..1f5a466777 100644
--- a/src/core/or/channeltls.c
+++ b/src/core/or/channeltls.c
@@ -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,14 @@ channel_tls_handle_incoming(or_connection_t *orconn)
/* Register it */
channel_register(chan);
+ /* 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, NULL,
+ time(NULL));
+ dos_new_client_conn(orconn, NULL);
+
return chan;
}
diff --git a/src/core/or/circuit_st.h b/src/core/or/circuit_st.h
index be6429438a..c28900e59f 100644
--- a/src/core/or/circuit_st.h
+++ b/src/core/or/circuit_st.h
@@ -88,11 +88,11 @@ struct circuit_t {
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. */
@@ -248,6 +248,27 @@ struct circuit_t {
/** 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 --git a/src/core/or/circuitbuild.c b/src/core/or/circuitbuild.c
index 511df4112b..d6e022e7fa 100644
--- a/src/core/or/circuitbuild.c
+++ b/src/core/or/circuitbuild.c
@@ -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.
*
@@ -45,6 +45,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"
@@ -89,7 +90,8 @@ 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);
@@ -465,6 +467,8 @@ origin_circuit_init(uint8_t purpose, int flags)
((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;
}
@@ -507,6 +511,47 @@ circuit_establish_circuit(uint8_t purpose, extend_info_t *exit_ei, int flags)
return circ;
}
+/**
+ * Build a new conflux circuit for <b>purpose</b>. If <b>exit</b> is defined,
+ * then use that as your exit router, else choose a suitable exit node.
+ * The <b>flags</b> 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, 0) < 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;
+}
+
/** Return the guard state associated with <b>circ</b>, which may be NULL. */
circuit_guard_state_t *
origin_circuit_get_guard_state(origin_circuit_t *circ)
@@ -1444,6 +1489,7 @@ route_len_for_purpose(uint8_t purpose, extend_info_t *exit_ei)
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;
@@ -1927,6 +1973,7 @@ choose_good_exit_server(origin_circuit_t *circ,
* since it should be random. */
tor_assert_nonfatal(is_internal);
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);
@@ -1974,6 +2021,8 @@ warn_if_last_router_excluded(origin_circuit_t *circ,
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";
@@ -2101,6 +2150,8 @@ onion_pick_cpath_exit(origin_circuit_t *circ, extend_info_t *exit_ei,
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 +2160,11 @@ onion_pick_cpath_exit(origin_circuit_t *circ, extend_info_t *exit_ei,
}
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 +2315,8 @@ build_vanguard_middle_exclude_list(uint8_t purpose,
* 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 +2333,9 @@ build_middle_exclude_list(uint8_t purpose,
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 +2429,8 @@ pick_vanguard_middle_node(const or_options_t *options,
* 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 +2445,7 @@ choose_good_middle_server(uint8_t purpose,
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 +2490,8 @@ choose_good_middle_server(uint8_t purpose,
* 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 +2513,7 @@ choose_good_entry_server(uint8_t purpose, cpath_build_state_t *state,
/* 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 +2559,7 @@ onion_extend_cpath(origin_circuit_t *circ)
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 +2572,7 @@ onion_extend_cpath(origin_circuit_t *circ)
}
} 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);
}
diff --git a/src/core/or/circuitbuild.h b/src/core/or/circuitbuild.h
index a66c611132..c76259fc29 100644
--- a/src/core/or/circuitbuild.h
+++ b/src/core/or/circuitbuild.h
@@ -24,6 +24,12 @@ origin_circuit_t *origin_circuit_init(uint8_t purpose, int flags);
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);
@@ -51,7 +57,8 @@ const char *build_state_get_exit_nickname(cpath_build_state_t *state);
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);
diff --git a/src/core/or/circuitlist.c b/src/core/or/circuitlist.c
index 50dc2ee338..b90c7ebb58 100644
--- a/src/core/or/circuitlist.c
+++ b/src/core/or/circuitlist.c
@@ -62,6 +62,8 @@
#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/extendinfo.h"
#include "core/or/status.h"
@@ -118,6 +120,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. */
@@ -841,6 +844,11 @@ circuit_purpose_to_controller_string(uint8_t purpose)
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 +878,8 @@ circuit_purpose_to_controller_hs_state_string(uint8_t purpose)
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 +983,12 @@ circuit_purpose_to_string(uint8_t purpose)
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;
@@ -1841,6 +1857,9 @@ get_circuit_purpose_needed_to_cannibalize(uint8_t purpose)
* 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 +1905,10 @@ circuit_find_to_cannibalize(uint8_t purpose_to_produce, extend_info_t *info,
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",
@@ -2234,6 +2257,11 @@ circuit_mark_for_close_, (circuit_t *circ, int reason, int line,
/* 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 +2305,8 @@ circuit_mark_for_close_, (circuit_t *circ, int reason, int line,
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 +2336,9 @@ circuit_about_to_free(circuit_t *circ)
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 +2381,7 @@ circuit_about_to_free(circuit_t *circ)
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;
@@ -2739,6 +2773,7 @@ circuits_handle_oom(size_t current_allocation)
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 +2866,27 @@ assert_circuit_ok,(const circuit_t *c))
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 --git a/src/core/or/circuitlist.h b/src/core/or/circuitlist.h
index 541a708de2..ca3c5bd0ee 100644
--- a/src/core/or/circuitlist.h
+++ b/src/core/or/circuitlist.h
@@ -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
@@ -247,6 +254,8 @@ MOCK_DECL(void, channel_note_destroy_not_pending,
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 --git a/src/core/or/circuitpadding.c b/src/core/or/circuitpadding.c
index 99dc5f9d83..590a2d60c9 100644
--- a/src/core/or/circuitpadding.c
+++ b/src/core/or/circuitpadding.c
@@ -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 @@ circpad_marked_circuit_for_padding(circuit_t *circ, int reason)
* 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);
diff --git a/src/core/or/circuitstats.c b/src/core/or/circuitstats.c
index f55771c79e..7a6c2014bf 100644
--- a/src/core/or/circuitstats.c
+++ b/src/core/or/circuitstats.c
@@ -709,7 +709,7 @@ circuit_build_times_handle_completed_hop(origin_circuit_t *circ)
* 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 @@ circuit_build_times_parse_state(circuit_build_times_t *cbt,
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 --git a/src/core/or/circuituse.c b/src/core/or/circuituse.c
index dbeea10821..ac9005e1d4 100644
--- a/src/core/or/circuituse.c
+++ b/src/core/or/circuituse.c
@@ -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,6 +75,8 @@
#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);
@@ -97,7 +103,7 @@ circuit_matches_with_rend_stream(const edge_connection_t *edge_conn,
/** Return 1 if <b>circ</b> 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 +143,8 @@ circuit_is_acceptable(const origin_circuit_t *origin_circ,
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 +168,8 @@ circuit_is_acceptable(const origin_circuit_t *origin_circ,
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 +338,7 @@ circuit_get_best(const entry_connection_t *conn,
{
origin_circuit_t *best=NULL;
struct timeval now;
+ time_t now_sec;
tor_assert(conn);
@@ -340,6 +350,14 @@ circuit_get_best(const entry_connection_t *conn,
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 +366,7 @@ circuit_get_best(const entry_connection_t *conn,
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 +713,6 @@ circuit_expire_building(void)
} 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 +951,7 @@ circuit_log_ancient_one_hop_circuits(int age)
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 +1019,8 @@ circuit_stream_is_being_handled(entry_connection_t *conn,
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 +1201,10 @@ circuit_predict_and_launch_new(void)
time_t now = time(NULL);
int flags = 0;
+ /* Attempt to launch predicted conflux circuits. This is outside the HS or
+ * Exit preemptive circuit set. */
+ 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 +1233,7 @@ circuit_predict_and_launch_new(void)
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;
}
@@ -1345,6 +1368,7 @@ circuit_detach_stream(circuit_t *circ, edge_connection_t *conn)
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;
@@ -1377,10 +1401,12 @@ circuit_detach_stream(circuit_t *circ, edge_connection_t *conn)
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 +1458,7 @@ circuit_expire_old_circuits_clientside(void)
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 +1476,8 @@ circuit_expire_old_circuits_clientside(void)
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 +1682,12 @@ circuit_has_opened(origin_circuit_t *circ)
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 +1785,11 @@ circuit_build_failed(origin_circuit_t *circ)
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 +1899,9 @@ circuit_build_failed(origin_circuit_t *circ)
"(%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 +2063,11 @@ circuit_should_cannibalize_to_build(uint8_t purpose_to_build,
return 0;
}
+ /* Do not cannibalize for conflux circuits */
+ if (purpose_to_build == CIRCUIT_PURPOSE_CONFLUX_UNLINKED) {
+ return 0;
+ }
+
return 1;
}
@@ -2507,6 +2552,11 @@ circuit_get_open_circ_or_launch(entry_connection_t *conn,
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 +2585,13 @@ circuit_get_open_circ_or_launch(entry_connection_t *conn,
}
/** Return true iff <b>crypt_path</b> is one of the crypt_paths for
- * <b>circ</b>. */
+ * <b>circ</b>.
+ *
+ * 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 +2629,7 @@ link_apconn_to_circ(entry_connection_t *apconn, origin_circuit_t *circ,
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 +2657,8 @@ link_apconn_to_circ(entry_connection_t *apconn, origin_circuit_t *circ,
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 ||
@@ -2710,6 +2769,9 @@ connection_ap_handshake_attach_chosen_circuit(entry_connection_t *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 +2846,10 @@ connection_ap_handshake_attach_circuit(entry_connection_t *conn)
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 +3009,16 @@ connection_ap_handshake_attach_circuit(entry_connection_t *conn)
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 +3050,8 @@ connection_ap_handshake_attach_circuit(entry_connection_t *conn)
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 +3101,13 @@ circuit_change_purpose(circuit_t *circ, uint8_t new_purpose)
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 +3161,10 @@ mark_circuit_unusable_for_new_conns(origin_circuit_t *circ)
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);
+ }
}
/**
diff --git a/src/core/or/circuituse.h b/src/core/or/circuituse.h
index c737ff1c9d..aa572f3212 100644
--- a/src/core/or/circuituse.h
+++ b/src/core/or/circuituse.h
@@ -52,6 +52,8 @@ void circuit_build_failed(origin_circuit_t *circ);
* 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 +79,11 @@ bool circuit_purpose_is_hs_service(const uint8_t purpose);
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 --git a/src/core/or/conflux.c b/src/core/or/conflux.c
new file mode 100644
index 0000000000..0a2806b1dc
--- /dev/null
+++ b/src/core/or/conflux.c
@@ -0,0 +1,906 @@
+/* Copyright (c) 2021, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file conflux.c
+ * \brief Conflux multipath core algorithms
+ */
+
+#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. */
+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;
+
+ // 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(conflux_cell_t);
+ }
+ 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);
+
+ uint64_t relative_seq = cfx->prev_leg->last_seq_sent -
+ cfx->curr_leg->last_seq_sent;
+
+ tor_assert(cfx->prev_leg->last_seq_sent >=
+ cfx->curr_leg->last_seq_sent);
+ conflux_send_switch_command(cfx->curr_leg->circ, relative_seq);
+ 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);
+ tor_assert(leg);
+
+ 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_cell_t *cell_a = a;
+ const conflux_cell_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, cell_t *cell,
+ relay_header_t *rh)
+{
+ tor_assert(in_circ);
+ tor_assert(cell);
+ tor_assert(rh);
+
+ 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(cell, rh->length);
+
+ /*
+ * 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), rh->length);
+ }
+
+ return 0;
+}
+
+/**
+ * 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_cell(conflux_t *cfx, circuit_t *in_circ,
+ crypt_path_t *layer_hint, cell_t *cell)
+{
+ // 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 (BUG(leg->last_seq_recv <= cfx->last_seq_delivered)) {
+ log_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 {
+ conflux_cell_t *c_cell = tor_malloc_zero(sizeof(conflux_cell_t));
+ c_cell->seq = leg->last_seq_recv;
+
+ memcpy(&c_cell->cell, cell, sizeof(cell_t));
+
+ smartlist_pqueue_add(cfx->ooo_q, conflux_queue_cmp,
+ offsetof(conflux_cell_t, heap_idx), c_cell);
+ total_ooo_q_bytes += sizeof(cell_t);
+
+ /* 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_cell_t *
+conflux_dequeue_cell(conflux_t *cfx)
+{
+ conflux_cell_t *top = 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_cell_t, heap_idx));
+ total_ooo_q_bytes -= sizeof(cell_t);
+ cfx->last_seq_delivered++;
+ return top;
+ } else {
+ return NULL;
+ }
+}
diff --git a/src/core/or/conflux.h b/src/core/or/conflux.h
new file mode 100644
index 0000000000..e01b323317
--- /dev/null
+++ b/src/core/or/conflux.h
@@ -0,0 +1,84 @@
+/* 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"
+
+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 cell for the out-of-order queue.
+ * XXX: Consider trying to use packed_cell_t instead here? */
+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 cell here is always guaranteed to have removed its
+ * extra conflux sequence number, for ease of processing */
+ cell_t cell;
+} conflux_cell_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, cell_t *cell,
+ relay_header_t *rh);
+bool conflux_should_multiplex(int relay_command);
+bool conflux_process_cell(conflux_t *cfx, circuit_t *in_circ,
+ crypt_path_t *layer_hint,
+ cell_t *cell);
+conflux_cell_t *conflux_dequeue_cell(conflux_t *cfx);
+void conflux_note_cell_sent(conflux_t *cfx, circuit_t *circ,
+ uint8_t relay_command);
+
+/* 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 --git a/src/core/or/conflux_cell.c b/src/core/or/conflux_cell.c
new file mode 100644
index 0000000000..a59fa735f1
--- /dev/null
+++ b/src/core/or/conflux_cell.c
@@ -0,0 +1,349 @@
+/* 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, 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,
+ 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] = {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] = {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] = {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 cell_t *cell, const uint16_t cell_len)
+{
+ conflux_cell_link_t *link = NULL;
+ trn_cell_conflux_link_t *trn_cell = NULL;
+
+ tor_assert(cell);
+
+ if (trn_cell_conflux_link_parse(&trn_cell,
+ cell->payload + RELAY_HEADER_SIZE,
+ cell_len) < 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 cell_t *cell, const uint16_t cell_len)
+{
+ /* At the moment, same exact payload so avoid code duplication. */
+ return conflux_cell_parse_link(cell, cell_len);
+}
+
+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 cell_t *cell, uint16_t rh_len)
+{
+ uint32_t seq = 0;
+ trn_cell_conflux_switch_t *switch_cell = NULL;
+ tor_assert(cell);
+
+ if (trn_cell_conflux_switch_parse(&switch_cell,
+ cell->payload + RELAY_HEADER_SIZE,
+ rh_len) < 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();
+ cell_t cell;
+ bool ret = true;
+
+ tor_assert(send_circ);
+ tor_assert(relative_seq < UINT32_MAX);
+
+ memset(&cell, 0, sizeof(cell));
+
+ trn_cell_conflux_switch_set_seqnum(switch_cell, (uint32_t)relative_seq);
+
+ if (trn_cell_conflux_switch_encode(cell.payload, RELAY_PAYLOAD_SIZE,
+ switch_cell) < 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*)cell.payload,
+ RELAY_PAYLOAD_SIZE,
+ TO_ORIGIN_CIRCUIT(send_circ)->cpath->prev);
+ } else {
+ relay_send_command_from_edge(0, send_circ,
+ RELAY_COMMAND_CONFLUX_SWITCH,
+ (const char*)cell.payload,
+ RELAY_PAYLOAD_SIZE, NULL);
+ }
+
+end:
+ trn_cell_conflux_switch_free(switch_cell);
+ return ret;
+}
+
diff --git a/src/core/or/conflux_cell.h b/src/core/or/conflux_cell.h
new file mode 100644
index 0000000000..60fff42241
--- /dev/null
+++ b/src/core/or/conflux_cell.h
@@ -0,0 +1,50 @@
+/* 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"
+
+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 cell_t *cell,
+ const uint16_t cell_len);
+conflux_cell_link_t *conflux_cell_parse_linked(const cell_t *cell,
+ const uint16_t cell_le);
+uint32_t conflux_cell_parse_switch(const cell_t *cell,
+ const uint16_t rh_len);
+
+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 --git a/src/core/or/conflux_params.c b/src/core/or/conflux_params.c
new file mode 100644
index 0000000000..dbf4ae5272
--- /dev/null
+++ b/src/core/or/conflux_params.c
@@ -0,0 +1,290 @@
+/* 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_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
+
+/*
+ * 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;
+/* 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;
+
+/* 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-relay@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 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;
+}
+
+/** 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);
+
+ /* 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);
+
+ count_exit_with_conflux_support(ns);
+}
diff --git a/src/core/or/conflux_params.h b/src/core/or/conflux_params.h
new file mode 100644
index 0000000000..22c3e4ad1f
--- /dev/null
+++ b/src/core/or/conflux_params.h
@@ -0,0 +1,29 @@
+/* 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_drain_pct(void);
+uint8_t conflux_params_get_send_pct(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 --git a/src/core/or/conflux_pool.c b/src/core/or/conflux_pool.c
new file mode 100644
index 0000000000..3a8f6ec8e3
--- /dev/null
+++ b/src/core/or/conflux_pool.c
@@ -0,0 +1,2144 @@
+/* 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;
+ }
+
+ 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_cell_t *, cell, tor_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;
+ }
+ /* 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)));
+
+ if (BUG(CONFLUX_NUM_LEGS(cfx) > CONFLUX_MAX_CIRCS)) {
+ return;
+ }
+
+ 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. */
+static 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);
+
+ /* 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;
+ }
+
+ /* 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);
+ if (!circ) {
+ goto err;
+ }
+ tor_assert(TO_CIRCUIT(circ)->conflux_pending_nonce);
+
+ /* 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) {
+ /* Launch a new leg for this set to recover. */
+ 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);
+ 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. */
+ cfx_del_leg(circ->conflux, circ);
+
+ 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 cell_t *cell,
+ const uint16_t cell_len)
+{
+ unlinked_circuits_t *unlinked = NULL;
+ conflux_cell_link_t *link = NULL;
+
+ tor_assert(circ);
+ tor_assert(cell);
+
+ 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(cell, cell_len);
+ 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 cell_t *cell,
+ const uint16_t cell_len)
+{
+ 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(cell, cell_len);
+ 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), cell_len);
+
+ 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)
+{
+ tor_assert(cfx);
+
+ 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);
+ }
+}
+
+/** 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)
+{
+ shutting_down = true;
+
+ 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 --git a/src/core/or/conflux_pool.h b/src/core/or/conflux_pool.h
new file mode 100644
index 0000000000..afa4d9d058
--- /dev/null
+++ b/src/core/or/conflux_pool.h
@@ -0,0 +1,51 @@
+/* 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"
+
+void conflux_pool_init(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_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 cell_t *cell,
+ const uint16_t cell_len);
+void conflux_process_linked(circuit_t *circ, crypt_path_t *layer_hint,
+ const cell_t *cell, const uint16_t cell_len);
+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);
+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 --git a/src/core/or/conflux_st.h b/src/core/or/conflux_st.h
new file mode 100644
index 0000000000..8d85ad1fbe
--- /dev/null
+++ b/src/core/or/conflux_st.h
@@ -0,0 +1,155 @@
+/* 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;
+
+/**
+ * Maximum number of linked circuits.
+ *
+ * We want to experiment with 3 guards, so we need at least 3 here.
+ *
+ * However, we need 1 more than this, to support using a test circuit to probe
+ * for a faster path, for applications that *require* a specific latency target
+ * (like VoIP).
+ *
+ * We may also want to raise this for traffic analysis defense evaluation.
+ */
+#define CONFLUX_MAX_CIRCS 4
+
+/** 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;
+
+ /**
+ * 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 --git a/src/core/or/conflux_sys.c b/src/core/or/conflux_sys.c
new file mode 100644
index 0000000000..7429b08b8f
--- /dev/null
+++ b/src/core/or/conflux_sys.c
@@ -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 --git a/src/core/or/conflux_sys.h b/src/core/or/conflux_sys.h
new file mode 100644
index 0000000000..f6fb85e007
--- /dev/null
+++ b/src/core/or/conflux_sys.h
@@ -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 --git a/src/core/or/conflux_util.c b/src/core/or/conflux_util.c
new file mode 100644
index 0000000000..31ab983f8f
--- /dev/null
+++ b/src/core/or/conflux_util.c
@@ -0,0 +1,437 @@
+/* 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)
+{
+ 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);
+ }
+}
diff --git a/src/core/or/conflux_util.h b/src/core/or/conflux_util.h
new file mode 100644
index 0000000000..c556ae1848
--- /dev/null
+++ b/src/core/or/conflux_util.h
@@ -0,0 +1,59 @@
+/* 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;
+ }
+}
+
+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 --git a/src/core/or/congestion_control_common.c b/src/core/or/congestion_control_common.c
index f5b7740bed..7dc9dbafdd 100644
--- a/src/core/or/congestion_control_common.c
+++ b/src/core/or/congestion_control_common.c
@@ -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 @@ int32_t cell_queue_low = CELL_QUEUE_LOW_DFLT;
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 @@ congestion_control_new_consensus_params(const networkstatus_t *ns)
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 @@ congestion_control_new_consensus_params(const networkstatus_t *ns)
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 @@ congestion_control_init_params(congestion_control_t *cc,
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 @@ congestion_control_enabled(void)
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 @@ congestion_control_set_cc_enabled(void)
}
/**
+ * 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 @@ congestion_control_init(congestion_control_t *cc,
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 @@ congestion_control_free_(congestion_control_t *cc)
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 @@ congestion_control_free_(congestion_control_t *cc)
/**
* 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 @@ enqueue_timestamp(smartlist_t *timestamps_u64, uint64_t timestamp_usec)
}
/**
- * 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 @@ congestion_control_note_cell_sent(congestion_control_t *cc,
}
/**
- * 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 @@ circuit_has_active_streams(const circuit_t *circ,
*/
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 @@ time_delta_should_use_heuristics(const congestion_control_t *cc)
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 @@ static bool is_monotime_clock_broken = false;
* 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 @@ is_monotime_clock_reliable(void)
* 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 @@ congestion_control_update_circuit_rtt(congestion_control_t *cc,
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 @@ congestion_control_update_circuit_bdp(congestion_control_t *cc,
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 @@ congestion_control_update_circuit_bdp(congestion_control_t *cc,
* 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 @@ congestion_control_update_circuit_bdp(congestion_control_t *cc,
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 @@ congestion_control_update_circuit_bdp(congestion_control_t *cc,
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 @@ congestion_control_update_circuit_bdp(congestion_control_t *cc,
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 @@ congestion_control_update_circuit_bdp(congestion_control_t *cc,
* 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 @@ congestion_control_update_circuit_bdp(congestion_control_t *cc,
*/
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 @@ congestion_control_dispatch_cc_alg(congestion_control_t *cc,
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;
}
@@ -1437,19 +1210,16 @@ bool
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;
diff --git a/src/core/or/congestion_control_common.h b/src/core/or/congestion_control_common.h
index fa8f67bb8b..e185a5d29e 100644
--- a/src/core/or/congestion_control_common.h
+++ b/src/core/or/congestion_control_common.h
@@ -46,16 +46,14 @@ congestion_control_t *congestion_control_new(
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 *);
@@ -174,14 +172,25 @@ percent_max_mix(uint64_t a, uint64_t b, uint8_t pct_max)
}
/* 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 --git a/src/core/or/congestion_control_flow.c b/src/core/or/congestion_control_flow.c
index 90b1927ef9..fa9455a8a1 100644
--- a/src/core/or/congestion_control_flow.c
+++ b/src/core/or/congestion_control_flow.c
@@ -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;
@@ -61,27 +62,6 @@ double cc_stats_flow_xon_outbuf_ma = 0;
#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.
*
@@ -265,13 +245,13 @@ circuit_process_stream_xoff(edge_connection_t *conn,
}
/* 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;
@@ -359,13 +339,13 @@ circuit_process_stream_xon(edge_connection_t *conn,
}
/* 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;
@@ -464,7 +444,7 @@ flow_control_decide_xoff(edge_connection_t *stream)
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;
}
@@ -717,21 +697,6 @@ edge_uses_flow_control(const edge_connection_t *stream)
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)
diff --git a/src/core/or/congestion_control_flow.h b/src/core/or/congestion_control_flow.h
index 5c735cce23..05e25c44d0 100644
--- a/src/core/or/congestion_control_flow.h
+++ b/src/core/or/congestion_control_flow.h
@@ -31,8 +31,6 @@ bool edge_uses_flow_control(const edge_connection_t *stream);
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 --git a/src/core/or/congestion_control_nola.c b/src/core/or/congestion_control_nola.c
deleted file mode 100644
index d8ad69a78c..0000000000
--- a/src/core/or/congestion_control_nola.c
+++ /dev/null
@@ -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 --git a/src/core/or/congestion_control_nola.h b/src/core/or/congestion_control_nola.h
deleted file mode 100644
index 9c7d6e0635..0000000000
--- a/src/core/or/congestion_control_nola.h
+++ /dev/null
@@ -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 --git a/src/core/or/congestion_control_st.h b/src/core/or/congestion_control_st.h
index 0cc4e43938..b87d230c2f 100644
--- a/src/core/or/congestion_control_st.h
+++ b/src/core/or/congestion_control_st.h
@@ -41,8 +41,8 @@ typedef enum {
* 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 @@ typedef enum {
/** 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 @@ struct vegas_params_t {
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 @@ struct congestion_control_t {
* 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 @@ struct congestion_control_t {
* 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 --git a/src/core/or/congestion_control_vegas.c b/src/core/or/congestion_control_vegas.c
index b82c685d51..97f1dc0a0e 100644
--- a/src/core/or/congestion_control_vegas.c
+++ b/src/core/or/congestion_control_vegas.c
@@ -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 @@ uint64_t cc_stats_vegas_circ_exited_ss = 0;
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 @@ cwnd_full_reset(const congestion_control_t *cc)
*/
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 @@ congestion_control_vegas_process_sendme(congestion_control_t *cc,
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 @@ congestion_control_vegas_process_sendme(congestion_control_t *cc,
} 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 @@ congestion_control_vegas_process_sendme(congestion_control_t *cc,
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 --git a/src/core/or/congestion_control_vegas.h b/src/core/or/congestion_control_vegas.h
index 84070664c8..24af16822c 100644
--- a/src/core/or/congestion_control_vegas.h
+++ b/src/core/or/congestion_control_vegas.h
@@ -35,8 +35,7 @@ extern uint64_t cc_stats_vegas_circ_exited_ss;
/* 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 --git a/src/core/or/congestion_control_westwood.c b/src/core/or/congestion_control_westwood.c
deleted file mode 100644
index d28ddf3442..0000000000
--- a/src/core/or/congestion_control_westwood.c
+++ /dev/null
@@ -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 --git a/src/core/or/congestion_control_westwood.h b/src/core/or/congestion_control_westwood.h
deleted file mode 100644
index c6fd596df4..0000000000
--- a/src/core/or/congestion_control_westwood.h
+++ /dev/null
@@ -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 --git a/src/core/or/connection_edge.c b/src/core/or/connection_edge.c
index 7dd0935b47..f21779a80c 100644
--- a/src/core/or/connection_edge.c
+++ b/src/core/or/connection_edge.c
@@ -70,6 +70,7 @@
#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/extendinfo.h"
@@ -628,6 +629,7 @@ connection_half_edge_add(const edge_connection_t *conn,
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 +675,25 @@ connection_half_edge_add(const edge_connection_t *conn,
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 <b>he</b> */
void
half_edge_free_(half_edge_t *he)
@@ -1192,7 +1213,10 @@ connection_ap_expire_beginning(void)
* 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 +1260,7 @@ connection_ap_expire_beginning(void)
}
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 +2054,19 @@ connection_ap_handle_onion(entry_connection_t *conn,
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),
@@ -3101,6 +3139,10 @@ get_unique_stream_id_by_circ(origin_circuit_t *circ)
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 +3154,8 @@ connection_ap_supports_optimistic_data(const entry_connection_t *conn)
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 +3182,8 @@ connection_ap_get_begincell_flags(entry_connection_t *ap_conn)
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 */
@@ -3222,6 +3267,7 @@ connection_ap_handshake_send_begin,(entry_connection_t *ap_conn))
tor_snprintf(payload,RELAY_PAYLOAD_SIZE, "%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);
@@ -3323,7 +3369,8 @@ connection_ap_handshake_send_resolve(entry_connection_t *ap_conn)
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));
diff --git a/src/core/or/connection_edge.h b/src/core/or/connection_edge.h
index 1816f2a463..59fc17dea5 100644
--- a/src/core/or/connection_edge.h
+++ b/src/core/or/connection_edge.h
@@ -218,6 +218,7 @@ int connection_half_edge_is_valid_end(smartlist_t *half_conns,
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;
diff --git a/src/core/or/connection_or.c b/src/core/or/connection_or.c
index dd93628654..343c1a67ed 100644
--- a/src/core/or/connection_or.c
+++ b/src/core/or/connection_or.c
@@ -1080,7 +1080,7 @@ connection_or_group_set_badness_(smartlist_t *group, int force)
* 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 +1089,8 @@ connection_or_group_set_badness_(smartlist_t *group, int force)
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);
diff --git a/src/core/or/connection_st.h b/src/core/or/connection_st.h
index d3a230daa0..87ab6af8d9 100644
--- a/src/core/or/connection_st.h
+++ b/src/core/or/connection_st.h
@@ -88,7 +88,7 @@ struct connection_t {
* 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 --git a/src/core/or/cpath_build_state_st.h b/src/core/or/cpath_build_state_st.h
index 2dc682de81..d4fba552ae 100644
--- a/src/core/or/cpath_build_state_st.h
+++ b/src/core/or/cpath_build_state_st.h
@@ -30,6 +30,8 @@ struct cpath_build_state_t {
* 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 --git a/src/core/or/dos.c b/src/core/or/dos.c
index 5bf7d148d7..ccdb30dbee 100644
--- a/src/core/or/dos.c
+++ b/src/core/or/dos.c
@@ -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"
@@ -528,7 +529,8 @@ conn_update_on_connect(conn_client_stats_t *stats, const tor_addr_t *addr)
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 +560,7 @@ conn_update_on_close(conn_client_stats_t *stats, const tor_addr_t *addr)
{
/* 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 +675,7 @@ dos_cc_new_create_cell(channel_t *chan)
/* 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) {
@@ -808,7 +810,7 @@ dos_geoip_entry_init(clientmap_entry_t *geoip_ent)
* 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
@@ -966,6 +968,7 @@ dos_new_client_conn(or_connection_t *or_conn, const char *transport_name)
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 +976,6 @@ dos_new_client_conn(or_connection_t *or_conn, const char *transport_name)
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 --git a/src/core/or/edge_connection_st.h b/src/core/or/edge_connection_st.h
index 942991f139..e8a3039b33 100644
--- a/src/core/or/edge_connection_st.h
+++ b/src/core/or/edge_connection_st.h
@@ -28,11 +28,15 @@ struct edge_connection_t {
* 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 @@ struct edge_connection_t {
* 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
diff --git a/src/core/or/entry_connection_st.h b/src/core/or/entry_connection_st.h
index 500de7521b..a9484bece2 100644
--- a/src/core/or/entry_connection_st.h
+++ b/src/core/or/entry_connection_st.h
@@ -96,6 +96,10 @@ struct entry_connection_t {
* 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 --git a/src/core/or/include.am b/src/core/or/include.am
index b08f8509cc..d0dffd5d3b 100644
--- a/src/core/or/include.am
+++ b/src/core/or/include.am
@@ -36,9 +36,13 @@ LIBTOR_APP_A_SOURCES += \
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/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
@@ -106,8 +110,13 @@ noinst_HEADERS += \
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/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 \
diff --git a/src/core/or/lttng_cc.inc b/src/core/or/lttng_cc.inc
index de06fa026f..d315be91f7 100644
--- a/src/core/or/lttng_cc.inc
+++ b/src/core/or/lttng_cc.inc
@@ -142,7 +142,7 @@ TRACEPOINT_EVENT(tor_cc, flow_decide_xoff_sending,
/* 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 @@ TRACEPOINT_EVENT(tor_cc, bdp_update,
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 --git a/src/core/or/or.h b/src/core/or/or.h
index dc8f516f0a..088c45342b 100644
--- a/src/core/or/or.h
+++ b/src/core/or/or.h
@@ -185,18 +185,27 @@ struct curve25519_public_key_t;
#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
@@ -436,10 +445,6 @@ typedef enum {
#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"
@@ -735,6 +740,9 @@ typedef struct protover_summary_flags_t {
/** 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. Requires Relay=5 */
+ unsigned int supports_conflux : 1;
} protover_summary_flags_t;
typedef struct routerinfo_t routerinfo_t;
diff --git a/src/core/or/or_circuit_st.h b/src/core/or/or_circuit_st.h
index 11695ec301..d5a7007928 100644
--- a/src/core/or/or_circuit_st.h
+++ b/src/core/or/or_circuit_st.h
@@ -35,10 +35,18 @@ struct or_circuit_t {
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
diff --git a/src/core/or/or_connection_st.h b/src/core/or/or_connection_st.h
index aceed4d2c4..97dfe7a637 100644
--- a/src/core/or/or_connection_st.h
+++ b/src/core/or/or_connection_st.h
@@ -28,7 +28,7 @@ struct or_connection_t {
/** 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 --git a/src/core/or/origin_circuit_st.h b/src/core/or/origin_circuit_st.h
index 73b971f72d..22fc3316b9 100644
--- a/src/core/or/origin_circuit_st.h
+++ b/src/core/or/origin_circuit_st.h
@@ -80,11 +80,18 @@ struct origin_circuit_t {
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 @@ struct origin_circuit_t {
* (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 --git a/src/core/or/policies.c b/src/core/or/policies.c
index a53849b4d0..1864b84d5e 100644
--- a/src/core/or/policies.c
+++ b/src/core/or/policies.c
@@ -1138,7 +1138,7 @@ authdir_policy_middleonly_address(const tor_addr_t *addr, uint16_t port)
/** Check <b>or_options</b> 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 &&
diff --git a/src/core/or/policies.h b/src/core/or/policies.h
index e11e1d0ff5..9276b76d01 100644
--- a/src/core/or/policies.h
+++ b/src/core/or/policies.h
@@ -108,6 +108,7 @@ int authdir_policy_valid_address(const tor_addr_t *addr, uint16_t port);
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 --git a/src/core/or/protover.c b/src/core/or/protover.c
index 4cd6510da7..175bfbdab0 100644
--- a/src/core/or/protover.c
+++ b/src/core/or/protover.c
@@ -55,6 +55,7 @@ static const struct {
{ PRT_PADDING, "Padding"},
{ PRT_CONS, "Cons" },
{ PRT_FLOWCTRL, "FlowCtrl"},
+ { PRT_CONFLUX, "Conflux"},
};
#define N_PROTOCOL_NAMES ARRAY_LENGTH(PROTOCOL_NAMES)
@@ -386,6 +387,7 @@ protocol_list_supports_protocol_or_later(const char *list,
* XXX START OF HAZARDOUS ZONE XXX
*/
/* All protocol version that this relay version supports. */
+#define PR_CONFLUX_V "1"
#define PR_CONS_V "1-2"
#define PR_DESC_V "1-2"
#define PR_DIRCACHE_V "2"
@@ -409,6 +411,7 @@ const char *
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 +474,7 @@ protover_get_supported_protocols(void)
*/
return
+ "Conflux=" PR_CONFLUX_V " "
"Cons=" PR_CONS_V " "
"Desc=" PR_DESC_V " "
"DirCache=" PR_DIRCACHE_V " "
diff --git a/src/core/or/protover.h b/src/core/or/protover.h
index 8f15c02fb2..9d8eb4dcc5 100644
--- a/src/core/or/protover.h
+++ b/src/core/or/protover.h
@@ -37,6 +37,8 @@ struct smartlist_t;
#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
@@ -72,6 +74,7 @@ typedef enum protocol_type_t {
PRT_CONS = 9,
PRT_PADDING = 10,
PRT_FLOWCTRL = 11,
+ PRT_CONFLUX = 12,
} protocol_type_t;
bool protover_list_is_invalid(const char *s);
diff --git a/src/core/or/relay.c b/src/core/or/relay.c
index d4df8ff7f5..6abe802355 100644
--- a/src/core/or/relay.c
+++ b/src/core/or/relay.c
@@ -99,6 +99,9 @@
#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"
static edge_connection_t *relay_lookup_conn(circuit_t *circ, cell_t *cell,
cell_direction_t cell_direction,
@@ -116,6 +119,14 @@ static void adjust_exit_policy_from_exitpolicy_failure(origin_circuit_t *circ,
entry_connection_t *conn,
node_t *node,
const tor_addr_t *addr);
+static int connection_edge_process_ordered_relay_cell(cell_t *cell,
+ circuit_t *circ,
+ edge_connection_t *conn,
+ crypt_path_t *layer_hint,
+ relay_header_t *rh);
+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)?
@@ -441,13 +452,12 @@ relay_lookup_conn(circuit_t *circ, cell_t *cell,
/* 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 &&
!tmpconn->base_.marked_for_close &&
- tmpconn->cpath_layer == layer_hint) {
+ edge_uses_cpath(tmpconn, layer_hint)) {
log_debug(LD_APP,"found conn for stream %d.", rh.stream_id);
return tmpconn;
}
@@ -535,6 +545,10 @@ relay_command_to_string(uint8_t command)
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);
@@ -610,7 +624,7 @@ pad_cell_payload(uint8_t *cell_payload, size_t data_len)
* 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))
@@ -618,6 +632,26 @@ relay_send_command_from_edge_,(streamid_t stream_id, circuit_t *circ,
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 (BUG(!circ)) {
+ log_warn(LD_BUG, "No circuit to send for conflux for relay command %d, "
+ "called from %s:%d", relay_command, filename, lineno);
+ conflux_log_set(LOG_WARN, orig_circ->conflux,
+ CIRCUIT_IS_ORIGIN(orig_circ));
+ circ = orig_circ;
+ } else {
+ /* 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);
+ }
+ }
+
/* XXXX NM Split this function into a separate versions per circuit type? */
tor_assert(circ);
@@ -640,6 +674,7 @@ relay_send_command_from_edge_,(streamid_t stream_id, circuit_t *circ,
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);
@@ -714,11 +749,24 @@ relay_send_command_from_edge_,(streamid_t stream_id, circuit_t *circ,
return -1;
}
+ 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
* we need to. This call needs to be after the circuit_package_relay_cell()
* because the cell digest is set within that function. */
if (relay_command == RELAY_COMMAND_DATA) {
sendme_record_cell_digest_on_circ(circ, cpath_layer);
+
+ /* 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 +790,7 @@ connection_edge_send_command(edge_connection_t *fromconn,
circuit_t *circ;
crypt_path_t *cpath_layer = fromconn->cpath_layer;
tor_assert(fromconn);
+
circ = fromconn->on_circuit;
if (fromconn->base_.marked_for_close) {
@@ -1423,7 +1472,7 @@ connection_edge_process_relay_cell_not_open(
(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 +1483,7 @@ connection_edge_process_relay_cell_not_open(
(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);
@@ -1510,25 +1559,6 @@ connection_edge_process_relay_cell_not_open(
// 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 <b>circ</b>. If it is a stream level
* cell, it is destined for the given <b>conn</b>. If it is a circuit level
* cell, it is destined for the <b>layer_hint</b>. The <b>domain</b> is the
@@ -1632,6 +1662,17 @@ handle_relay_cell_command(cell_t *cell, circuit_t *circ,
/* Now handle all the other commands */
switch (rh->command) {
+ case RELAY_COMMAND_CONFLUX_LINK:
+ conflux_process_link(circ, cell, rh->length);
+ return 0;
+ case RELAY_COMMAND_CONFLUX_LINKED:
+ conflux_process_linked(circ, layer_hint, cell, rh->length);
+ 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, cell, rh);
case RELAY_COMMAND_BEGIN:
case RELAY_COMMAND_BEGIN_DIR:
if (layer_hint &&
@@ -1666,19 +1707,6 @@ handle_relay_cell_command(cell_t *cell, circuit_t *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) {
log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "Relay data cell with zero "
"stream_id. Dropping.");
@@ -1703,7 +1731,6 @@ handle_relay_cell_command(cell_t *cell, circuit_t *circ,
/* 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.");
@@ -2051,9 +2078,6 @@ connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ,
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(circ);
@@ -2086,8 +2110,86 @@ connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ,
}
}
+ /* Regardless of conflux or not, we always decide to send a SENDME
+ * for RELAY_DATA immediately
+ */
+ if (rh.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(rh.command)) {
+ return connection_edge_process_ordered_relay_cell(cell, circ, conn,
+ layer_hint, &rh);
+ } 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_cell(circ->conflux, circ, layer_hint, cell)) {
+ conflux_cell_t *c_cell = NULL;
+ int ret = 0;
+
+ /* First, process this cell */
+ if ((ret = connection_edge_process_ordered_relay_cell(cell, circ, conn,
+ layer_hint, &rh)) < 0) {
+ return ret;
+ }
+
+ /* Now, check queue for more */
+ while ((c_cell = conflux_dequeue_cell(circ->conflux))) {
+ relay_header_unpack(&rh, c_cell->cell.payload);
+ conn = relay_lookup_conn(circ, &c_cell->cell, CELL_DIRECTION_OUT,
+ layer_hint);
+ if ((ret = connection_edge_process_ordered_relay_cell(&c_cell->cell,
+ circ, conn, layer_hint,
+ &rh)) < 0) {
+ /* Negative return value is a fatal error. Return early and tear down
+ * circuit */
+ tor_free(c_cell);
+ return ret;
+ }
+ tor_free(c_cell);
+ }
+ }
+ }
+
+ 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(cell_t *cell, circuit_t *circ,
+ edge_connection_t *conn,
+ crypt_path_t *layer_hint,
+ relay_header_t *rh)
+{
+ 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, rh->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 +2197,22 @@ connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ,
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) {
+ rh->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 (rh->stream_id == 0 && rh->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);
+ rh, cell, circ, conn, layer_hint);
}
}
return handle_relay_cell_command(cell, circ, conn, layer_hint,
- &rh, optimistic_data);
+ rh, optimistic_data);
}
/** How many relay_data cells have we built, ever? */
@@ -2234,7 +2336,7 @@ connection_edge_package_raw_inbuf(edge_connection_t *conn, int package_partial,
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);
@@ -2313,21 +2415,13 @@ connection_edge_package_raw_inbuf(edge_connection_t *conn, int package_partial,
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 +2453,15 @@ circuit_resume_edge_reading(circuit_t *circ, crypt_path_t *layer_hint)
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 +2495,6 @@ circuit_resume_edge_reading_helper(edge_connection_t *first_conn,
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 +2533,13 @@ circuit_resume_edge_reading_helper(edge_connection_t *first_conn,
/* 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 +2547,13 @@ circuit_resume_edge_reading_helper(edge_connection_t *first_conn,
}
/* 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 +2565,32 @@ circuit_resume_edge_reading_helper(edge_connection_t *first_conn,
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 +2604,7 @@ circuit_resume_edge_reading_helper(edge_connection_t *first_conn,
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 +2638,6 @@ circuit_resume_edge_reading_helper(edge_connection_t *first_conn,
*/
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 +2661,7 @@ circuit_consider_stop_edge_reading(circuit_t *circ, crypt_path_t *layer_hint)
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 +2672,11 @@ circuit_consider_stop_edge_reading(circuit_t *circ, crypt_path_t *layer_hint)
/* 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,6 +2912,8 @@ cell_queues_check_size(void)
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) {
@@ -2825,6 +2945,14 @@ cell_queues_check_size(void)
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;
@@ -2902,44 +3030,63 @@ channel_unlink_all_circuits(channel_t *chan, smartlist_t *circuits_out)
chan->num_p_circuits = 0;
}
-/** Block (if <b>block</b> is true) or unblock (if <b>block</b> is false)
+/**
+ * Called when a circuit becomes blocked or unblocked due to the channel
+ * cell queue.
+ *
+ * Block (if <b>block</b> is true) or unblock (if <b>block</b> is false)
* every edge connection that is using <b>circ</b> to write to <b>chan</b>,
* and start or stop reading as appropriate.
- *
- * If <b>stream_id</b> 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 <b>stream_id</b> is 0, apply the <b>block</b> 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 +3099,6 @@ set_streams_blocked_on_circ(circuit_t *circ, channel_t *chan,
connection_start_reading(conn);
}
}
-
- return n;
}
/** Extract the command from a packed cell. */
@@ -2991,7 +3136,7 @@ channel_flush_from_first_active_circuit, (channel_t *chan, int max))
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 +3176,31 @@ channel_flush_from_first_active_circuit, (channel_t *chan, int max))
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 +3282,8 @@ channel_flush_from_first_active_circuit, (channel_t *chan, int max))
/* 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 +3295,7 @@ channel_flush_from_first_active_circuit, (channel_t *chan, int max))
/* 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 +3328,7 @@ channel_flush_from_first_active_circuit, (channel_t *chan, int max))
#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;
@@ -3230,9 +3388,10 @@ append_cell_to_circuit_queue(circuit_t *circ, channel_t *chan,
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;
@@ -3240,13 +3399,16 @@ append_cell_to_circuit_queue(circuit_t *circ, channel_t *chan,
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)) {
@@ -3279,14 +3441,16 @@ append_cell_to_circuit_queue(circuit_t *circ, channel_t *chan,
return;
}
- /* 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 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 (streams_blocked && fromstream) {
- /* This edge connection is apparently not blocked; block it. */
- set_streams_blocked_on_circ(circ, chan, 1, fromstream);
+ 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);
@@ -3392,8 +3556,8 @@ static int
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->streams_blocked_on_p_chan;
+ return circ->circuit_blocked_on_p_chan;
}
}
diff --git a/src/core/or/scheduler.h b/src/core/or/scheduler.h
index 7d3c6f7390..dab7f37f0e 100644
--- a/src/core/or/scheduler.h
+++ b/src/core/or/scheduler.h
@@ -102,9 +102,9 @@ typedef struct scheduler_t {
*****************************************************************************/
/* 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 --git a/src/core/or/scheduler_kist.c b/src/core/or/scheduler_kist.c
index 52bc62f1b4..69804247c8 100644
--- a/src/core/or/scheduler_kist.c
+++ b/src/core/or/scheduler_kist.c
@@ -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"
@@ -810,12 +811,19 @@ kist_scheduler_run_interval(void)
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 --git a/src/core/or/sendme.c b/src/core/or/sendme.c
index 90f4dfcf05..03af990484 100644
--- a/src/core/or/sendme.c
+++ b/src/core/or/sendme.c
@@ -351,7 +351,7 @@ circuit_sendme_cell_is_next(int deliver_window, int sendme_inc)
*
* 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.
+ * first convert to received cells, or the modulus operator will fail.
*/
tor_assert(deliver_window <= CIRCWINDOW_START);
if (((CIRCWINDOW_START - (deliver_window - 1)) % sendme_inc) != 0) {
@@ -491,7 +491,7 @@ sendme_process_circuit_level(crypt_path_t *layer_hint,
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);
}
/**
diff --git a/src/core/or/versions.c b/src/core/or/versions.c
index 9913b3ee31..8f5503691e 100644
--- a/src/core/or/versions.c
+++ b/src/core/or/versions.c
@@ -488,6 +488,13 @@ memoize_protover_summary(protover_summary_flags_t *out,
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);
+
protover_summary_flags_t *new_cached = tor_memdup(out, sizeof(*out));
cached = strmap_set(protover_summary_map, protocols, new_cached);
tor_assert(!cached);
diff --git a/src/ext/.may_include b/src/ext/.may_include
index 1eafff2eeb..f55772f731 100644
--- a/src/ext/.may_include
+++ b/src/ext/.may_include
@@ -7,4 +7,6 @@ lib/cc/*.h
tinytest*.h
ext/siphash.h
ext/byteorder.h
-ext/tor_readpassphrase.h \ No newline at end of file
+ext/tor_readpassphrase.h
+
+ext/equix/hashx/src/blake2.h \ No newline at end of file
diff --git a/src/ext/Makefile.nmake b/src/ext/Makefile.nmake
deleted file mode 100644
index d02d03bf41..0000000000
--- a/src/ext/Makefile.nmake
+++ /dev/null
@@ -1,12 +0,0 @@
-all: csiphash.lib
-
-CFLAGS = /O2 /MT /I ..\win32 /I ..\..\..\build-alpha\include /I ..\common \
- /I ..\ext
-
-CSIPHASH_OBJECTS = csiphash.obj
-
-csiphash.lib: $(CSIPHASH_OBJECTS)
- lib $(CSIPHASH_OBJECTS) $(CURVE25519_DONNA_OBJECTS) /out:csiphash.lib
-
-clean:
- del *.obj *.lib
diff --git a/src/ext/compat_blake2.h b/src/ext/compat_blake2.h
new file mode 100644
index 0000000000..01adb2c34a
--- /dev/null
+++ b/src/ext/compat_blake2.h
@@ -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 <stddef.h>
+#include <string.h>
+#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 --git a/src/ext/equix/CMakeLists.txt b/src/ext/equix/CMakeLists.txt
new file mode 100644
index 0000000000..a9d0665408
--- /dev/null
+++ b/src/ext/equix/CMakeLists.txt
@@ -0,0 +1,75 @@
+# Copyright (c) 2020 tevador <tevador@gmail.com>
+# See LICENSE for licensing information
+
+cmake_minimum_required(VERSION 2.8.8)
+
+set(EQUIX_VERSION 1)
+set(EQUIX_VERSION_MINOR 0)
+set(EQUIX_VERSION_PATCH 0)
+set(EQUIX_VERSION_STR "${EQUIX_VERSION}.${EQUIX_VERSION_MINOR}.${EQUIX_VERSION_PATCH}")
+
+project(equix)
+
+add_definitions(-DHASHX_SIZE=8)
+add_definitions(-DEQUIX_SUPPORT_HUGEPAGES)
+
+add_subdirectory("hashx")
+
+set(equix_sources
+src/context.c
+src/equix.c
+src/solver.c)
+
+if(NOT CMAKE_BUILD_TYPE)
+ set(CMAKE_BUILD_TYPE Release)
+ message(STATUS "Setting default build type: ${CMAKE_BUILD_TYPE}")
+endif()
+
+include_directories(
+ include/
+ hashx/include/
+ hashx/src/)
+
+add_library(equix SHARED ${equix_sources})
+set_property(TARGET equix PROPERTY POSITION_INDEPENDENT_CODE ON)
+set_property(TARGET equix PROPERTY PUBLIC_HEADER include/equix.h)
+target_compile_definitions(equix PRIVATE HASHX_STATIC)
+target_compile_definitions(equix PRIVATE EQUIX_SHARED)
+target_link_libraries(equix
+ PRIVATE hashx_static)
+set_target_properties(equix PROPERTIES VERSION ${EQUIX_VERSION_STR}
+ SOVERSION ${EQUIX_VERSION})
+
+add_library(equix_static STATIC ${equix_sources})
+set_property(TARGET equix_static PROPERTY POSITION_INDEPENDENT_CODE ON)
+set_target_properties(equix_static PROPERTIES OUTPUT_NAME equix)
+target_compile_definitions(equix_static PRIVATE HASHX_STATIC)
+target_compile_definitions(equix_static PRIVATE EQUIX_STATIC)
+target_link_libraries(equix_static
+ PRIVATE hashx_static)
+
+include(GNUInstallDirs)
+install(TARGETS equix equix_static
+ LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+ ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
+ PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
+
+add_executable(equix-tests
+ src/tests.c)
+target_compile_definitions(equix-tests PRIVATE EQUIX_STATIC)
+target_link_libraries(equix-tests
+ PRIVATE equix_static)
+
+if(NOT Threads_FOUND AND UNIX AND NOT APPLE)
+ set(THREADS_PREFER_PTHREAD_FLAG ON)
+ find_package(Threads)
+endif()
+
+add_executable(equix-bench
+ src/bench.c
+ hashx/src/hashx_thread.c
+ hashx/src/hashx_time.c)
+target_compile_definitions(equix-bench PRIVATE EQUIX_STATIC)
+target_link_libraries(equix-bench
+ PRIVATE equix_static
+ PRIVATE ${CMAKE_THREAD_LIBS_INIT})
diff --git a/src/ext/equix/Cargo.toml b/src/ext/equix/Cargo.toml
new file mode 100644
index 0000000000..bedb1ed565
--- /dev/null
+++ b/src/ext/equix/Cargo.toml
@@ -0,0 +1,23 @@
+# See doc/HACKING/Rust.md
+#
+# This is a low-level Rust wrapper around Equi-X and its embedded copy of
+# HashX, provided for cross-compatibility testing within Arti.
+# This module does not make API stability guarantees.
+
+# Copyright (c) 2020 tevador <tevador@gmail.com>
+# See LICENSE for licensing information
+
+[package]
+name = "tor-c-equix"
+version = "0.2.0"
+edition = "2021"
+license = "LGPL-3.0-only"
+
+publish = false
+
+[build-dependencies]
+bindgen = "0.66.1"
+cc = { version = "1.0", features = ["parallel"] }
+
+[dev-dependencies]
+hex-literal = "0.4.1"
diff --git a/src/ext/equix/LICENSE b/src/ext/equix/LICENSE
new file mode 100644
index 0000000000..0a041280bd
--- /dev/null
+++ b/src/ext/equix/LICENSE
@@ -0,0 +1,165 @@
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+
+ This version of the GNU Lesser General Public License incorporates
+the terms and conditions of version 3 of the GNU General Public
+License, supplemented by the additional permissions listed below.
+
+ 0. Additional Definitions.
+
+ As used herein, "this License" refers to version 3 of the GNU Lesser
+General Public License, and the "GNU GPL" refers to version 3 of the GNU
+General Public License.
+
+ "The Library" refers to a covered work governed by this License,
+other than an Application or a Combined Work as defined below.
+
+ An "Application" is any work that makes use of an interface provided
+by the Library, but which is not otherwise based on the Library.
+Defining a subclass of a class defined by the Library is deemed a mode
+of using an interface provided by the Library.
+
+ A "Combined Work" is a work produced by combining or linking an
+Application with the Library. The particular version of the Library
+with which the Combined Work was made is also called the "Linked
+Version".
+
+ The "Minimal Corresponding Source" for a Combined Work means the
+Corresponding Source for the Combined Work, excluding any source code
+for portions of the Combined Work that, considered in isolation, are
+based on the Application, and not on the Linked Version.
+
+ The "Corresponding Application Code" for a Combined Work means the
+object code and/or source code for the Application, including any data
+and utility programs needed for reproducing the Combined Work from the
+Application, but excluding the System Libraries of the Combined Work.
+
+ 1. Exception to Section 3 of the GNU GPL.
+
+ You may convey a covered work under sections 3 and 4 of this License
+without being bound by section 3 of the GNU GPL.
+
+ 2. Conveying Modified Versions.
+
+ If you modify a copy of the Library, and, in your modifications, a
+facility refers to a function or data to be supplied by an Application
+that uses the facility (other than as an argument passed when the
+facility is invoked), then you may convey a copy of the modified
+version:
+
+ a) under this License, provided that you make a good faith effort to
+ ensure that, in the event an Application does not supply the
+ function or data, the facility still operates, and performs
+ whatever part of its purpose remains meaningful, or
+
+ b) under the GNU GPL, with none of the additional permissions of
+ this License applicable to that copy.
+
+ 3. Object Code Incorporating Material from Library Header Files.
+
+ The object code form of an Application may incorporate material from
+a header file that is part of the Library. You may convey such object
+code under terms of your choice, provided that, if the incorporated
+material is not limited to numerical parameters, data structure
+layouts and accessors, or small macros, inline functions and templates
+(ten or fewer lines in length), you do both of the following:
+
+ a) Give prominent notice with each copy of the object code that the
+ Library is used in it and that the Library and its use are
+ covered by this License.
+
+ b) Accompany the object code with a copy of the GNU GPL and this license
+ document.
+
+ 4. Combined Works.
+
+ You may convey a Combined Work under terms of your choice that,
+taken together, effectively do not restrict modification of the
+portions of the Library contained in the Combined Work and reverse
+engineering for debugging such modifications, if you also do each of
+the following:
+
+ a) Give prominent notice with each copy of the Combined Work that
+ the Library is used in it and that the Library and its use are
+ covered by this License.
+
+ b) Accompany the Combined Work with a copy of the GNU GPL and this license
+ document.
+
+ c) For a Combined Work that displays copyright notices during
+ execution, include the copyright notice for the Library among
+ these notices, as well as a reference directing the user to the
+ copies of the GNU GPL and this license document.
+
+ d) Do one of the following:
+
+ 0) Convey the Minimal Corresponding Source under the terms of this
+ License, and the Corresponding Application Code in a form
+ suitable for, and under terms that permit, the user to
+ recombine or relink the Application with a modified version of
+ the Linked Version to produce a modified Combined Work, in the
+ manner specified by section 6 of the GNU GPL for conveying
+ Corresponding Source.
+
+ 1) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (a) uses at run time
+ a copy of the Library already present on the user's computer
+ system, and (b) will operate properly with a modified version
+ of the Library that is interface-compatible with the Linked
+ Version.
+
+ e) Provide Installation Information, but only if you would otherwise
+ be required to provide such information under section 6 of the
+ GNU GPL, and only to the extent that such information is
+ necessary to install and execute a modified version of the
+ Combined Work produced by recombining or relinking the
+ Application with a modified version of the Linked Version. (If
+ you use option 4d0, the Installation Information must accompany
+ the Minimal Corresponding Source and Corresponding Application
+ Code. If you use option 4d1, you must provide the Installation
+ Information in the manner specified by section 6 of the GNU GPL
+ for conveying Corresponding Source.)
+
+ 5. Combined Libraries.
+
+ You may place library facilities that are a work based on the
+Library side by side in a single library together with other library
+facilities that are not Applications and are not covered by this
+License, and convey such a combined library under terms of your
+choice, if you do both of the following:
+
+ a) Accompany the combined library with a copy of the same work based
+ on the Library, uncombined with any other library facilities,
+ conveyed under the terms of this License.
+
+ b) Give prominent notice with the combined library that part of it
+ is a work based on the Library, and explaining where to find the
+ accompanying uncombined form of the same work.
+
+ 6. Revised Versions of the GNU Lesser General Public License.
+
+ The Free Software Foundation may publish revised and/or new versions
+of the GNU Lesser General Public License from time to time. Such new
+versions will be similar in spirit to the present version, but may
+differ in detail to address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Library as you received it specifies that a certain numbered version
+of the GNU Lesser General Public License "or any later version"
+applies to it, you have the option of following the terms and
+conditions either of that published version or of any later version
+published by the Free Software Foundation. If the Library as you
+received it does not specify a version number of the GNU Lesser
+General Public License, you may choose any version of the GNU Lesser
+General Public License ever published by the Free Software Foundation.
+
+ If the Library as you received it specifies that a proxy can decide
+whether future versions of the GNU Lesser General Public License shall
+apply, that proxy's public statement of acceptance of any version is
+permanent authorization for you to choose that version for the
+Library.
diff --git a/src/ext/equix/README.md b/src/ext/equix/README.md
new file mode 100644
index 0000000000..d3e8c93125
--- /dev/null
+++ b/src/ext/equix/README.md
@@ -0,0 +1,77 @@
+# Equi-X
+
+Equi-X is a CPU-friendly [client puzzle](https://en.wikipedia.org/wiki/Client_Puzzle_Protocol)
+with fast verification and small solution size (16 bytes). It is based on Equihash(60,3) with
+two major changes:
+
+1. Blake2b hash function is replaced with [HashX](https://github.com/tevador/hashx).
+2. XOR is replaced with modular addition.
+
+An Equi-X solution for nonce `X` is a set of eight 16-bit indices <code>i<sub>0</sub>, ..., i<sub>7</sub></code> such that:
+
+<code>H<sub>X</sub>(i<sub>0</sub>) + H<sub>X</sub>(i<sub>1</sub>) + H<sub>X</sub>(i<sub>2</sub>) + H<sub>X</sub>(i<sub>3</sub>) + H<sub>X</sub>(i<sub>4</sub>) + H<sub>X</sub>(i<sub>5</sub>) + H<sub>X</sub>(i<sub>6</sub>) + H<sub>X</sub>(i<sub>7</sub>) = 0 (mod 2<sup>60</sup>)</code>
+
+where <code>H<sub>X</sub></code> is a HashX function generated for nonce `X`. Equi-X is therefore a variant of the [subset sum problem](https://en.wikipedia.org/wiki/Subset_sum_problem). Each nonce value provides 2 solutions on average.
+
+Equi-X also has additional requirements that prove that the solution was found using the Wagner's algorithm. See the [Equihash paper](https://eprint.iacr.org/2015/946.pdf) for details.
+
+### Example solution
+
+```
+H(0x6c31) = 0xcfa5375c0a7f5d7 \
+ (+) = 0xa73d9777f110000 \
+H(0x8803) = 0xd798601be690a29 / |
+ (+) = 0xefdaadb00000000 \
+H(0x80c2) = 0xcabd8974bbee8d5 \ | |
+ (+) = 0x489d16380ef0000 / |
+H(0xa1db) = 0x7ddf8cc3530172b / |
+ (+) = 0
+H(0x6592) = 0x348a96fd685dcba \ |
+ (+) = 0x357120e8ffb8000 \ |
+H(0x76b7) = 0x00e689eb975a346 / | |
+ (+) = 0x102552500000000 /
+H(0x74a6) = 0xacccc4ad2d06bcd \ |
+ (+) = 0xdab431670048000 /
+H(0xe259) = 0x2de76cb9d341433 /
+```
+
+## Performance
+
+|Algorithm |n |k |memory |solution size|verification <sup>1</sup>|CPU perf. <sup>2</sup>|GPU perf. <sup>3</sup>|
+|----------|---|---|-------|-------------|------------|-----------|----------|
+|**Equi-X**|60 |3 |1.8 MiB|16 bytes |~50 μs |2400 Sol/s| ? |
+|Zcash |200|9 |144 MiB|1344 bytes |>150 μs |30 Sol/s |~400 Sol/s <sup>4</sup>|
+|BTG |144|5 |2.5 GiB|100 bytes |~10 μs |1 Sol/s |~45 Sol/s <sup>5</sup>|
+
+1. Using AMD Ryzen 1700 with 1 thread.
+1. Using AMD Ryzen 1700 with 16 threads.
+1. Using NVIDIA GTX 1660 Ti.
+1. Estimated from http://www.zcashbenchmarks.info/ (GTX 1070)
+1. Estimated from https://miniz.ch/features/
+
+## Build
+
+```
+git clone --recursive https://github.com/tevador/equix.git
+cd equix
+mkdir build
+cd build
+cmake ..
+make
+```
+```
+./equix-tests
+./equix-bench --help
+```
+
+## Design notes
+
+See [devlog.md](devlog.md)
+
+## Donations
+
+You can support the development of Equi-X by sending XMR to this address:
+
+```
+85GkKXSD8EQ22EMC2ZKF64S6L6Lcm8Gr23VbAKB1zg6FUW81sUEmrvvRPoM3GCpUZSC9azCLdeityW2N3CVsV4CAC3p1evV
+``` \ No newline at end of file
diff --git a/src/ext/equix/build.rs b/src/ext/equix/build.rs
new file mode 100644
index 0000000000..b53f08e899
--- /dev/null
+++ b/src/ext/equix/build.rs
@@ -0,0 +1,53 @@
+fn main() {
+ cc::Build::new()
+ .files(vec![
+ "src/context.c",
+ "src/equix.c",
+ "src/solver.c",
+ "hashx/src/blake2.c",
+ "hashx/src/compiler.c",
+ "hashx/src/compiler_a64.c",
+ "hashx/src/compiler_x86.c",
+ "hashx/src/context.c",
+ "hashx/src/hashx.c",
+ "hashx/src/program.c",
+ "hashx/src/program_exec.c",
+ "hashx/src/siphash.c",
+ "hashx/src/siphash_rng.c",
+ "hashx/src/virtual_memory.c",
+ ])
+ // Activate our patch for hashx_rng_callback
+ .define("HASHX_RNG_CALLBACK", "1")
+ // Equi-X always uses HashX size 8 (64-bit output)
+ .define("HASHX_SIZE", "8")
+ // Avoid shared library API declarations, link statically
+ .define("HASHX_STATIC", "1")
+ .define("EQUIX_STATIC", "1")
+ .includes(vec!["include", "src", "hashx/include", "hashx/src"])
+ .compile("equix");
+
+ // Run bindgen to automatically extract types and functions. This time set
+ // HASHX_SHARED and EQUIX_SHARED, so the function symbols are not hidden.
+ let out_path = std::path::PathBuf::from(std::env::var("OUT_DIR").unwrap());
+ bindgen::Builder::default()
+ .header_contents(
+ "wrapper.h",
+ r#"
+ #define HASHX_RNG_CALLBACK 1
+ #define HASHX_SIZE 8
+ #define HASHX_SHARED 1
+ #define EQUIX_SHARED 1
+ #include "hashx/include/hashx.h"
+ #include "include/equix.h"
+ "#,
+ )
+ .parse_callbacks(Box::new(bindgen::CargoCallbacks))
+ .default_enum_style(bindgen::EnumVariation::Rust {
+ non_exhaustive: true,
+ })
+ .bitfield_enum(".*_flags")
+ .generate()
+ .unwrap()
+ .write_to_file(out_path.join("bindings.rs"))
+ .unwrap();
+}
diff --git a/src/ext/equix/devlog.md b/src/ext/equix/devlog.md
new file mode 100644
index 0000000000..fbd9da346e
--- /dev/null
+++ b/src/ext/equix/devlog.md
@@ -0,0 +1,178 @@
+# DoS protection for onion services: from RandomX to Equi-X
+
+In early May 2020, I was contacted by two Tor developers to help them with their denial-of-service (DoS) mitigation proposal. Onion services have been plagued by DoS for many years and there are no easy solutions due to the anonymous nature of the Tor network. The vulnerability stems from the fact that the service has to perform a series of expensive operations for each connecting client, so an attacker can simply flood the service with connection requests, which are comparatively cheap to make.
+
+## Proof of work
+
+One of the strategies that can be used against such attacks are client puzzles, which require the client to prove that they performed certain amount of computational work before the request is accepted. This is not a new idea – using a client puzzle to combat email spam was first proposed in 1997 [[1](https://cypherpunks.venona.com/date/1997/03/msg00774.html)] and there have been proposals to add a client puzzle to the TLS protocol that we all use every day to browse the web [[2](https://tools.ietf.org/html/draft-nygren-tls-client-puzzles-02)].
+
+The goal of the current Tor proposal [[3](https://lists.torproject.org/pipermail/tor-dev/2020-April/014215.html)] is to integrate some kind of client puzzle as part of the protocol used to connect to onion services. The client would download the hidden service descriptor, find that the service is protected by a client puzzle, calculate the solution and send it as part of the connection request. The service would give the request a priority value based on the "difficulty" of the puzzle solution.
+
+The main issue is to find a suitable puzzle. There are three main requirements that the algorithm must meet:
+
+1. The solution proof must be smaller than about 200 bytes.
+2. Solution verification must be fast.
+3. GPUs and FPGAs should not provide a large advantage for solving the puzzle.
+
+The first requirement is due to the limited space in the message that the client sends to the hidden service to negotiate a connection. This doesn't pose a big problem in practice.
+
+The second requirement is needed to prevent the client puzzle from becoming a DoS vector on its own. The service must be able to quickly verify if a proof provided by a client is valid or not, otherwise the attacker could just flood the service with invalid proofs.
+
+The third requirement is the most important one. Users of the Tor browser are equipped with an ordinary general-purpose CPU and an attacker must not be able to use similarly priced hardware that offers a much higher performance for solving the puzzle – otherwise it would be easy for an attacker to simulate many legitimate clients connecting to the service.
+
+It should be noted that the puzzle does not need to be resistant to speed-up by specialized fixed-function hardware (ASIC). This is called "ASIC resistance" and there are two main reasons why it's not strictly required in this case:
+
+1. The cost to produce a specialized chip for a given algorithm exceeds USD $1 million for the 28 nm process [[4](https://www.electronicdesign.com/technologies/embedded-revolution/article/21808278/the-economics-of-asics-at-what-point-does-a-custom-soc-become-viable)]. This is in contrast with the current state when bringing down an onion service requires very little resources [[5](https://www.reddit.com/r/darknet/comments/b3qvbq/this_ddos_is_massive_its_gotta_be_multiple/ej1jwzc/)].
+2. If an ASIC for the client puzzle is developed, the algorithm can be quickly changed with a simple patch, rendering the attacker's investment useless. This is in contrast with cryptocurrencies, which have complex consensus protocols and can take months or years to change their proof of work algorithm [[6](https://ethereum-magicians.org/t/eip-progpow-a-programmatic-proof-of-work/272)].
+
+Therefore the client puzzle algorithm must be CPU-friendly and minimize the advantage of programmable hardware such as GPUs and FPGAs.
+
+## RandomX
+
+In 2019, we developed a new CPU-friendly proof of work algorithm called RandomX to be used by Monero [[7](https://web.getmonero.org/resources/moneropedia/randomx.html)]. It has been audited and field tested, which makes it a good candidate to be considered for a Tor client puzzle.
+
+However, during the development of RandomX, we focused mainly on the "CPU-friendliness" of the algorithm to minimize the advantage of specialized hardware. Other aspects such as verification performance and memory requirements were secondary and only had upper limits. The result is that RandomX has quite high solution verification demands – over 2 GiB of memory and around 2 milliseconds to verify a hash. Alternatively, it is possible to use only 256 MiB of memory, but then verification takes around 15 ms. This is way too slow to be used as a client puzzle.
+
+So I began slimming down RandomX to make it less demanding for verification. I halved the memory requirements and reduced the number of rounds from 8 to 2, which is the minimum that can be considered safe from optimizations. The result is RandomX-Tor [[8](https://github.com/tevador/RandomX/tree/tor-pow)], which takes around 0.5 ms to verify with slightly over 1 GiB of memory. GPUs perform very poorly when running RandomX-Tor – similar to full RandomX.
+
+However, I see two main problems with RandomX-Tor:
+
+1. 2000 verifications per second still may not be fast enough to prevent flooding attacks on the service, especially since each connection request to an onion service requires very little network bandwidth (512 bytes).
+1. The 1 GB memory requirement is too high. Onion services would have to allocate over 2 GB just to verify puzzles because two different puzzles may be active at a given moment to allow for network synchronization delays.
+
+So I decided to continue my quest and look for a better puzzle.
+
+## Alternatives
+
+I briefly tested Argon2 [[9](https://github.com/p-h-c/phc-winner-argon2)] and Yespower [[10](https://www.openwall.com/yespower/)], which are password hashing algorithms claiming to be "GPU-resistant". However, both have slower verification performance than RandomX-Tor and both run faster on GPUs, so they are not suitable. See Appendix for details.
+
+Then I researched Equihash, which is an asymmetric client puzzle offering very fast solution verification [[11](https://eprint.iacr.org/2015/946.pdf)]. The main problem with Equihash is that GPUs perform up to 100x faster than CPUs, so it is unusable as a puzzle for CPU-based clients.
+
+## HashX
+
+I was ready to give up when I remembered SuperscalarHash, which is a part of RandomX that's used only to initialize the DAG [[12](https://github.com/tevador/RandomX/blob/master/doc/specs.md#6-superscalarhash)]. It could be considered a lightweight version of RandomX with only integer operations and no memory accesses. I began refactoring the code with the goal of creating a fast GPU-resistant hash function. The main idea is that each instance of the hash function would use a completely different randomly generated sequence of instructions. I managed to optimized the SuperscalarHash generator and reduce the time to generate a random program from 250 μs to 50 μs, which could mean up to 20000 verifications per second – ten times faster than RandomX-Tor.
+
+I named the new algorithm "HashX" and in the course of the next week, I made several other changes compared to the old SuperscalarHash:
+
+* improved code generator that can fully saturate the simulated 3-way superscalar pipeline
+* removed reciprocal multiplication, which was sometimes causing front-end stalls
+* implemented a more optimized JIT compiler for x86-64
+* added input-dependent branches to further hinder GPU performance
+
+I also made a few tweaks to the hash finalizer to pass SMHasher [[13](https://github.com/rurban/smhasher)]. The result is a CPU-friendly algorithm suitable to be used as a partial hash inversion client puzzle.
+
+## Equi-X
+
+I still felt a bit uneasy about HashX using no memory. This means that logic-only FPGAs could be a viable option to run HashX. Additionally, introducing the right amount of memory-hardness could affect GPUs more than CPUs. I remembered Equihash, which is a memory-hard algorithm, but still allows for fast solution verification. I could simply replace the Blake2b hash in the default implementation with HashX. Each solution attempt would then use a different randomly generated HashX instance.
+
+Equihash has two main parameters that determine the difficulty of the generalized birthday problem: `n` is the hash size in bits and <code>2<sup>k</sup></code> is the number of hashes that need to XOR to zero. The memory hardness is proportional to <code>2<sup>n/(k+1)</sup></code>. To get fast verification and a small proof size, `k` should be as low as possible. I chose `k=3`, which means the goal would be to find preimages to 8 hashes that XOR to zero.
+
+I first tried with `n=96`, which would require about 2 GB of memory for an efficient solver. However, the problem is that each HashX instance would be used for <code>2<sup>25</sup></code> hashes, which could make it feasible for GPUs to compile an optimized kernel for each new solution attempt. Additionally, GPUs are much better at the sorting phase of Equihash than CPUs due to their higher memory bandwidth.
+
+After some more benchmarking, I estimated that <code>2<sup>16</sup></code> hashes per solution attempt would be the sweet spot for CPUs because one solution attempt would take roughly 6-8 ms, the HashX compilation overhead would still be under 1% and the expected memory usage would be under 2 MiB. This can fit entirely into the CPU cache, which is the only case when CPUs can compete with GPUs in memory bandwidth. The optimal Equihash parameters are then `n=60` and `k=3`. I call this algorithm "Equi-X" (portmanteau of **Equi**hash and Hash**X**). The exact memory requirements for Equi-X are 1.81 MiB with negligible solution discarding. It could be reduced to a minimum of 1 MiB with perfect bit packing and around 25% of discarded solutions, although this is viable only for custom hardware.
+
+However, when testing Equi-X, I discovered a fatal flaw: the generalized birthday problem, as used by Equihash, requires a collision resistant hash function. While HashX is preimage-resistant, it is not collision resistant. Some small fraction of HashX instances produce a significant number of hash collisions. With a 2<sup>k</sup>-XOR, finding 2<sup>k-1</sup> pairs of colliding hashes automatically produces a valid solution because equal values XOR to zero. But it gets worse. If the number of colliding hashes is higher than 2<sup>k</sup>, the number of valid solutions grows exponentially. For example, with `k=3` and 100 colliding hashes, it is possible to produce more than 180 billion valid solutions! Finding such a multicollision takes only a few minutes for HashX.
+
+Some modifications of HashX reduced the number of collisions, but I could not completely eliminate them, so I needed another solution. I began researching the generalized birthday problem and I found this paragraph in the seminal paper by David Wagner [[14](https://people.eecs.berkeley.edu/~daw/papers/genbday.html)]:
+
+![genbday](https://i.imgur.com/I7TAfTQ.png)
+
+The advantage of 2<sup>k</sup>-SUM compared to 2<sup>k</sup>-XOR is that identical hashes no longer produce valid solutions (except for `0x000000000000000` and `0x800000000000000`, but these are very rare). There are two additional advantages:
+
+1. While XOR and addition have the same performance in CPUs, XOR is much faster in custom hardware. This means, for example, that an FPGA-based solver will have to use slightly more resources to calculate the modular additions.
+1. With 2<sup>k</sup>-SUM, we can eliminate checking for duplicate indices, which simplifies both the solver and the verifier [[15](https://github.com/tevador/equix/issues/1)].
+
+With this modification, an Equi-X solution for nonce `X` is a set of eight 16-bit indices <code>i<sub>0</sub>, ..., i<sub>7</sub></code> such that:
+
+<code>H<sub>X</sub>(i<sub>0</sub>) + H<sub>X</sub>(i<sub>1</sub>) + H<sub>X</sub>(i<sub>2</sub>) + H<sub>X</sub>(i<sub>3</sub>) + H<sub>X</sub>(i<sub>4</sub>) + H<sub>X</sub>(i<sub>5</sub>) + H<sub>X</sub>(i<sub>6</sub>) + H<sub>X</sub>(i<sub>7</sub>) = 0 (mod 2<sup>60</sup>)</code>
+
+where <code>H<sub>X</sub></code> is a HashX function generated for nonce `X`.
+
+Example of a solution:
+
+```
+H(0x6c31) = 0xcfa5375c0a7f5d7 \
+ (+) = 0xa73d9777f110000 \
+H(0x8803) = 0xd798601be690a29 / |
+ (+) = 0xefdaadb00000000 \
+H(0x80c2) = 0xcabd8974bbee8d5 \ | |
+ (+) = 0x489d16380ef0000 / |
+H(0xa1db) = 0x7ddf8cc3530172b / |
+ (+) = 0
+H(0x6592) = 0x348a96fd685dcba \ |
+ (+) = 0x357120e8ffb8000 \ |
+H(0x76b7) = 0x00e689eb975a346 / | |
+ (+) = 0x102552500000000 /
+H(0x74a6) = 0xacccc4ad2d06bcd \ |
+ (+) = 0xdab431670048000 /
+H(0xe259) = 0x2de76cb9d341433 /
+```
+
+The following table compares Equi-X with the most common variants of Equihash:
+
+|Algorithm |n |k |memory|solution size|verification <sup>1</sup>|CPU perf. <sup>2</sup>|GPU perf. <sup>3</sup>|
+|----------|---|---|-------|-------------|------------|-----------|----------|
+|**Equi-X**|60 |3 |1.8 MiB|16 bytes |~50 μs |2400 Sol/s| ? |
+|Zcash |200|9 |144 MiB|1344 bytes |>150 μs |30 Sol/s |~400 Sol/s <sup>4</sup>|
+|BTG |144|5 |2.5 GiB|100 bytes |~10 μs |1 Sol/s |~45 Sol/s <sup>5</sup>|
+
+1. Using AMD Ryzen 1700 with 1 thread.
+1. Using AMD Ryzen 1700 with 16 threads.
+1. Using NVIDIA GTX 1660 Ti.
+1. Estimated from http://www.zcashbenchmarks.info/ (GTX 1070)
+1. Estimated from https://miniz.ch/features/
+
+## References
+
+[1] https://cypherpunks.venona.com/date/1997/03/msg00774.html
+
+[2] https://tools.ietf.org/html/draft-nygren-tls-client-puzzles-02
+
+[3] https://lists.torproject.org/pipermail/tor-dev/2020-April/014215.html
+
+[4] https://www.electronicdesign.com/technologies/embedded-revolution/article/21808278/the-economics-of-asics-at-what-point-does-a-custom-soc-become-viable
+
+[5] https://www.reddit.com/r/darknet/comments/b3qvbq/this_ddos_is_massive_its_gotta_be_multiple/ej1jwzc/
+
+[6] https://ethereum-magicians.org/t/eip-progpow-a-programmatic-proof-of-work/272
+
+[7] https://web.getmonero.org/resources/moneropedia/randomx.html
+
+[8] https://github.com/tevador/RandomX/tree/tor-pow
+
+[9] https://github.com/p-h-c/phc-winner-argon2
+
+[10] https://www.openwall.com/yespower/
+
+[11] https://eprint.iacr.org/2015/946.pdf
+
+[12] https://github.com/tevador/RandomX/blob/master/doc/specs.md#6-superscalarhash
+
+[13] https://github.com/rurban/smhasher
+
+[14] https://people.eecs.berkeley.edu/~daw/papers/genbday.html
+
+[15] https://github.com/tevador/equix/issues/1
+
+## Appendix: Comparison of GPU-resistant client puzzles
+
+|Algorithm|GPU speed <sup>6</sup>|Solver memory|Verifier memory|Verif./sec. <sup>11</sup>|Solution size <sup>12</sup>|
+|------------|---------|-------------|---------------|---------------|-------------|
+|**Equi-X** <sup>1</sup>|<50% <sup>7</sup>|1.81 MiB|< 20 KiB|19600| 32 bytes|
+|**HashX** <sup>2</sup>|<50% <sup>7</sup>|< 20 KiB|< 20 KiB|19700|16 bytes|
+|RandomX-Tor <sup>3</sup>|10% <sup>8</sup>| 1041 MiB|1041 MiB|2200|16 bytes|
+|Argon2 <sup>4</sup>|~300% <sup>9</sup>|2.00 MiB|2.00 MiB|1020|16 bytes|
+|Yespower <sup>5</sup>|~200% <sup>10</sup>|2.00 MiB|2.00 MiB|780|16 bytes|
+
+1. https://github.com/tevador/equix
+1. https://github.com/tevador/hashx
+1. https://github.com/tevador/RandomX/tree/tor-pow
+1. https://github.com/p-h-c/phc-winner-argon2
+1. https://www.openwall.com/yespower/
+1. Performance of NVIDIA GTX 1660 Ti compared to AMD Ryzen 1700
+1. No GPU implementation exists; upper bound based on RandomX performance
+1. Benchmarked using https://github.com/SChernykh/RandomX_CUDA
+1. Estimated from https://github.com/WebDollar/argon2-gpu
+1. Estimated from https://nlpool.nl/bench?algo=yescrypt
+1. Benchmarked on AMD Ryzen 1700 @ 3.3 GHz using 1 thread
+1. Including a 16-byte nonce.
diff --git a/src/ext/equix/hashx/CMakeLists.txt b/src/ext/equix/hashx/CMakeLists.txt
new file mode 100644
index 0000000000..1e8fe2fd6c
--- /dev/null
+++ b/src/ext/equix/hashx/CMakeLists.txt
@@ -0,0 +1,95 @@
+# Copyright (c) 2020 tevador <tevador@gmail.com>
+# See LICENSE for licensing information
+
+cmake_minimum_required(VERSION 2.8.8)
+
+set(HASHX_VERSION 1)
+set(HASHX_VERSION_MINOR 0)
+set(HASHX_VERSION_PATCH 0)
+set(HASHX_VERSION_STR "${HASHX_VERSION}.${HASHX_VERSION_MINOR}.${HASHX_VERSION_PATCH}")
+
+project(hashx)
+
+set(hashx_sources
+src/blake2.c
+src/compiler.c
+src/compiler_a64.c
+src/compiler_x86.c
+src/context.c
+src/hashx.c
+src/program.c
+src/program_exec.c
+src/siphash.c
+src/siphash_rng.c
+src/virtual_memory.c)
+
+if(NOT CMAKE_BUILD_TYPE)
+ set(CMAKE_BUILD_TYPE Release)
+ message(STATUS "Setting default build type: ${CMAKE_BUILD_TYPE}")
+endif()
+
+option(HASHX_BLOCK_MODE "Hash function for block mode" OFF)
+
+if(HASHX_BLOCK_MODE)
+ add_definitions(-DHASHX_BLOCK_MODE)
+endif()
+
+set(HASHX_SIZE CACHE STRING "Hash function output size in bytes")
+
+if(HASHX_SIZE)
+ if(HASHX_SIZE GREATER 32)
+ message(SEND_ERROR "The maximum hash size is 32 bytes")
+ else()
+ add_definitions(-DHASHX_SIZE=${HASHX_SIZE})
+ endif()
+endif()
+
+set(HASHX_SALT CACHE STRING "Implementation-specific salt value")
+
+if(HASHX_SALT)
+ string(LENGTH ${HASHX_SALT} HASHX_SALT_LENGTH)
+ if(HASHX_SALT_LENGTH GREATER 15)
+ message(SEND_ERROR "The maximum salt length is 15 characters")
+ else()
+ add_definitions(-DHASHX_SALT=${HASHX_SALT})
+ endif()
+endif()
+
+include_directories(include/)
+
+add_library(hashx SHARED ${hashx_sources})
+set_property(TARGET hashx PROPERTY POSITION_INDEPENDENT_CODE ON)
+set_property(TARGET hashx PROPERTY PUBLIC_HEADER include/hashx.h)
+target_compile_definitions(hashx PRIVATE HASHX_SHARED)
+set_target_properties(hashx PROPERTIES VERSION ${HASHX_VERSION_STR}
+ SOVERSION ${HASHX_VERSION})
+
+add_library(hashx_static STATIC ${hashx_sources})
+set_property(TARGET hashx_static PROPERTY POSITION_INDEPENDENT_CODE ON)
+set_target_properties(hashx_static PROPERTIES OUTPUT_NAME hashx)
+
+include(GNUInstallDirs)
+install(TARGETS hashx hashx_static
+ LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+ ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
+ PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
+
+add_executable(hashx-tests
+ src/tests.c)
+target_compile_definitions(hashx-tests PRIVATE HASHX_STATIC)
+target_link_libraries(hashx-tests
+ PRIVATE hashx_static)
+
+if(NOT Threads_FOUND AND UNIX AND NOT APPLE)
+ set(THREADS_PREFER_PTHREAD_FLAG ON)
+ find_package(Threads)
+endif()
+
+add_executable(hashx-bench
+ src/bench.c
+ src/hashx_thread.c
+ src/hashx_time.c)
+target_compile_definitions(hashx-bench PRIVATE HASHX_STATIC)
+target_link_libraries(hashx-bench
+ PRIVATE hashx_static
+ PRIVATE ${CMAKE_THREAD_LIBS_INIT})
diff --git a/src/ext/equix/hashx/LICENSE b/src/ext/equix/hashx/LICENSE
new file mode 100644
index 0000000000..0a041280bd
--- /dev/null
+++ b/src/ext/equix/hashx/LICENSE
@@ -0,0 +1,165 @@
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+
+ This version of the GNU Lesser General Public License incorporates
+the terms and conditions of version 3 of the GNU General Public
+License, supplemented by the additional permissions listed below.
+
+ 0. Additional Definitions.
+
+ As used herein, "this License" refers to version 3 of the GNU Lesser
+General Public License, and the "GNU GPL" refers to version 3 of the GNU
+General Public License.
+
+ "The Library" refers to a covered work governed by this License,
+other than an Application or a Combined Work as defined below.
+
+ An "Application" is any work that makes use of an interface provided
+by the Library, but which is not otherwise based on the Library.
+Defining a subclass of a class defined by the Library is deemed a mode
+of using an interface provided by the Library.
+
+ A "Combined Work" is a work produced by combining or linking an
+Application with the Library. The particular version of the Library
+with which the Combined Work was made is also called the "Linked
+Version".
+
+ The "Minimal Corresponding Source" for a Combined Work means the
+Corresponding Source for the Combined Work, excluding any source code
+for portions of the Combined Work that, considered in isolation, are
+based on the Application, and not on the Linked Version.
+
+ The "Corresponding Application Code" for a Combined Work means the
+object code and/or source code for the Application, including any data
+and utility programs needed for reproducing the Combined Work from the
+Application, but excluding the System Libraries of the Combined Work.
+
+ 1. Exception to Section 3 of the GNU GPL.
+
+ You may convey a covered work under sections 3 and 4 of this License
+without being bound by section 3 of the GNU GPL.
+
+ 2. Conveying Modified Versions.
+
+ If you modify a copy of the Library, and, in your modifications, a
+facility refers to a function or data to be supplied by an Application
+that uses the facility (other than as an argument passed when the
+facility is invoked), then you may convey a copy of the modified
+version:
+
+ a) under this License, provided that you make a good faith effort to
+ ensure that, in the event an Application does not supply the
+ function or data, the facility still operates, and performs
+ whatever part of its purpose remains meaningful, or
+
+ b) under the GNU GPL, with none of the additional permissions of
+ this License applicable to that copy.
+
+ 3. Object Code Incorporating Material from Library Header Files.
+
+ The object code form of an Application may incorporate material from
+a header file that is part of the Library. You may convey such object
+code under terms of your choice, provided that, if the incorporated
+material is not limited to numerical parameters, data structure
+layouts and accessors, or small macros, inline functions and templates
+(ten or fewer lines in length), you do both of the following:
+
+ a) Give prominent notice with each copy of the object code that the
+ Library is used in it and that the Library and its use are
+ covered by this License.
+
+ b) Accompany the object code with a copy of the GNU GPL and this license
+ document.
+
+ 4. Combined Works.
+
+ You may convey a Combined Work under terms of your choice that,
+taken together, effectively do not restrict modification of the
+portions of the Library contained in the Combined Work and reverse
+engineering for debugging such modifications, if you also do each of
+the following:
+
+ a) Give prominent notice with each copy of the Combined Work that
+ the Library is used in it and that the Library and its use are
+ covered by this License.
+
+ b) Accompany the Combined Work with a copy of the GNU GPL and this license
+ document.
+
+ c) For a Combined Work that displays copyright notices during
+ execution, include the copyright notice for the Library among
+ these notices, as well as a reference directing the user to the
+ copies of the GNU GPL and this license document.
+
+ d) Do one of the following:
+
+ 0) Convey the Minimal Corresponding Source under the terms of this
+ License, and the Corresponding Application Code in a form
+ suitable for, and under terms that permit, the user to
+ recombine or relink the Application with a modified version of
+ the Linked Version to produce a modified Combined Work, in the
+ manner specified by section 6 of the GNU GPL for conveying
+ Corresponding Source.
+
+ 1) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (a) uses at run time
+ a copy of the Library already present on the user's computer
+ system, and (b) will operate properly with a modified version
+ of the Library that is interface-compatible with the Linked
+ Version.
+
+ e) Provide Installation Information, but only if you would otherwise
+ be required to provide such information under section 6 of the
+ GNU GPL, and only to the extent that such information is
+ necessary to install and execute a modified version of the
+ Combined Work produced by recombining or relinking the
+ Application with a modified version of the Linked Version. (If
+ you use option 4d0, the Installation Information must accompany
+ the Minimal Corresponding Source and Corresponding Application
+ Code. If you use option 4d1, you must provide the Installation
+ Information in the manner specified by section 6 of the GNU GPL
+ for conveying Corresponding Source.)
+
+ 5. Combined Libraries.
+
+ You may place library facilities that are a work based on the
+Library side by side in a single library together with other library
+facilities that are not Applications and are not covered by this
+License, and convey such a combined library under terms of your
+choice, if you do both of the following:
+
+ a) Accompany the combined library with a copy of the same work based
+ on the Library, uncombined with any other library facilities,
+ conveyed under the terms of this License.
+
+ b) Give prominent notice with the combined library that part of it
+ is a work based on the Library, and explaining where to find the
+ accompanying uncombined form of the same work.
+
+ 6. Revised Versions of the GNU Lesser General Public License.
+
+ The Free Software Foundation may publish revised and/or new versions
+of the GNU Lesser General Public License from time to time. Such new
+versions will be similar in spirit to the present version, but may
+differ in detail to address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Library as you received it specifies that a certain numbered version
+of the GNU Lesser General Public License "or any later version"
+applies to it, you have the option of following the terms and
+conditions either of that published version or of any later version
+published by the Free Software Foundation. If the Library as you
+received it does not specify a version number of the GNU Lesser
+General Public License, you may choose any version of the GNU Lesser
+General Public License ever published by the Free Software Foundation.
+
+ If the Library as you received it specifies that a proxy can decide
+whether future versions of the GNU Lesser General Public License shall
+apply, that proxy's public statement of acceptance of any version is
+permanent authorization for you to choose that version for the
+Library.
diff --git a/src/ext/equix/hashx/README.md b/src/ext/equix/hashx/README.md
new file mode 100644
index 0000000000..f6352475b0
--- /dev/null
+++ b/src/ext/equix/hashx/README.md
@@ -0,0 +1,162 @@
+# HashX
+
+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.
+
+HashX functions are generated as a carefully crafted sequence of integer
+operations to fully saturate a 3-way superscalar CPU pipeline (modeled after
+the Intel Ivy Bridge architecture). Extra care is taken to avoid optimizations
+and to ensure that each function takes exactly the same number of CPU cycles
+(currently 512 instructions over 192 cycles).
+
+## API
+
+The API consists of 5 functions and is documented in the public header file
+[hashx.h](include/hashx.h).
+
+Example of usage:
+
+```c
+#include <hashx.h>
+#include <stdio.h>
+
+int main() {
+ char seed[] = "this is a seed that will generate a hash function";
+ char hash[HASHX_SIZE];
+ hashx_type func_type;
+ hashx_ctx* ctx = hashx_alloc(HASHX_TRY_COMPILE);
+ if (ctx == NULL)
+ return 1;
+ /* generate a hash function */
+ if (hashx_make(ctx, seed, sizeof(seed)) != HASHX_OK)
+ return 1;
+ if (hashx_query_type(ctx, &func_type) == HASHX_OK && func_type == HASHX_TYPE_COMPILED)
+ printf("Using the compiled implementation of HashX\n");
+ hashx_exec(ctx, 123456789, hash); /* calculate the hash of a nonce value */
+ hashx_free(ctx);
+ for (unsigned i = 0; i < HASHX_SIZE; ++i)
+ printf("%02x", hash[i] & 0xff);
+ printf("\n");
+ return 0;
+}
+```
+
+## Build
+
+A C99-compatible compiler and `cmake` are required.
+
+```
+git clone https://github.com/tevador/hashx.git
+cd hashx
+mkdir build
+cd build
+cmake .. [-DHASHX_BLOCK_MODE=ON] [-DHASHX_SIZE=<1-32>] [-DHASHX_SALT="my custom hash"]
+make
+```
+
+### Block mode (default: off)
+
+Because HashX is meant to be used in proof-of-work schemes and client puzzles,
+the input is a 64-bit counter value. If you need to hash arbitrary data, build
+with `-DHASHX_BLOCK_MODE=ON`. This will change the API to accept `const void*, size_t` instead of `uint64_t`.
+However, it is strongly recommended to use the counter mode, which is almost twice faster for short inputs.
+
+### Hash size (default: 32)
+
+The default hash output size is 32 bytes (256 bits). If you want to reduce the output
+size, build with, for example, `-DHASHX_SIZE=20`. Output sizes in the range of 1-32 bytes
+are supported. Shorter output sizes are formed by simply truncating the full 256-bit hash.
+
+### Generator salt (default: "HashX v1")
+
+An implementation-specific salt value may be specified when building, for example: `-DHASHX_SALT="my custom hash"`.
+This value is used as a salt when generating hash instances. The maximum supported
+salt size is 15 characters.
+
+## Performance
+
+HashX was designed for fast verification. Generating a hash function from seed
+takes about 50 μs and a 64-bit nonce can be hashed in under 100 ns (in compiled
+mode) or in about 1-2 μs (in interpreted mode).
+
+A benchmark executable is included:
+```
+./hashx-bench --seeds 500
+```
+
+## Error fallback
+
+The compiled implementation of HashX is much faster (very roughly 20x) so it
+should be used whenever possible. It may be necessary to use the interpreter
+for multiple reasons: either the platform is not supported at compile time,
+or various runtime policies disallow the memory protection changes that are
+necessary to do just-in-time compilation. Failures may be detected late, so
+the library provides a built-in mechanism to fall back from the compiled
+implementation to interpreted quickly without duplicating the whole context.
+
+The `hashx_query_type()` function is optional, provided for users of the
+`HASHX_TRY_COMPILE` context who need to know which implementation was
+ultimately used.
+
+The actual hash function, `hashx_exec()`, returns an error code for
+completeness in reporting programming errors, but if a caller has invoked
+`hashx_make()` successfully it can be considered infallible.
+
+It is always possible for `hashx_make()` to fail. In addition to the
+OS-specific failures you may see when forcing HashX to use the compiled
+implementation with `hashx_alloc(HASHX_TYPE_COMPILED)`, it's always possible
+for `hashx_make` to fail unpredictably for a particular seed value. These
+seeds should be discarded and a new one attempted by the caller when
+`hashx_make` returns `HASHX_FAIL_SEED`.
+
+## Security
+
+HashX should provide strong preimage resistance. No other security guarantees are made. About
+ 99% of HashX instances pass [SMHasher](https://github.com/tevador/smhasher),
+ but using HashX as a generic hash function is not recommended.
+
+Known vulnerabilities that should not affect intended use cases:
+
+1. HashX is not collision resistant. Around 0.2% of seeds produce "weak" hash functions for
+which hash collisions are plentiful.
+2. Secret values should not be used as inputs to HashX because the generated instructions
+include data-dependent branches by design.
+
+## Protocols based on HashX
+
+Here are two examples of how HashX can be used in practice:
+
+### Interactive client puzzle
+
+Client puzzles are protocols designed to protect server resources from abuse.
+A client requesting a resource from a server may be asked to solve a puzzle
+before the request is accepted.
+
+One of the first proposed client puzzles is [Hashcash](https://en.wikipedia.org/wiki/Hashcash),
+which requires the client to find a partial SHA-1 hash inversion. However,
+because of the static nature of cryptographic hash functions, an attacker can
+offload hashing to a GPU or FPGA to gain a significant advantage over legitimate
+clients equipped only with a CPU.
+
+In a HashX-based interactive client puzzle, the server sends each client
+a 256-bit challenge used to generate a unique HashX function. The client then
+has to find a 64-bit nonce value such that the resulting hash has a predefined
+number of leading zeroes. An attacker cannot easily parallelize the workload
+because each request would require a new GPU kernel or FPGA bistream.
+
+### Non-interactive proof-of-work
+
+In the absence of a central authority handing out challenges (for example in
+a cryptocurrency), the client takes some public information `T` (for example
+a block template) and combines it with a chosen 64-bit nonce `N1`.
+The resulting string `X = T||N1` is then used to generate a HashX function
+<code>H<sub>X</sub></code>. The client then tries to find a 16-bit nonce `N2`
+such that <code>r = H<sub>X</sub>(N2)</code> meets the difficulty target of
+the protocol. If no `N2` value is successful, the client increments `N1` and
+tries with a different hash function.
+
+In this protocol, each HashX function provides only 65536 attempts before it
+must be discarded. This limits the parallelization advantage of GPUs and FPGAs.
+A CPU core will be able to test about 200 different hash functions per second.
diff --git a/src/ext/equix/hashx/include/hashx.h b/src/ext/equix/hashx/include/hashx.h
new file mode 100644
index 0000000000..3f6d059b92
--- /dev/null
+++ b/src/ext/equix/hashx/include/hashx.h
@@ -0,0 +1,195 @@
+/* Copyright (c) 2020 tevador <tevador@gmail.com> */
+/* 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 <hashx.h>
+ #include <stdio.h>
+
+ 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 <stdint.h>
+#include <stddef.h>
+
+/*
+ * 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 --git a/src/ext/equix/hashx/src/bench.c b/src/ext/equix/hashx/src/bench.c
new file mode 100644
index 0000000000..a440825436
--- /dev/null
+++ b/src/ext/equix/hashx/src/bench.c
@@ -0,0 +1,147 @@
+/* Copyright (c) 2020 tevador <tevador@gmail.com> */
+/* See LICENSE for licensing information */
+
+#include "test_utils.h"
+#include "hashx_thread.h"
+#include "hashx_endian.h"
+#include "hashx_time.h"
+#include <assert.h>
+#include <limits.h>
+#include <inttypes.h>
+
+typedef struct worker_job {
+ int id;
+ hashx_thread thread;
+ hashx_ctx* ctx;
+ int64_t total_hashes;
+ uint64_t best_hash;
+ uint64_t threshold;
+ int start;
+ int step;
+ int end;
+ int nonces;
+} worker_job;
+
+static hashx_thread_retval worker(void* args) {
+ worker_job* job = (worker_job*)args;
+ job->total_hashes = 0;
+ job->best_hash = UINT64_MAX;
+ for (int seed = job->start; seed < job->end; seed += job->step) {
+ {
+ hashx_result result = hashx_make(job->ctx, &seed, sizeof(seed));
+ if (result == HASHX_FAIL_SEED) {
+ continue;
+ }
+ if (result == HASHX_FAIL_COMPILE) {
+ printf("Error: not supported. Try with --interpret\n");
+ }
+ assert(result == HASHX_OK);
+ if (result != HASHX_OK)
+ break;
+ }
+ for (int nonce = 0; nonce < job->nonces; ++nonce) {
+ uint8_t hash[HASHX_SIZE] = { 0 };
+ {
+#ifndef HASHX_BLOCK_MODE
+ hashx_result result = hashx_exec(job->ctx, nonce, hash);
+#else
+ hashx_result result = hashx_exec(job->ctx,
+ &nonce, sizeof(nonce), hash);
+#endif
+ assert(result == HASHX_OK);
+ if (result != HASHX_OK)
+ break;
+ }
+ uint64_t hashval = load64(hash);
+ if (hashval < job->best_hash) {
+ job->best_hash = hashval;
+ }
+ if (hashval < job->threshold) {
+ printf("[thread %2i] Hash (%5i, %5i) below threshold:"
+ " ...%02x%02x%02x%02x%02x%02x%02x%02x\n",
+ job->id,
+ seed,
+ nonce,
+ hash[0],
+ hash[1],
+ hash[2],
+ hash[3],
+ hash[4],
+ hash[5],
+ hash[6],
+ hash[7]);
+ }
+ }
+ job->total_hashes += job->nonces;
+ }
+ return HASHX_THREAD_SUCCESS;
+}
+
+int main(int argc, char** argv) {
+ int nonces, seeds, start, diff, threads;
+ bool interpret;
+ read_int_option("--diff", argc, argv, &diff, INT_MAX);
+ read_int_option("--start", argc, argv, &start, 0);
+ read_int_option("--seeds", argc, argv, &seeds, 500);
+ read_int_option("--nonces", argc, argv, &nonces, 65536);
+ read_int_option("--threads", argc, argv, &threads, 1);
+ read_option("--interpret", argc, argv, &interpret);
+ hashx_type ctx_type = HASHX_TYPE_INTERPRETED;
+ if (!interpret) {
+ ctx_type = HASHX_TYPE_COMPILED;
+ }
+ uint64_t best_hash = UINT64_MAX;
+ uint64_t diff_ex = (uint64_t)diff * 1000ULL;
+ uint64_t threshold = UINT64_MAX / diff_ex;
+ int seeds_end = seeds + start;
+ int64_t total_hashes = 0;
+ printf("Interpret: %i, Target diff.: %" PRIu64 ", Threads: %i\n", interpret, diff_ex, threads);
+ printf("Testing seeds %i-%i with %i nonces each ...\n", start, seeds_end - 1, nonces);
+ double time_start, time_end;
+ worker_job* jobs = malloc(sizeof(worker_job) * threads);
+ if (jobs == NULL) {
+ printf("Error: memory allocation failure\n");
+ return 1;
+ }
+ for (int thd = 0; thd < threads; ++thd) {
+ jobs[thd].ctx = hashx_alloc(ctx_type);
+ if (jobs[thd].ctx == NULL) {
+ printf("Error: memory allocation failure\n");
+ return 1;
+ }
+ jobs[thd].id = thd;
+ jobs[thd].start = start + thd;
+ jobs[thd].step = threads;
+ jobs[thd].end = seeds_end;
+ jobs[thd].nonces = nonces;
+ jobs[thd].threshold = threshold;
+ }
+ time_start = hashx_time();
+ if (threads > 1) {
+ for (int thd = 0; thd < threads; ++thd) {
+ jobs[thd].thread = hashx_thread_create(&worker, &jobs[thd]);
+ }
+ for (int thd = 0; thd < threads; ++thd) {
+ hashx_thread_join(jobs[thd].thread);
+ }
+ }
+ else {
+ worker(jobs);
+ }
+ time_end = hashx_time();
+ for (int thd = 0; thd < threads; ++thd) {
+ total_hashes += jobs[thd].total_hashes;
+ if (jobs[thd].best_hash < best_hash) {
+ best_hash = jobs[thd].best_hash;
+ }
+ }
+ double elapsed = time_end - time_start;
+ printf("Total hashes: %" PRIi64 "\n", total_hashes);
+ printf("%f hashes/sec.\n", total_hashes / elapsed);
+ printf("%f seeds/sec.\n", seeds / elapsed);
+ printf("Best hash: ...");
+ output_hex((char*)&best_hash, sizeof(best_hash));
+ printf(" (diff: %" PRIu64 ")\n", UINT64_MAX / best_hash);
+ free(jobs);
+ return 0;
+}
diff --git a/src/ext/equix/hashx/src/blake2.c b/src/ext/equix/hashx/src/blake2.c
new file mode 100644
index 0000000000..916dd9b6ba
--- /dev/null
+++ b/src/ext/equix/hashx/src/blake2.c
@@ -0,0 +1,462 @@
+/* Copyright (c) 2020 tevador <tevador@gmail.com> */
+/* 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 <stdint.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#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 --git a/src/ext/equix/hashx/src/blake2.h b/src/ext/equix/hashx/src/blake2.h
new file mode 100644
index 0000000000..ba535b21fb
--- /dev/null
+++ b/src/ext/equix/hashx/src/blake2.h
@@ -0,0 +1,73 @@
+/* Copyright (c) 2020 tevador <tevador@gmail.com> */
+/* 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 <stdint.h>
+#include <limits.h>
+#include <stddef.h>
+#include <hashx.h>
+
+#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 --git a/src/ext/equix/hashx/src/compiler.c b/src/ext/equix/hashx/src/compiler.c
new file mode 100644
index 0000000000..870f3654b6
--- /dev/null
+++ b/src/ext/equix/hashx/src/compiler.c
@@ -0,0 +1,19 @@
+/* Copyright (c) 2020 tevador <tevador@gmail.com> */
+/* See LICENSE for licensing information */
+
+#include <stdbool.h>
+
+#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 --git a/src/ext/equix/hashx/src/compiler.h b/src/ext/equix/hashx/src/compiler.h
new file mode 100644
index 0000000000..b7b47dfcb5
--- /dev/null
+++ b/src/ext/equix/hashx/src/compiler.h
@@ -0,0 +1,77 @@
+/* Copyright (c) 2020 tevador <tevador@gmail.com> */
+/* See LICENSE for licensing information */
+
+#ifndef COMPILER_H
+#define COMPILER_H
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <hashx.h>
+#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 --git a/src/ext/equix/hashx/src/compiler_a64.c b/src/ext/equix/hashx/src/compiler_a64.c
new file mode 100644
index 0000000000..f4efa561b9
--- /dev/null
+++ b/src/ext/equix/hashx/src/compiler_a64.c
@@ -0,0 +1,164 @@
+/* Copyright (c) 2020 tevador <tevador@gmail.com> */
+/* See LICENSE for licensing information */
+
+#include <string.h>
+#include <assert.h>
+
+#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 --git a/src/ext/equix/hashx/src/compiler_x86.c b/src/ext/equix/hashx/src/compiler_x86.c
new file mode 100644
index 0000000000..df4fdbebb8
--- /dev/null
+++ b/src/ext/equix/hashx/src/compiler_x86.c
@@ -0,0 +1,159 @@
+/* Copyright (c) 2020 tevador <tevador@gmail.com> */
+/* See LICENSE for licensing information */
+
+#include <string.h>
+
+#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 --git a/src/ext/equix/hashx/src/context.c b/src/ext/equix/hashx/src/context.c
new file mode 100644
index 0000000000..da1b997e16
--- /dev/null
+++ b/src/ext/equix/hashx/src/context.c
@@ -0,0 +1,67 @@
+/* Copyright (c) 2020 tevador <tevador@gmail.com> */
+/* See LICENSE for licensing information */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <hashx.h>
+#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 --git a/src/ext/equix/hashx/src/context.h b/src/ext/equix/hashx/src/context.h
new file mode 100644
index 0000000000..ad434eb66c
--- /dev/null
+++ b/src/ext/equix/hashx/src/context.h
@@ -0,0 +1,39 @@
+/* Copyright (c) 2020 tevador <tevador@gmail.com> */
+/* See LICENSE for licensing information */
+
+#ifndef CONTEXT_H
+#define CONTEXT_H
+
+#include <stdbool.h>
+
+#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 --git a/src/ext/equix/hashx/src/force_inline.h b/src/ext/equix/hashx/src/force_inline.h
new file mode 100644
index 0000000000..ba3002f0f3
--- /dev/null
+++ b/src/ext/equix/hashx/src/force_inline.h
@@ -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 --git a/src/ext/equix/hashx/src/hashx.c b/src/ext/equix/hashx/src/hashx.c
new file mode 100644
index 0000000000..36a32fc298
--- /dev/null
+++ b/src/ext/equix/hashx/src/hashx.c
@@ -0,0 +1,172 @@
+/* Copyright (c) 2020 tevador <tevador@gmail.com> */
+/* See LICENSE for licensing information */
+
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+#include <hashx.h>
+#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 --git a/src/ext/equix/hashx/src/hashx_endian.h b/src/ext/equix/hashx/src/hashx_endian.h
new file mode 100644
index 0000000000..23537cfba5
--- /dev/null
+++ b/src/ext/equix/hashx/src/hashx_endian.h
@@ -0,0 +1,103 @@
+#ifndef ENDIAN_H
+#define ENDIAN_H
+
+#include <stdint.h>
+#include <string.h>
+#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 --git a/src/ext/equix/hashx/src/hashx_thread.c b/src/ext/equix/hashx/src/hashx_thread.c
new file mode 100644
index 0000000000..6618378e66
--- /dev/null
+++ b/src/ext/equix/hashx/src/hashx_thread.c
@@ -0,0 +1,27 @@
+/* Copyright (c) 2020 tevador <tevador@gmail.com> */
+/* See LICENSE for licensing information */
+
+#include "hashx_thread.h"
+
+hashx_thread hashx_thread_create(hashx_thread_func* func, void* args) {
+#ifdef HASHX_WIN
+ return CreateThread(NULL, 0, func, args, 0, NULL);
+#else
+ hashx_thread thread;
+ if (pthread_create(&thread, NULL, func, args) != 0)
+ {
+ thread = 0;
+ }
+ return thread;
+#endif
+}
+
+void hashx_thread_join(hashx_thread thread) {
+#ifdef HASHX_WIN
+ WaitForSingleObject(thread, INFINITE);
+ CloseHandle(thread);
+#else
+ void* retval;
+ pthread_join(thread, &retval);
+#endif
+}
diff --git a/src/ext/equix/hashx/src/hashx_thread.h b/src/ext/equix/hashx/src/hashx_thread.h
new file mode 100644
index 0000000000..01556626d8
--- /dev/null
+++ b/src/ext/equix/hashx/src/hashx_thread.h
@@ -0,0 +1,27 @@
+/* Copyright (c) 2020 tevador <tevador@gmail.com> */
+/* See LICENSE for licensing information */
+
+#ifndef HASHX_THREAD_H
+#define HASHX_THREAD_H
+
+#include <hashx.h>
+
+#ifdef HASHX_WIN
+#include <Windows.h>
+typedef HANDLE hashx_thread;
+typedef DWORD hashx_thread_retval;
+#define HASHX_THREAD_SUCCESS 0
+#else
+#include <pthread.h>
+typedef pthread_t hashx_thread;
+typedef void* hashx_thread_retval;
+#define HASHX_THREAD_SUCCESS NULL
+#endif
+
+typedef hashx_thread_retval hashx_thread_func(void* args);
+
+hashx_thread hashx_thread_create(hashx_thread_func* func, void* args);
+
+void hashx_thread_join(hashx_thread thread);
+
+#endif
diff --git a/src/ext/equix/hashx/src/hashx_time.c b/src/ext/equix/hashx/src/hashx_time.c
new file mode 100644
index 0000000000..d3eaaed10e
--- /dev/null
+++ b/src/ext/equix/hashx/src/hashx_time.c
@@ -0,0 +1,35 @@
+/* Copyright (c) 2020 tevador <tevador@gmail.com> */
+/* See LICENSE for licensing information */
+
+#include "hashx_time.h"
+#include <hashx.h>
+
+#if defined(HASHX_WIN)
+#include <windows.h>
+#else
+#include <sys/time.h>
+#endif
+
+double hashx_time() {
+#ifdef HASHX_WIN
+ static double freq = 0;
+ if (freq == 0) {
+ LARGE_INTEGER freq_long;
+ if (!QueryPerformanceFrequency(&freq_long)) {
+ return 0;
+ }
+ freq = freq_long.QuadPart;
+ }
+ LARGE_INTEGER time;
+ if (!QueryPerformanceCounter(&time)) {
+ return 0;
+ }
+ return time.QuadPart / freq;
+#else
+ struct timeval time;
+ if (gettimeofday(&time, NULL) != 0) {
+ return 0;
+ }
+ return (double)time.tv_sec + (double)time.tv_usec * 1.0e-6;
+#endif
+}
diff --git a/src/ext/equix/hashx/src/hashx_time.h b/src/ext/equix/hashx/src/hashx_time.h
new file mode 100644
index 0000000000..da1ca746fc
--- /dev/null
+++ b/src/ext/equix/hashx/src/hashx_time.h
@@ -0,0 +1,9 @@
+/* Copyright (c) 2020 tevador <tevador@gmail.com> */
+/* See LICENSE for licensing information */
+
+#ifndef HASHX_TIME_H
+#define HASHX_TIME_H
+
+double hashx_time(void);
+
+#endif
diff --git a/src/ext/equix/hashx/src/instruction.h b/src/ext/equix/hashx/src/instruction.h
new file mode 100644
index 0000000000..f17582ffea
--- /dev/null
+++ b/src/ext/equix/hashx/src/instruction.h
@@ -0,0 +1,31 @@
+/* Copyright (c) 2020 tevador <tevador@gmail.com> */
+/* See LICENSE for licensing information */
+
+#ifndef INSTRUCTION_H
+#define INSTRUCTION_H
+
+#include <stdint.h>
+
+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 --git a/src/ext/equix/hashx/src/program.c b/src/ext/equix/hashx/src/program.c
new file mode 100644
index 0000000000..267ab5956a
--- /dev/null
+++ b/src/ext/equix/hashx/src/program.c
@@ -0,0 +1,777 @@
+/* Copyright (c) 2020 tevador <tevador@gmail.com> */
+/* See LICENSE for licensing information */
+
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#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 --git a/src/ext/equix/hashx/src/program.h b/src/ext/equix/hashx/src/program.h
new file mode 100644
index 0000000000..78dbb8b6e3
--- /dev/null
+++ b/src/ext/equix/hashx/src/program.h
@@ -0,0 +1,52 @@
+/* Copyright (c) 2020 tevador <tevador@gmail.com> */
+/* See LICENSE for licensing information */
+
+#ifndef PROGRAM_H
+#define PROGRAM_H
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <hashx.h>
+#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 --git a/src/ext/equix/hashx/src/program_exec.c b/src/ext/equix/hashx/src/program_exec.c
new file mode 100644
index 0000000000..f00eb5ef69
--- /dev/null
+++ b/src/ext/equix/hashx/src/program_exec.c
@@ -0,0 +1,158 @@
+/* Copyright (c) 2020 tevador <tevador@gmail.com> */
+/* 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 <intrin.h>
+#include <stdlib.h>
+
+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 --git a/src/ext/equix/hashx/src/siphash.c b/src/ext/equix/hashx/src/siphash.c
new file mode 100644
index 0000000000..0acfca8814
--- /dev/null
+++ b/src/ext/equix/hashx/src/siphash.c
@@ -0,0 +1,66 @@
+/* Copyright (c) 2020 tevador <tevador@gmail.com> */
+/* 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 --git a/src/ext/equix/hashx/src/siphash.h b/src/ext/equix/hashx/src/siphash.h
new file mode 100644
index 0000000000..bb468402c3
--- /dev/null
+++ b/src/ext/equix/hashx/src/siphash.h
@@ -0,0 +1,35 @@
+/* Copyright (c) 2020 tevador <tevador@gmail.com> */
+/* See LICENSE for licensing information */
+
+#ifndef SIPHASH_H
+#define SIPHASH_H
+
+#include <stdint.h>
+#include <hashx.h>
+
+#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 --git a/src/ext/equix/hashx/src/siphash_rng.c b/src/ext/equix/hashx/src/siphash_rng.c
new file mode 100644
index 0000000000..c0f457be76
--- /dev/null
+++ b/src/ext/equix/hashx/src/siphash_rng.c
@@ -0,0 +1,41 @@
+/* Copyright (c) 2020 tevador <tevador@gmail.com> */
+/* 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 --git a/src/ext/equix/hashx/src/siphash_rng.h b/src/ext/equix/hashx/src/siphash_rng.h
new file mode 100644
index 0000000000..7b402fdc6e
--- /dev/null
+++ b/src/ext/equix/hashx/src/siphash_rng.h
@@ -0,0 +1,34 @@
+/* Copyright (c) 2020 tevador <tevador@gmail.com> */
+/* See LICENSE for licensing information */
+
+#ifndef SIPHASH_GENERATOR_H
+#define SIPHASH_GENERATOR_H
+
+#include <stdint.h>
+#include <hashx.h>
+#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 --git a/src/ext/equix/hashx/src/test_utils.h b/src/ext/equix/hashx/src/test_utils.h
new file mode 100644
index 0000000000..54c2f7ec80
--- /dev/null
+++ b/src/ext/equix/hashx/src/test_utils.h
@@ -0,0 +1,60 @@
+/* Copyright (c) 2020 tevador <tevador@gmail.com> */
+/* See LICENSE for licensing information */
+
+#ifndef TEST_UTILS_H
+#define TEST_UTILS_H
+
+#include <stdio.h>
+#include <stdbool.h>
+#include <string.h>
+#include <stdlib.h>
+#include <hashx.h>
+
+static inline void read_option(const char* option, int argc, char** argv, bool* out) {
+ for (int i = 0; i < argc; ++i) {
+ if (strcmp(argv[i], option) == 0) {
+ *out = true;
+ return;
+ }
+ }
+ *out = false;
+}
+
+static inline void read_int_option(const char* option, int argc, char** argv, int* out, int default_val) {
+ for (int i = 0; i < argc - 1; ++i) {
+ if (strcmp(argv[i], option) == 0 && (*out = atoi(argv[i + 1])) > 0) {
+ return;
+ }
+ }
+ *out = default_val;
+}
+
+static inline char parse_nibble(char hex) {
+ hex &= ~0x20;
+ return (hex & 0x40) ? hex - ('A' - 10) : hex & 0xf;
+}
+
+static inline void hex2bin(const char* in, int length, char* out) {
+ for (int i = 0; i < length; i += 2) {
+ char nibble1 = parse_nibble(*in++);
+ char nibble2 = parse_nibble(*in++);
+ *out++ = nibble1 << 4 | nibble2;
+ }
+}
+
+static inline void output_hex(const char* data, int length) {
+ for (unsigned i = 0; i < length; ++i)
+ printf("%02x", data[i] & 0xff);
+}
+
+static inline bool hashes_equal(char* a, char* b) {
+ return memcmp(a, b, HASHX_SIZE) == 0;
+}
+
+static inline bool equals_hex(const void* hash, const char* hex) {
+ char reference[HASHX_SIZE];
+ hex2bin(hex, 2 * HASHX_SIZE, reference);
+ return memcmp(hash, reference, sizeof(reference)) == 0;
+}
+
+#endif
diff --git a/src/ext/equix/hashx/src/tests.c b/src/ext/equix/hashx/src/tests.c
new file mode 100644
index 0000000000..f0a4ebe713
--- /dev/null
+++ b/src/ext/equix/hashx/src/tests.c
@@ -0,0 +1,275 @@
+/* Copyright (c) 2020 tevador <tevador@gmail.com> */
+/* See LICENSE for licensing information */
+
+#ifdef NDEBUG
+#undef NDEBUG
+#endif
+
+#include <assert.h>
+#include "test_utils.h"
+
+typedef bool test_func();
+
+static int test_no = 0;
+
+static hashx_ctx* ctx_int = NULL;
+static hashx_ctx* ctx_cmp = NULL;
+static hashx_ctx* ctx_auto = NULL;
+
+static const char seed1[] = "This is a test";
+static const char seed2[] = "Lorem ipsum dolor sit amet";
+
+static const uint64_t counter1 = 0;
+static const uint64_t counter2 = 123456;
+static const uint64_t counter3 = 987654321123456789;
+
+#ifdef HASHX_BLOCK_MODE
+static const unsigned char long_input[] = {
+ 0x0b, 0x0b, 0x98, 0xbe, 0xa7, 0xe8, 0x05, 0xe0, 0x01, 0x0a, 0x21, 0x26,
+ 0xd2, 0x87, 0xa2, 0xa0, 0xcc, 0x83, 0x3d, 0x31, 0x2c, 0xb7, 0x86, 0x38,
+ 0x5a, 0x7c, 0x2f, 0x9d, 0xe6, 0x9d, 0x25, 0x53, 0x7f, 0x58, 0x4a, 0x9b,
+ 0xc9, 0x97, 0x7b, 0x00, 0x00, 0x00, 0x00, 0x66, 0x6f, 0xd8, 0x75, 0x3b,
+ 0xf6, 0x1a, 0x86, 0x31, 0xf1, 0x29, 0x84, 0xe3, 0xfd, 0x44, 0xf4, 0x01,
+ 0x4e, 0xca, 0x62, 0x92, 0x76, 0x81, 0x7b, 0x56, 0xf3, 0x2e, 0x9b, 0x68,
+ 0xbd, 0x82, 0xf4, 0x16
+};
+#endif
+
+#define RUN_TEST(x) run_test(#x, &x)
+
+static void run_test(const char* name, test_func* func) {
+ printf("[%2i] %-40s ... ", ++test_no, name);
+ printf(func() ? "PASSED\n" : "SKIPPED\n");
+}
+
+static bool test_alloc() {
+ ctx_int = hashx_alloc(HASHX_TYPE_INTERPRETED);
+ assert(ctx_int != NULL);
+ return true;
+}
+
+static bool test_free() {
+ hashx_free(ctx_int);
+ hashx_free(ctx_cmp);
+ hashx_free(ctx_auto);
+ return true;
+}
+
+static bool test_make1() {
+ hashx_result result = hashx_make(ctx_int, seed1, sizeof(seed1));
+ assert(result == HASHX_OK);
+ return true;
+}
+
+static bool test_hash_ctr1() {
+#ifdef HASHX_SALT
+ return false;
+#endif
+#ifndef HASHX_BLOCK_MODE
+ char hash[HASHX_SIZE];
+ hashx_result result = hashx_exec(ctx_int, counter2, hash);
+ assert(result == HASHX_OK);
+ /* printf("\n");
+ output_hex(hash, HASHX_SIZE);
+ printf("\n"); */
+ assert(equals_hex(hash, "aebdd50aa67c93afb82a4c534603b65e46decd584c55161c526ebc099415ccf1"));
+ return true;
+#else
+ return false;
+#endif
+}
+
+static bool test_hash_ctr2() {
+#ifdef HASHX_SALT
+ return false;
+#endif
+#ifndef HASHX_BLOCK_MODE
+ char hash[HASHX_SIZE];
+ hashx_result result = hashx_exec(ctx_int, counter1, hash);
+ assert(result == HASHX_OK);
+ assert(equals_hex(hash, "2b2f54567dcbea98fdb5d5e5ce9a65983c4a4e35ab1464b1efb61e83b7074bb2"));
+ return true;
+#else
+ return false;
+#endif
+}
+
+static bool test_make2() {
+ hashx_result result = hashx_make(ctx_int, seed2, sizeof(seed2));
+ assert(result == HASHX_OK);
+ return true;
+}
+
+static bool test_hash_ctr3() {
+#ifdef HASHX_SALT
+ return false;
+#endif
+#ifndef HASHX_BLOCK_MODE
+ char hash[HASHX_SIZE];
+ hashx_result result = hashx_exec(ctx_int, counter2, hash);
+ assert(result == HASHX_OK);
+ assert(equals_hex(hash, "ab3d155bf4bbb0aa3a71b7801089826186e44300e6932e6ffd287cf302bbb0ba"));
+ return true;
+#else
+ return false;
+#endif
+}
+
+static bool test_hash_ctr4() {
+#ifdef HASHX_SALT
+ return false;
+#endif
+#ifndef HASHX_BLOCK_MODE
+ char hash[HASHX_SIZE];
+ hashx_result result = hashx_exec(ctx_int, counter3, hash);
+ assert(result == HASHX_OK);
+ assert(equals_hex(hash, "8dfef0497c323274a60d1d93292b68d9a0496379ba407b4341cf868a14d30113"));
+ return true;
+#else
+ return false;
+#endif
+}
+
+static bool test_hash_block1() {
+#ifdef HASHX_SALT
+ return false;
+#endif
+#ifndef HASHX_BLOCK_MODE
+ return false;
+#else
+ char hash[HASHX_SIZE];
+ hashx_result result = hashx_exec(ctx_int, long_input, sizeof(long_input), hash);
+ assert(result == HASHX_OK);
+ assert(equals_hex(hash, "d0b232b832459501ca1ac9dc0429fd931414ead7624a457e375a43ea3e5e737a"));
+ return true;
+#endif
+}
+
+static bool test_alloc_compiler() {
+ ctx_cmp = hashx_alloc(HASHX_TYPE_COMPILED);
+ assert(ctx_cmp != NULL);
+ return true;
+}
+
+static bool test_make3() {
+ hashx_result result = hashx_make(ctx_cmp, seed2, sizeof(seed2));
+ if (result == HASHX_FAIL_COMPILE) {
+ return false;
+ }
+ assert(result == HASHX_OK);
+ return true;
+}
+
+static bool test_compiler_ctr1() {
+#ifndef HASHX_BLOCK_MODE
+ hashx_result result;
+ char hash1[HASHX_SIZE];
+ char hash2[HASHX_SIZE];
+ result = hashx_exec(ctx_int, counter2, hash1);
+ assert(result == HASHX_OK);
+ result = hashx_exec(ctx_cmp, counter2, hash2);
+ if (result == HASHX_FAIL_UNPREPARED) {
+ return false;
+ }
+ assert(result == HASHX_OK);
+ assert(hashes_equal(hash1, hash2));
+ return true;
+#else
+ return false;
+#endif
+}
+
+static bool test_compiler_ctr2() {
+#ifndef HASHX_BLOCK_MODE
+ hashx_result result;
+ char hash1[HASHX_SIZE];
+ char hash2[HASHX_SIZE];
+ result = hashx_exec(ctx_int, counter1, hash1);
+ assert(result == HASHX_OK);
+ result = hashx_exec(ctx_cmp, counter1, hash2);
+ if (result == HASHX_FAIL_UNPREPARED) {
+ return false;
+ }
+ assert(result == HASHX_OK);
+ assert(hashes_equal(hash1, hash2));
+ return true;
+#else
+ return false;
+#endif
+}
+
+static bool test_compiler_block1() {
+#ifndef HASHX_BLOCK_MODE
+ return false;
+#else
+ hashx_result result;
+ char hash1[HASHX_SIZE];
+ char hash2[HASHX_SIZE];
+ result = hashx_exec(ctx_int, long_input, sizeof(long_input), hash1);
+ assert(result == HASHX_OK);
+ result = hashx_exec(ctx_cmp, long_input, sizeof(long_input), hash2);
+ if (result == HASHX_FAIL_UNPREPARED) {
+ return false;
+ }
+ assert(result == HASHX_OK);
+ assert(hashes_equal(hash1, hash2));
+ return true;
+#endif
+}
+
+static bool test_alloc_automatic() {
+ ctx_auto = hashx_alloc(HASHX_TRY_COMPILE);
+ assert(ctx_auto != NULL);
+ return true;
+}
+
+static bool test_auto_fallback() {
+ hashx_result result = hashx_make(ctx_auto, seed2, sizeof(seed2));
+ assert(result == HASHX_OK);
+ hashx_type actual_type = (hashx_type)-1;
+ result = hashx_query_type(ctx_auto, &actual_type);
+ assert(result == HASHX_OK);
+ assert(actual_type == HASHX_TYPE_INTERPRETED ||
+ actual_type == HASHX_TYPE_COMPILED);
+ return actual_type == HASHX_TYPE_INTERPRETED;
+}
+
+static bool test_bad_seeds() {
+#ifdef HASHX_SALT
+ return false;
+#else
+ hashx_result result;
+ result = hashx_make(ctx_auto, "\xf8\x05\x00\x00", 4);
+ assert(result == HASHX_OK);
+ result = hashx_make(ctx_auto, "\xf9\x05\x00\x00", 4);
+ assert(result == HASHX_FAIL_SEED);
+ result = hashx_make(ctx_auto, "\x5d\x93\x02\x00", 4);
+ assert(result == HASHX_FAIL_SEED);
+ result = hashx_make(ctx_auto, "\x5e\x93\x02\x00", 4);
+ assert(result == HASHX_OK);
+ return true;
+#endif
+}
+
+int main() {
+ RUN_TEST(test_alloc);
+ RUN_TEST(test_make1);
+ RUN_TEST(test_hash_ctr1);
+ RUN_TEST(test_hash_ctr2);
+ RUN_TEST(test_make2);
+ RUN_TEST(test_hash_ctr3);
+ RUN_TEST(test_hash_ctr4);
+ RUN_TEST(test_alloc_compiler);
+ RUN_TEST(test_make3);
+ RUN_TEST(test_compiler_ctr1);
+ RUN_TEST(test_compiler_ctr2);
+ RUN_TEST(test_hash_block1);
+ RUN_TEST(test_compiler_block1);
+ RUN_TEST(test_alloc_automatic);
+ RUN_TEST(test_auto_fallback);
+ RUN_TEST(test_bad_seeds);
+ RUN_TEST(test_free);
+
+ printf("\nAll tests were successful\n");
+ return 0;
+}
diff --git a/src/ext/equix/hashx/src/unreachable.h b/src/ext/equix/hashx/src/unreachable.h
new file mode 100644
index 0000000000..69807fb395
--- /dev/null
+++ b/src/ext/equix/hashx/src/unreachable.h
@@ -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 --git a/src/ext/equix/hashx/src/virtual_memory.c b/src/ext/equix/hashx/src/virtual_memory.c
new file mode 100644
index 0000000000..2dff6f7552
--- /dev/null
+++ b/src/ext/equix/hashx/src/virtual_memory.c
@@ -0,0 +1,140 @@
+/* Copyright (c) 2020 tevador <tevador@gmail.com> */
+/* See LICENSE for licensing information */
+
+#include "virtual_memory.h"
+
+#ifdef HASHX_WIN
+#include <windows.h>
+#else
+#ifdef __APPLE__
+#include <mach/vm_statistics.h>
+#endif
+#include <sys/types.h>
+#include <sys/mman.h>
+#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
+
+#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
+
+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
+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 --git a/src/ext/equix/hashx/src/virtual_memory.h b/src/ext/equix/hashx/src/virtual_memory.h
new file mode 100644
index 0000000000..63633bed3f
--- /dev/null
+++ b/src/ext/equix/hashx/src/virtual_memory.h
@@ -0,0 +1,23 @@
+/* Copyright (c) 2020 tevador <tevador@gmail.com> */
+/* See LICENSE for licensing information */
+
+#ifndef VIRTUAL_MEMORY_H
+#define VIRTUAL_MEMORY_H
+
+#include <stdint.h>
+#include <stddef.h>
+#include <stdbool.h>
+#include <hashx.h>
+
+#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 --git a/src/ext/equix/include/equix.h b/src/ext/equix/include/equix.h
new file mode 100644
index 0000000000..75b25a4d53
--- /dev/null
+++ b/src/ext/equix/include/equix.h
@@ -0,0 +1,166 @@
+/* Copyright (c) 2020 tevador <tevador@gmail.com> */
+/* See LICENSE for licensing information */
+
+#ifndef EQUIX_H
+#define EQUIX_H
+
+#include <stdint.h>
+#include <stddef.h>
+
+/*
+ * 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 --git a/src/ext/equix/src/bench.c b/src/ext/equix/src/bench.c
new file mode 100644
index 0000000000..8d3c82e855
--- /dev/null
+++ b/src/ext/equix/src/bench.c
@@ -0,0 +1,181 @@
+/* Copyright (c) 2020 tevador <tevador@gmail.com> */
+/* See LICENSE for licensing information */
+
+#include <stdio.h>
+#include <stdbool.h>
+#include <string.h>
+#include <stdlib.h>
+#include <equix.h>
+#include <test_utils.h>
+#include <hashx_thread.h>
+#include <hashx_time.h>
+
+typedef struct worker_job {
+ int id;
+ hashx_thread thread;
+ equix_ctx* ctx;
+ int64_t total_sols;
+ int start;
+ int step;
+ int end;
+ equix_solutions_buffer* output;
+} worker_job;
+
+static hashx_thread_retval worker(void* args) {
+ worker_job* job = (worker_job*)args;
+ job->total_sols = 0;
+ equix_solutions_buffer* outptr = job->output;
+ for (int seed = job->start; seed < job->end; seed += job->step) {
+ equix_result result = equix_solve(job->ctx, &seed,
+ sizeof(seed), outptr);
+ if (result == EQUIX_OK) {
+ job->total_sols += outptr->count;
+ } else if (result == EQUIX_FAIL_CHALLENGE) {
+ outptr->count = 0;
+ } else if (result == EQUIX_FAIL_COMPILE) {
+ printf("Error: not supported. Try with --interpret\n");
+ exit(1);
+ break;
+ } else {
+ printf("Error: unexpected solve failure (%d)\n", (int)result);
+ exit(1);
+ break;
+ }
+ outptr++;
+ }
+ return HASHX_THREAD_SUCCESS;
+}
+
+static void print_solution(int nonce, const equix_solution* sol) {
+ output_hex((char*)&nonce, sizeof(nonce));
+ printf(" : { ");
+ for (int idx = 0; idx < EQUIX_NUM_IDX; ++idx) {
+ printf("%#06x%s", sol->idx[idx],
+ idx != EQUIX_NUM_IDX - 1 ? ", " : "");
+ }
+ printf(" }\n");
+}
+
+static const char* result_names[] = {
+ "OK",
+ "Invalid nonce",
+ "Indices out of order",
+ "Nonzero partial sum",
+ "Nonzero final sum",
+ "HashX compiler failed",
+ "(Internal) Solver not allocated",
+ "(Internal error)"
+};
+
+static void print_help(char* executable) {
+ printf("Usage: %s [OPTIONS]\n", executable);
+ printf("Supported options:\n");
+ printf(" --help show this message\n");
+ printf(" --nonces N solve N nonces (default: N=500)\n");
+ printf(" --start S start with nonce S (default: S=0)\n");
+ printf(" --threads T use T threads (default: T=1)\n");
+ printf(" --interpret use HashX interpreter\n");
+ printf(" --hugepages use hugepages\n");
+ printf(" --sols print all solutions\n");
+}
+
+int main(int argc, char** argv) {
+ int nonces, start, threads;
+ bool interpret, huge_pages, print_sols, help;
+ read_option("--help", argc, argv, &help);
+ if (help) {
+ print_help(argv[0]);
+ return 0;
+ }
+ read_int_option("--nonces", argc, argv, &nonces, 500);
+ read_int_option("--start", argc, argv, &start, 0);
+ read_option("--interpret", argc, argv, &interpret);
+ read_option("--hugepages", argc, argv, &huge_pages);
+ read_option("--sols", argc, argv, &print_sols);
+ read_int_option("--threads", argc, argv, &threads, 1);
+ equix_ctx_flags flags = EQUIX_CTX_SOLVE;
+ if (!interpret) {
+ flags |= EQUIX_CTX_MUST_COMPILE;
+ }
+ if (huge_pages) {
+ flags |= EQUIX_CTX_HUGEPAGES;
+ }
+ worker_job* jobs = malloc(sizeof(worker_job) * threads);
+ if (jobs == NULL) {
+ printf("Error: memory allocation failure\n");
+ return 1;
+ }
+ int per_thread = (nonces + threads - 1) / threads;
+ for (int thd = 0; thd < threads; ++thd) {
+ jobs[thd].ctx = equix_alloc(flags);
+ if (jobs[thd].ctx == NULL) {
+ printf("Error: memory allocation failure\n");
+ return 1;
+ }
+ jobs[thd].id = thd;
+ jobs[thd].start = start + thd;
+ jobs[thd].step = threads;
+ jobs[thd].end = start + nonces;
+ jobs[thd].output = malloc(sizeof(equix_solutions_buffer) * per_thread);
+ if (jobs[thd].output == NULL) {
+ printf("Error: memory allocation failure\n");
+ return 1;
+ }
+ }
+ printf("Solving nonces %i-%i (interpret: %i, hugepages: %i, threads: %i) ...\n", start, start + nonces - 1, interpret, huge_pages, threads);
+ int total_sols = 0;
+ double time_start, time_end;
+ time_start = hashx_time();
+ if (threads > 1) {
+ for (int thd = 0; thd < threads; ++thd) {
+ jobs[thd].thread = hashx_thread_create(&worker, &jobs[thd]);
+ }
+ for (int thd = 0; thd < threads; ++thd) {
+ hashx_thread_join(jobs[thd].thread);
+ }
+ }
+ else {
+ worker(jobs);
+ }
+ time_end = hashx_time();
+ for (int thd = 0; thd < threads; ++thd) {
+ total_sols += jobs[thd].total_sols;
+ }
+ double elapsed = time_end - time_start;
+ printf("%f solutions/nonce\n", total_sols / (double)nonces);
+ printf("%f solutions/sec. (%i thread%s)\n", total_sols / elapsed, threads, threads > 1 ? "s" : "");
+ if (print_sols) {
+ for (int thd = 0; thd < threads; ++thd) {
+ worker_job* job = &jobs[thd];
+ equix_solutions_buffer* outptr = job->output;
+ for (int seed = job->start; seed < job->end; seed += job->step) {
+ for (int sol = 0; sol < outptr->count; ++sol) {
+ print_solution(seed, &outptr->sols[sol]);
+ }
+ outptr++;
+ }
+ }
+ }
+ time_start = hashx_time();
+ for (int thd = 0; thd < threads; ++thd) {
+ worker_job* job = &jobs[thd];
+ equix_solutions_buffer* outptr = job->output;
+ for (int seed = job->start; seed < job->end; seed += job->step) {
+ for (int sol = 0; sol < outptr->count; ++sol) {
+ equix_result result = equix_verify(job->ctx, &seed, sizeof(seed), &outptr->sols[sol]);
+ if (result != EQUIX_OK) {
+ printf("Invalid solution (%s):\n", result_names[result]);
+ print_solution(seed, &outptr->sols[sol]);
+ }
+ }
+ outptr++;
+ }
+ }
+ time_end = hashx_time();
+ printf("%f verifications/sec. (1 thread)\n", total_sols / (time_end - time_start));
+ for (int thd = 0; thd < threads; ++thd) {
+ free(jobs[thd].output);
+ }
+ free(jobs);
+ return 0;
+}
diff --git a/src/ext/equix/src/context.c b/src/ext/equix/src/context.c
new file mode 100644
index 0000000000..3ae4fdf9cf
--- /dev/null
+++ b/src/ext/equix/src/context.c
@@ -0,0 +1,66 @@
+/* Copyright (c) 2020 tevador <tevador@gmail.com> */
+/* See LICENSE for licensing information */
+
+#include <stdlib.h>
+#include <equix.h>
+#include <virtual_memory.h>
+#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 --git a/src/ext/equix/src/context.h b/src/ext/equix/src/context.h
new file mode 100644
index 0000000000..69dadb8069
--- /dev/null
+++ b/src/ext/equix/src/context.h
@@ -0,0 +1,18 @@
+/* Copyright (c) 2020 tevador <tevador@gmail.com> */
+/* See LICENSE for licensing information */
+
+#ifndef CONTEXT_H
+#define CONTEXT_H
+
+#include <equix.h>
+#include <hashx.h>
+
+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 --git a/src/ext/equix/src/equix.c b/src/ext/equix/src/equix.c
new file mode 100644
index 0000000000..5511201695
--- /dev/null
+++ b/src/ext/equix/src/equix.c
@@ -0,0 +1,131 @@
+/* Copyright (c) 2020 tevador <tevador@gmail.com> */
+/* See LICENSE for licensing information */
+
+#include <stdlib.h>
+#include <stdbool.h>
+#include <string.h>
+#include <assert.h>
+
+#include <equix.h>
+#include <hashx.h>
+#include "context.h"
+#include "solver.h"
+#include <hashx_endian.h>
+
+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 --git a/src/ext/equix/src/lib.rs b/src/ext/equix/src/lib.rs
new file mode 100644
index 0000000000..b5281ff149
--- /dev/null
+++ b/src/ext/equix/src/lib.rs
@@ -0,0 +1,997 @@
+//! Rust wrapper for Equi-X and HashX
+//!
+//! This is a Rust wrapper for the original C implementation of Equi-X and
+//! HashX, as used by the C implementation of Tor. For cross-compatibility
+//! testing conducted by Arti.
+//!
+//! The wrapper statically links with a modified version of the original
+//! implementation by tevador, covered by the LGPL version 3. This modified
+//! codebase is maintained as an ext module within the tor source distribution.
+//!
+//! Equi-X and HashX are `Copyright (c) 2020 tevador <tevador@gmail.com>`.
+//! See `LICENSE` for licensing information.
+//!
+
+use core::ffi::c_void;
+use core::mem;
+use core::ptr::null_mut;
+
+pub mod ffi {
+ //! Low-level access to the C API
+
+ #![allow(non_upper_case_globals)]
+ #![allow(non_camel_case_types)]
+ #![allow(non_snake_case)]
+
+ include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
+}
+
+/// Type parameter for [`HashX::new()`]
+pub type HashXType = ffi::hashx_type;
+
+/// Result codes for HashX
+pub type HashXResult = ffi::hashx_result;
+
+/// Configured size of the HashX output. Always 8 in this implementation.
+pub const HASHX_SIZE: usize = ffi::HASHX_SIZE as usize;
+
+/// Output value obtained by executing a HashX hash function
+pub type HashXOutput = [u8; HASHX_SIZE];
+
+/// Type for callback functions that inspect or replace the pseudorandom stream
+pub type RngCallback = Box<dyn FnMut(u64) -> u64>;
+
+/// Safe wrapper around a HashX context
+pub struct HashX {
+ ctx: *mut ffi::hashx_ctx,
+ rng_callback: Option<RngCallback>,
+}
+
+impl HashX {
+ /// Allocate a new HashX context
+ pub fn new(ht: HashXType) -> Self {
+ let ctx = unsafe { ffi::hashx_alloc(ht) };
+ if ctx.is_null() {
+ panic!("out of memory in hashx_alloc");
+ }
+ Self {
+ ctx,
+ rng_callback: None,
+ }
+ }
+
+ /// Create a new hash function within this context, using the given seed
+ ///
+ /// May fail if the seed is unusable or if a runtime compiler
+ /// error occurs while the interpreter is disabled.
+ #[inline(always)]
+ pub fn make(&mut self, seed: &[u8]) -> HashXResult {
+ unsafe { ffi::hashx_make(self.ctx, seed.as_ptr() as *const c_void, seed.len()) }
+ }
+
+ /// Check which implementation was selected by `make`
+ #[inline(always)]
+ pub fn query_type(&mut self) -> Result<HashXType, HashXResult> {
+ let mut buffer = HashXType::HASHX_TYPE_INTERPRETED; // Arbitrary default
+ let result =
+ unsafe { ffi::hashx_query_type(self.ctx, &mut buffer as *mut ffi::hashx_type) };
+ match result {
+ HashXResult::HASHX_OK => Ok(buffer),
+ e => Err(e),
+ }
+ }
+
+ /// Execute the hash function for a given input
+ #[inline(always)]
+ pub fn exec(&mut self, input: u64) -> Result<HashXOutput, HashXResult> {
+ let mut buffer: HashXOutput = Default::default();
+ let result =
+ unsafe { ffi::hashx_exec(self.ctx, input, &mut buffer as *mut u8 as *mut c_void) };
+ match result {
+ HashXResult::HASHX_OK => Ok(buffer),
+ e => Err(e),
+ }
+ }
+
+ /// Set a callback function that may inspect and/or modify the internal
+ /// pseudorandom number stream used by this context.
+ ///
+ /// The function will be owned by this context, and it replaces any
+ /// previous function that may have been set. Returns the previous callback
+ /// if any.
+ pub fn rng_callback(&mut self, callback: Option<RngCallback>) -> Option<RngCallback> {
+ // Keep ownership of our Rust value in the context wrapper, to match
+ // the lifetime of the mutable pointer that the C API saves.
+ let result = mem::replace(&mut self.rng_callback, callback);
+ match &mut self.rng_callback {
+ None => unsafe { ffi::hashx_rng_callback(self.ctx, None, null_mut()) },
+ Some(callback) => unsafe {
+ ffi::hashx_rng_callback(
+ self.ctx,
+ Some(wrapper),
+ callback as *mut RngCallback as *mut c_void,
+ );
+ },
+ }
+ unsafe extern "C" fn wrapper(buffer: *mut u64, callback: *mut c_void) {
+ let callback = &mut *(callback as *mut RngCallback);
+ buffer.write(callback(buffer.read()));
+ }
+ result
+ }
+}
+
+impl Drop for HashX {
+ fn drop(&mut self) {
+ let ctx = mem::replace(&mut self.ctx, null_mut());
+ unsafe {
+ ffi::hashx_free(ctx);
+ }
+ }
+}
+
+/// Option flags for [`EquiX::new()`]
+pub type EquiXFlags = ffi::equix_ctx_flags;
+
+/// A single Equi-X solution
+pub type EquiXSolution = ffi::equix_solution;
+
+/// Flags with additional information about solutions
+pub type EquiXSolutionFlags = ffi::equix_solution_flags;
+
+/// A buffer with space for several Equi-X solutions
+pub type EquiXSolutionsBuffer = ffi::equix_solutions_buffer;
+
+/// Number of indices in a single Equi-X solution
+pub const EQUIX_NUM_IDX: usize = ffi::EQUIX_NUM_IDX as usize;
+
+/// Maximum number of Equi-X solutions we will return at once
+pub const EQUIX_MAX_SOLS: usize = ffi::EQUIX_MAX_SOLS as usize;
+
+impl Default for EquiXSolutionsBuffer {
+ fn default() -> Self {
+ Self {
+ count: 0,
+ flags: ffi::equix_solution_flags(0),
+ sols: [EquiXSolution {
+ idx: [0; EQUIX_NUM_IDX],
+ }; EQUIX_MAX_SOLS],
+ }
+ }
+}
+
+/// Result codes for Equi-X
+pub type EquiXResult = ffi::equix_result;
+
+/// Safe wrapper around an Equi-X context
+pub struct EquiX(*mut ffi::equix_ctx);
+
+impl EquiX {
+ /// Allocate a new Equi-X context
+ pub fn new(flags: EquiXFlags) -> Self {
+ let ctx = unsafe { ffi::equix_alloc(flags) };
+ if ctx.is_null() {
+ panic!("out of memory in equix_alloc");
+ }
+ Self(ctx)
+ }
+
+ /// Verify an Equi-X solution against a particular challenge
+ #[inline(always)]
+ pub fn verify(&mut self, challenge: &[u8], solution: &EquiXSolution) -> EquiXResult {
+ unsafe {
+ ffi::equix_verify(
+ self.0,
+ challenge.as_ptr() as *const c_void,
+ challenge.len(),
+ solution as *const ffi::equix_solution,
+ )
+ }
+ }
+
+ /// Run the solver, returning a variable number of solutions for a challenge
+ #[inline(always)]
+ pub fn solve(&mut self, challenge: &[u8], buffer: &mut EquiXSolutionsBuffer) -> EquiXResult {
+ unsafe {
+ ffi::equix_solve(
+ self.0,
+ challenge.as_ptr() as *const c_void,
+ challenge.len(),
+ buffer as *mut ffi::equix_solutions_buffer,
+ )
+ }
+ }
+}
+
+impl Drop for EquiX {
+ fn drop(&mut self) {
+ let ctx = mem::replace(&mut self.0, null_mut());
+ unsafe {
+ ffi::equix_free(ctx);
+ }
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use crate::*;
+ use hex_literal::hex;
+ use std::cell::RefCell;
+ use std::rc::Rc;
+
+ #[test]
+ fn equix_context() {
+ let _ = EquiX::new(EquiXFlags::EQUIX_CTX_TRY_COMPILE | EquiXFlags::EQUIX_CTX_SOLVE);
+ let _ = EquiX::new(EquiXFlags::EQUIX_CTX_SOLVE);
+ let _ = EquiX::new(EquiXFlags::EQUIX_CTX_VERIFY);
+ }
+
+ #[test]
+ fn equix_verify_only() {
+ let mut ctx = EquiX::new(EquiXFlags::EQUIX_CTX_TRY_COMPILE | EquiXFlags::EQUIX_CTX_VERIFY);
+
+ assert_eq!(
+ ctx.verify(
+ b"a",
+ &EquiXSolution {
+ idx: [0x2227, 0xa173, 0x365a, 0xb47d, 0x1bb2, 0xa077, 0x0d5e, 0xf25f]
+ }
+ ),
+ EquiXResult::EQUIX_OK
+ );
+ assert_eq!(
+ ctx.verify(
+ b"a",
+ &EquiXSolution {
+ idx: [0x1bb2, 0xa077, 0x0d5e, 0xf25f, 0x2220, 0xa173, 0x365a, 0xb47d]
+ }
+ ),
+ EquiXResult::EQUIX_FAIL_ORDER
+ );
+ assert_eq!(
+ ctx.verify(
+ b"a",
+ &EquiXSolution {
+ idx: [0x2220, 0xa173, 0x365a, 0xb47d, 0x1bb2, 0xa077, 0x0d5e, 0xf25f]
+ }
+ ),
+ EquiXResult::EQUIX_FAIL_PARTIAL_SUM
+ );
+ }
+
+ #[test]
+ fn equix_solve_only() {
+ let mut ctx = EquiX::new(EquiXFlags::EQUIX_CTX_TRY_COMPILE | EquiXFlags::EQUIX_CTX_SOLVE);
+ let mut buffer = Default::default();
+ assert_eq!(
+ ctx.solve(b"01234567890123456789", &mut buffer),
+ EquiXResult::EQUIX_OK
+ );
+ assert_eq!(buffer.count, 5);
+ assert_eq!(
+ buffer.sols[0].idx,
+ [0x4803, 0x6775, 0xc5c9, 0xd1b0, 0x1bc3, 0xe4f6, 0x4027, 0xf5ad,]
+ );
+ assert_eq!(
+ buffer.sols[1].idx,
+ [0x5a8a, 0x9542, 0xef99, 0xf0b9, 0x4905, 0x4e29, 0x2da5, 0xfbd5,]
+ );
+ assert_eq!(
+ buffer.sols[2].idx,
+ [0x4c79, 0xc935, 0x2bcb, 0xcd0f, 0x0362, 0x9fa9, 0xa62e, 0xf83a,]
+ );
+ assert_eq!(
+ buffer.sols[3].idx,
+ [0x5878, 0x6edf, 0x1e00, 0xf5e3, 0x43de, 0x9212, 0xd01e, 0xfd11,]
+ );
+ assert_eq!(
+ buffer.sols[4].idx,
+ [0x0b69, 0x2d17, 0x01be, 0x6cb4, 0x0fba, 0x4a9e, 0x8d75, 0xa50f,]
+ );
+ }
+
+ #[test]
+ fn hashx_context() {
+ // Context creation should always succeed
+ let _ = HashX::new(HashXType::HASHX_TYPE_INTERPRETED);
+ let _ = HashX::new(HashXType::HASHX_TYPE_COMPILED);
+ let _ = HashX::new(HashXType::HASHX_TRY_COMPILE);
+ }
+
+ #[test]
+ fn bad_seeds() {
+ // Some seed values we expect to fail (and one control).
+ // Also tests query_type while we're here.
+ let mut ctx = HashX::new(HashXType::HASHX_TYPE_INTERPRETED);
+ assert_eq!(ctx.query_type(), Err(HashXResult::HASHX_FAIL_UNPREPARED));
+ assert_eq!(ctx.make(b"qfjsfv"), HashXResult::HASHX_FAIL_SEED);
+ assert_eq!(ctx.query_type(), Err(HashXResult::HASHX_FAIL_UNPREPARED));
+ assert_eq!(ctx.make(b"llompmb"), HashXResult::HASHX_OK);
+ assert_eq!(ctx.query_type(), Ok(HashXType::HASHX_TYPE_INTERPRETED));
+ assert_eq!(ctx.make(b"mhelht"), HashXResult::HASHX_FAIL_SEED);
+ assert_eq!(ctx.query_type(), Err(HashXResult::HASHX_FAIL_UNPREPARED));
+ }
+
+ #[test]
+ fn hash_values() {
+ // Some sample hash values
+ let mut ctx = HashX::new(HashXType::HASHX_TRY_COMPILE);
+ assert_eq!(ctx.make(b"ebrazua"), HashXResult::HASHX_OK);
+ assert_eq!(ctx.exec(0xebc19ba9cafb0863), Ok(hex!("41cb0b4b24551d26")));
+ assert_eq!(ctx.make(b"This is a test\0"), HashXResult::HASHX_OK);
+ assert_eq!(ctx.exec(0), Ok(hex!("2b2f54567dcbea98")));
+ assert_eq!(ctx.exec(123456), Ok(hex!("aebdd50aa67c93af")));
+ assert_eq!(
+ ctx.make(b"Lorem ipsum dolor sit amet\0"),
+ HashXResult::HASHX_OK
+ );
+ assert_eq!(ctx.exec(123456), Ok(hex!("ab3d155bf4bbb0aa")));
+ assert_eq!(ctx.exec(987654321123456789), Ok(hex!("8dfef0497c323274")));
+ }
+
+ #[test]
+ fn rng_callback_read() {
+ // Use a Rng callback to read the sequence of pseudorandom numbers
+ // without changing them, and spot check the list we get back.
+ let mut ctx = HashX::new(HashXType::HASHX_TRY_COMPILE);
+ let seq = Rc::new(RefCell::new(Vec::new()));
+ {
+ let seq = seq.clone();
+ ctx.rng_callback(Some(Box::new(move |value| {
+ seq.borrow_mut().push(value);
+ value
+ })));
+ }
+ assert_eq!(seq.borrow().len(), 0);
+ assert_eq!(ctx.make(b"abc"), HashXResult::HASHX_OK);
+ assert_eq!(ctx.exec(12345).unwrap(), hex!("c0bc95da7cc30f37"));
+ assert_eq!(seq.borrow().len(), 563);
+ assert_eq!(
+ seq.borrow()[..4],
+ [
+ 0xf695edd02205449d,
+ 0x51c1ac51cd19a7d1,
+ 0xadf4cb303b9814cf,
+ 0x79793a52d965083d
+ ]
+ );
+ }
+
+ #[test]
+ fn rng_callback_replace() {
+ // Use a Rng callback to replace the random number stream.
+ // We have to choose the replacement somewhat carefully since
+ // many stationary replacement values will cause infinite loops.
+ let mut ctx = HashX::new(HashXType::HASHX_TYPE_INTERPRETED);
+ let counter = Rc::new(RefCell::new(0u32));
+ {
+ let counter = counter.clone();
+ ctx.rng_callback(Some(Box::new(move |_value| {
+ *counter.borrow_mut() += 1;
+ 0x0807060504030201
+ })));
+ }
+ assert_eq!(*counter.borrow(), 0);
+ assert_eq!(ctx.make(b"abc"), HashXResult::HASHX_OK);
+ assert_eq!(ctx.exec(12345).unwrap(), hex!("825a9b6dd5d074af"));
+ assert_eq!(*counter.borrow(), 575);
+ }
+
+ #[test]
+ fn rng_large_compiler_output() {
+ // This is really a general HashX test rather than a test for the Rust
+ // wrapper. It's easier to implement here than in hashx-test, since
+ // the Rng callback is disabled by default in the cmake build system.
+ //
+ // The purpose of this test is to use a specially crafted Rng sequence
+ // to generate an especially large compiled hash program, to test for
+ // length-related problems.
+ //
+ // There are various ways to generate these Rng sequences. The fuzzer
+ // in Arti will do this on its own. The sequence here was found with
+ // a simple ad-hoc optimizer that modifies one byte at a time in a
+ // search for peaks in either x86_64 or aarch64 code size.
+ //
+ // The expected compiled program length:
+ //
+ // - On x86_64, 3188 bytes
+ // (safely less than a page still)
+ //
+ // - On aarch64, 4388 bytes
+ // (would overflow a single page buffer by 292 bytes)
+ //
+
+ const SEQUENCE: [u64; 558] = [
+ 0xffffffffffffffff, // 0
+ 0xffffffffffffffff, // 1
+ 0xfbfefefbfbfeffff, // 2
+ 0xffffffffffffffff, // 3
+ 0xffffffffffffffff, // 4
+ 0xfffffffffffffdff, // 5
+ 0xffffffffffffffff, // 6
+ 0xffffffffffffffff, // 7
+ 0xfffffffefffffffd, // 8
+ 0xffffffffffffffff, // 9
+ 0xffffffffffffffff, // 10
+ 0xffffffffffffffff, // 11
+ 0xfefffffeffffffff, // 12
+ 0xffffffffffffffff, // 13
+ 0xffffffffffffffff, // 14
+ 0xfefbfcfdfefffefb, // 15
+ 0xfffffffffffffffc, // 16
+ 0xffffffffffffffff, // 17
+ 0xffffffffffffffff, // 18
+ 0xffffffffffffffff, // 19
+ 0xffffffffffffffff, // 20
+ 0xfffffffffffefffe, // 21
+ 0xfffffefffbfefbfe, // 22
+ 0xffffffffffffffff, // 23
+ 0xfefeffffffffffff, // 24
+ 0xffffffffffffffff, // 25
+ 0xffffffffffffffff, // 26
+ 0xffffffffffffffff, // 27
+ 0xffffffffffffffff, // 28
+ 0xffffffffffffffff, // 29
+ 0xffffffffffffffff, // 30
+ 0xffffffffffffffff, // 31
+ 0xffffffffffffffff, // 32
+ 0xffffffffffffffff, // 33
+ 0xfffffffeffffffff, // 34
+ 0xffffffffffffffff, // 35
+ 0xfffffffffffffffe, // 36
+ 0xffffffffffffffff, // 37
+ 0xfbfbfffefffbffff, // 38
+ 0xffffffffffffffff, // 39
+ 0xfffffffffffffffe, // 40
+ 0xffffffffffffffff, // 41
+ 0xffffffffffffffff, // 42
+ 0xffffffffffffffff, // 43
+ 0xffffffffffffffff, // 44
+ 0xfffffffeffffffff, // 45
+ 0xffffffffffffffff, // 46
+ 0xffffffffffffffff, // 47
+ 0xffffffffffffffff, // 48
+ 0xfefefffdffffffff, // 49
+ 0xfefbfefefefcfdff, // 50
+ 0xffffffffffffffff, // 51
+ 0xffffffffffffffff, // 52
+ 0xffffffffffffffff, // 53
+ 0xffffffffffffffff, // 54
+ 0xfefffffffefefffc, // 55
+ 0xfffffffeffffffff, // 56
+ 0xfbfefffefbfefefb, // 57
+ 0xfffffffeffffffff, // 58
+ 0xffffffffffffffff, // 59
+ 0xfffffffffffffefc, // 60
+ 0xfffffffffffffffc, // 61
+ 0xffffffffffffffff, // 62
+ 0xffffffffffffffff, // 63
+ 0xffffffffffffffff, // 64
+ 0xfffffefdffffffff, // 65
+ 0xffffffffffffffff, // 66
+ 0xffffffffffffffff, // 67
+ 0xffffffffffffffff, // 68
+ 0xfefbfefbfefbfbfe, // 69
+ 0xffffffffffffffff, // 70
+ 0xffffffffffffffff, // 71
+ 0xfffefeffffffffff, // 72
+ 0xfffffffffffffffe, // 73
+ 0xffffffffffffffff, // 74
+ 0xffffffffffffffff, // 75
+ 0xfeffffffffffffff, // 76
+ 0xffffffffffffffff, // 77
+ 0xffffffffffffffff, // 78
+ 0xffffffffffffffff, // 79
+ 0xffffffffffffffff, // 80
+ 0xffffffffffffffff, // 81
+ 0xfffffffefcfdfeff, // 82
+ 0xffffffffffffffff, // 83
+ 0xfefeffffffffffff, // 84
+ 0xffffffffffffffff, // 85
+ 0xffffffffffffffff, // 86
+ 0xffffffffffffffff, // 87
+ 0xfffffffdffffffff, // 88
+ 0xffffffffffffffff, // 89
+ 0xffffffffffffffff, // 90
+ 0xffffffffffffffff, // 91
+ 0xfefbfffefefbfbfe, // 92
+ 0xffffffffffffffff, // 93
+ 0xfffffffeffffffff, // 94
+ 0xfffffffffefeffff, // 95
+ 0xffffffffffffffff, // 96
+ 0xfffffffffffffffe, // 97
+ 0xffffffffffffffff, // 98
+ 0xffffffffffffffff, // 99
+ 0xffffffffffffffff, // 100
+ 0xfffffffffffffffe, // 101
+ 0xfffffffffeffffff, // 102
+ 0xfdfdffffffffffff, // 103
+ 0xfbfefbfefefefefe, // 104
+ 0xffffffffffffffff, // 105
+ 0xffffffffffffffff, // 106
+ 0xfffffffffffffffd, // 107
+ 0xfefffffffffefdff, // 108
+ 0xfffffffffefffffe, // 109
+ 0xfffffffffffffffe, // 110
+ 0xffffffffffffffff, // 111
+ 0xffffffffffffffff, // 112
+ 0xfbfefef8fffefefb, // 113
+ 0xfffffffcffffffff, // 114
+ 0xfefefefdffffffff, // 115
+ 0xffffffffffffffff, // 116
+ 0xfffffffdffffffff, // 117
+ 0xfffffffffdfdfdfb, // 118
+ 0xffffffffffffffff, // 119
+ 0xfffdfdffffffffff, // 120
+ 0xffffffffffffffff, // 121
+ 0xffffffffffffffff, // 122
+ 0xfffffffffffffffd, // 123
+ 0xfdfffefffffcfffe, // 124
+ 0xfcfefffffffefeff, // 125
+ 0xffffffffffffffff, // 126
+ 0xffffffffffffffff, // 127
+ 0xffffffffffffffff, // 128
+ 0xfffbf8f8fbf8fefe, // 129
+ 0xfffffffffefcfdff, // 130
+ 0xfffffffffffffffd, // 131
+ 0xffffffffffffffff, // 132
+ 0xfffffffffcfcffff, // 133
+ 0xffffffffffffffff, // 134
+ 0xffffffffffffffff, // 135
+ 0xfffffffffdfefdff, // 136
+ 0xffffffffffffffff, // 137
+ 0xfcfefbfdfffffffe, // 138
+ 0xfffffffffeffffff, // 139
+ 0xf8fbfefefefffeff, // 140
+ 0xffffffffffffffff, // 141
+ 0xfefefefffefffffe, // 142
+ 0xffffffffffffffff, // 143
+ 0xfffffffffcfefeff, // 144
+ 0xffffffffffffffff, // 145
+ 0xfffffffffffffffe, // 146
+ 0xfffffffffffffffe, // 147
+ 0xffffffffffffffff, // 148
+ 0xfffffffffefffeff, // 149
+ 0xfffefffeffffffff, // 150
+ 0xffffffffffffffff, // 151
+ 0xffffffffffffffff, // 152
+ 0xfffffbfefffffcff, // 153
+ 0xffffffffffffffff, // 154
+ 0xfdfefefaffffffff, // 155
+ 0xffffffffffffffff, // 156
+ 0xfffffffffffffffd, // 157
+ 0xfffffffffffffffe, // 158
+ 0xffffffffffffffff, // 159
+ 0xffffffffffffffff, // 160
+ 0xfdfefefbfffbfffe, // 161
+ 0xfffffffefffffffe, // 162
+ 0xffffffffffffffff, // 163
+ 0xffffffffffffffff, // 164
+ 0xfeffffffffffffff, // 165
+ 0xfffdfffdffffffff, // 166
+ 0xfffffffdffffffff, // 167
+ 0xfeffffffffffffff, // 168
+ 0xffffffffffffffff, // 169
+ 0xffffffffffffffff, // 170
+ 0xffffffffffffffff, // 171
+ 0xfcfffefefffefbfe, // 172
+ 0xffffffffffffffff, // 173
+ 0xfffffffffffeffff, // 174
+ 0xffffffffffffffff, // 175
+ 0xfffffffffffffffe, // 176
+ 0xfffffffffdfefdfd, // 177
+ 0xffffffffffffffff, // 178
+ 0xffffffffffffffff, // 179
+ 0xfffffffdffffffff, // 180
+ 0xffffffffffffffff, // 181
+ 0xffffffffffffffff, // 182
+ 0xffffffffffffffff, // 183
+ 0xffffffffffffffff, // 184
+ 0xfbfffefffefefbfd, // 185
+ 0xfffffffffffeffff, // 186
+ 0xffffffffffffffff, // 187
+ 0xffffffffffffffff, // 188
+ 0xffffffffffffffff, // 189
+ 0xffffffffffffffff, // 190
+ 0xfffdfeffffffffff, // 191
+ 0xffffffffffffffff, // 192
+ 0xfffffffeffffffff, // 193
+ 0xffffffffffffffff, // 194
+ 0xffffffffffffffff, // 195
+ 0xfffffffefeffffff, // 196
+ 0xfcfefff8fefffbfe, // 197
+ 0xffffffffffffffff, // 198
+ 0xffffffffffffffff, // 199
+ 0xffffffffffffffff, // 200
+ 0xffffffffffffffff, // 201
+ 0xffffffffffffffff, // 202
+ 0xffffffffffffffff, // 203
+ 0xffffffffffffffff, // 204
+ 0xfbfbfefbfefefeff, // 205
+ 0xffffffffffffffff, // 206
+ 0xfffeffffffffffff, // 207
+ 0xffffffffffffffff, // 208
+ 0xffffffffffffffff, // 209
+ 0xffffffffffffffff, // 210
+ 0xffffffffffffffff, // 211
+ 0xffffffffffffffff, // 212
+ 0xfffffffffefeffff, // 213
+ 0xfefefefeffffffff, // 214
+ 0xffffffffffffffff, // 215
+ 0xffffffffffffffff, // 216
+ 0xfffffffffefeffff, // 217
+ 0xfbfefbfefffefefb, // 218
+ 0xffffffffffffffff, // 219
+ 0xfffffffffffffffe, // 220
+ 0xfffffffefdfffefe, // 221
+ 0xffffffffffffffff, // 222
+ 0xffffffffffffffff, // 223
+ 0xffffffffffffffff, // 224
+ 0xfffefffcffffffff, // 225
+ 0xfffffefffffdfdff, // 226
+ 0xfffefeffffffffff, // 227
+ 0xfffffeffffffffff, // 228
+ 0xffffffffffffffff, // 229
+ 0xfffffffffefefefd, // 230
+ 0xfcfdfefffefffffe, // 231
+ 0xfefdffffffffffff, // 232
+ 0xfffffffeffffffff, // 233
+ 0xfdfefdffffffffff, // 234
+ 0xffffffffffffffff, // 235
+ 0xfdfefffeffffffff, // 236
+ 0xffffffffffffffff, // 237
+ 0xffffffffffffffff, // 238
+ 0xfbfffffefbfefefe, // 239
+ 0xfefcfdffffffffff, // 240
+ 0xfffffffffffffffe, // 241
+ 0xfffffffefefdfefd, // 242
+ 0xffffffffffffffff, // 243
+ 0xfffeffffffffffff, // 244
+ 0xffffffffffffffff, // 245
+ 0xfffffffeffffffff, // 246
+ 0xffffffffffffffff, // 247
+ 0xfffffffffefefeff, // 248
+ 0xfffffffdfefffefe, // 249
+ 0xfffefeffffffffff, // 250
+ 0xffffffffffffffff, // 251
+ 0xfbfbfefefefbfffe, // 252
+ 0xffffffffffffffff, // 253
+ 0xfffffffeffffffff, // 254
+ 0xfffffffeffffffff, // 255
+ 0xfefffeffffffffff, // 256
+ 0xfffffdffffffffff, // 257
+ 0xffffffffffffffff, // 258
+ 0xffffffffffffffff, // 259
+ 0xfffffffffdfffdff, // 260
+ 0xfffffffffefffffe, // 261
+ 0xfefffffffffffefe, // 262
+ 0xfefffcfdfffefefb, // 263
+ 0xffffffffffffffff, // 264
+ 0xffffffffffffffff, // 265
+ 0xffffffffffffffff, // 266
+ 0xfffffffffeffffff, // 267
+ 0xffffffffffffffff, // 268
+ 0xffffffffffffffff, // 269
+ 0xffffffffffffffff, // 270
+ 0xfefbfefbfbfefefe, // 271
+ 0xfffffffffffffdff, // 272
+ 0xfffffffffffffffe, // 273
+ 0xffffffffffffffff, // 274
+ 0xffffffffffffffff, // 275
+ 0xffffffffffffffff, // 276
+ 0xffffffffffffffff, // 277
+ 0xffffffffffffffff, // 278
+ 0xffffffffffffffff, // 279
+ 0xfffffcfcfffffeff, // 280
+ 0xffffffffffffffff, // 281
+ 0xfbf8fefefbfbfeff, // 282
+ 0xfffffffffffffffe, // 283
+ 0xfffffffffffffffe, // 284
+ 0xffffffffffffffff, // 285
+ 0xffffffffffffffff, // 286
+ 0xffffffffffffffff, // 287
+ 0xffffffffffffffff, // 288
+ 0xffffffffffffffff, // 289
+ 0xffffffffffffffff, // 290
+ 0xffffffffffffffff, // 291
+ 0xffffffffffffffff, // 292
+ 0xffffffffffffffff, // 293
+ 0xffffffffffffffff, // 294
+ 0xffffffffffffffff, // 295
+ 0xfefefdfcfdfefffe, // 296
+ 0xfffffffeffffffff, // 297
+ 0xffffffffffffffff, // 298
+ 0xfffffeffffffffff, // 299
+ 0xffffffffffffffff, // 300
+ 0xfffefffffefefffe, // 301
+ 0xfffffffeffffffff, // 302
+ 0xffffffffffffffff, // 303
+ 0xfbfffefefbfefffe, // 304
+ 0xffffffffffffffff, // 305
+ 0xfffffffffffeffff, // 306
+ 0xffffffffffffffff, // 307
+ 0xfffeffffffffffff, // 308
+ 0xffffffffffffffff, // 309
+ 0xffffffffffffffff, // 310
+ 0xffffffffffffffff, // 311
+ 0xffffffffffffffff, // 312
+ 0xffffffffffffffff, // 313
+ 0xffffffffffffffff, // 314
+ 0xffffffffffffffff, // 315
+ 0xfffffffeffffffff, // 316
+ 0xfbfefbfbfefbfeff, // 317
+ 0xffffffffffffffff, // 318
+ 0xfffffffefefeffff, // 319
+ 0xfffffffeffffffff, // 320
+ 0xffffffffffffffff, // 321
+ 0xffffffffffffffff, // 322
+ 0xffffffffffffffff, // 323
+ 0xffffffffffffffff, // 324
+ 0xffffffffffffffff, // 325
+ 0xffffffffffffffff, // 326
+ 0xffffffffffffffff, // 327
+ 0xffffffffffffffff, // 328
+ 0xfffffffffefefeff, // 329
+ 0xfefefefefbfdfeff, // 330
+ 0xffffffffffffffff, // 331
+ 0xffffffffffffffff, // 332
+ 0xfffffffffeffffff, // 333
+ 0xffffffffffffffff, // 334
+ 0xfefffffffffffffe, // 335
+ 0xfcfbfefffefbfefe, // 336
+ 0xfffffffffffefeff, // 337
+ 0xffffffffffffffff, // 338
+ 0xffffffffffffffff, // 339
+ 0xfeffffffffffffff, // 340
+ 0xfffdfeffffffffff, // 341
+ 0xffffffffffffffff, // 342
+ 0xffffffffffffffff, // 343
+ 0xffffffffffffffff, // 344
+ 0xffffffffffffffff, // 345
+ 0xfffffffdffffffff, // 346
+ 0xffffffffffffffff, // 347
+ 0xfefbfbfefbfeffff, // 348
+ 0xffffffffffffffff, // 349
+ 0xffffffffffffffff, // 350
+ 0xffffffffffffffff, // 351
+ 0xffffffffffffffff, // 352
+ 0xffffffffffffffff, // 353
+ 0xffffffffffffffff, // 354
+ 0xffffffffffffffff, // 355
+ 0xfffffffeffffffff, // 356
+ 0xffffffffffffffff, // 357
+ 0xffffffffffffffff, // 358
+ 0xfefbfefffefffbff, // 359
+ 0xffffffffffffffff, // 360
+ 0xfefffffffffffffe, // 361
+ 0xffffffffffffffff, // 362
+ 0xffffffffffffffff, // 363
+ 0xffffffffffffffff, // 364
+ 0xfffffefdffffffff, // 365
+ 0xfffffffeffffffff, // 366
+ 0xffffffffffffffff, // 367
+ 0xfffefefefffffffe, // 368
+ 0xfffffffffffffffe, // 369
+ 0xfffffffffffffffc, // 370
+ 0xfcfdfffefefbfffe, // 371
+ 0xfcfdfcfcfffffffe, // 372
+ 0xffffffffffffffff, // 373
+ 0xffffffffffffffff, // 374
+ 0xffffffffffffffff, // 375
+ 0xfdfdfffeffffffff, // 376
+ 0xfffffffffffffeff, // 377
+ 0xfffffffeffffffff, // 378
+ 0xfbfefefbfbfefefb, // 379
+ 0xfffffffdffffffff, // 380
+ 0xffffffffffffffff, // 381
+ 0xffffffffffffffff, // 382
+ 0xffffffffffffffff, // 383
+ 0xffffffffffffffff, // 384
+ 0xffffffffffffffff, // 385
+ 0xffffffffffffffff, // 386
+ 0xfffffffffffffffe, // 387
+ 0xfffffffffffffffe, // 388
+ 0xffffffffffffffff, // 389
+ 0xffffffffffffffff, // 390
+ 0xffffffffffffffff, // 391
+ 0xfefefbfbfefffeff, // 392
+ 0xfffffffffffffffe, // 393
+ 0xffffffffffffffff, // 394
+ 0xfffffffffffffffd, // 395
+ 0xffffffffffffffff, // 396
+ 0xffffffffffffffff, // 397
+ 0xffffffffffffffff, // 398
+ 0xfffeffffffffffff, // 399
+ 0xffffffffffffffff, // 400
+ 0xffffffffffffffff, // 401
+ 0xfffffefeffffffff, // 402
+ 0xfefdfcfefffffeff, // 403
+ 0xffffffffffffffff, // 404
+ 0xfffffffffffffffe, // 405
+ 0xffffffffffffffff, // 406
+ 0xffffffffffffffff, // 407
+ 0xfffffffeffffffff, // 408
+ 0xffffffffffffffff, // 409
+ 0xfffffffffefeffff, // 410
+ 0xfefefbfbfefbfefe, // 411
+ 0xfffffffffffefffe, // 412
+ 0xffffffffffffffff, // 413
+ 0xffffffffffffffff, // 414
+ 0xfffffffffffffffe, // 415
+ 0xffffffffffffffff, // 416
+ 0xffffffffffffffff, // 417
+ 0xfffffffffffffffe, // 418
+ 0xfffffffffffffffe, // 419
+ 0xfffffffffffffffe, // 420
+ 0xffffffffffffffff, // 421
+ 0xfffffffefffeffff, // 422
+ 0xfffffffeffffffff, // 423
+ 0xfffffffeffffffff, // 424
+ 0xfefefefefefbfbfe, // 425
+ 0xfffffffffdfffefb, // 426
+ 0xfffffffeffffffff, // 427
+ 0xfffffffeffffffff, // 428
+ 0xfffdfdfffffffffe, // 429
+ 0xfef8fffbfefbfeff, // 430
+ 0xffffffffffffffff, // 431
+ 0xffffffffffffffff, // 432
+ 0xfffffffffffefdfe, // 433
+ 0xffffffffffffffff, // 434
+ 0xffffffffffffffff, // 435
+ 0xffffffffffffffff, // 436
+ 0xffffffffffffffff, // 437
+ 0xfefffeffffffffff, // 438
+ 0xfcfdfefbfffefefb, // 439
+ 0xffffffffffffffff, // 440
+ 0xffffffffffffffff, // 441
+ 0xffffffffffffffff, // 442
+ 0xffffffffffffffff, // 443
+ 0xfffefeffffffffff, // 444
+ 0xffffffffffffffff, // 445
+ 0xffffffffffffffff, // 446
+ 0xfffffffeffffffff, // 447
+ 0xffffffffffffffff, // 448
+ 0xffffffffffffffff, // 449
+ 0xfefbfbfefffffffe, // 450
+ 0xffffffffffffffff, // 451
+ 0xfffffffffeffffff, // 452
+ 0xffffffffffffffff, // 453
+ 0xffffffffffffffff, // 454
+ 0xfffffffeffffffff, // 455
+ 0xffffffffffffffff, // 456
+ 0xffffffffffffffff, // 457
+ 0xffffffffffffffff, // 458
+ 0xffffffffffffffff, // 459
+ 0xfffffffefffffffe, // 460
+ 0xfbfefefbfffbfbfe, // 461
+ 0xfffffffffffffffe, // 462
+ 0xffffffffffffffff, // 463
+ 0xfefdfeffffffffff, // 464
+ 0xffffffffffffffff, // 465
+ 0xffffffffffffffff, // 466
+ 0xffffffffffffffff, // 467
+ 0xfefffefeffffffff, // 468
+ 0xfffffffffeffffff, // 469
+ 0xffffffffffffffff, // 470
+ 0xfffffffdffffffff, // 471
+ 0xffffffffffffffff, // 472
+ 0xfffffffffdfbfbfe, // 473
+ 0xfcfdfefffefbfffe, // 474
+ 0xfffffffffffdfffe, // 475
+ 0xfffffffffefdffff, // 476
+ 0xffffffffffffffff, // 477
+ 0xfefffffeffffffff, // 478
+ 0xfdfffefdfefffefd, // 479
+ 0xffffffffffffffff, // 480
+ 0xfffbfefbfefbfefb, // 481
+ 0xfbfcfdfdffffffff, // 482
+ 0xfffffffffffffffe, // 483
+ 0xfffffffffffffffe, // 484
+ 0xffffffffffffffff, // 485
+ 0xfffffffffffffffe, // 486
+ 0xfffffefffffffffe, // 487
+ 0xffffffffffffffff, // 488
+ 0xffffffffffffffff, // 489
+ 0xffffffffffffffff, // 490
+ 0xffffffffffffffff, // 491
+ 0xffffffffffffffff, // 492
+ 0xffffffffffffffff, // 493
+ 0xffffffffffffffff, // 494
+ 0xfbfefefbfffef8fe, // 495
+ 0xffffffffffffffff, // 496
+ 0xffffffffffffffff, // 497
+ 0xffffffffffffffff, // 498
+ 0xffffffffffffffff, // 499
+ 0xfffffffeffffffff, // 500
+ 0xffffffffffffffff, // 501
+ 0xfffffffffffffffe, // 502
+ 0xffffffffffffffff, // 503
+ 0xfffffffffffffffe, // 504
+ 0xffffffffffffffff, // 505
+ 0xfffffffffffffffe, // 506
+ 0xfcfdfffffefefbff, // 507
+ 0xffffffffffffffff, // 508
+ 0xffffffffffffffff, // 509
+ 0xffffffffffffffff, // 510
+ 0xffffffffffffffff, // 511
+ 0xffffffffffffffff, // 512
+ 0xfefbfefefefefbfe, // 513
+ 0xffffffffffffffff, // 514
+ 0xfffffeffffffffff, // 515
+ 0xffffffffffffffff, // 516
+ 0xfffffffeffffffff, // 517
+ 0xfffffffeffffffff, // 518
+ 0xfffffffeffffffff, // 519
+ 0xfffffffefefeffff, // 520
+ 0xffffffffffffffff, // 521
+ 0xfefbfbfefbfefefb, // 522
+ 0xffffffffffffffff, // 523
+ 0xffffffffffffffff, // 524
+ 0xffffffffffffffff, // 525
+ 0xffffffffffffffff, // 526
+ 0xffffffffffffffff, // 527
+ 0xffffffffffffffff, // 528
+ 0xffffffffffffffff, // 529
+ 0xffffffffffffffff, // 530
+ 0xffffffffffffffff, // 531
+ 0xffffffffffffffff, // 532
+ 0xffffffffffffffff, // 533
+ 0xfffefefbfcfdfeff, // 534
+ 0xffffffffffffffff, // 535
+ 0xffffffffffffffff, // 536
+ 0xffffffffffffffff, // 537
+ 0xffffffffffffffff, // 538
+ 0xffffffffffffffff, // 539
+ 0xffffffffffffffff, // 540
+ 0xffffffffffffffff, // 541
+ 0xffffffffffffffff, // 542
+ 0xfbfbfefffefefbfb, // 543
+ 0xffffffffffffffff, // 544
+ 0xffffffffffffffff, // 545
+ 0xffffffffffffffff, // 546
+ 0xffffffffffffffff, // 547
+ 0xffffffffffffffff, // 548
+ 0xffffffffffffffff, // 549
+ 0xffffffffffffffff, // 550
+ 0xffffffffffffffff, // 551
+ 0xffffffffffffffff, // 552
+ 0xfefefbffffffffff, // 553
+ 0xffffffffffffffff, // 554
+ 0xffffffffffffffff, // 555
+ 0xffffffffffffffff, // 556
+ 0xffffffffffffffff, // 557
+ ];
+
+ // Do a test run against the interpreter, then check the compiler.
+ for hash_type in [
+ HashXType::HASHX_TYPE_INTERPRETED,
+ HashXType::HASHX_TYPE_COMPILED,
+ ] {
+ let mut ctx = HashX::new(hash_type);
+
+ // Fully replace the Rng stream, which must be exactly the right size
+ let counter = Rc::new(RefCell::new(0_usize));
+ {
+ let counter = counter.clone();
+ ctx.rng_callback(Some(Box::new(move |_value| {
+ let mut counter = counter.borrow_mut();
+ let result = SEQUENCE[*counter];
+ *counter += 1;
+ result
+ })));
+ }
+
+ // Seed choice: This seed will normally fail constraint checks.
+ // Using it here is a way of verifying that Rng replacement works.
+ assert_eq!(*counter.borrow(), 0);
+ assert_eq!(ctx.make(b"qfjsfv"), HashXResult::HASHX_OK);
+ assert_eq!(*counter.borrow(), SEQUENCE.len());
+ assert_eq!(ctx.query_type(), Ok(hash_type));
+
+ // Make sure we can run the hash function, spot-testing the output.
+ assert_eq!(ctx.exec(0).unwrap(), hex!("7d7442b95fc9ea3d"));
+ assert_eq!(ctx.exec(123).unwrap(), hex!("1519ee923bf1e699"));
+ assert_eq!(ctx.exec(12345).unwrap(), hex!("726c4073ff1bb595"));
+ }
+ }
+}
diff --git a/src/ext/equix/src/solver.c b/src/ext/equix/src/solver.c
new file mode 100644
index 0000000000..618c6e1130
--- /dev/null
+++ b/src/ext/equix/src/solver.c
@@ -0,0 +1,283 @@
+/* Copyright (c) 2020 tevador <tevador@gmail.com> */
+/* See LICENSE for licensing information */
+
+#include "solver.h"
+#include "context.h"
+#include "solver_heap.h"
+#include <hashx_endian.h>
+#include <string.h>
+#include <stdbool.h>
+#include <assert.h>
+#include <stdio.h>
+
+#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 --git a/src/ext/equix/src/solver.h b/src/ext/equix/src/solver.h
new file mode 100644
index 0000000000..4cf4105679
--- /dev/null
+++ b/src/ext/equix/src/solver.h
@@ -0,0 +1,44 @@
+/* Copyright (c) 2020 tevador <tevador@gmail.com> */
+/* See LICENSE for licensing information */
+
+#ifndef SOLVER_H
+#define SOLVER_H
+
+#include <equix.h>
+#include <hashx_endian.h>
+#include <stdbool.h>
+#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 --git a/src/ext/equix/src/solver_heap.h b/src/ext/equix/src/solver_heap.h
new file mode 100644
index 0000000000..71c5f0ca48
--- /dev/null
+++ b/src/ext/equix/src/solver_heap.h
@@ -0,0 +1,108 @@
+/* Copyright (c) 2020 tevador <tevador@gmail.com> */
+/* See LICENSE for licensing information */
+
+#ifndef SOLVER_HEAP_H
+#define SOLVER_HEAP_H
+
+#include <stdint.h>
+#include <equix.h>
+
+#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 --git a/src/ext/equix/src/tests.c b/src/ext/equix/src/tests.c
new file mode 100644
index 0000000000..75937a7995
--- /dev/null
+++ b/src/ext/equix/src/tests.c
@@ -0,0 +1,129 @@
+/* Copyright (c) 2020 tevador <tevador@gmail.com> */
+/* See LICENSE for licensing information */
+
+#ifdef NDEBUG
+#undef NDEBUG
+#endif
+
+#include <assert.h>
+#include <equix.h>
+#include <stdbool.h>
+#include <stdio.h>
+
+typedef bool test_func();
+
+static equix_ctx* ctx = NULL;
+static equix_solutions_buffer output;
+static int nonce;
+static int valid_count = 0;
+static int test_no = 0;
+
+#define SWAP_IDX(a, b) \
+ do { \
+ equix_idx temp = a; \
+ a = b; \
+ b = temp; \
+ } while(0)
+
+static bool test_alloc() {
+ ctx = equix_alloc(EQUIX_CTX_SOLVE | EQUIX_CTX_TRY_COMPILE);
+ assert(ctx != NULL);
+ return true;
+}
+
+static bool test_free() {
+ equix_free(ctx);
+ return true;
+}
+
+static bool test_solve() {
+ output.count = 0;
+ for (nonce = 0; output.count == 0 && nonce < 20; ++nonce) {
+ equix_result result = equix_solve(ctx, &nonce, sizeof(nonce), &output);
+ assert(result == EQUIX_OK);
+ }
+ --nonce;
+ assert(output.count > 0);
+ assert(output.flags == EQUIX_SOLVER_DID_USE_COMPILER || output.flags == 0);
+ printf("(using %s HashX) ",
+ (EQUIX_SOLVER_DID_USE_COMPILER & output.flags)
+ ? "compiled" : "interpreted");
+ return true;
+}
+
+static bool test_verify1() {
+ equix_result result = equix_verify(ctx, &nonce, sizeof(nonce), &output.sols[0]);
+ assert(result == EQUIX_OK);
+ return true;
+}
+
+static bool test_verify2() {
+ SWAP_IDX(output.sols[0].idx[0], output.sols[0].idx[1]);
+ equix_result result = equix_verify(ctx, &nonce, sizeof(nonce), &output.sols[0]);
+ assert(result == EQUIX_FAIL_ORDER);
+ return true;
+}
+
+static bool test_verify3() {
+ SWAP_IDX(output.sols[0].idx[0], output.sols[0].idx[4]);
+ SWAP_IDX(output.sols[0].idx[1], output.sols[0].idx[5]);
+ SWAP_IDX(output.sols[0].idx[2], output.sols[0].idx[6]);
+ SWAP_IDX(output.sols[0].idx[3], output.sols[0].idx[7]);
+ equix_result result = equix_verify(ctx, &nonce, sizeof(nonce), &output.sols[0]);
+ assert(result == EQUIX_FAIL_ORDER);
+ SWAP_IDX(output.sols[0].idx[0], output.sols[0].idx[4]);
+ SWAP_IDX(output.sols[0].idx[1], output.sols[0].idx[5]);
+ SWAP_IDX(output.sols[0].idx[2], output.sols[0].idx[6]);
+ SWAP_IDX(output.sols[0].idx[3], output.sols[0].idx[7]);
+ return true;
+}
+
+static bool test_verify4() {
+ SWAP_IDX(output.sols[0].idx[1], output.sols[0].idx[2]);
+ equix_result result = equix_verify(ctx, &nonce, sizeof(nonce), &output.sols[0]);
+ assert(result == EQUIX_FAIL_PARTIAL_SUM);
+ SWAP_IDX(output.sols[0].idx[1], output.sols[0].idx[2]);
+ return true;
+}
+
+static void permute_idx(int start) {
+ if (start == EQUIX_NUM_IDX - 1) {
+ equix_result result = equix_verify(ctx, &nonce, sizeof(nonce), &output.sols[0]);
+ valid_count += result == EQUIX_OK;
+ }
+ else {
+ for (int i = start; i < EQUIX_NUM_IDX; ++i) {
+ SWAP_IDX(output.sols[0].idx[start], output.sols[0].idx[i]);
+ permute_idx(start + 1);
+ SWAP_IDX(output.sols[0].idx[start], output.sols[0].idx[i]);
+ }
+ }
+}
+
+static bool test_permutations() {
+ permute_idx(0);
+ assert(valid_count == 1); /* check that only one of the 40320 possible
+ permutations of indices is a valid solution */
+ return true;
+}
+
+#define RUN_TEST(x) run_test(#x, &x)
+
+static void run_test(const char* name, test_func* func) {
+ printf("[%2i] %-40s ... ", ++test_no, name);
+ printf(func() ? "PASSED\n" : "SKIPPED\n");
+}
+
+int main() {
+ RUN_TEST(test_alloc);
+ RUN_TEST(test_solve);
+ RUN_TEST(test_verify1);
+ RUN_TEST(test_verify2);
+ RUN_TEST(test_verify3);
+ RUN_TEST(test_verify4);
+ RUN_TEST(test_permutations);
+ RUN_TEST(test_free);
+
+ printf("\nAll tests were successful\n");
+ return 0;
+}
diff --git a/src/ext/include.am b/src/ext/include.am
index 8b646b1b4e..dad6a592b7 100644
--- a/src/ext/include.am
+++ b/src/ext/include.am
@@ -1,5 +1,7 @@
-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
@@ -14,6 +16,7 @@ EXTHEADERS = \
src/ext/tinytest_macros.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 @@ noinst_HEADERS += $(ED25519_DONNA_HDRS)
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@
diff --git a/src/feature/client/bridges.c b/src/feature/client/bridges.c
index 9e36d26929..a0375828a7 100644
--- a/src/feature/client/bridges.c
+++ b/src/feature/client/bridges.c
@@ -140,6 +140,41 @@ bridge_list_get(void)
}
/**
+ * 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 <b>bridge</b>, return a pointer to its RSA identity digest, or
* NULL if we don't know one for it.
*/
diff --git a/src/feature/client/bridges.h b/src/feature/client/bridges.h
index dd3e498a0a..2b514ba6c9 100644
--- a/src/feature/client/bridges.h
+++ b/src/feature/client/bridges.h
@@ -67,6 +67,7 @@ MOCK_DECL(download_status_t *, get_bridge_dl_status_by_id,
(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 --git a/src/feature/client/circpathbias.c b/src/feature/client/circpathbias.c
index ff9e05a645..144a53c972 100644
--- a/src/feature/client/circpathbias.c
+++ b/src/feature/client/circpathbias.c
@@ -334,12 +334,23 @@ pathbias_should_count(origin_circuit_t *circ)
* 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)) {
diff --git a/src/feature/client/entrynodes.c b/src/feature/client/entrynodes.c
index 5436b74b9c..e5c89645f6 100644
--- a/src/feature/client/entrynodes.c
+++ b/src/feature/client/entrynodes.c
@@ -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 @@ mark_primary_guards_maybe_reachable(guard_selection_t *gs)
}
/* 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 @@ get_max_sample_size(guard_selection_t *gs,
}
/**
- * 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 *<b>n_guards_out</b>
@@ -1589,6 +1592,19 @@ guard_create_exit_restriction(const uint8_t *exit_id)
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)
+{
+ 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);
+ 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
@@ -1681,6 +1697,8 @@ entry_guard_obeys_restriction(const entry_guard_t *guard,
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 !smartlist_contains_digest(rst->excluded, guard->identity);
}
tor_assert_nonfatal_unreached();
@@ -1896,7 +1914,7 @@ make_guard_confirmed(guard_selection_t *gs, entry_guard_t *guard)
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);
@@ -2428,6 +2446,11 @@ entry_guard_has_higher_priority(entry_guard_t *a, entry_guard_t *b)
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 +3804,8 @@ guards_update_all(void)
/** 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 +3813,18 @@ guards_choose_guard(cpath_build_state_t *state,
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))) {
+ rst = guard_create_conflux_restriction(circ);
+ /* 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 --git a/src/feature/client/entrynodes.h b/src/feature/client/entrynodes.h
index 08fd7cf745..2a94775430 100644
--- a/src/feature/client/entrynodes.h
+++ b/src/feature/client/entrynodes.h
@@ -294,7 +294,9 @@ typedef enum guard_restriction_type_t {
/* 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 @@ struct entry_guard_restriction_t {
* 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 @@ struct circuit_guard_state_t {
/* 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_exit_restriction(
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);
+
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 --git a/src/feature/client/transports.c b/src/feature/client/transports.c
index 80903ac9e5..4d92a2a67a 100644
--- a/src/feature/client/transports.c
+++ b/src/feature/client/transports.c
@@ -519,8 +519,10 @@ proxy_prepare_for_restart(managed_proxy_t *mp)
tor_assert(mp->conf_state == PT_PROTO_COMPLETED);
/* 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);
+ process_terminate(mp->process);
+ }
/* destroy all its registered transports, since we will no longer
use them. */
@@ -541,7 +543,7 @@ proxy_prepare_for_restart(managed_proxy_t *mp)
mp->proxy_supported = 0;
/* flag it as an infant proxy so that it gets launched on next tick */
- mp->conf_state = PT_PROTO_INFANT;
+ managed_proxy_set_state(mp, PT_PROTO_INFANT);
unconfigured_proxies_n++;
}
@@ -554,6 +556,8 @@ launch_managed_proxy(managed_proxy_t *mp)
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 +582,7 @@ launch_managed_proxy(managed_proxy_t *mp)
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;
}
@@ -648,7 +652,7 @@ configure_proxy(managed_proxy_t *mp)
/* 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;
+ managed_proxy_set_state(mp, PT_PROTO_FAILED_LAUNCH);
handle_finished_proxy(mp);
}
return 0;
@@ -810,8 +814,12 @@ handle_finished_proxy(managed_proxy_t *mp)
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_LAUNCHED:
@@ -857,7 +865,7 @@ handle_methods_done(const managed_proxy_t *mp)
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 +889,7 @@ handle_proxy_line(const char *line, managed_proxy_t *mp)
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 +897,7 @@ handle_proxy_line(const char *line, managed_proxy_t *mp)
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 +905,7 @@ handle_proxy_line(const char *line, managed_proxy_t *mp)
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 +976,7 @@ handle_proxy_line(const char *line, managed_proxy_t *mp)
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]);
}
@@ -1529,12 +1537,14 @@ managed_proxy_create(const smartlist_t *with_transport_list,
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,
@@ -1945,9 +1955,24 @@ managed_proxy_exit_callback(process_t *process, process_exit_code_t exit_code)
{
tor_assert(process);
+ managed_proxy_t *mp = process_get_data(process);
+ const char *name = mp ? mp->argv[0] : "N/A";
+
log_warn(LD_PT,
- "Pluggable Transport process terminated with status code %" PRIu64,
- exit_code);
+ "Managed proxy \"%s\" process terminated with status code %" PRIu64,
+ name, exit_code);
+
+ 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);
+
+ /* 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 +2048,45 @@ managed_proxy_outbound_address(const or_options_t *options, sa_family_t family)
/* 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_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 <b>mp</b> to the given <b>new_state</b>
+ * 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 --git a/src/feature/client/transports.h b/src/feature/client/transports.h
index 3f08beadba..535689537c 100644
--- a/src/feature/client/transports.h
+++ b/src/feature/client/transports.h
@@ -153,6 +153,8 @@ STATIC int managed_proxy_severity_parse(const char *);
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 --git a/src/feature/control/control_fmt.c b/src/feature/control/control_fmt.c
index cc8686818a..b6efd18163 100644
--- a/src/feature/control/control_fmt.c
+++ b/src/feature/control/control_fmt.c
@@ -153,6 +153,13 @@ circuit_describe_status_for_controller(origin_circuit_t *circ)
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);
+ }
+
rv = smartlist_join_strings(descparts, " ", 0, NULL);
SMARTLIST_FOREACH(descparts, char *, cp, tor_free(cp));
diff --git a/src/feature/control/getinfo_geoip.c b/src/feature/control/getinfo_geoip.c
index be89c2c641..e2d277f256 100644
--- a/src/feature/control/getinfo_geoip.c
+++ b/src/feature/control/getinfo_geoip.c
@@ -44,10 +44,7 @@ getinfo_helper_geoip(control_connection_t *control_conn,
*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 --git a/src/feature/dirauth/dirauth_options.inc b/src/feature/dirauth/dirauth_options.inc
index a43ed285ce..e2056c9cc7 100644
--- a/src/feature/dirauth/dirauth_options.inc
+++ b/src/feature/dirauth/dirauth_options.inc
@@ -86,11 +86,12 @@ CONF_VAR(AuthDirVoteGuard, ROUTERSET, 0, NULL)
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 --git a/src/feature/dirauth/dirvote.c b/src/feature/dirauth/dirvote.c
index 0591125d51..1080415827 100644
--- a/src/feature/dirauth/dirvote.c
+++ b/src/feature/dirauth/dirvote.c
@@ -390,7 +390,8 @@ format_networkstatus_vote(crypto_pk_t *private_signing_key,
rsf = routerstatus_format_entry(&vrs->status,
vrs->version, vrs->protocols,
NS_V3_VOTE,
- vrs);
+ vrs,
+ -1);
if (rsf)
smartlist_add(chunks, rsf);
@@ -618,8 +619,8 @@ compare_vote_rs(const vote_routerstatus_t *a, const vote_routerstatus_t *b)
* 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 +639,8 @@ compare_vote_rs(const vote_routerstatus_t *a, const vote_routerstatus_t *b)
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 +693,10 @@ compute_routerstatus_consensus(smartlist_t *votes, int consensus_method,
} 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 +704,7 @@ compute_routerstatus_consensus(smartlist_t *votes, int consensus_method,
} 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.
@@ -1780,7 +1781,7 @@ networkstatus_compute_consensus(smartlist_t *votes,
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);
+ param_list, "maxunmeasuredbw", DEFAULT_MAX_UNMEASURED_BW_KB);
if (max_unmeasured_bw_kb < 1)
max_unmeasured_bw_kb = 1;
}
@@ -2047,7 +2048,6 @@ networkstatus_compute_consensus(smartlist_t *votes,
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 +2055,21 @@ networkstatus_compute_consensus(smartlist_t *votes,
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 {
@@ -2276,7 +2291,7 @@ networkstatus_compute_consensus(smartlist_t *votes,
/* 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);
}
@@ -4744,6 +4759,7 @@ dirserv_generate_networkstatus_vote_obj(crypto_pk_t *private_key,
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 --git a/src/feature/dirauth/dirvote.h b/src/feature/dirauth/dirvote.h
index 64aaec116e..ae8d43a6f0 100644
--- a/src/feature/dirauth/dirvote.h
+++ b/src/feature/dirauth/dirvote.h
@@ -53,7 +53,7 @@
#define MIN_SUPPORTED_CONSENSUS_METHOD 28
/** The highest consensus method that we currently support. */
-#define MAX_SUPPORTED_CONSENSUS_METHOD 32
+#define MAX_SUPPORTED_CONSENSUS_METHOD 33
/**
* Lowest consensus method where microdescriptor lines are put in canonical
@@ -74,6 +74,12 @@
*/
#define MIN_METHOD_FOR_MIDDLEONLY 32
+/**
+ * Lowest consensus method for which we suppress the published time in
+ * microdescriptor consensuses.
+ */
+#define MIN_METHOD_TO_SUPPRESS_MD_PUBLISHED 33
+
/** Default bandwidth to clip unmeasured bandwidths to using method >=
* MIN_METHOD_TO_CLIP_UNMEASURED_BW. (This is not a consensus method; do not
* get confused with the above macros.) */
diff --git a/src/feature/dirauth/process_descs.c b/src/feature/dirauth/process_descs.c
index f1d4f49c46..7fd930e246 100644
--- a/src/feature/dirauth/process_descs.c
+++ b/src/feature/dirauth/process_descs.c
@@ -110,7 +110,7 @@ add_rsa_fingerprint_to_dir(const char *fp, authdir_config_t *list,
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;
@@ -404,17 +404,8 @@ dirserv_rejects_tor_version(const char *platform,
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")) {
+ /* Anything before 0.4.7.0 is unsupported. Reject them. */
+ if (!tor_version_as_new_as(platform,"0.4.7.0-alpha-dev")) {
if (msg) {
*msg = please_upgrade_string;
}
diff --git a/src/feature/dirclient/dirclient.c b/src/feature/dirclient/dirclient.c
index 4e9c8e2f45..84eefdd90b 100644
--- a/src/feature/dirclient/dirclient.c
+++ b/src/feature/dirclient/dirclient.c
@@ -242,14 +242,21 @@ directory_post_to_dirservers(uint8_t dir_purpose, uint8_t router_purpose,
* 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 @@ directory_post_to_dirservers(uint8_t dir_purpose, uint8_t router_purpose,
}
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 @@ directory_get_from_all_authorities(uint8_t dir_purpose,
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);
diff --git a/src/feature/dirparse/ns_parse.c b/src/feature/dirparse/ns_parse.c
index cd3e2731be..3e1f9a3bd3 100644
--- a/src/feature/dirparse/ns_parse.c
+++ b/src/feature/dirparse/ns_parse.c
@@ -371,14 +371,17 @@ routerstatus_parse_entry_from_string(memarea_t *area,
}
}
+ 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 --git a/src/feature/dirparse/parsecommon.h b/src/feature/dirparse/parsecommon.h
index 675c5f68d5..9333ec4b27 100644
--- a/src/feature/dirparse/parsecommon.h
+++ b/src/feature/dirparse/parsecommon.h
@@ -173,6 +173,7 @@ typedef enum {
R3_DESC_AUTH_CLIENT,
R3_ENCRYPTED,
R3_FLOW_CONTROL,
+ R3_POW_PARAMS,
R_IPO_IDENTIFIER,
R_IPO_IP_ADDRESS,
diff --git a/src/feature/hs/hs_cache.c b/src/feature/hs/hs_cache.c
index cf8e377313..0cc7dfd031 100644
--- a/src/feature/hs/hs_cache.c
+++ b/src/feature/hs/hs_cache.c
@@ -581,6 +581,8 @@ cache_client_intro_state_lookup(const ed25519_public_key_t *service_pk,
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);
@@ -1081,7 +1083,7 @@ hs_cache_handle_oom(time_t now, size_t min_remove_bytes)
*
* 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.
+ * 2) Set K = K - 1 hour and repeat process until K is < 0.
*
* This ends up being O(Kn).
*/
@@ -1104,8 +1106,9 @@ hs_cache_handle_oom(time_t now, size_t min_remove_bytes)
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;
+ /* Decrement K by a post period to shorten the cutoff, Two minutes
+ * if we are a testing network, or one hour otherwise. */
+ k -= get_options()->TestingTorNetwork ? 120 : 3600;
}
} while (bytes_removed < min_remove_bytes);
diff --git a/src/feature/hs/hs_cell.c b/src/feature/hs/hs_cell.c
index 490f05e54f..0039825f3c 100644
--- a/src/feature/hs/hs_cell.c
+++ b/src/feature/hs/hs_cell.c
@@ -374,6 +374,80 @@ introduce1_encrypt_and_encode(trn_cell_introduce1_t *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_introduce_cc_extension(trn_extension_t *extensions)
/* 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 @@ introduce1_set_encrypted(trn_cell_introduce1_t *cell,
/* 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. */
@@ -716,6 +794,70 @@ hs_cell_parse_intro_established(const uint8_t *payload, size_t payload_len)
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 <b>encrypted_section</b>, use the crypto
* material in <b>data</b> to compute the right ntor keys. Also validate the
* INTRO2 MAC to ensure that the keys are the right ones.
@@ -735,7 +877,7 @@ get_introduce2_keys_and_verify_mac(hs_cell_introduce2_data_t *data,
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 +927,42 @@ get_introduce2_keys_and_verify_mac(hs_cell_introduce2_data_t *data,
}
/** 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 +972,8 @@ parse_introduce_cell_extension(hs_cell_introduce2_data_t *data,
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 +1024,7 @@ hs_cell_parse_introduce2(hs_cell_introduce2_data_t *data,
* 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 +1040,13 @@ hs_cell_parse_introduce2(hs_cell_introduce2_data_t *data,
{
/* 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 +1073,12 @@ hs_cell_parse_introduce2(hs_cell_introduce2_data_t *data,
/* 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 +1092,7 @@ hs_cell_parse_introduce2(hs_cell_introduce2_data_t *data,
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 +1106,22 @@ hs_cell_parse_introduce2(hs_cell_introduce2_data_t *data,
/* 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) {
diff --git a/src/feature/hs/hs_cell.h b/src/feature/hs/hs_cell.h
index c76a0690a8..02631cf376 100644
--- a/src/feature/hs/hs_cell.h
+++ b/src/feature/hs/hs_cell.h
@@ -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 @@ typedef struct hs_cell_introduce1_data_t {
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 @@ typedef struct hs_cell_introduce2_data_t {
/*** 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 @@ ssize_t hs_cell_parse_intro_established(const uint8_t *payload,
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 --git a/src/feature/hs/hs_circuit.c b/src/feature/hs/hs_circuit.c
index 53855d40a9..4904f3ddf9 100644
--- a/src/feature/hs/hs_circuit.c
+++ b/src/feature/hs/hs_circuit.c
@@ -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"
@@ -45,6 +47,18 @@
#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
* <b>circ_purpose</b> and ensure that it's properly set. Return true iff
* circuit purpose is properly set, otherwise return false. */
@@ -238,6 +252,7 @@ create_intro_circuit_identifier(const hs_service_t *service,
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;
}
@@ -310,24 +325,26 @@ get_service_anonymity_string(const hs_service_t *service)
* 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 +391,8 @@ launch_rendezvous_point_circuit,(const hs_service_t *service,
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 +409,10 @@ launch_rendezvous_point_circuit,(const hs_service_t *service,
* 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 +423,22 @@ launch_rendezvous_point_circuit,(const hs_service_t *service,
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 +520,10 @@ retry_service_rendezvous_point(const origin_circuit_t *circ)
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 +624,298 @@ cleanup_on_free_client_circ(circuit_t *circ)
* 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(&ocirc->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 */
/* ========== */
@@ -864,13 +1186,17 @@ hs_circ_service_rp_has_opened(const hs_service_t *service,
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 +1206,8 @@ hs_circ_service_rp_has_opened(const hs_service_t *service,
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 +1308,7 @@ hs_circ_handle_introduce2(const hs_service_t *service,
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 +1322,28 @@ hs_circ_handle_introduce2(const hs_service_t *service,
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 +1354,8 @@ hs_circ_handle_introduce2(const hs_service_t *service,
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 +1363,33 @@ hs_circ_handle_introduce2(const hs_service_t *service,
* 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,7 +1436,8 @@ int
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;
@@ -1114,6 +1471,9 @@ hs_circ_send_introduce1(origin_circuit_t *intro_circ,
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) {
diff --git a/src/feature/hs/hs_circuit.h b/src/feature/hs/hs_circuit.h
index afbff7b894..8b0692d76b 100644
--- a/src/feature/hs/hs_circuit.h
+++ b/src/feature/hs/hs_circuit.h
@@ -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_handle_introduce2(const hs_service_t *service,
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 @@ create_rp_circuit_identifier(const hs_service_t *service,
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 --git a/src/feature/hs/hs_client.c b/src/feature/hs/hs_client.c
index a50598d9f3..2bb59f078e 100644
--- a/src/feature/hs/hs_client.c
+++ b/src/feature/hs/hs_client.c
@@ -541,7 +541,7 @@ intro_circ_is_ok(const origin_circuit_t *circ)
/** 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 @@ find_desc_intro_point_by_ident(const hs_ident_circuit_t *ident,
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 @@ find_desc_intro_point_by_legacy_id(const char *legacy_id,
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 @@ send_introduce1(origin_circuit_t *intro_circ,
* 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 @@ send_introduce1(origin_circuit_t *intro_circ,
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 @@ send_introduce1(origin_circuit_t *intro_circ,
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 @@ send_introduce1(origin_circuit_t *intro_circ,
*
* 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 @@ client_intro_circ_has_opened(origin_circuit_t *circ)
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);
}
@@ -1390,9 +1494,20 @@ can_client_refetch_desc(const ed25519_public_key_t *identity_pk,
/* 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 +2087,7 @@ hs_client_circuit_cleanup_on_free(const circuit_t *circ)
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 +2102,22 @@ hs_client_circuit_cleanup_on_free(const circuit_t *circ)
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 +2259,7 @@ int
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 --git a/src/feature/hs/hs_client.h b/src/feature/hs/hs_client.h
index 2fe955605f..234306a3c3 100644
--- a/src/feature/hs/hs_client.h
+++ b/src/feature/hs/hs_client.h
@@ -78,6 +78,10 @@ typedef struct hs_client_service_authorization_t {
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 @@ void hs_client_launch_v3_desc_fetch(
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_any_intro_points_usable(const ed25519_public_key_t *service_pk,
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 --git a/src/feature/hs/hs_common.c b/src/feature/hs/hs_common.c
index e326581dd1..cd7e4890d1 100644
--- a/src/feature/hs/hs_common.c
+++ b/src/feature/hs/hs_common.c
@@ -432,7 +432,7 @@ get_second_cached_disaster_srv(void)
* 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,7 +1680,7 @@ hs_get_extend_info_from_lspecs(const smartlist_t *lspecs,
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;
}
diff --git a/src/feature/hs/hs_common.h b/src/feature/hs/hs_common.h
index a7a8f23a3c..48c112110c 100644
--- a/src/feature/hs/hs_common.h
+++ b/src/feature/hs/hs_common.h
@@ -256,7 +256,14 @@ link_specifier_t *link_specifier_dup(const link_specifier_t *src);
#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 --git a/src/feature/hs/hs_config.c b/src/feature/hs/hs_config.c
index a76893fe1a..296941138b 100644
--- a/src/feature/hs/hs_config.c
+++ b/src/feature/hs/hs_config.c
@@ -320,6 +320,19 @@ config_validate_service(const hs_service_config_t *config)
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 @@ config_service_v3(const hs_opts_t *hs_opts,
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 @@ config_service_v3(const hs_opts_t *hs_opts,
}
}
+ /* 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 --git a/src/feature/hs/hs_config.h b/src/feature/hs/hs_config.h
index b250c62c8b..bde6da9612 100644
--- a/src/feature/hs/hs_config.h
+++ b/src/feature/hs/hs_config.h
@@ -25,6 +25,9 @@
#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
+
/* API */
int hs_config_service_all(const or_options_t *options, int validate_only);
diff --git a/src/feature/hs/hs_descriptor.c b/src/feature/hs/hs_descriptor.c
index d61ce237fa..da7bb662e1 100644
--- a/src/feature/hs/hs_descriptor.c
+++ b/src/feature/hs/hs_descriptor.c
@@ -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 @@ static const struct {
{ 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 @@ static token_rule_t hs_desc_encrypted_v3_token_table[] = {
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),
+ T01(str_pow_params, R3_POW_PARAMS, GE(4), NO_OBJ),
END_OF_TABLE
};
@@ -758,6 +771,13 @@ get_inner_encrypted_layer_plaintext(const hs_descriptor_t *desc)
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 @@ get_inner_encrypted_layer_plaintext(const hs_descriptor_t *desc)
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,70 @@ desc_sig_is_valid(const char *b64_sig,
return ret;
}
+/** Given the token tok for PoW params, decode it as hs_pow_desc_params_t.
+ * tok->args MUST contain at least 4 elements Return 0 on success else -1 on
+ * failure. */
+static int
+decode_pow_params(const directory_token_t *tok,
+ hs_pow_desc_params_t *pow_params)
+{
+ int ret = -1;
+
+ tor_assert(tok);
+ tor_assert(tok->n_args >= 4);
+ tor_assert(pow_params);
+
+ /* Find the type of PoW system being used. */
+ int match = 0;
+ for (int idx = 0; pow_types[idx].identifier; idx++) {
+ if (!strncmp(tok->args[0], pow_types[idx].identifier,
+ strlen(pow_types[idx].identifier))) {
+ pow_params->type = pow_types[idx].type;
+ match = 1;
+ break;
+ }
+ }
+ if (!match) {
+ log_warn(LD_REND, "Unknown PoW type from descriptor.");
+ goto done;
+ }
+
+ 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;
+
+ /* Success. */
+ ret = 0;
+
+ done:
+ 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 +2473,18 @@ desc_decode_encrypted_v3(const hs_descriptor_t *desc,
desc_encrypted_out->sendme_inc = sendme_inc;
}
+ /* Get PoW if any. */
+ tok = find_opt_by_keyword(tokens, R3_POW_PARAMS);
+ if (tok) {
+ hs_pow_desc_params_t *pow_params =
+ tor_malloc_zero(sizeof(hs_pow_desc_params_t));
+ if (decode_pow_params(tok, pow_params)) {
+ tor_free(pow_params);
+ goto err;
+ }
+ desc_encrypted_out->pow_params = pow_params;
+ }
+
/* 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 +2825,15 @@ hs_desc_encode_descriptor,(const hs_descriptor_t *desc,
}
/* 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 +2903,7 @@ hs_desc_encrypted_data_free_contents(hs_desc_encrypted_data_t *desc)
smartlist_free(desc->intro_points);
}
tor_free(desc->flow_control_pv);
+ tor_free(desc->pow_params);
memwipe(desc, 0, sizeof(*desc));
}
diff --git a/src/feature/hs/hs_descriptor.h b/src/feature/hs/hs_descriptor.h
index 8ae16825d2..22517470c1 100644
--- a/src/feature/hs/hs_descriptor.h
+++ b/src/feature/hs/hs_descriptor.h
@@ -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 @@ typedef struct hs_desc_encrypted_data_t {
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 --git a/src/feature/hs/hs_dos.c b/src/feature/hs/hs_dos.c
index 6323dbeeac..80ad3b1daa 100644
--- a/src/feature/hs/hs_dos.c
+++ b/src/feature/hs/hs_dos.c
@@ -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 @@ hs_dos_setup_default_intro2_defenses(or_circuit_t *circ)
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 @@ hs_dos_can_send_intro2(or_circuit_t *s_intro_circ)
/* 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 --git a/src/feature/hs/hs_intropoint.c b/src/feature/hs/hs_intropoint.c
index 0a656b78dd..02b5b4866b 100644
--- a/src/feature/hs/hs_intropoint.c
+++ b/src/feature/hs/hs_intropoint.c
@@ -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 @@ handle_establish_intro_cell_dos_extension(
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 @@ handle_establish_intro(or_circuit_t *circ, const uint8_t *request,
/* 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 @@ handle_establish_intro(or_circuit_t *circ, const uint8_t *request,
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 @@ handle_establish_intro(or_circuit_t *circ, const uint8_t *request,
(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 @@ handle_establish_intro(or_circuit_t *circ, const uint8_t *request,
/* 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 @@ hs_intro_received_establish_intro(or_circuit_t *circ, const uint8_t *request,
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 @@ hs_intro_received_establish_intro(or_circuit_t *circ, const uint8_t *request,
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 @@ handle_introduce1(or_circuit_t *client_circ, const uint8_t *request,
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 @@ handle_introduce1(or_circuit_t *client_circ, const uint8_t *request,
/* 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 @@ handle_introduce1(or_circuit_t *client_circ, const uint8_t *request,
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 @@ handle_introduce1(or_circuit_t *client_circ, const uint8_t *request,
/* 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,6 +709,7 @@ handle_introduce1(or_circuit_t *client_circ, const uint8_t *request,
if (relay_send_command_from_edge(CONTROL_CELL_ID, TO_CIRCUIT(service_circ),
RELAY_COMMAND_INTRODUCE2,
(char *) request, request_len, NULL)) {
+ relay_increment_intro1_action(INTRO1_CIRCUIT_DEAD);
log_warn(LD_PROTOCOL, "Unable to send INTRODUCE2 cell to the service.");
/* 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. */
@@ -702,6 +717,7 @@ handle_introduce1(or_circuit_t *client_circ, const uint8_t *request,
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 +748,7 @@ circuit_is_suitable_for_introduce1(const or_circuit_t *circ)
}
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 +758,7 @@ circuit_is_suitable_for_introduce1(const or_circuit_t *circ)
/* 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 +780,7 @@ hs_intro_received_introduce1(or_circuit_t *circ, const uint8_t *request,
/* 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 --git a/src/feature/hs/hs_metrics.c b/src/feature/hs/hs_metrics.c
index e80d98c2dd..19a330a01e 100644
--- a/src/feature/hs/hs_metrics.c
+++ b/src/feature/hs/hs_metrics.c
@@ -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 @@ port_to_str(const uint16_t port)
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. */
+ * <b>metric</b> is the index of the metric in the <b>base_metrics</b> 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,25 +164,38 @@ hs_metrics_update_by_service(const hs_metrics_key_t key,
* 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;
@@ -121,7 +209,7 @@ hs_metrics_update_by_ident(const hs_metrics_key_t key,
* 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 --git a/src/feature/hs/hs_metrics.h b/src/feature/hs/hs_metrics.h
index 2e0fa5048d..f2e5dbd9ec 100644
--- a/src/feature/hs/hs_metrics.h
+++ b/src/feature/hs/hs_metrics.h
@@ -26,45 +26,87 @@ const smartlist_t *hs_metrics_get_stores(void);
/* 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 --git a/src/feature/hs/hs_metrics_entry.c b/src/feature/hs/hs_metrics_entry.c
index 46d2d88aca..d862d0adec 100644
--- a/src/feature/hs/hs_metrics_entry.c
+++ b/src/feature/hs/hs_metrics_entry.c
@@ -8,12 +8,37 @@
#define HS_METRICS_ENTRY_PRIVATE
+#include <stddef.h>
+
#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 @@ const hs_metrics_entry_t base_metrics[] =
.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 @@ const hs_metrics_entry_t base_metrics[] =
.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 --git a/src/feature/hs/hs_metrics_entry.h b/src/feature/hs/hs_metrics_entry.h
index b9786ac6f7..1a1bc701ec 100644
--- a/src/feature/hs/hs_metrics_entry.h
+++ b/src/feature/hs/hs_metrics_entry.h
@@ -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 @@ typedef enum {
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 @@ typedef struct hs_metrics_entry_t {
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 @@ typedef struct hs_metrics_entry_t {
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 --git a/src/feature/hs/hs_options.inc b/src/feature/hs/hs_options.inc
index d3ca688b46..4ec62d592b 100644
--- a/src/feature/hs/hs_options.inc
+++ b/src/feature/hs/hs_options.inc
@@ -31,5 +31,8 @@ CONF_VAR(HiddenServiceEnableIntroDoSDefense, BOOL, 0, "0")
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 --git a/src/feature/hs/hs_pow.c b/src/feature/hs/hs_pow.c
new file mode 100644
index 0000000000..5cee3b00d7
--- /dev/null
+++ b/src/feature/hs/hs_pow.c
@@ -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 <stdio.h>
+
+#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 <b>job</b>.
+ */
+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 --git a/src/feature/hs/hs_pow.h b/src/feature/hs/hs_pow.h
new file mode 100644
index 0000000000..d47eba82ab
--- /dev/null
+++ b/src/feature/hs/hs_pow.h
@@ -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 --git a/src/feature/hs/hs_service.c b/src/feature/hs/hs_service.c
index 7d9fbe546a..3cc8c23e0b 100644
--- a/src/feature/hs/hs_service.c
+++ b/src/feature/hs/hs_service.c
@@ -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 @@ hs_service_ht_hash(const hs_service_t *service)
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 @@ is_client_auth_enabled(const hs_service_t *service)
}
/** 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,61 @@ set_service_default_config(hs_service_config_t *c,
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_dos_defense_enabled = HS_CONFIG_V3_POW_DEFENSES_DEFAULT;
+}
+
+/** 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
@@ -2250,6 +2306,14 @@ pick_needed_intro_points(hs_service_t *service,
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 +2431,88 @@ update_all_descriptors_intro_points(time_t now)
} 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 +2566,7 @@ should_remove_intro_point(hs_service_intro_point_t *ip, time_t now)
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 +2654,131 @@ cleanup_intro_points(hs_service_t *service, time_t now)
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 +2923,12 @@ run_housekeeping_event(time_t now)
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 +2962,11 @@ run_build_descriptor_event(time_t now)
* 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
@@ -3414,6 +3696,11 @@ service_rendezvous_circ_has_opened(origin_circuit_t *circ)
* 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 +3754,13 @@ service_handle_intro_established(origin_circuit_t *circ,
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 +3803,9 @@ service_handle_introduce2(origin_circuit_t *circ, const uint8_t *payload,
"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 +3822,7 @@ service_handle_introduce2(origin_circuit_t *circ, const uint8_t *payload,
return 0;
err:
+
return -1;
}
@@ -4352,6 +4648,9 @@ hs_service_free_(hs_service_t *service)
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 --git a/src/feature/hs/hs_service.h b/src/feature/hs/hs_service.h
index 95461289ce..36d67719ca 100644
--- a/src/feature/hs/hs_service.h
+++ b/src/feature/hs/hs_service.h
@@ -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 @@ typedef struct hs_service_intro_point_t {
/** 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;
@@ -257,6 +266,11 @@ typedef struct hs_service_config_t {
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 @@ typedef struct hs_service_state_t {
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. */
diff --git a/src/feature/hs/include.am b/src/feature/hs/include.am
index c55abd3d47..b64ab1b41c 100644
--- a/src/feature/hs/include.am
+++ b/src/feature/hs/include.am
@@ -20,6 +20,14 @@ LIBTOR_APP_A_SOURCES += \
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 \
@@ -38,6 +46,7 @@ noinst_HEADERS += \
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 \
diff --git a/src/feature/nodelist/fmt_routerstatus.c b/src/feature/nodelist/fmt_routerstatus.c
index 8c02a302af..4be2ec2a18 100644
--- a/src/feature/nodelist/fmt_routerstatus.c
+++ b/src/feature/nodelist/fmt_routerstatus.c
@@ -26,6 +26,9 @@
/** Helper: write the router-status information in <b>rs</b> into a newly
* allocated character buffer. Use the same format as in network-status
* documents. If <b>version</b> is non-NULL, add a "v" line for the platform.
+ * If <b>declared_publish_time</b> is nonnegative, we declare it as the
+ * publication time. Otherwise we look for a publication time in <b>vrs</b>,
+ * 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 <b>vrs</b> 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 @@ routerstatus_format_entry(const routerstatus_t *rs, const char *version,
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 --git a/src/feature/nodelist/fmt_routerstatus.h b/src/feature/nodelist/fmt_routerstatus.h
index 7482f373e1..740ea51dd9 100644
--- a/src/feature/nodelist/fmt_routerstatus.h
+++ b/src/feature/nodelist/fmt_routerstatus.h
@@ -35,6 +35,7 @@ char *routerstatus_format_entry(
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 --git a/src/feature/nodelist/microdesc.c b/src/feature/nodelist/microdesc.c
index a95d535dc0..9e5f0bb9a4 100644
--- a/src/feature/nodelist/microdesc.c
+++ b/src/feature/nodelist/microdesc.c
@@ -626,7 +626,7 @@ microdesc_cache_clean(microdesc_cache_t *cache, time_t cutoff, int force)
(*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! */
diff --git a/src/feature/nodelist/networkstatus.c b/src/feature/nodelist/networkstatus.c
index af3bde83a5..61eef5bfa5 100644
--- a/src/feature/nodelist/networkstatus.c
+++ b/src/feature/nodelist/networkstatus.c
@@ -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 @@ routerstatus_has_visibly_changed(const routerstatus_t *a,
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 @@ notify_after_networkstatus_changes(void)
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();
@@ -2372,7 +2373,7 @@ char *
networkstatus_getinfo_helper_single(const routerstatus_t *rs)
{
return routerstatus_format_entry(rs, NULL, NULL, NS_CONTROL_PORT,
- NULL);
+ NULL, -1);
}
/**
@@ -2404,7 +2405,6 @@ set_routerstatus_from_routerinfo(routerstatus_t *rs,
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 +2451,9 @@ networkstatus_getinfo_by_purpose(const char *purpose_string, time_t now)
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 +2624,12 @@ networkstatus_parse_flavor_name(const char *flavname)
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 --git a/src/feature/nodelist/node_select.h b/src/feature/nodelist/node_select.h
index 18a14ff0cb..cc2e656e70 100644
--- a/src/feature/nodelist/node_select.h
+++ b/src/feature/nodelist/node_select.h
@@ -34,6 +34,8 @@ typedef enum router_crn_flags_t {
CRN_RENDEZVOUS_V3 = 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 --git a/src/feature/nodelist/nodelist.c b/src/feature/nodelist/nodelist.c
index b895a2c7f8..bbaa51a407 100644
--- a/src/feature/nodelist/nodelist.c
+++ b/src/feature/nodelist/nodelist.c
@@ -1205,7 +1205,7 @@ node_ed25519_id_matches(const node_t *node, const ed25519_public_key_t *id)
/** 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
};
/** Return the protover_summary_flags for a given node. */
@@ -1341,6 +1341,15 @@ node_supports_accepting_ipv6_extends(const node_t *node,
}
}
+/** 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)
diff --git a/src/feature/nodelist/nodelist.h b/src/feature/nodelist/nodelist.h
index 5a45490dbb..3d5ad9c0ea 100644
--- a/src/feature/nodelist/nodelist.h
+++ b/src/feature/nodelist/nodelist.h
@@ -84,6 +84,7 @@ bool node_supports_establish_intro_dos_extension(const node_t *node);
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,
diff --git a/src/feature/nodelist/routerlist.c b/src/feature/nodelist/routerlist.c
index c00f7ffb26..63de68dda7 100644
--- a/src/feature/nodelist/routerlist.c
+++ b/src/feature/nodelist/routerlist.c
@@ -243,7 +243,6 @@ router_rebuild_store(int flags, desc_store_t *store)
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 @@ router_rebuild_store(int flags, desc_store_t *store)
goto done;
}
if (sd->do_not_cache) {
- ++nocache;
continue;
}
c = tor_malloc(sizeof(sized_chunk_t));
@@ -560,6 +558,7 @@ router_can_choose_node(const node_t *node, int flags)
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 or_options_t *options = get_options();
const bool check_reach =
@@ -594,6 +593,10 @@ router_can_choose_node(const node_t *node, int flags)
if (rendezvous_v3 &&
!node_supports_v3_rendezvous_point(node))
return false;
+ /* 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,
@@ -1924,11 +1927,9 @@ routerlist_remove_old_routers(void)
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 +2654,7 @@ update_consensus_router_descriptor_downloads(time_t now, int is_vote,
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 +2670,17 @@ update_consensus_router_descriptor_downloads(time_t now, int is_vote,
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 +2729,20 @@ update_consensus_router_descriptor_downloads(time_t now, int is_vote,
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);
diff --git a/src/feature/nodelist/routerstatus_st.h b/src/feature/nodelist/routerstatus_st.h
index 55b76de581..a36c80917c 100644
--- a/src/feature/nodelist/routerstatus_st.h
+++ b/src/feature/nodelist/routerstatus_st.h
@@ -21,7 +21,6 @@ struct routerstatus_t {
* 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 --git a/src/feature/nodelist/vote_routerstatus_st.h b/src/feature/nodelist/vote_routerstatus_st.h
index 6b2f7b92a9..41d465db8f 100644
--- a/src/feature/nodelist/vote_routerstatus_st.h
+++ b/src/feature/nodelist/vote_routerstatus_st.h
@@ -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 --git a/src/feature/relay/dns.c b/src/feature/relay/dns.c
index a38bf5cf5a..f6a020d061 100644
--- a/src/feature/relay/dns.c
+++ b/src/feature/relay/dns.c
@@ -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"
@@ -650,6 +651,7 @@ dns_resolve(edge_connection_t *exitconn)
* connected cell. */
exitconn->next_stream = oncirc->n_streams;
oncirc->n_streams = exitconn;
+ conflux_update_n_streams(oncirc, exitconn);
}
break;
case 0:
@@ -658,6 +660,7 @@ dns_resolve(edge_connection_t *exitconn)
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 +771,11 @@ dns_resolve_impl,(edge_connection_t *exitconn, int is_resolve,
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));
@@ -1234,6 +1237,7 @@ inform_pending_connections(cached_resolve_t *resolve)
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 +1463,7 @@ configure_libevent_options(void)
* 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 --git a/src/feature/relay/onion_queue.c b/src/feature/relay/onion_queue.c
index b844aefcd1..f3f4b169f4 100644
--- a/src/feature/relay/onion_queue.c
+++ b/src/feature/relay/onion_queue.c
@@ -115,7 +115,7 @@ get_onion_queue_max_delay(const or_options_t *options)
/**
* 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)
diff --git a/src/feature/relay/relay_config.c b/src/feature/relay/relay_config.c
index 85ccfc18a7..0b02461318 100644
--- a/src/feature/relay/relay_config.c
+++ b/src/feature/relay/relay_config.c
@@ -30,9 +30,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"
@@ -942,7 +944,8 @@ options_validate_relay_accounting(const or_options_t *old_options,
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 +1121,8 @@ options_validate_relay_mode(const or_options_t *old_options,
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 +1151,13 @@ options_validate_relay_mode(const or_options_t *old_options,
REJECT("BridgeRelay is 1, ORPort is not set. This is an invalid "
"combination.");
+ if (options->BridgeRelay == 1 && (options->ExitRelay == 1 ||
+ !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)) {
@@ -1324,12 +1335,6 @@ options_act_relay(const or_options_t *old_options)
"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 --git a/src/feature/relay/relay_find_addr.c b/src/feature/relay/relay_find_addr.c
index f4f9d40823..106117b236 100644
--- a/src/feature/relay/relay_find_addr.c
+++ b/src/feature/relay/relay_find_addr.c
@@ -78,7 +78,7 @@ relay_address_new_suggestion(const tor_addr_t *suggested_addr,
/* 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 @@ relay_addr_learn_from_dirauth(void)
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 --git a/src/feature/relay/relay_metrics.c b/src/feature/relay/relay_metrics.c
index cdf34a3404..8f3b82bd96 100644
--- a/src/feature/relay/relay_metrics.c
+++ b/src/feature/relay/relay_metrics.c
@@ -32,8 +32,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 <event2/dns.h>
@@ -55,6 +57,12 @@ static void fill_streams_values(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 +182,41 @@ static const relay_metrics_entry_t base_metrics[] =
.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,
+ },
};
static const size_t num_base_metrics = ARRAY_LENGTH(base_metrics);
@@ -222,8 +265,8 @@ fill_circuits_values(void)
{
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 +298,57 @@ fill_relay_flags(void)
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 +360,15 @@ fill_traffic_values(void)
{
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,57 +379,57 @@ static void
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());
@@ -399,8 +442,8 @@ fill_cc_counters_values(void)
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 +451,7 @@ fill_cc_counters_values(void)
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 +460,7 @@ fill_cc_counters_values(void)
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 +469,7 @@ fill_cc_counters_values(void)
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 +478,7 @@ fill_cc_counters_values(void)
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 +486,7 @@ fill_cc_counters_values(void)
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 +494,7 @@ fill_cc_counters_values(void)
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 +502,7 @@ fill_cc_counters_values(void)
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 +510,7 @@ fill_cc_counters_values(void)
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 +518,7 @@ fill_cc_counters_values(void)
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 +533,8 @@ fill_cc_gauges_values(void)
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 +543,7 @@ fill_cc_gauges_values(void)
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 +552,7 @@ fill_cc_gauges_values(void)
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 +561,7 @@ fill_cc_gauges_values(void)
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 +570,7 @@ fill_cc_gauges_values(void)
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 +579,7 @@ fill_cc_gauges_values(void)
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 +588,7 @@ fill_cc_gauges_values(void)
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 +597,7 @@ fill_cc_gauges_values(void)
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 +606,7 @@ fill_cc_gauges_values(void)
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 +615,7 @@ fill_cc_gauges_values(void)
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 +624,7 @@ fill_cc_gauges_values(void)
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 +633,7 @@ fill_cc_gauges_values(void)
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 +642,7 @@ fill_cc_gauges_values(void)
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 +651,7 @@ fill_cc_gauges_values(void)
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 +660,7 @@ fill_cc_gauges_values(void)
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 +669,7 @@ fill_cc_gauges_values(void)
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 +678,7 @@ fill_cc_gauges_values(void)
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 +702,16 @@ fill_streams_values(void)
{
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 +747,31 @@ fill_conn_counter_values(void)
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 +791,21 @@ fill_conn_gauge_values(void)
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 +820,7 @@ fill_tcp_exhaustion_values(void)
&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 +878,7 @@ fill_dns_error_values(void)
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 +892,7 @@ fill_dns_error_values(void)
/* 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 +916,7 @@ fill_dns_query_values(void)
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 +925,7 @@ fill_dns_query_values(void)
#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 +938,13 @@ fill_global_bw_limit_values(void)
&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 +959,13 @@ fill_socket_values(void)
&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 +983,7 @@ fill_onionskins_values(void)
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 +991,7 @@ fill_onionskins_values(void)
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 +1010,196 @@ fill_oom_values(void)
&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]);
+ }
+}
+
/** Reset the global store and fill it with all the metrics from base_metrics
* and their associated values.
*
diff --git a/src/feature/relay/relay_metrics.h b/src/feature/relay/relay_metrics.h
index 1d2d649d8a..cf9dddf955 100644
--- a/src/feature/relay/relay_metrics.h
+++ b/src/feature/relay/relay_metrics.h
@@ -47,6 +47,16 @@ typedef enum {
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,
} relay_metrics_key_t;
/** The metadata of a relay metric. */
@@ -70,4 +80,54 @@ void relay_metrics_free(void);
/* 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 --git a/src/feature/relay/relay_periodic.c b/src/feature/relay/relay_periodic.c
index dd9be4e36f..7661d00afc 100644
--- a/src/feature/relay/relay_periodic.c
+++ b/src/feature/relay/relay_periodic.c
@@ -102,7 +102,9 @@ rotate_onion_key_callback(time_t now, const or_options_t *options)
}
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");
diff --git a/src/feature/relay/relay_stub.c b/src/feature/relay/relay_stub.c
index c7ac9093fa..4531096316 100644
--- a/src/feature/relay/relay_stub.c
+++ b/src/feature/relay/relay_stub.c
@@ -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 @@ const struct subsys_fns_t sys_relay = {
.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 --git a/src/feature/relay/router.c b/src/feature/relay/router.c
index bc98fd985c..1ed9630e09 100644
--- a/src/feature/relay/router.c
+++ b/src/feature/relay/router.c
@@ -482,8 +482,10 @@ get_my_v3_legacy_signing_key(void)
* - 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 +493,7 @@ rotate_onion_key(void)
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 +543,7 @@ rotate_onion_key(void)
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 +553,7 @@ rotate_onion_key(void)
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
@@ -911,9 +916,9 @@ router_write_fingerprint(int hashed, int ed25519_identity)
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;
@@ -2554,8 +2559,6 @@ mark_my_descriptor_dirty_if_too_old(time_t now)
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";
}
diff --git a/src/feature/relay/router.h b/src/feature/relay/router.h
index b5b5a1fffa..f201fdbd63 100644
--- a/src/feature/relay/router.h
+++ b/src/feature/relay/router.h
@@ -45,7 +45,7 @@ authority_cert_t *get_my_v3_legacy_cert(void);
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);
diff --git a/src/feature/relay/routerkeys.h b/src/feature/relay/routerkeys.h
index 7b6d80773c..b97615a9c9 100644
--- a/src/feature/relay/routerkeys.h
+++ b/src/feature/relay/routerkeys.h
@@ -53,7 +53,6 @@ void routerkeys_free_all(void);
static inline void *
relay_key_is_unavailable_(void)
{
- tor_assert_nonfatal_unreached();
return NULL;
}
#define relay_key_is_unavailable(type) \
diff --git a/src/feature/rend/rendmid.c b/src/feature/rend/rendmid.c
index 8f6a45dfef..dee91629ec 100644
--- a/src/feature/rend/rendmid.c
+++ b/src/feature/rend/rendmid.c
@@ -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 @@ rend_mid_establish_rendezvous(or_circuit_t *circ, const uint8_t *request,
(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 @@ rend_mid_establish_rendezvous(or_circuit_t *circ, const uint8_t *request,
* 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 @@ rend_mid_establish_rendezvous(or_circuit_t *circ, const uint8_t *request,
}
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 @@ rend_mid_establish_rendezvous(or_circuit_t *circ, const uint8_t *request,
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 @@ rend_mid_rendezvous(or_circuit_t *circ, const uint8_t *request,
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 @@ rend_mid_rendezvous(or_circuit_t *circ, const uint8_t *request,
}
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 @@ rend_mid_rendezvous(or_circuit_t *circ, const uint8_t *request,
* 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 @@ rend_mid_rendezvous(or_circuit_t *circ, const uint8_t *request,
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 @@ rend_mid_rendezvous(or_circuit_t *circ, const uint8_t *request,
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 --git a/src/feature/stats/geoip_stats.h b/src/feature/stats/geoip_stats.h
index b54304337a..3a455b2705 100644
--- a/src/feature/stats/geoip_stats.h
+++ b/src/feature/stats/geoip_stats.h
@@ -20,7 +20,7 @@
* 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,
diff --git a/src/feature/stats/rephist.c b/src/feature/stats/rephist.c
index d1ccc5edf5..8f4f33151a 100644
--- a/src/feature/stats/rephist.c
+++ b/src/feature/stats/rephist.c
@@ -2292,7 +2292,7 @@ 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.
+ * use this function to convert the cell type to a stat index.
*/
static inline uint16_t
onionskin_type_to_stat(uint16_t type)
@@ -2315,7 +2315,7 @@ onionskin_type_to_stat(uint16_t type)
* 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
diff --git a/src/include.am b/src/include.am
index 36d323e6eb..29a392a132 100644
--- a/src/include.am
+++ b/src/include.am
@@ -87,6 +87,5 @@ include src/app/include.am
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 --git a/src/lib/compress/compress.c b/src/lib/compress/compress.c
index 83e63905cc..346e77f07d 100644
--- a/src/lib/compress/compress.c
+++ b/src/lib/compress/compress.c
@@ -66,7 +66,15 @@ tor_compress_is_compression_bomb,(size_t size_in, size_t size_out))
if (size_in == 0 || size_out < CHECK_FOR_COMPRESSION_BOMB_AFTER)
return 0;
- return (size_out / size_in > MAX_UNCOMPRESSION_FACTOR);
+ if (size_out / size_in > MAX_UNCOMPRESSION_FACTOR) {
+ log_warn(LD_GENERAL,
+ "Detected possible compression bomb with "
+ "input size = %"TOR_PRIuSZ " and output size = %"TOR_PRIuSZ,
+ size_in, size_out);
+ return 1;
+ }
+
+ return 0;
}
/** Guess the size that <b>in_len</b> will be after compression or
diff --git a/src/lib/crypt_ops/compat_openssl.h b/src/lib/crypt_ops/compat_openssl.h
index 0f56f338b5..c5eccdb015 100644
--- a/src/lib/crypt_ops/compat_openssl.h
+++ b/src/lib/crypt_ops/compat_openssl.h
@@ -20,32 +20,36 @@
* \brief compatibility definitions for working with different openssl forks
**/
-#if !defined(LIBRESSL_VERSION_NUMBER) && \
- OPENSSL_VERSION_NUMBER < OPENSSL_V_SERIES(1,0,1)
+#if 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)
+#if OPENSSL_VERSION_NUMBER >= OPENSSL_V_SERIES(1,1,0)
/* 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 these OpenSSL 1.1 APIs */
+#if !defined(OPENSSL_1_1_API) || 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) */
-#define tor_OpenSSL_version_num() OpenSSL_version_num()
+#else
#define STATE_IS_SW_SERVER_HELLO(st) \
((st) == TLS_ST_SW_SRVR_HELLO)
#define CONST_IF_OPENSSL_1_1_API const
+#endif
+
+/* OpenSSL 1.1 and LibreSSL both have these APIs */
+#ifndef OPENSSL_1_1_API
+#define OpenSSL_version(v) SSLeay_version(v)
+#define tor_OpenSSL_version_num() SSLeay()
+#else /* defined(OPENSSL_1_1_API) */
+#define tor_OpenSSL_version_num() OpenSSL_version_num()
#endif /* !defined(OPENSSL_1_1_API) */
#endif /* defined(ENABLE_OPENSSL) */
diff --git a/src/lib/crypt_ops/crypto_openssl_mgt.h b/src/lib/crypt_ops/crypto_openssl_mgt.h
index c6f63ffa08..96a37721dd 100644
--- a/src/lib/crypt_ops/crypto_openssl_mgt.h
+++ b/src/lib/crypt_ops/crypto_openssl_mgt.h
@@ -54,8 +54,7 @@
#define DISABLE_ENGINES
#endif
-#if OPENSSL_VERSION_NUMBER >= OPENSSL_VER(1,1,0,0,5) && \
- !defined(LIBRESSL_VERSION_NUMBER)
+#if OPENSSL_VERSION_NUMBER >= OPENSSL_VER(1,1,0,0,5)
/* OpenSSL as of 1.1.0pre4 has an "new" thread API, which doesn't require
* setting up various callbacks.
*
diff --git a/src/lib/crypt_ops/crypto_rsa_openssl.c b/src/lib/crypt_ops/crypto_rsa_openssl.c
index a21c4a65cf..544d72e6ca 100644
--- a/src/lib/crypt_ops/crypto_rsa_openssl.c
+++ b/src/lib/crypt_ops/crypto_rsa_openssl.c
@@ -572,7 +572,9 @@ static bool
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 defined(OPENSSL_1_1_API) && \
+ (!defined(LIBRESSL_VERSION_NUMBER) || \
+ LIBRESSL_VERSION_NUMBER >= OPENSSL_V_SERIES(3,5,0))
#if OPENSSL_VERSION_NUMBER >= OPENSSL_V_SERIES(1,1,1)
n = RSA_get0_n(rsa);
@@ -591,7 +593,7 @@ rsa_private_key_too_long(RSA *rsa, int max_bits)
if (RSA_bits(rsa) > max_bits)
return true;
-#else /* !defined(OPENSSL_1_1_API) */
+#else /* !defined(OPENSSL_1_1_API) && ... */
n = rsa->n;
e = rsa->e;
p = rsa->p;
@@ -600,7 +602,7 @@ rsa_private_key_too_long(RSA *rsa, int max_bits)
dmp1 = rsa->dmp1;
dmq1 = rsa->dmq1;
iqmp = rsa->iqmp;
-#endif /* defined(OPENSSL_1_1_API) */
+#endif /* defined(OPENSSL_1_1_API) && ... */
if (n && BN_num_bits(n) > max_bits)
return true;
diff --git a/src/lib/dispatch/dispatch_cfg_st.h b/src/lib/dispatch/dispatch_cfg_st.h
index 636f2e6df5..503d13e010 100644
--- a/src/lib/dispatch/dispatch_cfg_st.h
+++ b/src/lib/dispatch/dispatch_cfg_st.h
@@ -24,9 +24,9 @@ struct dispatch_cfg_t {
struct smartlist_t *type_by_msg;
/** A list of channel_id_t (cast to void*), indexed by msg_t. */
struct smartlist_t *chan_by_msg;
- /** A list of dispatch_rcv_t, indexed by msg_type_id_t. */
+ /** 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 --git a/src/lib/evloop/compat_libevent.c b/src/lib/evloop/compat_libevent.c
index fd840f8085..c882d3478e 100644
--- a/src/lib/evloop/compat_libevent.c
+++ b/src/lib/evloop/compat_libevent.c
@@ -137,10 +137,8 @@ tor_libevent_initialize(tor_libevent_cfg_t *torcfg)
(void)torcfg;
{
- int attempts = 0;
struct event_config *cfg;
- ++attempts;
cfg = event_config_new();
tor_assert(cfg);
diff --git a/src/lib/evloop/token_bucket.c b/src/lib/evloop/token_bucket.c
index 16452314e2..9bcfeb9367 100644
--- a/src/lib/evloop/token_bucket.c
+++ b/src/lib/evloop/token_bucket.c
@@ -111,7 +111,9 @@ token_bucket_raw_dec(token_bucket_raw_t *bucket,
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 @@ rate_per_sec_to_rate_per_step(uint32_t rate)
/**
* Initialize a token bucket in *<b>bucket</b>, set up to allow <b>rate</b>
* bytes per second, with a maximum burst of <b>burst</b> bytes. The bucket
- * is created such that <b>now_ts</b> is the current timestamp. The bucket
- * starts out full.
+ * is created such that <b>now_ts_stamp</b> 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 @@ token_bucket_rw_adjust(token_bucket_rw_t *bucket,
}
/**
- * Reset <b>bucket</b> to be full, as of timestamp <b>now_ts</b>.
+ * Reset <b>bucket</b> to be full, as of timestamp <b>now_ts_stamp</b>.
*/
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 <b>bucket</b> as appropriate, given that the current timestamp
- * is <b>now_ts</b>.
+ * is <b>now_ts_stamp</b> 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;
- 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;
+ 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;
+ }
- bucket->last_refilled_at_timestamp = now_ts;
+ bucket->last_refilled_at_timestamp = now_ts_stamp;
return flags;
}
@@ -259,15 +259,17 @@ token_bucket_rw_dec(token_bucket_rw_t *bucket,
/** Initialize a token bucket in <b>bucket</b>, set up to allow <b>rate</b>
* per second, with a maximum burst of <b>burst</b>. The bucket is created
- * such that <b>now_ts</b> is the current timestamp. The bucket starts out
- * full. */
+ * such that <b>now_ts_sec</b> 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_ctr_adjust(token_bucket_ctr_t *bucket, uint32_t rate,
token_bucket_raw_adjust(&bucket->counter, &bucket->cfg);
}
-/** Reset <b>bucket</b> to be full, as of timestamp <b>now_ts</b>. */
+/** Reset <b>bucket</b> to be full, as of timestamp <b>now_ts_sec</b>. */
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 <b>bucket</b> as appropriate, given that the current timestamp is
- * <b>now_ts</b>. */
+ * <b>now_ts_sec</b> 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 --git a/src/lib/evloop/token_bucket.h b/src/lib/evloop/token_bucket.h
index b57d704298..d042041e02 100644
--- a/src/lib/evloop/token_bucket.h
+++ b/src/lib/evloop/token_bucket.h
@@ -66,19 +66,19 @@ typedef struct token_bucket_rw_t {
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 @@ typedef struct token_bucket_ctr_t {
} 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 --git a/src/lib/evloop/workqueue.c b/src/lib/evloop/workqueue.c
index bc929148eb..9a0c02fbd0 100644
--- a/src/lib/evloop/workqueue.c
+++ b/src/lib/evloop/workqueue.c
@@ -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"
diff --git a/src/lib/geoip/geoip.c b/src/lib/geoip/geoip.c
index 686040613d..f13354dbe1 100644
--- a/src/lib/geoip/geoip.c
+++ b/src/lib/geoip/geoip.c
@@ -387,7 +387,7 @@ geoip_load_file(sa_family_t family, const char *filename, int severity)
* 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 @@ geoip_get_country_by_ipv4(uint32_t ipaddr)
* 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 --git a/src/lib/geoip/geoip.h b/src/lib/geoip/geoip.h
index 764ed1d5a5..e68573fd1a 100644
--- a/src/lib/geoip/geoip.h
+++ b/src/lib/geoip/geoip.h
@@ -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 --git a/src/lib/malloc/malloc.h b/src/lib/malloc/malloc.h
index cc031f843a..48a3ac32cf 100644
--- a/src/lib/malloc/malloc.h
+++ b/src/lib/malloc/malloc.h
@@ -11,6 +11,7 @@
#ifndef TOR_UTIL_MALLOC_H
#define TOR_UTIL_MALLOC_H
+#include <assert.h>
#include <stddef.h>
#include <stdlib.h>
#include "lib/cc/compat_compiler.h"
@@ -45,6 +46,9 @@ void tor_free_(void *mem);
#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 --git a/src/lib/math/prob_distr.c b/src/lib/math/prob_distr.c
index a57fc1020c..9e60b9f37a 100644
--- a/src/lib/math/prob_distr.c
+++ b/src/lib/math/prob_distr.c
@@ -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 --git a/src/lib/math/stats.h b/src/lib/math/stats.h
index 14315a2506..7acc6fa43d 100644
--- a/src/lib/math/stats.h
+++ b/src/lib/math/stats.h
@@ -25,7 +25,7 @@ n_count_ewma_double(double avg, double value, uint64_t N)
/* 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 --git a/src/lib/metrics/metrics_common.c b/src/lib/metrics/metrics_common.c
index f3f7e22d88..5836a581f1 100644
--- a/src/lib/metrics/metrics_common.c
+++ b/src/lib/metrics/metrics_common.c
@@ -24,6 +24,8 @@ metrics_type_to_str(const metrics_type_t type)
return "counter";
case METRICS_TYPE_GAUGE:
return "gauge";
+ case METRICS_TYPE_HISTOGRAM:
+ return "histogram";
default:
tor_assert_unreached();
}
diff --git a/src/lib/metrics/metrics_common.h b/src/lib/metrics/metrics_common.h
index 3644ad3d50..6c8e8bdbdc 100644
--- a/src/lib/metrics/metrics_common.h
+++ b/src/lib/metrics/metrics_common.h
@@ -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 @@ typedef enum {
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 @@ typedef struct metrics_gauge_t {
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 --git a/src/lib/metrics/metrics_store.c b/src/lib/metrics/metrics_store.c
index b017e97688..db80ca029b 100644
--- a/src/lib/metrics/metrics_store.c
+++ b/src/lib/metrics/metrics_store.c
@@ -107,7 +107,9 @@ metrics_store_get_all(const metrics_store_t *store, const char *name)
* 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 @@ metrics_store_add(metrics_store_t *store, metrics_type_t type,
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 --git a/src/lib/metrics/metrics_store.h b/src/lib/metrics/metrics_store.h
index d85f484bd6..d06c87303c 100644
--- a/src/lib/metrics/metrics_store.h
+++ b/src/lib/metrics/metrics_store.h
@@ -26,8 +26,10 @@ metrics_store_t *metrics_store_new(void);
/* 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 --git a/src/lib/metrics/metrics_store_entry.c b/src/lib/metrics/metrics_store_entry.c
index 482ec8d7d9..649fd660c3 100644
--- a/src/lib/metrics/metrics_store_entry.c
+++ b/src/lib/metrics/metrics_store_entry.c
@@ -6,6 +6,7 @@
* @brief Metrics store entry which contains the gathered data.
**/
+#include "metrics_common.h"
#define METRICS_STORE_ENTRY_PRIVATE
#include <string.h>
@@ -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 @@ metrics_store_entry_new(const metrics_type_t type, const char *name,
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 @@ metrics_store_entry_free_(metrics_store_entry_t *entry)
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 @@ metrics_store_entry_update(metrics_store_entry_t *entry, const int64_t value)
{
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 @@ metrics_store_entry_update(metrics_store_entry_t *entry, const int64_t value)
/* 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 @@ void
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 @@ metrics_store_entry_get_value(const metrics_store_entry_t *entry)
{
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 @@ metrics_store_entry_get_value(const metrics_store_entry_t *entry)
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 @@ metrics_store_entry_get_value(const metrics_store_entry_t *entry)
// 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 @@ metrics_store_entry_has_label(const metrics_store_entry_t *entry,
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 --git a/src/lib/metrics/metrics_store_entry.h b/src/lib/metrics/metrics_store_entry.h
index e4dc7a8b9a..53fa437406 100644
--- a/src/lib/metrics/metrics_store_entry.h
+++ b/src/lib/metrics/metrics_store_entry.h
@@ -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 @@ struct metrics_store_entry_t {
union {
metrics_counter_t counter;
metrics_gauge_t gauge;
+ metrics_histogram_t histogram;
} u;
};
@@ -47,7 +49,9 @@ typedef struct metrics_store_entry_t metrics_store_entry_t;
/* 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 @@ void metrics_store_entry_free_(metrics_store_entry_t *entry);
/* 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_add_label(metrics_store_entry_t *entry,
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 --git a/src/lib/metrics/prometheus.c b/src/lib/metrics/prometheus.c
index aac23ac92e..2f98f8ebb6 100644
--- a/src/lib/metrics/prometheus.c
+++ b/src/lib/metrics/prometheus.c
@@ -17,6 +17,8 @@
#include "lib/metrics/prometheus.h"
+#include <string.h>
+
/** Return a static buffer containing all the labels properly formatted
* for the output as a string.
*
@@ -33,13 +35,54 @@ format_labels(smartlist_t *labels)
}
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 @@ prometheus_format_store_entry(const metrics_store_entry_t *entry, buf_t *data,
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 --git a/src/lib/osinfo/libc.c b/src/lib/osinfo/libc.c
index f52dea41aa..f7cfde8642 100644
--- a/src/lib/osinfo/libc.c
+++ b/src/lib/osinfo/libc.c
@@ -26,11 +26,18 @@
#define STR_IMPL(x) #x
#define STR(x) STR_IMPL(x)
+#if defined(__BSD_VISIBLE) || defined(__NETBSD_SOURCE)
+#include <sys/param.h>
+#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 @@ tor_libc_get_name(void)
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 --git a/src/lib/process/process_win32.c b/src/lib/process/process_win32.c
index dfcb17a480..6458f93752 100644
--- a/src/lib/process/process_win32.c
+++ b/src/lib/process/process_win32.c
@@ -888,7 +888,7 @@ process_win32_read_from_handle(process_win32_handle_t *handle,
/* 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 --git a/src/lib/sandbox/sandbox.c b/src/lib/sandbox/sandbox.c
index 5dace3a8a2..8ac07abfc9 100644
--- a/src/lib/sandbox/sandbox.c
+++ b/src/lib/sandbox/sandbox.c
@@ -141,10 +141,12 @@ static sandbox_cfg_t *filter_dynamic = NULL;
* 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.
@@ -439,7 +441,14 @@ sb_mmap2(scmp_filter_ctx ctx, sandbox_cfg_t *filter)
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;
}
@@ -520,14 +529,6 @@ libc_uses_openat_for_opendir(void)
(is_libc_at_least(2, 15) && !is_libc_at_least(2, 22));
}
-/* 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);
-}
-
/** Allow a single file to be opened. If <b>use_openat</b> is true,
* we're using a libc that remaps all the opens into openats. */
static int
@@ -535,7 +536,7 @@ allow_file_open(scmp_filter_ctx ctx, int use_openat, const char *file)
{
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),
@@ -616,6 +617,32 @@ sb_chmod(scmp_filter_ctx ctx, sandbox_cfg_t *filter)
return 0;
}
+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;
+}
+
#ifdef __i386__
static int
sb_chown32(scmp_filter_ctx ctx, sandbox_cfg_t *filter)
@@ -668,6 +695,32 @@ sb_chown(scmp_filter_ctx ctx, sandbox_cfg_t *filter)
}
#endif /* defined(__i386__) */
+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;
+}
+
/**
* Function responsible for setting up the rename syscall for
* the seccomp filter sandbox.
@@ -700,6 +753,39 @@ sb_rename(scmp_filter_ctx ctx, sandbox_cfg_t *filter)
}
/**
+ * 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;
+}
+
+/**
* Function responsible for setting up the openat syscall for
* the seccomp filter sandbox.
*/
@@ -716,7 +802,7 @@ sb_openat(scmp_filter_ctx ctx, sandbox_cfg_t *filter)
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));
@@ -1328,7 +1414,9 @@ static sandbox_filter_func_t filter_func[] = {
#else
sb_chown,
#endif
+ sb_fchownat,
sb_chmod,
+ sb_fchmodat,
sb_open,
sb_openat,
sb_opendir,
@@ -1336,6 +1424,7 @@ static sandbox_filter_func_t filter_func[] = {
sb_ptrace,
#endif
sb_rename,
+ sb_renameat,
#ifdef __NR_fcntl64
sb_fcntl64,
#endif
@@ -1603,10 +1692,24 @@ new_element(int syscall, char *value)
#ifdef __i386__
#define SCMP_chown SCMP_SYS(chown32)
+#elif defined(__aarch64__) && defined(__LP64__)
+#define SCMP_chown SCMP_SYS(fchownat)
#else
#define SCMP_chown SCMP_SYS(chown)
#endif
+#if defined(__aarch64__) && defined(__LP64__)
+#define SCMP_chmod SCMP_SYS(fchmodat)
+#else
+#define SCMP_chmod SCMP_SYS(chmod)
+#endif
+
+#if defined(__aarch64__) && defined(__LP64__)
+#define SCMP_rename SCMP_SYS(renameat)
+#else
+#define SCMP_rename SCMP_SYS(rename)
+#endif
+
#ifdef __NR_stat64
#define SCMP_stat SCMP_SYS(stat64)
#else
@@ -1644,7 +1747,7 @@ sandbox_cfg_allow_chmod_filename(sandbox_cfg_t **cfg, char *file)
{
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 +1773,7 @@ sandbox_cfg_allow_rename(sandbox_cfg_t **cfg, char *file1, char *file2)
{
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;
diff --git a/src/lib/time/compat_time.c b/src/lib/time/compat_time.c
index eb716259c4..57a1e45b84 100644
--- a/src/lib/time/compat_time.c
+++ b/src/lib/time/compat_time.c
@@ -812,6 +812,12 @@ monotime_absolute_msec(void)
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 +842,17 @@ monotime_coarse_absolute_msec(void)
{
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 --git a/src/lib/time/compat_time.h b/src/lib/time/compat_time.h
index da96023894..eaf676ae84 100644
--- a/src/lib/time/compat_time.h
+++ b/src/lib/time/compat_time.h
@@ -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 @@ MOCK_DECL(uint64_t, monotime_absolute_usec,(void));
* 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 <b>out</b> to zero.
*/
@@ -259,11 +271,13 @@ void monotime_coarse_get(monotime_coarse_t *out);
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) */
/**
diff --git a/src/lib/tls/tortls_openssl.c b/src/lib/tls/tortls_openssl.c
index f3257d5f24..ee91715e2d 100644
--- a/src/lib/tls/tortls_openssl.c
+++ b/src/lib/tls/tortls_openssl.c
@@ -340,8 +340,10 @@ tor_tls_init(void)
SSL_load_error_strings();
#endif /* defined(OPENSSL_1_1_API) */
-#if (SIZEOF_VOID_P >= 8 && \
- OPENSSL_VERSION_NUMBER >= OPENSSL_V_SERIES(1,0,1))
+#if (SIZEOF_VOID_P >= 8 && \
+ OPENSSL_VERSION_NUMBER >= OPENSSL_V_SERIES(1,0,1) && \
+ (!defined(LIBRESSL_VERSION_NUMBER) || \
+ LIBRESSL_VERSION_NUMBER < 0x3080000fL))
long version = tor_OpenSSL_version_num();
/* LCOV_EXCL_START : we can't test these lines on the same machine */
@@ -1760,8 +1762,7 @@ tor_tls_export_key_material,(tor_tls_t *tls, uint8_t *secrets_out,
* 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)
diff --git a/src/test/Makefile.nmake b/src/test/Makefile.nmake
deleted file mode 100644
index ca6a84cf8a..0000000000
--- a/src/test/Makefile.nmake
+++ /dev/null
@@ -1,35 +0,0 @@
-all: test.exe bench.exe
-
-CFLAGS = /I ..\win32 /I ..\..\..\build-alpha\include /I ..\common /I ..\or \
- /I ..\ext
-
-LIBS = ..\..\..\build-alpha\lib\libevent.lib \
- ..\..\..\build-alpha\lib\libcrypto.lib \
- ..\..\..\build-alpha\lib\libssl.lib \
- ..\..\..\build-alpha\lib\libz.lib \
- ..\or\libtor.lib \
- ws2_32.lib advapi32.lib shell32.lib \
- crypt32.lib gdi32.lib user32.lib
-
-TEST_OBJECTS = test.obj test_addr.obj test_channel.obj test_channeltls.obj \
- test_consdiff.obj test_containers.obj \
- test_controller_events.obj test_crypto.obj test_data.obj test_dir.obj \
- test_checkdir.obj test_microdesc.obj test_pt.obj test_util.obj \
- test_config.obj test_connection.obj \
- test_cell_formats.obj test_relay.obj test_replay.obj \
- test_channelpadding.obj \
- test_circuitstats.obj \
- test_circuitpadding.obj \
- test_scheduler.obj test_introduce.obj test_hs.obj tinytest.obj
-
-tinytest.obj: ..\ext\tinytest.c
- $(CC) $(CFLAGS) /D snprintf=_snprintf /c ..\ext\tinytest.c
-
-test.exe: $(TEST_OBJECTS)
- $(CC) $(CFLAGS) $(LIBS) ..\common\*.lib $(TEST_OBJECTS) /Fe$@
-
-bench.exe: bench.obj
- $(CC) $(CFLAGS) bench.obj $(LIBS) ..\common\*.lib /Fe$@
-
-clean:
- del *.obj *.lib test.exe bench.exe
diff --git a/src/test/bench.c b/src/test/bench.c
index a76ea67eb8..a76e600cfa 100644
--- a/src/test/bench.c
+++ b/src/test/bench.c
@@ -380,6 +380,7 @@ bench_rand_len(int len)
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));
diff --git a/src/test/conf_examples/large_1/expected b/src/test/conf_examples/large_1/expected
index fcd19db3df..85f96a24c9 100644
--- a/src/test/conf_examples/large_1/expected
+++ b/src/test/conf_examples/large_1/expected
@@ -19,7 +19,6 @@ ClientPreferIPv6DirPort 1
ClientPreferIPv6ORPort 1
ClientRejectInternalAddresses 0
ClientUseIPv4 0
-ClientUseIPv6 1
ConnDirectionStatistics 1
ConnectionPadding 1
ConnLimit 64
@@ -126,7 +125,6 @@ ReachableORAddresses 128.0.0.0/8
RejectPlaintextPorts 23
RelayBandwidthBurst 10000
RelayBandwidthRate 1000
-RendPostPeriod 600
RephistTrackTime 600
SafeLogging 0
Schedulers Vanilla,KISTLite,Kist
diff --git a/src/test/conf_examples/large_1/expected_no_dirauth b/src/test/conf_examples/large_1/expected_no_dirauth
index 4a19bc546c..e4e811caaf 100644
--- a/src/test/conf_examples/large_1/expected_no_dirauth
+++ b/src/test/conf_examples/large_1/expected_no_dirauth
@@ -19,7 +19,6 @@ ClientPreferIPv6DirPort 1
ClientPreferIPv6ORPort 1
ClientRejectInternalAddresses 0
ClientUseIPv4 0
-ClientUseIPv6 1
ConnDirectionStatistics 1
ConnectionPadding 1
ConnLimit 64
@@ -125,7 +124,6 @@ ReachableORAddresses 128.0.0.0/8
RejectPlaintextPorts 23
RelayBandwidthBurst 10000
RelayBandwidthRate 1000
-RendPostPeriod 600
RephistTrackTime 600
SafeLogging 0
Schedulers Vanilla,KISTLite,Kist
diff --git a/src/test/conf_examples/large_1/torrc b/src/test/conf_examples/large_1/torrc
index 3f5b1e179f..ebf4a3fb96 100644
--- a/src/test/conf_examples/large_1/torrc
+++ b/src/test/conf_examples/large_1/torrc
@@ -133,7 +133,6 @@ ReachableORAddresses 128.0.0.0/8
RejectPlaintextPorts 23
RelayBandwidthBurst 10000
RelayBandwidthRate 1000
-RendPostPeriod 10 minutes
RephistTrackTime 10 minutes
SafeLogging 0
SafeSocks 0
diff --git a/src/test/fakecircs.c b/src/test/fakecircs.c
index cca3b43483..e52df022d0 100644
--- a/src/test/fakecircs.c
+++ b/src/test/fakecircs.c
@@ -17,6 +17,9 @@
#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"
@@ -41,8 +44,8 @@ new_fake_orcirc(channel_t *nchan, channel_t *pchan)
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;
@@ -87,5 +90,8 @@ free_fake_orcirc(or_circuit_t *orcirc)
circuitmux_detach_circuit(circ->n_chan->cmux, circ);
}
+ conflux_circuit_about_to_free(circ);
+ congestion_control_free(circ->ccontrol);
+
tor_free_(circ);
}
diff --git a/src/test/hs_test_helpers.c b/src/test/hs_test_helpers.c
index 20b225ba4a..4ef2398095 100644
--- a/src/test/hs_test_helpers.c
+++ b/src/test/hs_test_helpers.c
@@ -354,6 +354,18 @@ hs_helper_desc_equal(const hs_descriptor_t *desc1,
}
}
+ /* 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 --git a/src/test/include.am b/src/test/include.am
index 2765cf27d0..b3e3f8bbf2 100644
--- a/src/test/include.am
+++ b/src/test/include.am
@@ -147,8 +147,11 @@ src_test_test_SOURCES += \
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 \
@@ -186,6 +189,7 @@ src_test_test_SOURCES += \
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 +268,7 @@ src_test_test_slow_SOURCES += \
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 \
diff --git a/src/test/test.c b/src/test/test.c
index 6b7e0b6442..2030a8336e 100644
--- a/src/test/test.c
+++ b/src/test/test.c
@@ -778,6 +778,9 @@ struct testgroup_t testgroups[] = {
{ "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 },
@@ -822,6 +825,7 @@ struct testgroup_t testgroups[] = {
{ "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 --git a/src/test/test.h b/src/test/test.h
index e17bce427c..7a405b649e 100644
--- a/src/test/test.h
+++ b/src/test/test.h
@@ -107,8 +107,11 @@ extern struct testcase_t circuitstats_tests[];
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[];
@@ -145,6 +148,7 @@ extern struct testcase_t hs_intropoint_tests[];
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 +209,7 @@ extern struct testcase_t voting_schedule_tests[];
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 --git a/src/test/test_bwmgt.c b/src/test/test_bwmgt.c
index a034c369d1..51ad8be59f 100644
--- a/src/test/test_bwmgt.c
+++ b/src/test/test_bwmgt.c
@@ -243,10 +243,30 @@ test_bwmgt_token_buf_refill(void *arg)
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 --git a/src/test/test_channel.c b/src/test/test_channel.c
index a74d69fefc..a6f403a25c 100644
--- a/src/test/test_channel.c
+++ b/src/test/test_channel.c
@@ -1264,8 +1264,9 @@ test_channel_duplicates(void *arg)
/* 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 @@ test_channel_duplicates(void *arg)
/* 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 @@ test_channel_duplicates(void *arg)
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 --git a/src/test/test_channelpadding.c b/src/test/test_channelpadding.c
index 261e1f8a37..63c9a3b753 100644
--- a/src/test/test_channelpadding.c
+++ b/src/test/test_channelpadding.c
@@ -862,7 +862,7 @@ test_channelpadding_decide_to_pad_channel(void *arg)
* 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 --git a/src/test/test_config.c b/src/test/test_config.c
index 3ebe095a6a..a53d0b8227 100644
--- a/src/test/test_config.c
+++ b/src/test/test_config.c
@@ -6435,7 +6435,7 @@ test_config_include_opened_file_list(void *data)
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 --git a/src/test/test_conflux_cell.c b/src/test/test_conflux_cell.c
new file mode 100644
index 0000000000..bb440d0d0a
--- /dev/null
+++ b/src/test/test_conflux_cell.c
@@ -0,0 +1,60 @@
+/* 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 "lib/crypt_ops/crypto_rand.h"
+
+static void
+test_link(void *arg)
+{
+ cell_t cell;
+ conflux_cell_link_t link;
+ conflux_cell_link_t *decoded_link = NULL;
+
+ (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, cell.payload+RELAY_HEADER_SIZE);
+ tt_int_op(cell_len, OP_GT, 0);
+
+ decoded_link = conflux_cell_parse_link(&cell, cell_len);
+ tt_assert(decoded_link);
+
+ uint8_t buf[RELAY_PAYLOAD_SIZE];
+ ssize_t enc_cell_len = build_link_cell(decoded_link, buf);
+ 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:
+ tor_free(decoded_link);
+}
+
+struct testcase_t conflux_cell_tests[] = {
+ { "link", test_link, TT_FORK, NULL, NULL },
+
+ END_OF_TESTCASES
+};
+
diff --git a/src/test/test_conflux_pool.c b/src/test/test_conflux_pool.c
new file mode 100644
index 0000000000..fc30677377
--- /dev/null
+++ b/src/test/test_conflux_pool.c
@@ -0,0 +1,1339 @@
+#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 <event.h>
+#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/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;
+
+ 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);
+
+ switch (cell->payload[0]) {
+ case RELAY_COMMAND_CONFLUX_LINK:
+ tor_assert(!CIRCUIT_IS_ORIGIN(dest_circ));
+ conflux_process_link(dest_circ, cell, rh.length);
+ 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,
+ cell, rh.length);
+ 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, cell, &rh);
+ break;
+ }
+
+ tor_free(delivery);
+ tor_free(cell);
+ 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;
+
+ // 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, NULL,
+ &addr, exit, NULL, exit);
+
+ cpath_init_circuit_crypto(hop, whatevs_key, sizeof(whatevs_key), 0, 0);
+
+ 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)
+{
+ 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;
+}
+
+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 --git a/src/test/test_congestion_control.c b/src/test/test_congestion_control.c
new file mode 100644
index 0000000000..26095d310a
--- /dev/null
+++ b/src/test/test_congestion_control.c
@@ -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(&params, 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(&params, 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(&params, 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(&params, 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(&params, 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(&params, 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 --git a/src/test/test_connection.c b/src/test/test_connection.c
index fbf9d6a5ab..ed94fe8aaa 100644
--- a/src/test/test_connection.c
+++ b/src/test/test_connection.c
@@ -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 @@ test_conn_get_basic_teardown(const struct testcase_t *tc, void *arg)
/* 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 @@ test_conn_get_basic_teardown(const struct testcase_t *tc, void *arg)
/* 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 --git a/src/test/test_crypto.c b/src/test/test_crypto.c
index 87e309f25a..db5a2db650 100644
--- a/src/test/test_crypto.c
+++ b/src/test/test_crypto.c
@@ -10,6 +10,8 @@
#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"
@@ -1043,6 +1045,7 @@ test_crypto_mac_sha3(void *arg)
{
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 +1080,12 @@ test_crypto_mac_sha3(void *arg)
/* 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 */
@@ -2844,6 +2852,181 @@ test_crypto_siphash(void *arg)
;
}
+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
@@ -3073,6 +3256,8 @@ struct testcase_t crypto_tests[] = {
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 },
END_OF_TESTCASES
};
diff --git a/src/test/test_crypto_slow.c b/src/test/test_crypto_slow.c
index bcfea10cf6..52091f190c 100644
--- a/src/test/test_crypto_slow.c
+++ b/src/test/test_crypto_slow.c
@@ -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 @@ test_crypto_ed25519_fuzz_donna(void *arg)
;
}
+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 @@ struct testcase_t slow_crypto_tests[] = {
{ "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 --git a/src/test/test_dir.c b/src/test/test_dir.c
index 186e09f236..248fd8ab5d 100644
--- a/src/test/test_dir.c
+++ b/src/test/test_dir.c
@@ -2971,7 +2971,7 @@ test_vrs_for_v3ns(vote_routerstatus_t *vrs, int voter, time_t now)
(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 +2996,7 @@ test_vrs_for_v3ns(vote_routerstatus_t *vrs, int voter, time_t now)
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 +3057,7 @@ test_consensus_for_v3ns(networkstatus_t *con, time_t now)
static void
test_routerstatus_for_v3ns(routerstatus_t *rs, time_t now)
{
+ (void)now;
tor_addr_t addr_ipv6;
tt_assert(rs);
@@ -3093,7 +3094,6 @@ test_routerstatus_for_v3ns(routerstatus_t *rs, time_t now)
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 +3968,7 @@ gen_routerstatus_for_umbw(int idx, time_t now)
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 +3993,7 @@ gen_routerstatus_for_umbw(int idx, time_t now)
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 +4020,7 @@ gen_routerstatus_for_umbw(int idx, time_t now)
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 +4046,7 @@ gen_routerstatus_for_umbw(int idx, time_t now)
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);
@@ -4146,7 +4146,7 @@ test_vrs_for_umbw(vote_routerstatus_t *vrs, int voter, time_t now)
* 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 +4170,7 @@ test_vrs_for_umbw(vote_routerstatus_t *vrs, int voter, time_t now)
* 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 +4245,7 @@ test_consensus_for_umbw(networkstatus_t *con, time_t now)
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 +4286,6 @@ test_routerstatus_for_umbw(routerstatus_t *rs, time_t now)
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 +4385,6 @@ test_dir_fmt_control_ns(void *arg)
(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 +4402,7 @@ test_dir_fmt_control_ns(void *arg)
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");
diff --git a/src/test/test_dir_common.c b/src/test/test_dir_common.c
index 201ea900ff..50ba32b562 100644
--- a/src/test/test_dir_common.c
+++ b/src/test/test_dir_common.c
@@ -93,7 +93,7 @@ dir_common_gen_routerstatus_for_v3ns(int idx, time_t now)
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 @@ dir_common_gen_routerstatus_for_v3ns(int idx, time_t now)
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 @@ dir_common_gen_routerstatus_for_v3ns(int idx, time_t now)
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 @@ dir_common_gen_routerstatus_for_v3ns(int idx, time_t now)
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 --git a/src/test/test_dir_handle_get.c b/src/test/test_dir_handle_get.c
index a7f9fa1d7b..5f93b04c96 100644
--- a/src/test/test_dir_handle_get.c
+++ b/src/test/test_dir_handle_get.c
@@ -2073,7 +2073,7 @@ test_dir_handle_get_status_vote_next_bandwidth_not_found(void* data)
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 --git a/src/test/test_dos.c b/src/test/test_dos.c
index a34420024f..6c57e85cb8 100644
--- a/src/test/test_dos.c
+++ b/src/test/test_dos.c
@@ -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 @@ mock_enable_dos_protection(const networkstatus_t *ns)
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 @@ test_dos_conn_creation(void *arg)
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 @@ test_dos_conn_creation(void *arg)
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 @@ test_dos_conn_creation(void *arg)
done:
dos_free_all();
+ monotime_disable_test_mocking();
}
/** Helper mock: Place a fake IP addr for this channel in <b>addr_out</b> */
@@ -141,6 +154,7 @@ test_dos_circuit_creation(void *arg)
/* 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 @@ test_dos_circuit_creation(void *arg)
* 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 @@ test_dos_bucket_refill(void *arg)
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 @@ test_dos_bucket_refill(void *arg)
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 @@ test_known_relay(void *arg)
/* 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 @@ test_known_relay(void *arg)
* 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 @@ test_dos_conn_rate(void *arg)
/* 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 @@ test_dos_conn_rate(void *arg)
{ /* 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 @@ test_dos_conn_rate(void *arg)
/* 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 --git a/src/test/test_hs_client.c b/src/test/test_hs_client.c
index 11a5589d21..a02dca1b60 100644
--- a/src/test/test_hs_client.c
+++ b/src/test/test_hs_client.c
@@ -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 @@ helper_get_circ_and_stream_for_test(origin_circuit_t **circ_out,
/* 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;
@@ -1186,6 +1188,7 @@ test_socks_hs_errors(void *arg)
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,
diff --git a/src/test/test_hs_common.c b/src/test/test_hs_common.c
index 347a5b7174..ea7c589be9 100644
--- a/src/test/test_hs_common.c
+++ b/src/test/test_hs_common.c
@@ -645,6 +645,19 @@ test_disaster_srv(void *arg)
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 @@ test_reachability(void *arg)
}
}
+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 <b>onion_identity_pk</b> as a client. Put
* its identity digest in <b>hsdir_digest_out</b>. */
static void
@@ -1843,6 +1917,7 @@ test_client_service_hsdir_set_sync(void *arg)
}
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 --git a/src/test/test_hs_control.c b/src/test/test_hs_control.c
index c32803b380..eaeba47b0c 100644
--- a/src/test/test_hs_control.c
+++ b/src/test/test_hs_control.c
@@ -628,7 +628,7 @@ test_hs_control_store_permanent_creds(void *arg)
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");
diff --git a/src/test/test_hs_descriptor.c b/src/test/test_hs_descriptor.c
index 469e3c39f9..89815f4858 100644
--- a/src/test/test_hs_descriptor.c
+++ b/src/test/test_hs_descriptor.c
@@ -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 @@ test_decode_descriptor(void *arg)
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 @@ test_validate_sendme(void *arg)
{
(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 --git a/src/test/test_hs_dos.c b/src/test/test_hs_dos.c
index 70f2ef412f..81410f7b9b 100644
--- a/src/test/test_hs_dos.c
+++ b/src/test/test_hs_dos.c
@@ -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 @@ free_mock_consensus(void)
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 @@ test_can_send_intro2(void *arg)
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 @@ test_can_send_intro2(void *arg)
/* 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 @@ test_can_send_intro2(void *arg)
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 @@ test_can_send_intro2(void *arg)
/* 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 @@ test_can_send_intro2(void *arg)
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 @@ test_can_send_intro2(void *arg)
}
/* 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 @@ test_can_send_intro2(void *arg)
hs_free_all();
free_mock_consensus();
+ monotime_disable_test_mocking();
}
static void
diff --git a/src/test/test_hs_intropoint.c b/src/test/test_hs_intropoint.c
index cbcdeade92..82b7ec029d 100644
--- a/src/test/test_hs_intropoint.c
+++ b/src/test/test_hs_intropoint.c
@@ -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 @@ helper_create_intro_circuit(void)
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;
}
diff --git a/src/test/test_hs_metrics.c b/src/test/test_hs_metrics.c
index 8625933df7..acb0649434 100644
--- a/src/test/test_hs_metrics.c
+++ b/src/test/test_hs_metrics.c
@@ -40,7 +40,8 @@ test_metrics(void *arg)
/* 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 @@ test_metrics(void *arg)
/* 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 --git a/src/test/test_hs_pow.c b/src/test/test_hs_pow.c
new file mode 100644
index 0000000000..072fbacff4
--- /dev/null
+++ b/src/test/test_hs_pow.c
@@ -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 --git a/src/test/test_hs_pow_slow.c b/src/test/test_hs_pow_slow.c
new file mode 100644
index 0000000000..ff715cf53e
--- /dev/null
+++ b/src/test/test_hs_pow_slow.c
@@ -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 --git a/src/test/test_hs_service.c b/src/test/test_hs_service.c
index 482ee1a014..dc60c7ca29 100644
--- a/src/test/test_hs_service.c
+++ b/src/test/test_hs_service.c
@@ -1183,6 +1183,8 @@ test_bad_introduce2(void *arg)
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 +1229,37 @@ test_bad_introduce2(void *arg)
"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 +1276,33 @@ test_bad_introduce2(void *arg)
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;
@@ -2219,12 +2279,16 @@ mock_build_state_get_exit_node(cpath_build_state_t *state)
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 @@ test_intro2_handling(void *arg)
/* 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 @@ test_intro2_handling(void *arg)
/* 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 @@ test_intro2_handling(void *arg)
/* 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 @@ test_intro2_handling(void *arg)
/* 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 @@ test_intro2_handling(void *arg)
(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 @@ test_intro2_handling(void *arg)
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 @@ test_intro2_handling(void *arg)
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 @@ test_intro2_handling(void *arg)
(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 @@ test_intro2_handling(void *arg)
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 @@ test_intro2_handling(void *arg)
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 --git a/src/test/test_metrics.c b/src/test/test_metrics.c
index ba1a763f0c..0bf072dbfc 100644
--- a/src/test/test_metrics.c
+++ b/src/test/test_metrics.c
@@ -28,11 +28,16 @@
#include "lib/encoding/confline.h"
#include "lib/metrics/metrics_store.h"
+#include <limits.h>
+
#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 @@ test_prometheus(void *arg)
/* 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 @@ test_prometheus(void *arg)
}
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 @@ test_store(void *arg)
/* 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 @@ test_store(void *arg)
/* 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 @@ test_store(void *arg)
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 @@ struct testcase_t metrics_tests[] = {
{ "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 --git a/src/test/test_nodelist.c b/src/test/test_nodelist.c
index 250db9a964..ecd29f5464 100644
--- a/src/test/test_nodelist.c
+++ b/src/test/test_nodelist.c
@@ -1273,7 +1273,6 @@ test_nodelist_routerstatus_has_visibly_changed(void *arg)
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 @@ test_nodelist_routerstatus_has_visibly_changed(void *arg)
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 @@ test_nodelist_routerstatus_has_visibly_changed(void *arg)
strlcpy(rs.nickname, "fr1end1y", sizeof(rs.nickname));
ASSERT_CHANGED();
- rs.published_on += 3600;
- ASSERT_CHANGED();
-
rs.ipv4_orport = 55;
ASSERT_CHANGED();
diff --git a/src/test/test_ntor_v3.c b/src/test/test_ntor_v3.c
index 1d06403076..0d51c684a0 100644
--- a/src/test/test_ntor_v3.c
+++ b/src/test/test_ntor_v3.c
@@ -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"
@@ -262,6 +264,7 @@ test_ntor3_handshake(void *arg)
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 --git a/src/test/test_options.c b/src/test/test_options.c
index 182e6dd572..6610e317a7 100644
--- a/src/test/test_options.c
+++ b/src/test/test_options.c
@@ -2006,43 +2006,6 @@ test_options_validate__testing(void *ignored)
}
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 @@ struct testcase_t options_tests[] = {
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 --git a/src/test/test_parsecommon.c b/src/test/test_parsecommon.c
index b32840264e..866f89a4e1 100644
--- a/src/test/test_parsecommon.c
+++ b/src/test/test_parsecommon.c
@@ -254,6 +254,50 @@ test_parsecommon_get_next_token_success(void *arg)
}
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 @@ test_parsecommon_get_next_token_err_bad_base64(void *arg)
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 --git a/src/test/test_parseconf.sh b/src/test/test_parseconf.sh
index c02b8b23c0..85a8cbbf0c 100755
--- a/src/test/test_parseconf.sh
+++ b/src/test/test_parseconf.sh
@@ -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 @@ echo "This pattern should not match any log messages" \
"$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 @@ TOR_LIBS_ENABLED_SEARCH="$(echo "$TOR_LIBS_ENABLED_SEARCH" | tr ' ' '\n' \
| 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 --git a/src/test/test_periodic_event.c b/src/test/test_periodic_event.c
index 6a9569ae89..58565f6af1 100644
--- a/src/test/test_periodic_event.c
+++ b/src/test/test_periodic_event.c
@@ -50,7 +50,7 @@ test_pe_initialize(void *arg)
/* 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 --git a/src/test/test_process_descs.c b/src/test/test_process_descs.c
index abcb6ae2fe..c13e8b58c4 100644
--- a/src/test/test_process_descs.c
+++ b/src/test/test_process_descs.c
@@ -47,17 +47,15 @@ test_process_descs_versions(void *arg)
{ "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 */
+ /* The 0.4.7.x series is supported. */
{ "Tor 0.4.7.0-alpha-dev", false },
{ "Tor 0.4.7.3-alpha", false },
{ "Tor 0.4.7.12", false },
diff --git a/src/test/test_rebind.sh b/src/test/test_rebind.sh
index aae2a9a6a0..d87e008f9a 100755
--- a/src/test/test_rebind.sh
+++ b/src/test/test_rebind.sh
@@ -51,6 +51,7 @@ tmpdir=
# shellcheck disable=SC2317
clean () {
if [ -n "$tmpdir" ] && [ -d "$tmpdir" ]; then
+ ls -l "$tmpdir"
rm -rf "$tmpdir"
fi
}
diff --git a/src/test/test_router.c b/src/test/test_router.c
index 15cc93fbfc..47084bba01 100644
--- a/src/test/test_router.c
+++ b/src/test/test_router.c
@@ -282,7 +282,6 @@ test_router_mark_if_too_old(void *arg)
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 @@ test_router_mark_if_too_old(void *arg)
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 --git a/src/test/test_sandbox.c b/src/test/test_sandbox.c
index 7ec08a3546..64182ecc91 100644
--- a/src/test/test_sandbox.c
+++ b/src/test/test_sandbox.c
@@ -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 @@ test_sandbox_stat_filename(void *arg)
(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 }
@@ -343,6 +397,8 @@ struct testcase_t sandbox_tests[] = {
#else
SANDBOX_TEST_SKIPPED(stat_filename),
#endif
+
+ SANDBOX_TEST_IN_SANDBOX(crypto_equix),
END_OF_TESTCASES
};
diff --git a/src/test/test_scheduler.c b/src/test/test_scheduler.c
index 7e41a4be25..06b3dafce8 100644
--- a/src/test/test_scheduler.c
+++ b/src/test/test_scheduler.c
@@ -81,8 +81,7 @@ mock_vanilla_networkstatus_get_param(
(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 @@ mock_kist_networkstatus_get_param(
(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 @@ test_scheduler_initfree(void *arg)
/* 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 @@ test_scheduler_can_use_kist(void *arg)
#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 --git a/src/test/test_slow.c b/src/test/test_slow.c
index 5f42b43103..08366416ca 100644
--- a/src/test/test_slow.c
+++ b/src/test/test_slow.c
@@ -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 --git a/src/test/test_util.c b/src/test/test_util.c
index 1dae2c617e..391c3d07c1 100644
--- a/src/test/test_util.c
+++ b/src/test/test_util.c
@@ -2945,7 +2945,7 @@ test_util_gzip_compression_bomb(void *arg)
tt_int_op(-1, OP_EQ, tor_compress(&result, &result_len,
one_mb, one_million,
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.");
diff --git a/src/test/test_voting_flags.c b/src/test/test_voting_flags.c
index 457b0fa796..a5b1248cc1 100644
--- a/src/test/test_voting_flags.c
+++ b/src/test/test_voting_flags.c
@@ -40,7 +40,6 @@ setup_cfg(flag_vote_test_cfg_t *c)
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 @@ check_result(flag_vote_test_cfg_t *c)
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 @@ test_voting_flags_staledesc(void *arg)
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 --git a/src/test/testing_common.c b/src/test/testing_common.c
index 2fd424c07e..88d04e6082 100644
--- a/src/test/testing_common.c
+++ b/src/test/testing_common.c
@@ -244,14 +244,18 @@ void tinytest_postfork(void);
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 --git a/src/tools/Makefile.nmake b/src/tools/Makefile.nmake
deleted file mode 100644
index e223d9b135..0000000000
--- a/src/tools/Makefile.nmake
+++ /dev/null
@@ -1,22 +0,0 @@
-all: tor-resolve.exe tor-gencert.exe tor-print-ed-signing-cert.exe
-
-CFLAGS = /I ..\win32 /I ..\..\..\build-alpha\include /I ..\common /I ..\or
-
-LIBS = ..\..\..\build-alpha\lib\libevent.lib \
- ..\..\..\build-alpha\lib\libcrypto.lib \
- ..\..\..\build-alpha\lib\libssl.lib \
- ..\..\..\build-alpha\lib\libz.lib \
- ws2_32.lib advapi32.lib shell32.lib \
- crypt32.lib gdi32.lib user32.lib
-
-tor-gencert.exe: tor-gencert.obj
- $(CC) $(CFLAGS) $(LIBS) ..\common\*.lib tor-gencert.obj
-
-tor-resolve.exe: tor-resolve.obj
- $(CC) $(CFLAGS) $(LIBS) ..\common\*.lib tor-resolve.obj
-
-tor-print-ed-signing-cert.exe: tor-print-ed-signing-cert.obj
- $(CC) $(CFLAGS) $(LIBS) ..\common\*.lib tor-print-ed-signing-cert.obj
-
-clean:
- del *.obj *.lib *.exe
diff --git a/src/trunnel/conflux.c b/src/trunnel/conflux.c
new file mode 100644
index 0000000000..5f1cb41ff2
--- /dev/null
+++ b/src/trunnel/conflux.c
@@ -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 <stdlib.h>
+#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 --git a/src/trunnel/conflux.h b/src/trunnel/conflux.h
new file mode 100644
index 0000000000..fa6f093b4f
--- /dev/null
+++ b/src/trunnel/conflux.h
@@ -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 <stdint.h>
+#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 --git a/src/trunnel/conflux.trunnel b/src/trunnel/conflux.trunnel
new file mode 100644
index 0000000000..4f1855faf3
--- /dev/null
+++ b/src/trunnel/conflux.trunnel
@@ -0,0 +1,66 @@
+/*
+ * This file contains the definition for the Conflux related cells. See
+ * proposal 329.
+ */
+
+/* No Opinion means the endpoint can choose whatever it thinks is best. */
+const CONFLUX_UX_NO_OPINION = 0x00;
+/* Min latency always only uses the lowest RTT */
+const CONFLUX_UX_MIN_LATENCY = 0x01;
+/* Min latency always only uses the lowest RTT */
+const CONFLUX_UX_LOW_MEM_LATENCY = 0x02;
+/* Use a high-throughput algorithm that maximizes throughput
+ * by using the full congestion window of all circuits, at the expense
+ * of more reordering queue at the receiver */
+const CONFLUX_UX_HIGH_THROUGHPUT = 0x03;
+/* THRPT_LO uses a high-throughput algorithm that tries to minimize
+ * out-of-order queues at the receiver */
+const CONFLUX_UX_LOW_MEM_THROUGHPUT = 0x04;
+
+/* The RELAY_CONFLUX_LINK definition. */
+struct trn_cell_conflux_link {
+ /* Version field. */
+ u8 version IN [0x01];
+
+ /* Payload */
+ u8 payload[];
+};
+
+/* The RELAY_CIRCUIT_LINKED definition. */
+struct trn_cell_conflux_linked {
+ /* Version field. */
+ u8 version IN [0x01];
+
+ /* Payload of the cell. */
+ u8 payload[];
+};
+
+/* The RELAY_CONFLUX_LINKED_ACK definition. */
+struct trn_cell_conflux_linked_ack {
+ /* Payload. At the moment, empty. */
+ u8 payload[];
+};
+
+/* The RELAY_CONFLUX_SWITCH definition. */
+struct trn_cell_conflux_switch {
+ /* Relative sequence number. */
+ u32 seqnum;
+};
+
+/* The payload version 1 of RELAY_CONFLUX_LINK and RELAY_CIRCUIT_LINKED cells.
+ * */
+struct trn_cell_conflux_link_payload_v1 {
+ /* Used to identify the other conflux to link with. */
+ u8 nonce[32];
+
+ /* Last sequence number sent and received. */
+ u64 last_seqno_sent;
+ u64 last_seqno_recv;
+
+ /* Desired user experience behavior */
+ u8 desired_ux IN [CONFLUX_UX_NO_OPINION,
+ CONFLUX_UX_MIN_LATENCY,
+ CONFLUX_UX_LOW_MEM_LATENCY,
+ CONFLUX_UX_LOW_MEM_THROUGHPUT,
+ CONFLUX_UX_HIGH_THROUGHPUT];
+};
diff --git a/src/trunnel/hs/cell_introduce1.c b/src/trunnel/hs/cell_introduce1.c
index a6873b4199..27a62f83de 100644
--- a/src/trunnel/hs/cell_introduce1.c
+++ b/src/trunnel/hs/cell_introduce1.c
@@ -44,6 +44,350 @@ ssize_t link_specifier_encoded_len(const link_specifier_t *obj);
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 --git a/src/trunnel/hs/cell_introduce1.h b/src/trunnel/hs/cell_introduce1.h
index ea37502d8e..b81c562343 100644
--- a/src/trunnel/hs/cell_introduce1.h
+++ b/src/trunnel/hs/cell_introduce1.h
@@ -19,6 +19,23 @@ struct link_specifier_st;
#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 @@ struct trn_cell_introduce_encrypted_st {
};
#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 --git a/src/trunnel/hs/cell_introduce1.trunnel b/src/trunnel/hs/cell_introduce1.trunnel
index 6682227b44..ed01bd6a7d 100644
--- a/src/trunnel/hs/cell_introduce1.trunnel
+++ b/src/trunnel/hs/cell_introduce1.trunnel
@@ -73,3 +73,40 @@ struct trn_cell_introduce_encrypted {
/* Optional padding. This might be empty or not. */
u8 pad[];
};
+
+/*
+ * INTRODUCE1 cell (encrypted section) extensions.
+ */
+
+/* Cell extenstion type Congestion Control Request. */
+const TRUNNEL_EXT_TYPE_CC_REQUEST = 0x01;
+/* Cell extension type PoW. */
+const TRUNNEL_EXT_TYPE_POW = 0x02;
+
+/*
+ * PoW Solution Extension. Proposal 327.
+ */
+
+const TRUNNEL_POW_NONCE_LEN = 16;
+const TRUNNEL_POW_SOLUTION_LEN = 16;
+const TRUNNEL_POW_SEED_HEAD_LEN = 4;
+
+/* Version 1 is based on Equi-X scheme. */
+const TRUNNEL_POW_VERSION_EQUIX = 0x01;
+
+struct trn_cell_extension_pow {
+ /* Type of PoW system used. */
+ u8 pow_version IN [0x01];
+
+ /* Nonce */
+ u8 pow_nonce[TRUNNEL_POW_NONCE_LEN];
+
+ /* Effort */
+ u32 pow_effort;
+
+ /* Identifiable prefix from the seed. */
+ u8 pow_seed[TRUNNEL_POW_SEED_HEAD_LEN];
+
+ /* Solution. */
+ u8 pow_solution[TRUNNEL_POW_SOLUTION_LEN];
+};
diff --git a/src/trunnel/include.am b/src/trunnel/include.am
index b2aee81da9..8154a5e932 100644
--- a/src/trunnel/include.am
+++ b/src/trunnel/include.am
@@ -16,7 +16,8 @@ TRUNNELINPUTS = \
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
TRUNNELSOURCES = \
src/ext/trunnel/trunnel.c \
@@ -33,7 +34,8 @@ TRUNNELSOURCES = \
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
TRUNNELHEADERS = \
src/ext/trunnel/trunnel.h \
@@ -52,7 +54,8 @@ TRUNNELHEADERS = \
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_libor_trunnel_a_SOURCES = $(TRUNNELSOURCES)
src_trunnel_libor_trunnel_a_CPPFLAGS = \
diff --git a/src/win32/include.am b/src/win32/include.am
deleted file mode 100644
index dad59af3ae..0000000000
--- a/src/win32/include.am
+++ /dev/null
@@ -1,3 +0,0 @@
-
-EXTRA_DIST+= src/win32/orconfig.h
-
diff --git a/src/win32/orconfig.h b/src/win32/orconfig.h
deleted file mode 100644
index c99b2dc53a..0000000000
--- a/src/win32/orconfig.h
+++ /dev/null
@@ -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 <arpa/inet.h> header file. */
-#undef HAVE_ARPA_INET_H
-
-/* Define to 1 if you have the <assert.h> header file. */
-#define HAVE_ASSERT_H
-
-/* Define to 1 if you have the <ctype.h> header file. */
-#define HAVE_CTYPE_H
-
-/* Define to 1 if you have the <errno.h> header file. */
-#define HAVE_ERRNO_H
-
-/* Define to 1 if you have the <fcntl.h> 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 <grp.h> 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 <inttypes.h> header file. */
-/* #define HAVE_INTTYPES_H */
-
-/* Define to 1 if you have the <limits.h> header file. */
-#define HAVE_LIMITS_H
-
-/* Define to 1 if you have the <machine/limits.h> header file. */
-#undef HAVE_MACHINE_LIMITS_H
-
-/* Define to 1 if you have the <memory.h> header file. */
-#define HAVE_MEMORY_H
-
-/* Define to 1 if you have the <netdb.h> header file. */
-#undef HAVE_NETDB_H
-
-/* Define to 1 if you have the <netinet/in.h> header file. */
-#undef HAVE_NETINET_IN_H
-
-/* Define to 1 if you have the <poll.h> header file. */
-#undef HAVE_POLL_H
-
-/* Define to 1 if you have the <pwd.h> header file. */
-#undef HAVE_PWD_H
-
-/* Define to 1 if you have the <signal.h> 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 <stdint.h> header file. */
-#undef HAVE_STDINT_H
-
-/* Define to 1 if you have the <stdlib.h> header file. */
-#define HAVE_STDLIB_H
-
-/* Define to 1 if you have the <strings.h> header file. */
-#undef HAVE_STRINGS_H
-
-/* Define to 1 if you have the <string.h> 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 <sys/fcntl.h> header file. */
-#undef HAVE_SYS_FCNTL_H
-
-/* Define to 1 if you have the <sys/ioctl.h> header file. */
-#undef HAVE_SYS_IOCTL_H
-
-/* Define to 1 if you have the <sys/limits.h> header file. */
-#undef HAVE_SYS_LIMITS_H
-
-/* Define to 1 if you have the <sys/poll.h> header file. */
-#undef HAVE_SYS_POLL_H
-
-/* Define to 1 if you have the <sys/socket.h> header file. */
-#undef HAVE_SYS_SOCKET_H
-
-/* Define to 1 if you have the <sys/stat.h> header file. */
-#define HAVE_SYS_STAT_H
-
-/* Define to 1 if you have the <sys/time.h> header file. */
-#undef HAVE_SYS_TIME_H
-
-/* Define to 1 if you have the <sys/types.h> header file. */
-#define HAVE_SYS_TYPES_H
-
-/* Define to 1 if you have the <sys/utime.h> header file. */
-#define HAVE_SYS_UTIME_H
-
-/* Define to 1 if you have the <sys/wait.h> header file. */
-#undef HAVE_SYS_WAIT_H
-
-/* Define to 1 if you have the <time.h> 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 <unistd.h> 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.15-dev"
-
-#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
-