aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/app/config/config.c220
-rw-r--r--src/app/config/config.h2
-rw-r--r--src/app/config/or_options_st.h66
-rw-r--r--src/app/config/or_state_st.h2
-rw-r--r--src/app/config/quiet_level.c2
-rw-r--r--src/app/config/quiet_level.h2
-rw-r--r--src/app/config/resolve_addr.c16
-rw-r--r--src/app/config/resolve_addr.h6
-rw-r--r--src/app/config/statefile.c2
-rw-r--r--src/app/config/statefile.h2
-rw-r--r--src/app/config/tor_cmdline_mode.h2
-rw-r--r--src/app/include.am3
-rw-r--r--src/app/main/main.c84
-rw-r--r--src/app/main/main.h2
-rw-r--r--src/app/main/ntmain.c5
-rw-r--r--src/app/main/ntmain.h2
-rw-r--r--src/app/main/risky_options.c2
-rw-r--r--src/app/main/risky_options.h4
-rw-r--r--src/app/main/shutdown.c6
-rw-r--r--src/app/main/shutdown.h2
-rw-r--r--src/app/main/subsysmgr.c2
-rw-r--r--src/app/main/subsysmgr.h2
-rw-r--r--src/app/main/subsystem_list.c4
-rw-r--r--src/app/main/tor_main.c2
-rw-r--r--src/config/README29
-rw-r--r--src/config/mmdb-convert.py471
-rw-r--r--src/config/torrc.minimal.in-staging2
-rw-r--r--src/config/torrc.sample.in2
-rw-r--r--src/core/crypto/hs_ntor.c2
-rw-r--r--src/core/crypto/hs_ntor.h2
-rw-r--r--src/core/crypto/include.am2
-rw-r--r--src/core/crypto/onion_crypto.c258
-rw-r--r--src/core/crypto/onion_crypto.h25
-rw-r--r--src/core/crypto/onion_fast.c2
-rw-r--r--src/core/crypto/onion_fast.h2
-rw-r--r--src/core/crypto/onion_ntor.c2
-rw-r--r--src/core/crypto/onion_ntor.h2
-rw-r--r--src/core/crypto/onion_ntor_v3.c760
-rw-r--r--src/core/crypto/onion_ntor_v3.h140
-rw-r--r--src/core/crypto/onion_tap.c2
-rw-r--r--src/core/crypto/onion_tap.h2
-rw-r--r--src/core/crypto/relay_crypto.c2
-rw-r--r--src/core/crypto/relay_crypto.h2
-rw-r--r--src/core/mainloop/connection.c203
-rw-r--r--src/core/mainloop/connection.h6
-rw-r--r--src/core/mainloop/cpuworker.c87
-rw-r--r--src/core/mainloop/cpuworker.h9
-rw-r--r--src/core/mainloop/mainloop.c64
-rw-r--r--src/core/mainloop/mainloop.h2
-rw-r--r--src/core/mainloop/mainloop_pubsub.c2
-rw-r--r--src/core/mainloop/mainloop_pubsub.h2
-rw-r--r--src/core/mainloop/mainloop_state_st.h2
-rw-r--r--src/core/mainloop/mainloop_sys.c2
-rw-r--r--src/core/mainloop/mainloop_sys.h2
-rw-r--r--src/core/mainloop/netstatus.c5
-rw-r--r--src/core/mainloop/netstatus.h2
-rw-r--r--src/core/mainloop/periodic.c2
-rw-r--r--src/core/mainloop/periodic.h2
-rw-r--r--src/core/or/addr_policy_st.h2
-rw-r--r--src/core/or/address_set.c2
-rw-r--r--src/core/or/address_set.h2
-rw-r--r--src/core/or/cell_queue_st.h2
-rw-r--r--src/core/or/cell_st.h2
-rw-r--r--src/core/or/channel.c60
-rw-r--r--src/core/or/channel.h2
-rw-r--r--src/core/or/channelpadding.c6
-rw-r--r--src/core/or/channelpadding.h2
-rw-r--r--src/core/or/channeltls.c7
-rw-r--r--src/core/or/channeltls.h2
-rw-r--r--src/core/or/circuit_st.h6
-rw-r--r--src/core/or/circuitbuild.c160
-rw-r--r--src/core/or/circuitbuild.h6
-rw-r--r--src/core/or/circuitlist.c140
-rw-r--r--src/core/or/circuitlist.h19
-rw-r--r--src/core/or/circuitmux.c2
-rw-r--r--src/core/or/circuitmux.h2
-rw-r--r--src/core/or/circuitmux_ewma.c28
-rw-r--r--src/core/or/circuitmux_ewma.h2
-rw-r--r--src/core/or/circuitpadding.c19
-rw-r--r--src/core/or/circuitpadding.h2
-rw-r--r--src/core/or/circuitstats.c177
-rw-r--r--src/core/or/circuitstats.h13
-rw-r--r--src/core/or/circuituse.c236
-rw-r--r--src/core/or/circuituse.h3
-rw-r--r--src/core/or/command.c39
-rw-r--r--src/core/or/command.h2
-rw-r--r--src/core/or/congestion_control_common.c1570
-rw-r--r--src/core/or/congestion_control_common.h190
-rw-r--r--src/core/or/congestion_control_flow.c751
-rw-r--r--src/core/or/congestion_control_flow.h54
-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.h276
-rw-r--r--src/core/or/congestion_control_vegas.c619
-rw-r--r--src/core/or/congestion_control_vegas.h55
-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.c341
-rw-r--r--src/core/or/connection_edge.h3
-rw-r--r--src/core/or/connection_or.c25
-rw-r--r--src/core/or/connection_or.h2
-rw-r--r--src/core/or/connection_st.h6
-rw-r--r--src/core/or/cpath_build_state_st.h7
-rw-r--r--src/core/or/crypt_path.c8
-rw-r--r--src/core/or/crypt_path_reference_st.h2
-rw-r--r--src/core/or/crypt_path_st.h10
-rw-r--r--src/core/or/destroy_cell_queue_st.h2
-rw-r--r--src/core/or/dos.c419
-rw-r--r--src/core/or/dos.h52
-rw-r--r--src/core/or/dos_config.c29
-rw-r--r--src/core/or/dos_config.h16
-rw-r--r--src/core/or/dos_options.inc59
-rw-r--r--src/core/or/dos_options_st.h20
-rw-r--r--src/core/or/dos_sys.c60
-rw-r--r--src/core/or/dos_sys.h25
-rw-r--r--src/core/or/edge_connection_st.h60
-rw-r--r--src/core/or/entry_connection_st.h2
-rw-r--r--src/core/or/entry_port_cfg_st.h2
-rw-r--r--src/core/or/extend_info_st.h6
-rw-r--r--src/core/or/extendinfo.c32
-rw-r--r--src/core/or/extendinfo.h10
-rw-r--r--src/core/or/half_edge_st.h14
-rw-r--r--src/core/or/include.am21
-rw-r--r--src/core/or/listener_connection_st.h2
-rw-r--r--src/core/or/lttng_cc.inc166
-rw-r--r--src/core/or/ocirc_event.c2
-rw-r--r--src/core/or/ocirc_event.h2
-rw-r--r--src/core/or/onion.c16
-rw-r--r--src/core/or/onion.h2
-rw-r--r--src/core/or/or.h164
-rw-r--r--src/core/or/or_circuit_st.h13
-rw-r--r--src/core/or/or_connection_st.h4
-rw-r--r--src/core/or/or_handshake_certs_st.h2
-rw-r--r--src/core/or/or_handshake_state_st.h2
-rw-r--r--src/core/or/or_periodic.c2
-rw-r--r--src/core/or/or_periodic.h2
-rw-r--r--src/core/or/or_sys.c2
-rw-r--r--src/core/or/or_sys.h2
-rw-r--r--src/core/or/orconn_event.c2
-rw-r--r--src/core/or/orconn_event.h2
-rw-r--r--src/core/or/origin_circuit_st.h29
-rw-r--r--src/core/or/policies.c24
-rw-r--r--src/core/or/policies.h3
-rw-r--r--src/core/or/port_cfg_st.h2
-rw-r--r--src/core/or/protover.c76
-rw-r--r--src/core/or/protover.h12
-rw-r--r--src/core/or/protover_rust.c34
-rw-r--r--src/core/or/reasons.c2
-rw-r--r--src/core/or/reasons.h2
-rw-r--r--src/core/or/relay.c180
-rw-r--r--src/core/or/relay.h12
-rw-r--r--src/core/or/relay_crypto_st.h2
-rw-r--r--src/core/or/scheduler.c2
-rw-r--r--src/core/or/scheduler.h2
-rw-r--r--src/core/or/scheduler_kist.c14
-rw-r--r--src/core/or/scheduler_vanilla.c2
-rw-r--r--src/core/or/sendme.c164
-rw-r--r--src/core/or/sendme.h7
-rw-r--r--src/core/or/server_port_cfg_st.h2
-rw-r--r--src/core/or/socks_request_st.h2
-rw-r--r--src/core/or/status.c57
-rw-r--r--src/core/or/status.h7
-rw-r--r--src/core/or/tor_version_st.h2
-rw-r--r--src/core/or/trace_probes_cc.c34
-rw-r--r--src/core/or/trace_probes_cc.h22
-rw-r--r--src/core/or/trace_probes_circuit.c6
-rw-r--r--src/core/or/trace_probes_circuit.h4
-rw-r--r--src/core/or/var_cell_st.h2
-rw-r--r--src/core/or/versions.c8
-rw-r--r--src/core/or/versions.h2
-rw-r--r--src/core/proto/proto_cell.c2
-rw-r--r--src/core/proto/proto_cell.h2
-rw-r--r--src/core/proto/proto_control0.c2
-rw-r--r--src/core/proto/proto_control0.h2
-rw-r--r--src/core/proto/proto_ext_or.c2
-rw-r--r--src/core/proto/proto_ext_or.h2
-rw-r--r--src/core/proto/proto_haproxy.c2
-rw-r--r--src/core/proto/proto_haproxy.h2
-rw-r--r--src/core/proto/proto_http.c2
-rw-r--r--src/core/proto/proto_http.h2
-rw-r--r--src/core/proto/proto_socks.c2
-rw-r--r--src/core/proto/proto_socks.h2
-rw-r--r--src/ext/ed25519/donna/test-ticks.h4
m---------src/ext/rust0
-rw-r--r--src/feature/api/tor_api.c6
-rw-r--r--src/feature/api/tor_api.h2
-rw-r--r--src/feature/api/tor_api_internal.h2
-rw-r--r--src/feature/client/addressmap.c17
-rw-r--r--src/feature/client/addressmap.h4
-rw-r--r--src/feature/client/bridges.c24
-rw-r--r--src/feature/client/bridges.h5
-rw-r--r--src/feature/client/circpathbias.c2
-rw-r--r--src/feature/client/circpathbias.h2
-rw-r--r--src/feature/client/dnsserv.c5
-rw-r--r--src/feature/client/dnsserv.h2
-rw-r--r--src/feature/client/entrynodes.c315
-rw-r--r--src/feature/client/entrynodes.h7
-rw-r--r--src/feature/client/proxymode.c2
-rw-r--r--src/feature/client/proxymode.h2
-rw-r--r--src/feature/client/transports.c16
-rw-r--r--src/feature/client/transports.h2
-rw-r--r--src/feature/control/btrack.c2
-rw-r--r--src/feature/control/btrack_circuit.c2
-rw-r--r--src/feature/control/btrack_circuit.h2
-rw-r--r--src/feature/control/btrack_orconn.c2
-rw-r--r--src/feature/control/btrack_orconn.h2
-rw-r--r--src/feature/control/btrack_orconn_cevent.c2
-rw-r--r--src/feature/control/btrack_orconn_cevent.h2
-rw-r--r--src/feature/control/btrack_orconn_maps.c2
-rw-r--r--src/feature/control/btrack_orconn_maps.h2
-rw-r--r--src/feature/control/btrack_sys.h2
-rw-r--r--src/feature/control/control.c10
-rw-r--r--src/feature/control/control.h2
-rw-r--r--src/feature/control/control_auth.c2
-rw-r--r--src/feature/control/control_auth.h2
-rw-r--r--src/feature/control/control_bootstrap.c2
-rw-r--r--src/feature/control/control_cmd.c338
-rw-r--r--src/feature/control/control_cmd.h13
-rw-r--r--src/feature/control/control_cmd_args_st.h2
-rw-r--r--src/feature/control/control_connection_st.h2
-rw-r--r--src/feature/control/control_events.c166
-rw-r--r--src/feature/control/control_events.h17
-rw-r--r--src/feature/control/control_fmt.c12
-rw-r--r--src/feature/control/control_fmt.h2
-rw-r--r--src/feature/control/control_getinfo.c33
-rw-r--r--src/feature/control/control_getinfo.h2
-rw-r--r--src/feature/control/control_hs.c2
-rw-r--r--src/feature/control/control_hs.h2
-rw-r--r--src/feature/control/control_proto.c2
-rw-r--r--src/feature/control/control_proto.h2
-rw-r--r--src/feature/control/getinfo_geoip.c2
-rw-r--r--src/feature/control/getinfo_geoip.h2
-rw-r--r--src/feature/dirauth/authmode.c2
-rw-r--r--src/feature/dirauth/authmode.h2
-rw-r--r--src/feature/dirauth/bridgeauth.c2
-rw-r--r--src/feature/dirauth/bridgeauth.h2
-rw-r--r--src/feature/dirauth/bwauth.c2
-rw-r--r--src/feature/dirauth/bwauth.h2
-rw-r--r--src/feature/dirauth/dirauth_config.c7
-rw-r--r--src/feature/dirauth/dirauth_config.h2
-rw-r--r--src/feature/dirauth/dirauth_options.inc29
-rw-r--r--src/feature/dirauth/dirauth_options_st.h2
-rw-r--r--src/feature/dirauth/dirauth_periodic.c2
-rw-r--r--src/feature/dirauth/dirauth_periodic.h2
-rw-r--r--src/feature/dirauth/dirauth_stub.c2
-rw-r--r--src/feature/dirauth/dirauth_sys.c2
-rw-r--r--src/feature/dirauth/dirauth_sys.h2
-rw-r--r--src/feature/dirauth/dircollate.c2
-rw-r--r--src/feature/dirauth/dircollate.h2
-rw-r--r--src/feature/dirauth/dirvote.c180
-rw-r--r--src/feature/dirauth/dirvote.h16
-rw-r--r--src/feature/dirauth/dsigs_parse.c2
-rw-r--r--src/feature/dirauth/dsigs_parse.h2
-rw-r--r--src/feature/dirauth/guardfraction.c2
-rw-r--r--src/feature/dirauth/guardfraction.h2
-rw-r--r--src/feature/dirauth/keypin.c14
-rw-r--r--src/feature/dirauth/keypin.h2
-rw-r--r--src/feature/dirauth/ns_detached_signatures_st.h2
-rw-r--r--src/feature/dirauth/process_descs.c35
-rw-r--r--src/feature/dirauth/process_descs.h5
-rw-r--r--src/feature/dirauth/reachability.c2
-rw-r--r--src/feature/dirauth/reachability.h2
-rw-r--r--src/feature/dirauth/recommend_pkg.c2
-rw-r--r--src/feature/dirauth/recommend_pkg.h2
-rw-r--r--src/feature/dirauth/shared_random.c2
-rw-r--r--src/feature/dirauth/shared_random.h2
-rw-r--r--src/feature/dirauth/shared_random_state.c2
-rw-r--r--src/feature/dirauth/shared_random_state.h2
-rw-r--r--src/feature/dirauth/vote_microdesc_hash_st.h2
-rw-r--r--src/feature/dirauth/voteflags.c90
-rw-r--r--src/feature/dirauth/voteflags.h5
-rw-r--r--src/feature/dirauth/voting_schedule.c2
-rw-r--r--src/feature/dirauth/voting_schedule.h2
-rw-r--r--src/feature/dircache/cached_dir_st.h2
-rw-r--r--src/feature/dircache/conscache.c2
-rw-r--r--src/feature/dircache/conscache.h2
-rw-r--r--src/feature/dircache/consdiffmgr.c6
-rw-r--r--src/feature/dircache/consdiffmgr.h2
-rw-r--r--src/feature/dircache/dircache.c5
-rw-r--r--src/feature/dircache/dircache.h2
-rw-r--r--src/feature/dircache/dircache_stub.c2
-rw-r--r--src/feature/dircache/dirserv.c2
-rw-r--r--src/feature/dircache/dirserv.h2
-rw-r--r--src/feature/dirclient/dir_server_st.h8
-rw-r--r--src/feature/dirclient/dirclient.c279
-rw-r--r--src/feature/dirclient/dirclient.h6
-rw-r--r--src/feature/dirclient/dirclient_modes.c2
-rw-r--r--src/feature/dirclient/dirclient_modes.h2
-rw-r--r--src/feature/dirclient/dlstatus.c19
-rw-r--r--src/feature/dirclient/dlstatus.h2
-rw-r--r--src/feature/dirclient/download_status_st.h2
-rw-r--r--src/feature/dircommon/consdiff.c2
-rw-r--r--src/feature/dircommon/consdiff.h2
-rw-r--r--src/feature/dircommon/dir_connection_st.h5
-rw-r--r--src/feature/dircommon/directory.c6
-rw-r--r--src/feature/dircommon/directory.h17
-rw-r--r--src/feature/dircommon/fp_pair.c2
-rw-r--r--src/feature/dircommon/fp_pair.h2
-rw-r--r--src/feature/dircommon/vote_timing_st.h2
-rw-r--r--src/feature/dirparse/authcert_members.h2
-rw-r--r--src/feature/dirparse/authcert_parse.c2
-rw-r--r--src/feature/dirparse/authcert_parse.h2
-rw-r--r--src/feature/dirparse/microdesc_parse.c2
-rw-r--r--src/feature/dirparse/microdesc_parse.h2
-rw-r--r--src/feature/dirparse/ns_parse.c6
-rw-r--r--src/feature/dirparse/ns_parse.h2
-rw-r--r--src/feature/dirparse/parsecommon.c29
-rw-r--r--src/feature/dirparse/parsecommon.h4
-rw-r--r--src/feature/dirparse/policy_parse.c6
-rw-r--r--src/feature/dirparse/policy_parse.h2
-rw-r--r--src/feature/dirparse/routerparse.c2
-rw-r--r--src/feature/dirparse/routerparse.h2
-rw-r--r--src/feature/dirparse/sigcommon.c2
-rw-r--r--src/feature/dirparse/sigcommon.h2
-rw-r--r--src/feature/dirparse/signing.c2
-rw-r--r--src/feature/dirparse/signing.h2
-rw-r--r--src/feature/dirparse/unparseable.c4
-rw-r--r--src/feature/dirparse/unparseable.h2
-rw-r--r--src/feature/hibernate/hibernate.c2
-rw-r--r--src/feature/hibernate/hibernate.h2
-rw-r--r--src/feature/hs/hs_cache.c89
-rw-r--r--src/feature/hs/hs_cache.h22
-rw-r--r--src/feature/hs/hs_cell.c200
-rw-r--r--src/feature/hs/hs_cell.h12
-rw-r--r--src/feature/hs/hs_circuit.c264
-rw-r--r--src/feature/hs/hs_circuit.h8
-rw-r--r--src/feature/hs/hs_circuitmap.c64
-rw-r--r--src/feature/hs/hs_circuitmap.h15
-rw-r--r--src/feature/hs/hs_client.c110
-rw-r--r--src/feature/hs/hs_client.h2
-rw-r--r--src/feature/hs/hs_common.c440
-rw-r--r--src/feature/hs/hs_common.h34
-rw-r--r--src/feature/hs/hs_config.c96
-rw-r--r--src/feature/hs/hs_config.h2
-rw-r--r--src/feature/hs/hs_control.c2
-rw-r--r--src/feature/hs/hs_control.h2
-rw-r--r--src/feature/hs/hs_descriptor.c62
-rw-r--r--src/feature/hs/hs_descriptor.h27
-rw-r--r--src/feature/hs/hs_dos.c2
-rw-r--r--src/feature/hs/hs_dos.h2
-rw-r--r--src/feature/hs/hs_ident.c2
-rw-r--r--src/feature/hs/hs_ident.h2
-rw-r--r--src/feature/hs/hs_intropoint.c72
-rw-r--r--src/feature/hs/hs_intropoint.h3
-rw-r--r--src/feature/hs/hs_metrics.c28
-rw-r--r--src/feature/hs/hs_metrics.h2
-rw-r--r--src/feature/hs/hs_metrics_entry.c2
-rw-r--r--src/feature/hs/hs_metrics_entry.h4
-rw-r--r--src/feature/hs/hs_ob.c2
-rw-r--r--src/feature/hs/hs_ob.h2
-rw-r--r--src/feature/hs/hs_options.inc1
-rw-r--r--src/feature/hs/hs_opts_st.h2
-rw-r--r--src/feature/hs/hs_service.c235
-rw-r--r--src/feature/hs/hs_service.h31
-rw-r--r--src/feature/hs/hs_stats.c19
-rw-r--r--src/feature/hs/hs_stats.h5
-rw-r--r--src/feature/hs/hs_sys.c2
-rw-r--r--src/feature/hs/hs_sys.h2
-rw-r--r--src/feature/hs/hsdir_index_st.h2
-rw-r--r--src/feature/hs_common/replaycache.c2
-rw-r--r--src/feature/hs_common/replaycache.h2
-rw-r--r--src/feature/hs_common/shared_random_client.c23
-rw-r--r--src/feature/hs_common/shared_random_client.h2
-rw-r--r--src/feature/keymgt/loadkey.c4
-rw-r--r--src/feature/keymgt/loadkey.h2
-rw-r--r--src/feature/metrics/metrics.c2
-rw-r--r--src/feature/metrics/metrics.h2
-rw-r--r--src/feature/metrics/metrics_sys.c2
-rw-r--r--src/feature/metrics/metrics_sys.h2
-rw-r--r--src/feature/nodelist/authcert.c2
-rw-r--r--src/feature/nodelist/authcert.h2
-rw-r--r--src/feature/nodelist/authority_cert_st.h2
-rw-r--r--src/feature/nodelist/desc_store_st.h2
-rw-r--r--src/feature/nodelist/describe.c2
-rw-r--r--src/feature/nodelist/describe.h2
-rw-r--r--src/feature/nodelist/dirlist.c146
-rw-r--r--src/feature/nodelist/dirlist.h37
-rw-r--r--src/feature/nodelist/document_signature_st.h2
-rw-r--r--src/feature/nodelist/extrainfo_st.h2
-rw-r--r--src/feature/nodelist/fmt_routerstatus.c34
-rw-r--r--src/feature/nodelist/fmt_routerstatus.h2
-rw-r--r--src/feature/nodelist/microdesc.c2
-rw-r--r--src/feature/nodelist/microdesc.h2
-rw-r--r--src/feature/nodelist/microdesc_st.h2
-rw-r--r--src/feature/nodelist/networkstatus.c20
-rw-r--r--src/feature/nodelist/networkstatus.h2
-rw-r--r--src/feature/nodelist/networkstatus_sr_info_st.h2
-rw-r--r--src/feature/nodelist/networkstatus_st.h2
-rw-r--r--src/feature/nodelist/networkstatus_voter_info_st.h2
-rw-r--r--src/feature/nodelist/nickname.c2
-rw-r--r--src/feature/nodelist/nickname.h2
-rw-r--r--src/feature/nodelist/node_select.c2
-rw-r--r--src/feature/nodelist/node_select.h2
-rw-r--r--src/feature/nodelist/node_st.h4
-rw-r--r--src/feature/nodelist/nodefamily.c2
-rw-r--r--src/feature/nodelist/nodefamily.h2
-rw-r--r--src/feature/nodelist/nodefamily_st.h2
-rw-r--r--src/feature/nodelist/nodelist.c17
-rw-r--r--src/feature/nodelist/nodelist.h2
-rw-r--r--src/feature/nodelist/routerinfo.c2
-rw-r--r--src/feature/nodelist/routerinfo.h2
-rw-r--r--src/feature/nodelist/routerinfo_st.h2
-rw-r--r--src/feature/nodelist/routerlist.c35
-rw-r--r--src/feature/nodelist/routerlist.h3
-rw-r--r--src/feature/nodelist/routerlist_st.h2
-rw-r--r--src/feature/nodelist/routerset.c2
-rw-r--r--src/feature/nodelist/routerset.h2
-rw-r--r--src/feature/nodelist/routerstatus_st.h5
-rw-r--r--src/feature/nodelist/signed_descriptor_st.h2
-rw-r--r--src/feature/nodelist/torcert.c4
-rw-r--r--src/feature/nodelist/torcert.h2
-rw-r--r--src/feature/nodelist/vote_routerstatus_st.h2
-rw-r--r--src/feature/relay/circuitbuild_relay.c6
-rw-r--r--src/feature/relay/circuitbuild_relay.h2
-rw-r--r--src/feature/relay/dns.c169
-rw-r--r--src/feature/relay/dns.h5
-rw-r--r--src/feature/relay/dns_structs.h2
-rw-r--r--src/feature/relay/ext_orport.c73
-rw-r--r--src/feature/relay/ext_orport.h13
-rw-r--r--src/feature/relay/include.am2
-rw-r--r--src/feature/relay/onion_queue.c211
-rw-r--r--src/feature/relay/onion_queue.h4
-rw-r--r--src/feature/relay/relay_config.c4
-rw-r--r--src/feature/relay/relay_config.h4
-rw-r--r--src/feature/relay/relay_find_addr.c4
-rw-r--r--src/feature/relay/relay_find_addr.h4
-rw-r--r--src/feature/relay/relay_handshake.c2
-rw-r--r--src/feature/relay/relay_handshake.h2
-rw-r--r--src/feature/relay/relay_metrics.c1058
-rw-r--r--src/feature/relay/relay_metrics.h73
-rw-r--r--src/feature/relay/relay_periodic.c22
-rw-r--r--src/feature/relay/relay_periodic.h2
-rw-r--r--src/feature/relay/relay_stub.c2
-rw-r--r--src/feature/relay/relay_sys.c7
-rw-r--r--src/feature/relay/relay_sys.h2
-rw-r--r--src/feature/relay/router.c26
-rw-r--r--src/feature/relay/router.h2
-rw-r--r--src/feature/relay/routerkeys.c2
-rw-r--r--src/feature/relay/routerkeys.h2
-rw-r--r--src/feature/relay/routermode.c2
-rw-r--r--src/feature/relay/routermode.h2
-rw-r--r--src/feature/relay/selftest.c192
-rw-r--r--src/feature/relay/selftest.h15
-rw-r--r--src/feature/relay/transport_config.c2
-rw-r--r--src/feature/relay/transport_config.h2
-rw-r--r--src/feature/rend/feature_rend.md7
-rw-r--r--src/feature/rend/include.am16
-rw-r--r--src/feature/rend/rend_authorized_client_st.h22
-rw-r--r--src/feature/rend/rend_encoded_v2_service_descriptor_st.h21
-rw-r--r--src/feature/rend/rend_intro_point_st.h81
-rw-r--r--src/feature/rend/rend_service_descriptor_st.h38
-rw-r--r--src/feature/rend/rendcache.c1029
-rw-r--r--src/feature/rend/rendcache.h132
-rw-r--r--src/feature/rend/rendclient.c1322
-rw-r--r--src/feature/rend/rendclient.h54
-rw-r--r--src/feature/rend/rendcommon.c944
-rw-r--r--src/feature/rend/rendcommon.h55
-rw-r--r--src/feature/rend/rendmid.c213
-rw-r--r--src/feature/rend/rendmid.h2
-rw-r--r--src/feature/rend/rendparse.c612
-rw-r--r--src/feature/rend/rendparse.h32
-rw-r--r--src/feature/rend/rendservice.c4535
-rw-r--r--src/feature/rend/rendservice.h223
-rw-r--r--src/feature/stats/bw_array_st.h2
-rw-r--r--src/feature/stats/bwhist.c2
-rw-r--r--src/feature/stats/bwhist.h4
-rw-r--r--src/feature/stats/connstats.c2
-rw-r--r--src/feature/stats/connstats.h2
-rw-r--r--src/feature/stats/geoip_stats.c11
-rw-r--r--src/feature/stats/geoip_stats.h2
-rw-r--r--src/feature/stats/predict_ports.c4
-rw-r--r--src/feature/stats/predict_ports.h2
-rw-r--r--src/feature/stats/rephist.c1103
-rw-r--r--src/feature/stats/rephist.h105
-rw-r--r--src/include.am1
-rw-r--r--src/lib/arch/bytes.h2
-rw-r--r--src/lib/buf/buffers.c2
-rw-r--r--src/lib/buf/buffers.h2
-rw-r--r--src/lib/cc/compat_compiler.h33
-rw-r--r--src/lib/cc/tokpaste.h2
-rw-r--r--src/lib/cc/torint.h2
-rw-r--r--src/lib/compress/compress.c2
-rw-r--r--src/lib/compress/compress.h2
-rw-r--r--src/lib/compress/compress_buf.c2
-rw-r--r--src/lib/compress/compress_lzma.c2
-rw-r--r--src/lib/compress/compress_lzma.h2
-rw-r--r--src/lib/compress/compress_none.c2
-rw-r--r--src/lib/compress/compress_none.h2
-rw-r--r--src/lib/compress/compress_sys.h2
-rw-r--r--src/lib/compress/compress_zlib.c2
-rw-r--r--src/lib/compress/compress_zlib.h2
-rw-r--r--src/lib/compress/compress_zstd.c2
-rw-r--r--src/lib/compress/compress_zstd.h2
-rw-r--r--src/lib/conf/confdecl.h2
-rw-r--r--src/lib/conf/confmacros.h2
-rw-r--r--src/lib/conf/conftesting.h2
-rw-r--r--src/lib/conf/conftypes.h2
-rw-r--r--src/lib/confmgt/confmgt.c2
-rw-r--r--src/lib/confmgt/confmgt.h2
-rw-r--r--src/lib/confmgt/structvar.c2
-rw-r--r--src/lib/confmgt/structvar.h2
-rw-r--r--src/lib/confmgt/type_defs.c2
-rw-r--r--src/lib/confmgt/type_defs.h2
-rw-r--r--src/lib/confmgt/typedvar.c2
-rw-r--r--src/lib/confmgt/typedvar.h2
-rw-r--r--src/lib/confmgt/unitparse.c2
-rw-r--r--src/lib/confmgt/unitparse.h2
-rw-r--r--src/lib/confmgt/var_type_def_st.h2
-rw-r--r--src/lib/container/bitarray.h2
-rw-r--r--src/lib/container/bloomfilt.c2
-rw-r--r--src/lib/container/bloomfilt.h2
-rw-r--r--src/lib/container/handles.h2
-rw-r--r--src/lib/container/map.c2
-rw-r--r--src/lib/container/map.h2
-rw-r--r--src/lib/container/namemap.c2
-rw-r--r--src/lib/container/namemap.h2
-rw-r--r--src/lib/container/namemap_st.h2
-rw-r--r--src/lib/container/order.c2
-rw-r--r--src/lib/container/order.h2
-rw-r--r--src/lib/container/smartlist.c2
-rw-r--r--src/lib/container/smartlist.h2
-rw-r--r--src/lib/crypt_ops/aes.h2
-rw-r--r--src/lib/crypt_ops/aes_nss.c2
-rw-r--r--src/lib/crypt_ops/aes_openssl.c2
-rw-r--r--src/lib/crypt_ops/compat_openssl.h2
-rw-r--r--src/lib/crypt_ops/crypto_cipher.c2
-rw-r--r--src/lib/crypt_ops/crypto_cipher.h2
-rw-r--r--src/lib/crypt_ops/crypto_curve25519.c2
-rw-r--r--src/lib/crypt_ops/crypto_curve25519.h2
-rw-r--r--src/lib/crypt_ops/crypto_dh.c2
-rw-r--r--src/lib/crypt_ops/crypto_dh.h2
-rw-r--r--src/lib/crypt_ops/crypto_dh_nss.c2
-rw-r--r--src/lib/crypt_ops/crypto_dh_openssl.c2
-rw-r--r--src/lib/crypt_ops/crypto_digest.c2
-rw-r--r--src/lib/crypt_ops/crypto_digest.h2
-rw-r--r--src/lib/crypt_ops/crypto_digest_nss.c2
-rw-r--r--src/lib/crypt_ops/crypto_digest_openssl.c2
-rw-r--r--src/lib/crypt_ops/crypto_ed25519.c2
-rw-r--r--src/lib/crypt_ops/crypto_ed25519.h2
-rw-r--r--src/lib/crypt_ops/crypto_format.c2
-rw-r--r--src/lib/crypt_ops/crypto_format.h2
-rw-r--r--src/lib/crypt_ops/crypto_hkdf.c2
-rw-r--r--src/lib/crypt_ops/crypto_hkdf.h2
-rw-r--r--src/lib/crypt_ops/crypto_init.c2
-rw-r--r--src/lib/crypt_ops/crypto_init.h2
-rw-r--r--src/lib/crypt_ops/crypto_nss_mgt.c2
-rw-r--r--src/lib/crypt_ops/crypto_nss_mgt.h2
-rw-r--r--src/lib/crypt_ops/crypto_ope.c2
-rw-r--r--src/lib/crypt_ops/crypto_ope.h2
-rw-r--r--src/lib/crypt_ops/crypto_openssl_mgt.c4
-rw-r--r--src/lib/crypt_ops/crypto_openssl_mgt.h2
-rw-r--r--src/lib/crypt_ops/crypto_options_st.h2
-rw-r--r--src/lib/crypt_ops/crypto_pwbox.c2
-rw-r--r--src/lib/crypt_ops/crypto_pwbox.h2
-rw-r--r--src/lib/crypt_ops/crypto_rand.c4
-rw-r--r--src/lib/crypt_ops/crypto_rand.h2
-rw-r--r--src/lib/crypt_ops/crypto_rand_fast.c2
-rw-r--r--src/lib/crypt_ops/crypto_rsa.c2
-rw-r--r--src/lib/crypt_ops/crypto_rsa.h2
-rw-r--r--src/lib/crypt_ops/crypto_rsa_nss.c2
-rw-r--r--src/lib/crypt_ops/crypto_rsa_openssl.c2
-rw-r--r--src/lib/crypt_ops/crypto_s2k.c2
-rw-r--r--src/lib/crypt_ops/crypto_s2k.h2
-rw-r--r--src/lib/crypt_ops/crypto_sys.h2
-rw-r--r--src/lib/crypt_ops/crypto_util.c2
-rw-r--r--src/lib/crypt_ops/crypto_util.h2
-rw-r--r--src/lib/crypt_ops/digestset.c2
-rw-r--r--src/lib/crypt_ops/digestset.h2
-rw-r--r--src/lib/ctime/di_ops.c2
-rw-r--r--src/lib/ctime/di_ops.h2
-rw-r--r--src/lib/defs/dh_sizes.h2
-rw-r--r--src/lib/defs/digest_sizes.h2
-rw-r--r--src/lib/defs/logging_types.h2
-rw-r--r--src/lib/defs/time.h2
-rw-r--r--src/lib/defs/x25519_sizes.h2
-rw-r--r--src/lib/dispatch/dispatch.h2
-rw-r--r--src/lib/dispatch/dispatch_cfg.c2
-rw-r--r--src/lib/dispatch/dispatch_cfg.h2
-rw-r--r--src/lib/dispatch/dispatch_cfg_st.h2
-rw-r--r--src/lib/dispatch/dispatch_core.c2
-rw-r--r--src/lib/dispatch/dispatch_naming.c2
-rw-r--r--src/lib/dispatch/dispatch_naming.h2
-rw-r--r--src/lib/dispatch/dispatch_new.c2
-rw-r--r--src/lib/dispatch/dispatch_st.h2
-rw-r--r--src/lib/dispatch/msgtypes.h2
-rw-r--r--src/lib/encoding/binascii.c2
-rw-r--r--src/lib/encoding/binascii.h2
-rw-r--r--src/lib/encoding/confline.c2
-rw-r--r--src/lib/encoding/confline.h2
-rw-r--r--src/lib/encoding/cstring.c2
-rw-r--r--src/lib/encoding/cstring.h2
-rw-r--r--src/lib/encoding/keyval.c2
-rw-r--r--src/lib/encoding/keyval.h2
-rw-r--r--src/lib/encoding/kvline.c2
-rw-r--r--src/lib/encoding/kvline.h2
-rw-r--r--src/lib/encoding/pem.c2
-rw-r--r--src/lib/encoding/pem.h2
-rw-r--r--src/lib/encoding/qstring.c2
-rw-r--r--src/lib/encoding/qstring.h2
-rw-r--r--src/lib/encoding/time_fmt.c2
-rw-r--r--src/lib/encoding/time_fmt.h2
-rw-r--r--src/lib/err/backtrace.c2
-rw-r--r--src/lib/err/backtrace.h2
-rw-r--r--src/lib/err/torerr.c2
-rw-r--r--src/lib/err/torerr.h2
-rw-r--r--src/lib/err/torerr_sys.c2
-rw-r--r--src/lib/err/torerr_sys.h2
-rw-r--r--src/lib/evloop/compat_libevent.c2
-rw-r--r--src/lib/evloop/compat_libevent.h2
-rw-r--r--src/lib/evloop/evloop_sys.c2
-rw-r--r--src/lib/evloop/evloop_sys.h2
-rw-r--r--src/lib/evloop/procmon.c2
-rw-r--r--src/lib/evloop/procmon.h2
-rw-r--r--src/lib/evloop/timers.c2
-rw-r--r--src/lib/evloop/timers.h2
-rw-r--r--src/lib/evloop/token_bucket.c2
-rw-r--r--src/lib/evloop/token_bucket.h2
-rw-r--r--src/lib/evloop/workqueue.c8
-rw-r--r--src/lib/evloop/workqueue.h3
-rw-r--r--src/lib/fdio/fdio.c2
-rw-r--r--src/lib/fdio/fdio.h2
-rw-r--r--src/lib/fs/conffile.c2
-rw-r--r--src/lib/fs/conffile.h2
-rw-r--r--src/lib/fs/dir.c2
-rw-r--r--src/lib/fs/dir.h2
-rw-r--r--src/lib/fs/files.c2
-rw-r--r--src/lib/fs/files.h2
-rw-r--r--src/lib/fs/freespace.c2
-rw-r--r--src/lib/fs/lockfile.c2
-rw-r--r--src/lib/fs/lockfile.h2
-rw-r--r--src/lib/fs/mmap.c2
-rw-r--r--src/lib/fs/mmap.h2
-rw-r--r--src/lib/fs/path.c16
-rw-r--r--src/lib/fs/path.h2
-rw-r--r--src/lib/fs/storagedir.c2
-rw-r--r--src/lib/fs/storagedir.h2
-rw-r--r--src/lib/fs/userdb.c2
-rw-r--r--src/lib/fs/userdb.h2
-rw-r--r--src/lib/fs/winlib.c2
-rw-r--r--src/lib/fs/winlib.h2
-rw-r--r--src/lib/geoip/country.h2
-rw-r--r--src/lib/geoip/geoip.c2
-rw-r--r--src/lib/geoip/geoip.h2
-rw-r--r--src/lib/intmath/addsub.c2
-rw-r--r--src/lib/intmath/addsub.h2
-rw-r--r--src/lib/intmath/bits.c2
-rw-r--r--src/lib/intmath/bits.h2
-rw-r--r--src/lib/intmath/cmp.h2
-rw-r--r--src/lib/intmath/logic.h2
-rw-r--r--src/lib/intmath/muldiv.c2
-rw-r--r--src/lib/intmath/muldiv.h2
-rw-r--r--src/lib/intmath/weakrng.c2
-rw-r--r--src/lib/intmath/weakrng.h2
-rw-r--r--src/lib/llharden/winprocess_sys.c2
-rw-r--r--src/lib/llharden/winprocess_sys.h2
-rw-r--r--src/lib/lock/compat_mutex.c2
-rw-r--r--src/lib/lock/compat_mutex.h13
-rw-r--r--src/lib/lock/compat_mutex_pthreads.c2
-rw-r--r--src/lib/lock/compat_mutex_winthreads.c80
-rw-r--r--src/lib/log/escape.c2
-rw-r--r--src/lib/log/escape.h2
-rw-r--r--src/lib/log/log.c2
-rw-r--r--src/lib/log/log.h2
-rw-r--r--src/lib/log/log_sys.c2
-rw-r--r--src/lib/log/log_sys.h2
-rw-r--r--src/lib/log/ratelim.c2
-rw-r--r--src/lib/log/ratelim.h2
-rw-r--r--src/lib/log/util_bug.c2
-rw-r--r--src/lib/log/util_bug.h4
-rw-r--r--src/lib/log/win32err.c2
-rw-r--r--src/lib/log/win32err.h2
-rw-r--r--src/lib/malloc/malloc.c2
-rw-r--r--src/lib/malloc/malloc.h2
-rw-r--r--src/lib/malloc/map_anon.c2
-rw-r--r--src/lib/malloc/map_anon.h2
-rw-r--r--src/lib/math/fp.c2
-rw-r--r--src/lib/math/fp.h2
-rw-r--r--src/lib/math/include.am3
-rw-r--r--src/lib/math/laplace.c2
-rw-r--r--src/lib/math/laplace.h2
-rw-r--r--src/lib/math/prob_distr.c2
-rw-r--r--src/lib/math/stats.h42
-rw-r--r--src/lib/memarea/memarea.c2
-rw-r--r--src/lib/memarea/memarea.h2
-rw-r--r--src/lib/meminfo/lib_meminfo.md5
-rw-r--r--src/lib/meminfo/meminfo.c2
-rw-r--r--src/lib/meminfo/meminfo.h2
-rw-r--r--src/lib/metrics/metrics_common.c13
-rw-r--r--src/lib/metrics/metrics_common.h5
-rw-r--r--src/lib/metrics/metrics_store.c23
-rw-r--r--src/lib/metrics/metrics_store.h3
-rw-r--r--src/lib/metrics/metrics_store_entry.c2
-rw-r--r--src/lib/metrics/metrics_store_entry.h4
-rw-r--r--src/lib/metrics/prometheus.c13
-rw-r--r--src/lib/metrics/prometheus.h4
-rw-r--r--src/lib/net/address.c24
-rw-r--r--src/lib/net/address.h2
-rw-r--r--src/lib/net/alertsock.c2
-rw-r--r--src/lib/net/alertsock.h2
-rw-r--r--src/lib/net/buffers_net.c2
-rw-r--r--src/lib/net/buffers_net.h2
-rw-r--r--src/lib/net/gethostname.c2
-rw-r--r--src/lib/net/gethostname.h2
-rw-r--r--src/lib/net/inaddr.c2
-rw-r--r--src/lib/net/inaddr.h2
-rw-r--r--src/lib/net/inaddr_st.h2
-rw-r--r--src/lib/net/nettypes.h2
-rw-r--r--src/lib/net/network_sys.c2
-rw-r--r--src/lib/net/network_sys.h2
-rw-r--r--src/lib/net/resolve.c2
-rw-r--r--src/lib/net/resolve.h2
-rw-r--r--src/lib/net/socket.c2
-rw-r--r--src/lib/net/socket.h2
-rw-r--r--src/lib/net/socketpair.c2
-rw-r--r--src/lib/net/socketpair.h2
-rw-r--r--src/lib/net/socks5_status.h2
-rw-r--r--src/lib/osinfo/libc.c2
-rw-r--r--src/lib/osinfo/libc.h2
-rw-r--r--src/lib/osinfo/uname.c2
-rw-r--r--src/lib/osinfo/uname.h2
-rw-r--r--src/lib/process/daemon.c2
-rw-r--r--src/lib/process/daemon.h2
-rw-r--r--src/lib/process/env.c2
-rw-r--r--src/lib/process/env.h2
-rw-r--r--src/lib/process/pidfile.c2
-rw-r--r--src/lib/process/pidfile.h2
-rw-r--r--src/lib/process/process.c2
-rw-r--r--src/lib/process/process.h2
-rw-r--r--src/lib/process/process_sys.c2
-rw-r--r--src/lib/process/process_sys.h2
-rw-r--r--src/lib/process/process_unix.c2
-rw-r--r--src/lib/process/process_unix.h2
-rw-r--r--src/lib/process/process_win32.c2
-rw-r--r--src/lib/process/process_win32.h2
-rw-r--r--src/lib/process/restrict.c2
-rw-r--r--src/lib/process/restrict.h2
-rw-r--r--src/lib/process/setuid.c2
-rw-r--r--src/lib/process/setuid.h2
-rw-r--r--src/lib/process/waitpid.c2
-rw-r--r--src/lib/process/waitpid.h2
-rw-r--r--src/lib/pubsub/pub_binding_st.h2
-rw-r--r--src/lib/pubsub/pubsub.h2
-rw-r--r--src/lib/pubsub/pubsub_build.c2
-rw-r--r--src/lib/pubsub/pubsub_build.h2
-rw-r--r--src/lib/pubsub/pubsub_builder_st.h2
-rw-r--r--src/lib/pubsub/pubsub_check.c2
-rw-r--r--src/lib/pubsub/pubsub_connect.h2
-rw-r--r--src/lib/pubsub/pubsub_flags.h2
-rw-r--r--src/lib/pubsub/pubsub_macros.h2
-rw-r--r--src/lib/pubsub/pubsub_publish.c2
-rw-r--r--src/lib/pubsub/pubsub_publish.h2
-rw-r--r--src/lib/sandbox/sandbox.c146
-rw-r--r--src/lib/sandbox/sandbox.h2
-rw-r--r--src/lib/smartlist_core/smartlist_core.c2
-rw-r--r--src/lib/smartlist_core/smartlist_core.h2
-rw-r--r--src/lib/smartlist_core/smartlist_foreach.h2
-rw-r--r--src/lib/smartlist_core/smartlist_split.c2
-rw-r--r--src/lib/smartlist_core/smartlist_split.h2
-rw-r--r--src/lib/string/compat_ctype.c2
-rw-r--r--src/lib/string/compat_ctype.h2
-rw-r--r--src/lib/string/compat_string.c2
-rw-r--r--src/lib/string/compat_string.h2
-rw-r--r--src/lib/string/parse_int.c2
-rw-r--r--src/lib/string/parse_int.h2
-rw-r--r--src/lib/string/printf.c6
-rw-r--r--src/lib/string/printf.h2
-rw-r--r--src/lib/string/scanf.c2
-rw-r--r--src/lib/string/scanf.h2
-rw-r--r--src/lib/string/util_string.c2
-rw-r--r--src/lib/string/util_string.h2
-rw-r--r--src/lib/subsys/subsys.h2
-rw-r--r--src/lib/term/getpass.c2
-rw-r--r--src/lib/term/getpass.h2
-rw-r--r--src/lib/testsupport/testsupport.h2
-rw-r--r--src/lib/thread/compat_pthreads.c2
-rw-r--r--src/lib/thread/compat_threads.c2
-rw-r--r--src/lib/thread/compat_winthreads.c10
-rw-r--r--src/lib/thread/numcpus.c16
-rw-r--r--src/lib/thread/numcpus.h2
-rw-r--r--src/lib/thread/thread_sys.h2
-rw-r--r--src/lib/thread/threads.h2
-rw-r--r--src/lib/time/compat_time.c2
-rw-r--r--src/lib/time/compat_time.h2
-rw-r--r--src/lib/time/time_sys.c2
-rw-r--r--src/lib/time/time_sys.h2
-rw-r--r--src/lib/time/tvdiff.c2
-rw-r--r--src/lib/time/tvdiff.h2
-rw-r--r--src/lib/tls/buffers_tls.c2
-rw-r--r--src/lib/tls/buffers_tls.h2
-rw-r--r--src/lib/tls/nss_countbytes.c2
-rw-r--r--src/lib/tls/nss_countbytes.h2
-rw-r--r--src/lib/tls/tortls.c2
-rw-r--r--src/lib/tls/tortls.h2
-rw-r--r--src/lib/tls/tortls_internal.h2
-rw-r--r--src/lib/tls/tortls_nss.c6
-rw-r--r--src/lib/tls/tortls_openssl.c8
-rw-r--r--src/lib/tls/tortls_st.h4
-rw-r--r--src/lib/tls/tortls_sys.h2
-rw-r--r--src/lib/tls/x509.c2
-rw-r--r--src/lib/tls/x509.h2
-rw-r--r--src/lib/tls/x509_internal.h2
-rw-r--r--src/lib/tls/x509_nss.c2
-rw-r--r--src/lib/tls/x509_openssl.c2
-rw-r--r--src/lib/trace/debug.h4
-rw-r--r--src/lib/trace/events.h2
-rw-r--r--src/lib/trace/trace.c2
-rw-r--r--src/lib/trace/trace.h4
-rw-r--r--src/lib/trace/trace_stub.c2
-rw-r--r--src/lib/trace/trace_sys.c2
-rw-r--r--src/lib/trace/trace_sys.h2
-rw-r--r--src/lib/version/git_revision.c2
-rw-r--r--src/lib/version/git_revision.h2
-rw-r--r--src/lib/version/torversion.h2
-rw-r--r--src/lib/version/version.c2
-rw-r--r--src/lib/wallclock/approx_time.c2
-rw-r--r--src/lib/wallclock/approx_time.h2
-rw-r--r--src/lib/wallclock/time_to_tm.c2
-rw-r--r--src/lib/wallclock/time_to_tm.h2
-rw-r--r--src/lib/wallclock/timeval.h2
-rw-r--r--src/lib/wallclock/tor_gettimeofday.c2
-rw-r--r--src/lib/wallclock/tor_gettimeofday.h2
-rw-r--r--src/lib/wallclock/wallclock_sys.h2
-rw-r--r--src/rust/.cargo/config.in12
-rw-r--r--src/rust/.rustfmt.toml12
-rw-r--r--src/rust/Cargo.lock122
-rw-r--r--src/rust/Cargo.toml26
-rw-r--r--src/rust/build.rs192
-rw-r--r--src/rust/crypto/Cargo.toml37
-rw-r--r--src/rust/crypto/digests/mod.rs7
-rw-r--r--src/rust/crypto/digests/sha2.rs234
-rw-r--r--src/rust/crypto/lib.rs46
-rw-r--r--src/rust/crypto/rand/mod.rs6
-rw-r--r--src/rust/crypto/rand/rng.rs145
-rw-r--r--src/rust/external/Cargo.toml20
-rw-r--r--src/rust/external/crypto_digest.rs454
-rw-r--r--src/rust/external/crypto_rand.rs84
-rw-r--r--src/rust/external/external.rs37
-rw-r--r--src/rust/external/lib.rs19
-rw-r--r--src/rust/include.am41
-rw-r--r--src/rust/protover/Cargo.toml33
-rw-r--r--src/rust/protover/errors.rs57
-rw-r--r--src/rust/protover/ffi.rs247
-rw-r--r--src/rust/protover/lib.rs40
-rw-r--r--src/rust/protover/protoset.rs697
-rw-r--r--src/rust/protover/protover.rs984
-rw-r--r--src/rust/protover/tests/protover.rs365
-rw-r--r--src/rust/smartlist/Cargo.toml18
-rw-r--r--src/rust/smartlist/lib.rs17
-rw-r--r--src/rust/smartlist/smartlist.rs115
-rw-r--r--src/rust/tor_allocate/Cargo.toml18
-rw-r--r--src/rust/tor_allocate/lib.rs20
-rw-r--r--src/rust/tor_allocate/tor_allocate.rs104
-rw-r--r--src/rust/tor_log/Cargo.toml21
-rw-r--r--src/rust/tor_log/lib.rs16
-rw-r--r--src/rust/tor_log/tor_log.rs265
-rw-r--r--src/rust/tor_rust/Cargo.toml22
-rw-r--r--src/rust/tor_rust/include.am28
-rw-r--r--src/rust/tor_rust/lib.rs5
-rw-r--r--src/rust/tor_util/Cargo.toml24
-rw-r--r--src/rust/tor_util/ffi.rs27
-rw-r--r--src/rust/tor_util/lib.rs14
-rw-r--r--src/rust/tor_util/strings.rs136
-rw-r--r--src/test/bench.c2
-rw-r--r--src/test/ed25519_exts_ref.py12
-rw-r--r--src/test/ed25519_vectors.inc22
-rw-r--r--src/test/fakechans.h2
-rw-r--r--src/test/fakecircs.c2
-rw-r--r--src/test/fakecircs.h2
-rw-r--r--src/test/fuzz/fuzz_address.c26
-rw-r--r--src/test/fuzz/fuzz_addressPTR.c32
-rw-r--r--src/test/fuzz/fuzz_consensus.c2
-rw-r--r--src/test/fuzz/fuzz_descriptor.c2
-rw-r--r--src/test/fuzz/fuzz_diff.c2
-rw-r--r--src/test/fuzz/fuzz_diff_apply.c2
-rw-r--r--src/test/fuzz/fuzz_extrainfo.c2
-rw-r--r--src/test/fuzz/fuzz_hsdescv2.c52
-rw-r--r--src/test/fuzz/fuzz_hsdescv3.c2
-rw-r--r--src/test/fuzz/fuzz_hsdescv3_inner.c119
-rw-r--r--src/test/fuzz/fuzz_hsdescv3_middle.c116
-rw-r--r--src/test/fuzz/fuzz_http.c2
-rw-r--r--src/test/fuzz/fuzz_http_connect.c2
-rw-r--r--src/test/fuzz/fuzz_iptsv2.c2
-rw-r--r--src/test/fuzz/fuzz_microdesc.c2
-rw-r--r--src/test/fuzz/fuzz_socks.c2
-rw-r--r--src/test/fuzz/fuzz_strops.c2
-rw-r--r--src/test/fuzz/fuzz_vrs.c2
-rw-r--r--src/test/fuzz/fuzzing.h2
-rw-r--r--src/test/fuzz/fuzzing_common.c2
-rw-r--r--src/test/fuzz/include.am183
-rw-r--r--src/test/hs_build_address.py14
-rw-r--r--src/test/hs_test_helpers.c27
-rw-r--r--src/test/hs_test_helpers.h6
-rw-r--r--src/test/include.am34
-rw-r--r--src/test/log_test_helpers.c2
-rw-r--r--src/test/log_test_helpers.h2
-rwxr-xr-xsrc/test/ntor_v3_ref.py308
-rw-r--r--src/test/opts_test_helpers.c2
-rw-r--r--src/test/opts_test_helpers.h2
-rw-r--r--src/test/prob_distr_mpfr_ref.c2
-rw-r--r--src/test/ptr_helpers.c2
-rw-r--r--src/test/ptr_helpers.h2
-rw-r--r--src/test/rend_test_helpers.c99
-rw-r--r--src/test/rend_test_helpers.h16
-rw-r--r--src/test/resolve_test_helpers.c2
-rw-r--r--src/test/resolve_test_helpers.h2
-rw-r--r--src/test/rng_test_helpers.c2
-rw-r--r--src/test/rng_test_helpers.h2
-rw-r--r--src/test/test-memwipe.c2
-rw-r--r--src/test/test-process.c2
-rw-r--r--src/test/test-timers.c2
-rw-r--r--src/test/test.c374
-rw-r--r--src/test/test.h8
-rw-r--r--src/test/test_accounting.c2
-rw-r--r--src/test/test_addr.c2
-rw-r--r--src/test/test_address.c39
-rw-r--r--src/test/test_address_set.c2
-rw-r--r--src/test/test_bridges.c2
-rw-r--r--src/test/test_bt_cl.c2
-rw-r--r--src/test/test_btrack.c2
-rw-r--r--src/test/test_buffers.c2
-rw-r--r--src/test/test_bwmgt.c2
-rw-r--r--src/test/test_cell_formats.c2
-rw-r--r--src/test/test_cell_queue.c2
-rw-r--r--src/test/test_channel.c2
-rw-r--r--src/test/test_channelpadding.c2
-rw-r--r--src/test/test_channeltls.c5
-rw-r--r--src/test/test_checkdir.c2
-rw-r--r--src/test/test_circuitbuild.c4
-rw-r--r--src/test/test_circuitlist.c64
-rw-r--r--src/test/test_circuitmux.c2
-rw-r--r--src/test/test_circuitmux_ewma.c2
-rw-r--r--src/test/test_circuitpadding.c8
-rw-r--r--src/test/test_circuitstats.c2
-rw-r--r--src/test/test_circuituse.c2
-rw-r--r--src/test/test_compat_libevent.c2
-rw-r--r--src/test/test_config.c14
-rw-r--r--src/test/test_confmgr.c2
-rw-r--r--src/test/test_confparse.c2
-rw-r--r--src/test/test_connection.c108
-rw-r--r--src/test/test_connection.h2
-rw-r--r--src/test/test_conscache.c2
-rw-r--r--src/test/test_consdiff.c2
-rw-r--r--src/test/test_consdiffmgr.c2
-rw-r--r--src/test/test_containers.c2
-rw-r--r--src/test/test_controller.c209
-rw-r--r--src/test/test_controller_events.c2
-rw-r--r--src/test/test_crypto.c2
-rw-r--r--src/test/test_crypto_ope.c2
-rw-r--r--src/test/test_crypto_openssl.c2
-rw-r--r--src/test/test_crypto_rng.c2
-rw-r--r--src/test/test_crypto_slow.c2
-rw-r--r--src/test/test_data.c2
-rw-r--r--src/test/test_dir.c39
-rw-r--r--src/test/test_dir_common.c2
-rw-r--r--src/test/test_dir_common.h2
-rw-r--r--src/test/test_dir_handle_get.c129
-rw-r--r--src/test/test_dirauth_ports.c152
-rw-r--r--src/test/test_dirvote.c27
-rw-r--r--src/test/test_dispatch.c2
-rw-r--r--src/test/test_dns.c2
-rw-r--r--src/test/test_dos.c67
-rw-r--r--src/test/test_entryconn.c9
-rw-r--r--src/test/test_entrynodes.c42
-rw-r--r--src/test/test_extorport.c59
-rw-r--r--src/test/test_geoip.c2
-rw-r--r--src/test/test_guardfraction.c2
-rw-r--r--src/test/test_handles.c2
-rw-r--r--src/test/test_helpers.c2
-rw-r--r--src/test/test_helpers.h2
-rw-r--r--src/test/test_hs.c1005
-rw-r--r--src/test/test_hs_cache.c5
-rw-r--r--src/test/test_hs_cell.c38
-rw-r--r--src/test/test_hs_client.c153
-rw-r--r--src/test/test_hs_common.c6
-rw-r--r--src/test/test_hs_config.c18
-rw-r--r--src/test/test_hs_control.c135
-rw-r--r--src/test/test_hs_descriptor.c47
-rw-r--r--src/test/test_hs_dos.c2
-rw-r--r--src/test/test_hs_intropoint.c82
-rw-r--r--src/test/test_hs_metrics.c2
-rw-r--r--src/test/test_hs_ntor.c2
-rw-r--r--src/test/test_hs_ntor_cl.c2
-rw-r--r--src/test/test_hs_ob.c3
-rw-r--r--src/test/test_hs_service.c28
-rwxr-xr-xsrc/test/test_include.sh3
-rw-r--r--src/test/test_introduce.c539
-rwxr-xr-xsrc/test/test_key_expiration.sh2
-rwxr-xr-xsrc/test/test_keygen.sh14
-rw-r--r--src/test/test_keypin.c2
-rw-r--r--src/test/test_link_handshake.c2
-rw-r--r--src/test/test_logging.c2
-rw-r--r--src/test/test_mainloop.c4
-rw-r--r--src/test/test_metrics.c2
-rw-r--r--src/test/test_microdesc.c2
-rw-r--r--src/test/test_namemap.c2
-rw-r--r--src/test/test_netinfo.c2
-rw-r--r--src/test/test_nodelist.c2
-rw-r--r--src/test/test_ntor_cl.c2
-rw-r--r--src/test/test_ntor_v3.c311
-rw-r--r--src/test/test_oom.c2
-rw-r--r--src/test/test_oos.c2
-rw-r--r--src/test/test_options.c53
-rw-r--r--src/test/test_options_act.c2
-rw-r--r--src/test/test_parsecommon.c9
-rw-r--r--src/test/test_pem.c2
-rw-r--r--src/test/test_periodic_event.c2
-rw-r--r--src/test/test_policy.c2
-rw-r--r--src/test/test_prob_distr.c2
-rw-r--r--src/test/test_process.c2
-rw-r--r--src/test/test_process_descs.c33
-rw-r--r--src/test/test_process_slow.c2
-rw-r--r--src/test/test_procmon.c2
-rw-r--r--src/test/test_proto_haproxy.c2
-rw-r--r--src/test/test_proto_http.c2
-rw-r--r--src/test/test_proto_misc.c2
-rw-r--r--src/test/test_protover.c30
-rw-r--r--src/test/test_pt.c6
-rw-r--r--src/test/test_ptr_slow.c2
-rw-r--r--src/test/test_pubsub_build.c2
-rw-r--r--src/test/test_pubsub_msg.c2
-rwxr-xr-xsrc/test/test_rebind.sh3
-rw-r--r--src/test/test_relay.c2
-rw-r--r--src/test/test_relaycell.c2
-rw-r--r--src/test/test_relaycrypt.c2
-rw-r--r--src/test/test_rendcache.c1248
-rw-r--r--src/test/test_replay.c2
-rw-r--r--src/test/test_rng.c2
-rw-r--r--src/test/test_router.c2
-rw-r--r--src/test/test_routerkeys.c2
-rw-r--r--src/test/test_routerlist.c2
-rw-r--r--src/test/test_routerset.c2
-rwxr-xr-xsrc/test/test_rust.sh28
-rw-r--r--src/test/test_sandbox.c349
-rw-r--r--src/test/test_scheduler.c2
-rw-r--r--src/test/test_sendme.c48
-rw-r--r--src/test/test_shared_random.c2
-rw-r--r--src/test/test_slow.c2
-rw-r--r--src/test/test_socks.c2
-rw-r--r--src/test/test_statefile.c2
-rw-r--r--src/test/test_stats.c358
-rw-r--r--src/test/test_status.c8
-rw-r--r--src/test/test_storagedir.c2
-rw-r--r--src/test/test_switch_id.c2
-rw-r--r--src/test/test_threads.c2
-rw-r--r--src/test/test_token_bucket.c2
-rw-r--r--src/test/test_tortls.c2
-rw-r--r--src/test/test_tortls.h2
-rw-r--r--src/test/test_tortls_openssl.c2
-rw-r--r--src/test/test_util.c37
-rw-r--r--src/test/test_util_format.c2
-rw-r--r--src/test/test_util_process.c2
-rw-r--r--src/test/test_voting_flags.c5
-rw-r--r--src/test/test_voting_schedule.c2
-rw-r--r--src/test/test_workqueue.c2
-rw-r--r--src/test/test_x509.c2
-rw-r--r--src/test/testing_common.c2
-rw-r--r--src/test/testing_rsakeys.c2
-rw-r--r--src/tools/include.am2
-rw-r--r--src/tools/tor-gencert.c17
-rw-r--r--src/tools/tor-print-ed-signing-cert.c2
-rw-r--r--src/tools/tor-resolve.c27
-rw-r--r--src/tools/tor_runner.c2
-rw-r--r--src/trunnel/congestion_control.c183
-rw-r--r--src/trunnel/congestion_control.h67
-rw-r--r--src/trunnel/congestion_control.trunnel22
-rw-r--r--src/trunnel/extension.c (renamed from src/trunnel/hs/cell_common.c)187
-rw-r--r--src/trunnel/extension.h197
-rw-r--r--src/trunnel/extension.trunnel14
-rw-r--r--src/trunnel/flow_control_cells.c382
-rw-r--r--src/trunnel/flow_control_cells.h120
-rw-r--r--src/trunnel/flow_control_cells.trunnel20
-rw-r--r--src/trunnel/hs/cell_common.h203
-rw-r--r--src/trunnel/hs/cell_common.trunnel12
-rw-r--r--src/trunnel/hs/cell_establish_intro.c68
-rw-r--r--src/trunnel/hs/cell_establish_intro.h22
-rw-r--r--src/trunnel/hs/cell_establish_intro.trunnel6
-rw-r--r--src/trunnel/hs/cell_introduce1.c94
-rw-r--r--src/trunnel/hs/cell_introduce1.h32
-rw-r--r--src/trunnel/hs/cell_introduce1.trunnel8
-rw-r--r--src/trunnel/include.am11
-rw-r--r--src/win32/orconfig.h2
1081 files changed, 17663 insertions, 23803 deletions
diff --git a/src/app/config/config.c b/src/app/config/config.c
index f8a140ad9f..e02bcf0387 100644
--- a/src/app/config/config.c
+++ b/src/app/config/config.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -103,8 +103,6 @@
#include "feature/relay/routermode.h"
#include "feature/relay/relay_config.h"
#include "feature/relay/transport_config.h"
-#include "feature/rend/rendclient.h"
-#include "feature/rend/rendservice.h"
#include "lib/geoip/geoip.h"
#include "feature/stats/geoip_stats.h"
#include "lib/compress/compress.h"
@@ -195,6 +193,7 @@ static const config_abbrev_t option_abbrevs_[] = {
PLURAL(AuthDirBadDirCC),
PLURAL(AuthDirBadExitCC),
PLURAL(AuthDirInvalidCC),
+ PLURAL(AuthDirMiddleOnlyCC),
PLURAL(AuthDirRejectCC),
PLURAL(EntryNode),
PLURAL(ExcludeNode),
@@ -333,6 +332,8 @@ static const config_var_t option_vars_[] = {
V(AuthDirBadExitCCs, CSV, ""),
V(AuthDirInvalid, LINELIST, NULL),
V(AuthDirInvalidCCs, CSV, ""),
+ V(AuthDirMiddleOnly, LINELIST, NULL),
+ V(AuthDirMiddleOnlyCCs, CSV, ""),
V(AuthDirReject, LINELIST, NULL),
V(AuthDirRejectCCs, CSV, ""),
OBSOLETE("AuthDirRejectUnlisted"),
@@ -354,6 +355,7 @@ static const config_var_t option_vars_[] = {
V(CacheDirectoryGroupReadable, AUTOBOOL, "auto"),
V(CellStatistics, BOOL, "0"),
V(PaddingStatistics, BOOL, "1"),
+ V(OverloadStatistics, BOOL, "1"),
V(LearnCircuitBuildTimeout, BOOL, "1"),
V(CircuitBuildTimeout, INTERVAL, "0"),
OBSOLETE("CircuitIdleTimeout"),
@@ -424,23 +426,11 @@ static const config_var_t option_vars_[] = {
OBSOLETE("DynamicDHGroups"),
VPORT(DNSPort),
OBSOLETE("DNSListenAddress"),
- V(DormantClientTimeout, INTERVAL, "24 hours"),
- V(DormantTimeoutDisabledByIdleStreams, BOOL, "1"),
+ V(DormantClientTimeout, INTERVAL, "24 hours"),
+ V(DormantTimeoutEnabled, BOOL, "1"),
+ V(DormantTimeoutDisabledByIdleStreams, BOOL, "1"),
V(DormantOnFirstStartup, BOOL, "0"),
V(DormantCanceledByStartup, BOOL, "0"),
- /* DoS circuit creation options. */
- V(DoSCircuitCreationEnabled, AUTOBOOL, "auto"),
- V(DoSCircuitCreationMinConnections, POSINT, "0"),
- V(DoSCircuitCreationRate, POSINT, "0"),
- V(DoSCircuitCreationBurst, POSINT, "0"),
- V(DoSCircuitCreationDefenseType, INT, "0"),
- V(DoSCircuitCreationDefenseTimePeriod, INTERVAL, "0"),
- /* DoS connection options. */
- V(DoSConnectionEnabled, AUTOBOOL, "auto"),
- V(DoSConnectionMaxConcurrentCount, POSINT, "0"),
- V(DoSConnectionDefenseType, INT, "0"),
- /* DoS single hop client options. */
- V(DoSRefuseSingleHopClientRendezvous, AUTOBOOL, "auto"),
V(DownloadExtraInfo, BOOL, "0"),
V(TestingEnableConnBwEvent, BOOL, "0"),
V(TestingEnableCellStatsEvent, BOOL, "0"),
@@ -498,12 +488,13 @@ static const config_var_t option_vars_[] = {
V(MainloopStats, BOOL, "0"),
V(HashedControlPassword, LINELIST, NULL),
OBSOLETE("HidServDirectoryV2"),
+ OBSOLETE("HiddenServiceAuthorizeClient"),
+ OBSOLETE("HidServAuth"),
VAR("HiddenServiceDir", LINELIST_S, RendConfigLines, NULL),
VAR("HiddenServiceDirGroupReadable", LINELIST_S, RendConfigLines, NULL),
VAR("HiddenServiceOptions",LINELIST_V, RendConfigLines, NULL),
VAR("HiddenServicePort", LINELIST_S, RendConfigLines, NULL),
VAR("HiddenServiceVersion",LINELIST_S, RendConfigLines, NULL),
- VAR("HiddenServiceAuthorizeClient",LINELIST_S,RendConfigLines, NULL),
VAR("HiddenServiceAllowUnknownPorts",LINELIST_S, RendConfigLines, NULL),
VAR("HiddenServiceMaxStreams",LINELIST_S, RendConfigLines, NULL),
VAR("HiddenServiceMaxStreamsCloseCircuit",LINELIST_S, RendConfigLines, NULL),
@@ -517,7 +508,6 @@ static const config_var_t option_vars_[] = {
VAR("HiddenServiceOnionBalanceInstance",
LINELIST_S, RendConfigLines, NULL),
VAR("HiddenServiceStatistics", BOOL, HiddenServiceStatistics_option, "1"),
- V(HidServAuth, LINELIST, NULL),
V(ClientOnionAuthDir, FILENAME, NULL),
OBSOLETE("CloseHSClientCircuitsImmediatelyOnTimeout"),
OBSOLETE("CloseHSServiceRendCircuitsImmediatelyOnTimeout"),
@@ -559,7 +549,7 @@ static const config_var_t option_vars_[] = {
V(MaxConsensusAgeForDiffs, INTERVAL, "0 seconds"),
VAR("MaxMemInQueues", MEMUNIT, MaxMemInQueues_raw, "0"),
OBSOLETE("MaxOnionsPending"),
- V(MaxOnionQueueDelay, MSEC_INTERVAL, "1750 msec"),
+ V(MaxOnionQueueDelay, MSEC_INTERVAL, "0"),
V(MaxUnparseableDescSizeToLog, MEMUNIT, "10 MB"),
VPORT(MetricsPort),
V(MetricsPortPolicy, LINELIST, NULL),
@@ -629,11 +619,12 @@ static const config_var_t option_vars_[] = {
V(ConnectionPadding, AUTOBOOL, "auto"),
V(RefuseUnknownExits, AUTOBOOL, "auto"),
V(CircuitPadding, BOOL, "1"),
+ V(ReconfigDropsBridgeDescs, BOOL, "0"),
V(ReducedCircuitPadding, BOOL, "0"),
V(RejectPlaintextPorts, CSV, ""),
V(RelayBandwidthBurst, MEMUNIT, "0"),
V(RelayBandwidthRate, MEMUNIT, "0"),
- V(RendPostPeriod, INTERVAL, "1 hour"),
+ V(RendPostPeriod, INTERVAL, "1 hour"), /* Used internally. */
V(RephistTrackTime, INTERVAL, "24 hours"),
V_IMMUTABLE(RunAsDaemon, BOOL, "0"),
V(ReducedExitPolicy, BOOL, "0"),
@@ -681,8 +672,11 @@ static const config_var_t option_vars_[] = {
VAR("UseEntryGuards", BOOL, UseEntryGuards_option, "1"),
OBSOLETE("UseEntryGuardsAsDirGuards"),
V(UseGuardFraction, AUTOBOOL, "auto"),
+ V(VanguardsLiteEnabled, AUTOBOOL, "auto"),
V(UseMicrodescriptors, AUTOBOOL, "auto"),
OBSOLETE("UseNTorHandshake"),
+ VAR("__AlwaysCongestionControl", BOOL, AlwaysCongestionControl, "0"),
+ VAR("__SbwsExit", BOOL, SbwsExit, "0"),
V_IMMUTABLE(User, STRING, NULL),
OBSOLETE("UserspaceIOCPBuffers"),
OBSOLETE("V1AuthoritativeDirectory"),
@@ -2104,7 +2098,7 @@ options_act,(const or_options_t *old_options))
return -1;
}
- if (rend_non_anonymous_mode_enabled(options)) {
+ if (hs_service_non_anonymous_mode_enabled(options)) {
log_warn(LD_GENERAL, "This copy of Tor was compiled or configured to run "
"in a non-anonymous mode. It will provide NO ANONYMITY.");
}
@@ -2322,6 +2316,8 @@ options_act,(const or_options_t *old_options))
}
if (transition_affects_guards) {
+ if (options->ReconfigDropsBridgeDescs)
+ routerlist_drop_bridge_descriptors();
if (guards_update_all()) {
abandon_circuits = 1;
}
@@ -2446,6 +2442,8 @@ typedef enum {
static const struct {
/** The string that the user has to provide. */
const char *name;
+ /** Optional short name. */
+ const char *short_name;
/** Does this option accept an argument? */
takes_argument_t takes_argument;
/** If not CMD_RUN_TOR, what should Tor do when it starts? */
@@ -2453,7 +2451,8 @@ static const struct {
/** If nonzero, set the quiet level to this. 1 is "hush", 2 is "quiet" */
int quiet;
} CMDLINE_ONLY_OPTIONS[] = {
- { .name="-f",
+ { .name="--torrc-file",
+ .short_name="-f",
.takes_argument=ARGUMENT_NECESSARY },
{ .name="--allow-missing-torrc" },
{ .name="--defaults-torrc",
@@ -2467,6 +2466,7 @@ static const struct {
.command=CMD_DUMP_CONFIG,
.quiet=QUIET_SILENT },
{ .name="--list-fingerprint",
+ .takes_argument=ARGUMENT_OPTIONAL,
.command=CMD_LIST_FINGERPRINT },
{ .name="--keygen",
.command=CMD_KEYGEN },
@@ -2495,10 +2495,8 @@ static const struct {
{ .name="--library-versions",
.command=CMD_IMMEDIATE,
.quiet=QUIET_HUSH },
- { .name="-h",
- .command=CMD_IMMEDIATE,
- .quiet=QUIET_HUSH },
{ .name="--help",
+ .short_name="-h",
.command=CMD_IMMEDIATE,
.quiet=QUIET_HUSH },
{ .name="--list-torrc-options",
@@ -2542,7 +2540,9 @@ config_parse_commandline(int argc, char **argv, int ignore_errors)
bool is_a_command = false;
for (j = 0; CMDLINE_ONLY_OPTIONS[j].name != NULL; ++j) {
- if (!strcmp(argv[i], CMDLINE_ONLY_OPTIONS[j].name)) {
+ if (!strcmp(argv[i], CMDLINE_ONLY_OPTIONS[j].name) ||
+ (CMDLINE_ONLY_OPTIONS[j].short_name &&
+ !strcmp(argv[i], CMDLINE_ONLY_OPTIONS[j].short_name))) {
is_cmdline = 1;
want_arg = CMDLINE_ONLY_OPTIONS[j].takes_argument;
if (CMDLINE_ONLY_OPTIONS[j].command != CMD_RUN_TOR) {
@@ -2585,8 +2585,11 @@ config_parse_commandline(int argc, char **argv, int ignore_errors)
parsed_cmdline_free(result);
return NULL;
}
- } else if (want_arg == ARGUMENT_OPTIONAL && is_last) {
+ } else if (want_arg == ARGUMENT_OPTIONAL &&
+ /* optional arguments may never start with '-'. */
+ (is_last || argv[i+1][0] == '-')) {
arg = tor_strdup("");
+ want_arg = ARGUMENT_NONE; // prevent skipping the next flag.
} else {
arg = (want_arg != ARGUMENT_NONE) ? tor_strdup(argv[i+1]) :
tor_strdup("");
@@ -2685,7 +2688,7 @@ print_usage(void)
printf(
"Copyright (c) 2001-2004, Roger Dingledine\n"
"Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson\n"
-"Copyright (c) 2007-2020, The Tor Project, Inc.\n\n"
+"Copyright (c) 2007-2021, The Tor Project, Inc.\n\n"
"tor -f <torrc> [args]\n"
"See man page for options, or https://www.torproject.org/ for "
"documentation.\n");
@@ -3210,7 +3213,7 @@ options_validate_single_onion(or_options_t *options, char **msg)
}
/* Now that we've checked that the two options are consistent, we can safely
- * call the rend_service_* functions that abstract these options. */
+ * call the hs_service_* functions that abstract these options. */
/* If you run an anonymous client with an active Single Onion service, the
* client loses anonymity. */
@@ -3219,13 +3222,13 @@ options_validate_single_onion(or_options_t *options, char **msg)
options->NATDPort_set ||
options->DNSPort_set ||
options->HTTPTunnelPort_set);
- if (rend_service_non_anonymous_mode_enabled(options) && client_port_set) {
+ if (hs_service_non_anonymous_mode_enabled(options) && client_port_set) {
REJECT("HiddenServiceNonAnonymousMode is incompatible with using Tor as "
"an anonymous client. Please set Socks/Trans/NATD/DNSPort to 0, or "
"revert HiddenServiceNonAnonymousMode to 0.");
}
- if (rend_service_allow_non_anonymous_connection(options)
+ if (hs_service_allow_non_anonymous_connection(options)
&& options->UseEntryGuards) {
/* Single Onion services only use entry guards when uploading descriptors;
* all other connections are one-hop. Further, Single Onions causes the
@@ -3275,7 +3278,7 @@ options_validate_cb(const void *old_options_, void *options_, char **msg)
}
#else /* defined(HAVE_SYS_UN_H) */
if (options->ControlSocketsGroupWritable && !options->ControlSocket) {
- *msg = tor_strdup("Setting ControlSocketGroupWritable without setting "
+ *msg = tor_strdup("Setting ControlSocketsGroupWritable without setting "
"a ControlSocket makes no sense.");
return -1;
}
@@ -3575,7 +3578,7 @@ options_validate_cb(const void *old_options_, void *options_, char **msg)
if (!(options->UseEntryGuards) &&
(options->RendConfigLines != NULL) &&
- !rend_service_allow_non_anonymous_connection(options)) {
+ !hs_service_allow_non_anonymous_connection(options)) {
log_warn(LD_CONFIG,
"UseEntryGuards is disabled, but you have configured one or more "
"hidden services on this Tor instance. Your hidden services "
@@ -3618,7 +3621,7 @@ options_validate_cb(const void *old_options_, void *options_, char **msg)
}
/* Single Onion Services: non-anonymous hidden services */
- if (rend_service_non_anonymous_mode_enabled(options)) {
+ if (hs_service_non_anonymous_mode_enabled(options)) {
log_warn(LD_CONFIG,
"HiddenServiceNonAnonymousMode is set. Every hidden service on "
"this tor instance is NON-ANONYMOUS. If "
@@ -4318,16 +4321,21 @@ find_torrc_filename(const config_line_t *cmd_arg,
char *fname=NULL;
const config_line_t *p_index;
const char *fname_opt = defaults_file ? "--defaults-torrc" : "-f";
+ const char *fname_long_opt = defaults_file ? "--defaults-torrc" :
+ "--torrc-file";
const char *ignore_opt = defaults_file ? NULL : "--ignore-missing-torrc";
+ const char *keygen_opt = "--keygen";
if (defaults_file)
*ignore_missing_torrc = 1;
for (p_index = cmd_arg; p_index; p_index = p_index->next) {
- if (!strcmp(p_index->key, fname_opt)) {
+ // options_init_from_torrc ensures only the short or long name is present
+ if (!strcmp(p_index->key, fname_opt) ||
+ !strcmp(p_index->key, fname_long_opt)) {
if (fname) {
log_warn(LD_CONFIG, "Duplicate %s options on command line.",
- fname_opt);
+ p_index->key);
tor_free(fname);
}
fname = expand_filename(p_index->value);
@@ -4340,7 +4348,8 @@ find_torrc_filename(const config_line_t *cmd_arg,
}
*using_default_fname = 0;
- } else if (ignore_opt && !strcmp(p_index->key,ignore_opt)) {
+ } else if ((ignore_opt && !strcmp(p_index->key, ignore_opt)) ||
+ (keygen_opt && !strcmp(p_index->key, keygen_opt))) {
*ignore_missing_torrc = 1;
}
}
@@ -4487,6 +4496,25 @@ options_init_from_torrc(int argc, char **argv)
if (config_line_find(cmdline_only_options, "--version")) {
printf("Tor version %s.\n",get_version());
+ 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(),
+ tor_libevent_get_version_str(),
+ crypto_get_library_name(),
+ crypto_get_library_version_string(),
+ tor_compress_supports_method(ZLIB_METHOD) ?
+ tor_compress_version_str(ZLIB_METHOD) : "N/A",
+ tor_compress_supports_method(LZMA_METHOD) ?
+ tor_compress_version_str(LZMA_METHOD) : "N/A",
+ tor_compress_supports_method(ZSTD_METHOD) ?
+ tor_compress_version_str(ZSTD_METHOD) : "N/A",
+ tor_libc_get_name() ?
+ tor_libc_get_name() : "Unknown",
+ tor_libc_get_version_str());
+ printf("Tor compiled with %s version %s\n",
+ strcmp(COMPILER_VENDOR, "gnu") == 0?
+ COMPILER:COMPILER_VENDOR, COMPILER_VERSION);
+
return 1;
}
@@ -4511,6 +4539,16 @@ options_init_from_torrc(int argc, char **argv)
} else {
cf_defaults = load_torrc_from_disk(cmdline_only_options, 1);
const config_line_t *f_line = config_line_find(cmdline_only_options, "-f");
+ const config_line_t *f_line_long = config_line_find(cmdline_only_options,
+ "--torrc-file");
+ if (f_line && f_line_long) {
+ log_err(LD_CONFIG, "-f and --torrc-file cannot be used together.");
+ retval = -1;
+ goto err;
+ } else if (f_line_long) {
+ f_line = f_line_long;
+ }
+
const int read_torrc_from_stdin =
(f_line != NULL && strcmp(f_line->value, "-") == 0);
@@ -4803,7 +4841,7 @@ addressmap_register_auto(const char *from, const char *to,
}
addressmap_register(from, tor_strdup(to), expires, addrmap_source,
- from_wildcard, to_wildcard);
+ from_wildcard, to_wildcard, 0);
return 0;
}
@@ -4950,9 +4988,9 @@ options_init_logs(const or_options_t *old_options, const or_options_t *options,
if (!validate_only) {
add_syslog_log(severity, options->SyslogIdentityTag);
}
-#else
+#else /* !defined(HAVE_SYSLOG_H) */
log_warn(LD_CONFIG, "The android logging API is no longer supported.");
-#endif
+#endif /* defined(HAVE_SYSLOG_H) */
goto cleanup;
}
}
@@ -5439,6 +5477,77 @@ pt_parse_transport_line(const or_options_t *options,
return r;
}
+/**
+ * Parse a flag describing an extra dirport for a directory authority.
+ *
+ * Right now, the supported format is exactly:
+ * `{upload,download,voting}=http://[IP:PORT]/`.
+ * Other URL schemes, and other suffixes, might be supported in the future.
+ *
+ * Only call this function if `flag` starts with one of the above strings.
+ *
+ * Return 0 on success, and -1 on failure.
+ *
+ * If `ds` is provided, then add any parsed dirport to `ds`. If `ds` is NULL,
+ * take no action other than parsing.
+ **/
+static int
+parse_dirauth_dirport(dir_server_t *ds, const char *flag)
+{
+ tor_assert(flag);
+
+ auth_dirport_usage_t usage;
+
+ if (!strcasecmpstart(flag, "upload=")) {
+ usage = AUTH_USAGE_UPLOAD;
+ } else if (!strcasecmpstart(flag, "download=")) {
+ usage = AUTH_USAGE_DOWNLOAD;
+ } else if (!strcasecmpstart(flag, "vote=")) {
+ usage = AUTH_USAGE_VOTING;
+ } else {
+ // We shouldn't get called with a flag that we don't recognize.
+ tor_assert_nonfatal_unreached();
+ return -1;
+ }
+
+ const char *eq = strchr(flag, '=');
+ tor_assert(eq);
+ const char *target = eq + 1;
+
+ // Find the part inside the http://{....}/
+ if (strcmpstart(target, "http://")) {
+ log_warn(LD_CONFIG, "Unsupported URL scheme in authority flag %s", flag);
+ return -1;
+ }
+ const char *addr = target + strlen("http://");
+
+ const char *eos = strchr(addr, '/');
+ size_t addr_len;
+ if (eos && strcmp(eos, "/")) {
+ log_warn(LD_CONFIG, "Unsupported URL prefix in authority flag %s", flag);
+ return -1;
+ } else if (eos) {
+ addr_len = eos - addr;
+ } else {
+ addr_len = strlen(addr);
+ }
+
+ // Finally, parse the addr:port part.
+ char *addr_string = tor_strndup(addr, addr_len);
+ tor_addr_port_t dirport;
+ memset(&dirport, 0, sizeof(dirport));
+ int rv = tor_addr_port_parse(LOG_WARN, addr_string,
+ &dirport.addr, &dirport.port, -1);
+ if (ds != NULL && rv == 0) {
+ trusted_dir_server_add_dirport(ds, usage, &dirport);
+ } else if (rv == -1) {
+ log_warn(LD_CONFIG, "Unable to parse address in authority flag %s",flag);
+ }
+
+ tor_free(addr_string);
+ return rv;
+}
+
/** Read the contents of a DirAuthority line from <b>line</b>. If
* <b>validate_only</b> is 0, and the line is well-formed, and it
* shares any bits with <b>required_type</b> or <b>required_type</b>
@@ -5459,6 +5568,7 @@ parse_dir_authority_line(const char *line, dirinfo_type_t required_type,
char v3_digest[DIGEST_LEN];
dirinfo_type_t type = 0;
double weight = 1.0;
+ smartlist_t *extra_dirports = smartlist_new();
memset(v3_digest, 0, sizeof(v3_digest));
@@ -5527,6 +5637,12 @@ parse_dir_authority_line(const char *line, dirinfo_type_t required_type,
}
ipv6_addrport_ptr = &ipv6_addrport;
}
+ } else if (!strcasecmpstart(flag, "upload=") ||
+ !strcasecmpstart(flag, "download=") ||
+ !strcasecmpstart(flag, "vote=")) {
+ // We'll handle these after creating the authority object.
+ smartlist_add(extra_dirports, flag);
+ flag = NULL; // prevent double-free.
} else {
log_warn(LD_CONFIG, "Unrecognized flag '%s' on DirAuthority line",
flag);
@@ -5570,6 +5686,13 @@ parse_dir_authority_line(const char *line, dirinfo_type_t required_type,
goto err;
}
+ if (validate_only) {
+ SMARTLIST_FOREACH_BEGIN(extra_dirports, const char *, cp) {
+ if (parse_dirauth_dirport(NULL, cp) < 0)
+ goto err;
+ } SMARTLIST_FOREACH_END(cp);
+ }
+
if (!validate_only && (!required_type || required_type & type)) {
dir_server_t *ds;
if (required_type)
@@ -5581,16 +5704,23 @@ parse_dir_authority_line(const char *line, dirinfo_type_t required_type,
ipv6_addrport_ptr,
digest, v3_digest, type, weight)))
goto err;
+
+ SMARTLIST_FOREACH_BEGIN(extra_dirports, const char *, cp) {
+ if (parse_dirauth_dirport(ds, cp) < 0)
+ goto err;
+ } SMARTLIST_FOREACH_END(cp);
dir_server_add(ds);
}
r = 0;
goto done;
- err:
+ err:
r = -1;
- done:
+ done:
+ SMARTLIST_FOREACH(extra_dirports, char*, s, tor_free(s));
+ smartlist_free(extra_dirports);
SMARTLIST_FOREACH(items, char*, s, tor_free(s));
smartlist_free(items);
tor_free(addrport);
@@ -6032,7 +6162,7 @@ port_parse_config(smartlist_t *out,
tor_free(addrtmp);
} else {
/* Try parsing integer port before address, because, who knows?
- "9050" might be a valid address. */
+ * "9050" might be a valid address. */
port = (int) tor_parse_long(addrport, 10, 0, 65535, &ok, NULL);
if (ok) {
tor_addr_copy(&addr, &default_addr);
diff --git a/src/app/config/config.h b/src/app/config/config.h
index ee78d1e0f7..de198e203d 100644
--- a/src/app/config/config.h
+++ b/src/app/config/config.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/app/config/or_options_st.h b/src/app/config/or_options_st.h
index 440c987365..290a2bb9b4 100644
--- a/src/app/config/or_options_st.h
+++ b/src/app/config/or_options_st.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -293,6 +293,13 @@ struct or_options_t {
* disabled. */
int CircuitPadding;
+ /** Boolean: if true, then this client will discard cached bridge
+ * descriptors on a setconf or other config change that impacts guards
+ * or bridges (see options_transition_affects_guards() for exactly which
+ * config changes trigger it). Useful for tools that test bridge
+ * reachability by fetching fresh descriptors. */
+ int ReconfigDropsBridgeDescs;
+
/** Boolean: if true, then this client will only use circuit padding
* algorithms that are known to use a low amount of overhead. If false,
* we will use all available circuit padding algorithms.
@@ -336,7 +343,7 @@ struct or_options_t {
/* Makes hidden service clients and servers non-anonymous on this tor
* instance. Allows the non-anonymous HiddenServiceSingleHopMode. Enables
* non-anonymous behaviour in the hidden service protocol.
- * Use rend_service_non_anonymous_mode_enabled() instead of using this option
+ * Use hs_service_non_anonymous_mode_enabled() instead of using this option
* directly.
*/
int HiddenServiceNonAnonymousMode;
@@ -428,9 +435,6 @@ struct or_options_t {
int NumCPUs; /**< How many CPUs should we try to use? */
struct config_line_t *RendConfigLines; /**< List of configuration lines
* for rendezvous services. */
- struct config_line_t *HidServAuth; /**< List of configuration lines for
- * client-side authorizations for hidden
- * services */
char *ClientOnionAuthDir; /**< Directory to keep client
* onion service authorization secret keys */
char *ContactInfo; /**< Contact info to be published in the directory. */
@@ -495,6 +499,9 @@ struct or_options_t {
struct smartlist_t *NodeFamilySets;
struct config_line_t *AuthDirBadExit; /**< Address policy for descriptors to
* mark as bad exits. */
+ /** Address policy for descriptors to mark as only suitable for the
+ * middle position in circuits. */
+ struct config_line_t *AuthDirMiddleOnly;
struct config_line_t *AuthDirReject; /**< Address policy for descriptors to
* reject. */
struct config_line_t *AuthDirInvalid; /**< Address policy for descriptors to
@@ -508,6 +515,7 @@ struct or_options_t {
*/
struct smartlist_t *AuthDirBadExitCCs;
struct smartlist_t *AuthDirInvalidCCs;
+ struct smartlist_t *AuthDirMiddleOnlyCCs;
struct smartlist_t *AuthDirRejectCCs;
/**@}*/
@@ -590,6 +598,15 @@ struct or_options_t {
* If 0, use value from NumEntryGuards. */
int NumPrimaryGuards; /**< How many primary guards do we want? */
+ /** Boolean: Switch to toggle the vanguards-lite subsystem */
+ int VanguardsLiteEnabled;
+
+ /** Boolean: Switch to override consensus to enable congestion control */
+ int AlwaysCongestionControl;
+
+ /** Boolean: Switch to specify this is an sbws measurement exit */
+ int SbwsExit;
+
int RephistTrackTime; /**< How many seconds do we keep rephist info? */
/** Should we always fetch our dir info on the mirror schedule (which
* means directly from the authorities) no matter our other config? */
@@ -677,6 +694,9 @@ struct or_options_t {
/** If true, include statistics file contents in extra-info documents. */
int ExtraInfoStatistics;
+ /** If true, include overload statistics in extra-info documents. */
+ int OverloadStatistics;
+
/** If true, do not believe anybody who tells us that a domain resolves
* to an internal address, or that an internal address has a PTR mapping.
* Helps avoid some cross-site attacks. */
@@ -1031,40 +1051,18 @@ struct or_options_t {
*/
int DisableSignalHandlers;
- /** Autobool: Is the circuit creation DoS mitigation subsystem enabled? */
- int DoSCircuitCreationEnabled;
- /** Minimum concurrent connection needed from one single address before any
- * defense is used. */
- int DoSCircuitCreationMinConnections;
- /** Circuit rate used to refill the token bucket. */
- int DoSCircuitCreationRate;
- /** Maximum allowed burst of circuits. Reaching that value, the address is
- * detected as malicious and a defense might be used. */
- int DoSCircuitCreationBurst;
- /** When an address is marked as malicious, what defense should be used
- * against it. See the dos_cc_defense_type_t enum. */
- int DoSCircuitCreationDefenseType;
- /** For how much time (in seconds) the defense is applicable for a malicious
- * address. A random time delta is added to the defense time of an address
- * which will be between 1 second and half of this value. */
- int DoSCircuitCreationDefenseTimePeriod;
-
- /** Autobool: Is the DoS connection mitigation subsystem enabled? */
- int DoSConnectionEnabled;
- /** Maximum concurrent connection allowed per address. */
- int DoSConnectionMaxConcurrentCount;
- /** When an address is reaches the maximum count, what defense should be
- * used against it. See the dos_conn_defense_type_t enum. */
- int DoSConnectionDefenseType;
-
- /** Autobool: Do we refuse single hop client rendezvous? */
- int DoSRefuseSingleHopClientRendezvous;
-
/** Interval: how long without activity does it take for a client
* to become dormant?
**/
int DormantClientTimeout;
+ /**
+ * Boolean: If enabled, then we consider the timeout when deciding whether
+ * to be dormant. If not enabled, then only the SIGNAL ACTIVE/DORMANT
+ * controls can change our status.
+ **/
+ int DormantTimeoutEnabled;
+
/** Boolean: true if having an idle stream is sufficient to prevent a client
* from becoming dormant.
**/
diff --git a/src/app/config/or_state_st.h b/src/app/config/or_state_st.h
index 807f546169..3f2d78d8cd 100644
--- a/src/app/config/or_state_st.h
+++ b/src/app/config/or_state_st.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/app/config/quiet_level.c b/src/app/config/quiet_level.c
index e04faaef3a..4a5f595144 100644
--- a/src/app/config/quiet_level.c
+++ b/src/app/config/quiet_level.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/app/config/quiet_level.h b/src/app/config/quiet_level.h
index 3a630b90e7..6b20284ced 100644
--- a/src/app/config/quiet_level.h
+++ b/src/app/config/quiet_level.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/app/config/resolve_addr.c b/src/app/config/resolve_addr.c
index 86db6ba680..09d4b800f6 100644
--- a/src/app/config/resolve_addr.c
+++ b/src/app/config/resolve_addr.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2020, The Tor Project, Inc. */
+/* Copyright (c) 2020-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -343,6 +343,18 @@ get_address_from_config(const or_options_t *options, int warn_severity,
* used, custom authorities must be defined else it is a fatal error.
* Furthermore, if the Address was resolved to an internal interface, we
* stop immediately. */
+ if (ret == ERR_ADDRESS_IS_INTERNAL) {
+ static bool logged_once = false;
+ if (!logged_once) {
+ log_warn(LD_CONFIG, "Address set with an internal address. Tor will "
+ "not work unless custom directory authorities "
+ "are defined (AlternateDirAuthority). It is also "
+ "possible to use an internal address if "
+ "PublishServerDescriptor is set to 0 and "
+ "AssumeReachable(IPv6) to 1.");
+ logged_once = true;
+ }
+ }
tor_free(*hostname_out);
return FN_RET_BAIL;
}
@@ -852,4 +864,4 @@ resolve_addr_reset_suggested(int family)
tor_addr_make_unspec(&last_suggested_addrs[af_to_idx(family)]);
}
-#endif /* TOR_UNIT_TESTS */
+#endif /* defined(TOR_UNIT_TESTS) */
diff --git a/src/app/config/resolve_addr.h b/src/app/config/resolve_addr.h
index 919d5d42cc..9a3846dfcb 100644
--- a/src/app/config/resolve_addr.h
+++ b/src/app/config/resolve_addr.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2020, The Tor Project, Inc. */
+/* Copyright (c) 2020-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -61,7 +61,7 @@ void resolve_addr_reset_suggested(int family);
#endif /* TOR_UNIT_TESTS */
-#endif /* RESOLVE_ADDR_PRIVATE */
+#endif /* defined(RESOLVE_ADDR_PRIVATE) */
-#endif /* TOR_CONFIG_RESOLVE_ADDR_H */
+#endif /* !defined(TOR_CONFIG_RESOLVE_ADDR_H) */
diff --git a/src/app/config/statefile.c b/src/app/config/statefile.c
index 22b15fcf24..c33468c20f 100644
--- a/src/app/config/statefile.c
+++ b/src/app/config/statefile.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/app/config/statefile.h b/src/app/config/statefile.h
index 89b10560f3..bffb8c444d 100644
--- a/src/app/config/statefile.h
+++ b/src/app/config/statefile.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/app/config/tor_cmdline_mode.h b/src/app/config/tor_cmdline_mode.h
index 30a339a438..989050b1b1 100644
--- a/src/app/config/tor_cmdline_mode.h
+++ b/src/app/config/tor_cmdline_mode.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/app/include.am b/src/app/include.am
index 8bb315fff1..5494d904a3 100644
--- a/src/app/include.am
+++ b/src/app/include.am
@@ -17,7 +17,6 @@ src_app_tor_SOURCES = src/app/main/tor_main.c
src_app_tor_LDFLAGS = @TOR_LDFLAGS_zlib@ $(TOR_LDFLAGS_CRYPTLIB) \
@TOR_LDFLAGS_libevent@ @TOR_STATIC_LDFLAGS@
src_app_tor_LDADD = libtor.a \
- $(rust_ldadd) \
@TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ @TOR_LIBEVENT_LIBS@ $(TOR_LIBS_CRYPTLIB) \
@TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_SHLWAPI@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@ \
@CURVE25519_LIBS@ @TOR_SYSTEMD_LIBS@ \
@@ -28,7 +27,7 @@ src_app_tor_cov_SOURCES = $(src_app_tor_SOURCES)
src_app_tor_cov_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS)
src_app_tor_cov_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS)
src_app_tor_cov_LDFLAGS = @TOR_LDFLAGS_zlib@ $(TOR_LDFLAGS_CRYPTLIB) \
- @TOR_LDFLAGS_libevent@ @TOR_STATIC_LDFALGS@
+ @TOR_LDFLAGS_libevent@ @TOR_STATIC_LDFLAGS@
src_app_tor_cov_LDADD = src/test/libtor-testing.a \
@TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ @TOR_LIBEVENT_LIBS@ $(TOR_LIBS_CRYPTLIB) \
@TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_SHLWAPI@ @TOR_LIB_GDI@ \
diff --git a/src/app/main/main.c b/src/app/main/main.c
index 5043caedb6..838e129d04 100644
--- a/src/app/main/main.c
+++ b/src/app/main/main.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -27,6 +27,8 @@
#include "core/or/channel.h"
#include "core/or/channelpadding.h"
#include "core/or/circuitpadding.h"
+#include "core/or/congestion_control_common.h"
+#include "core/or/congestion_control_flow.h"
#include "core/or/circuitlist.h"
#include "core/or/command.h"
#include "core/or/connection_or.h"
@@ -44,6 +46,7 @@
#include "feature/dirparse/routerparse.h"
#include "feature/hibernate/hibernate.h"
#include "feature/hs/hs_dos.h"
+#include "feature/hs/hs_service.h"
#include "feature/nodelist/authcert.h"
#include "feature/nodelist/networkstatus.h"
#include "feature/nodelist/routerlist.h"
@@ -51,13 +54,12 @@
#include "feature/relay/ext_orport.h"
#include "feature/relay/routerkeys.h"
#include "feature/relay/routermode.h"
-#include "feature/rend/rendcache.h"
-#include "feature/rend/rendservice.h"
#include "feature/stats/predict_ports.h"
#include "feature/stats/bwhist.h"
#include "feature/stats/rephist.h"
#include "lib/compress/compress.h"
#include "lib/buf/buffers.h"
+#include "lib/crypt_ops/crypto_format.h"
#include "lib/crypt_ops/crypto_rand.h"
#include "lib/crypt_ops/crypto_s2k.h"
#include "lib/net/resolve.h"
@@ -100,12 +102,6 @@
#include <systemd/sd-daemon.h>
#endif /* defined(HAVE_SYSTEMD) */
-#ifdef HAVE_RUST
-// helper function defined in Rust to output a log message indicating if tor is
-// running with Rust enabled. See src/rust/tor_util
-void rust_log_welcome_string(void);
-#endif
-
/********* PROTOTYPES **********/
static void dumpmemusage(int severity);
@@ -309,7 +305,7 @@ process_win32_console_ctrl(DWORD ctrl_type)
activate_signal(SIGINT);
return TRUE;
}
-#endif
+#endif /* defined(_WIN32) */
/**
* Write current memory usage information to the log.
@@ -425,7 +421,6 @@ dumpstats(int severity)
dumpmemusage(severity);
rep_hist_dump_stats(now,severity);
- rend_service_dump_stats(severity);
hs_service_dump_stats(severity);
}
@@ -515,7 +510,7 @@ handle_signals(void)
* to handle control signals like Ctrl+C in the console, we can use this to
* simulate the SIGINT signal */
if (enabled) SetConsoleCtrlHandler(process_win32_console_ctrl, TRUE);
-#endif
+#endif /* defined(_WIN32) */
}
/* Cause the signal handler for signal_num to be called in the event loop. */
@@ -551,7 +546,6 @@ tor_init(int argc, char *argv[])
rep_hist_init();
bwhist_init();
/* Initialize the service cache. */
- rend_cache_init();
addressmap_init(); /* Init the client dns cache. Do it always, since it's
* cheap. */
@@ -611,10 +605,6 @@ tor_init(int argc, char *argv[])
tor_compress_log_init_warnings();
}
-#ifdef HAVE_RUST
- rust_log_welcome_string();
-#endif /* defined(HAVE_RUST) */
-
/* Warn _if_ the tracing subsystem is built in. */
tracing_log_warning();
@@ -632,6 +622,8 @@ tor_init(int argc, char *argv[])
* until we get a consensus */
channelpadding_new_consensus_params(NULL);
circpad_new_consensus_params(NULL);
+ congestion_control_new_consensus_params(NULL);
+ flow_control_new_consensus_params(NULL);
/* Initialize circuit padding to defaults+torrc until we get a consensus */
circpad_machines_init();
@@ -734,29 +726,52 @@ tor_remove_file(const char *filename)
static int
do_list_fingerprint(void)
{
- char buf[FINGERPRINT_LEN+1];
+ const or_options_t *options = get_options();
+ const char *arg = options->command_arg;
+ char rsa[FINGERPRINT_LEN + 1];
crypto_pk_t *k;
- const char *nickname = get_options()->Nickname;
+ const ed25519_public_key_t *edkey;
+ const char *nickname = options->Nickname;
sandbox_disable_getaddrinfo_cache();
- if (!server_mode(get_options())) {
+
+ bool show_rsa = !strcmp(arg, "") || !strcmp(arg, "rsa");
+ bool show_ed25519 = !strcmp(arg, "ed25519");
+ if (!show_rsa && !show_ed25519) {
+ log_err(LD_GENERAL,
+ "If you give a key type, you must specify 'rsa' or 'ed25519'. Exiting.");
+ return -1;
+ }
+
+ if (!server_mode(options)) {
log_err(LD_GENERAL,
"Clients don't have long-term identity keys. Exiting.");
return -1;
}
tor_assert(nickname);
if (init_keys() < 0) {
- log_err(LD_GENERAL,"Error initializing keys; exiting.");
+ log_err(LD_GENERAL, "Error initializing keys; exiting.");
return -1;
}
if (!(k = get_server_identity_key())) {
- log_err(LD_GENERAL,"Error: missing identity key.");
+ log_err(LD_GENERAL, "Error: missing RSA identity key.");
return -1;
}
- if (crypto_pk_get_fingerprint(k, buf, 1)<0) {
- log_err(LD_BUG, "Error computing fingerprint");
+ if (crypto_pk_get_fingerprint(k, rsa, 1) < 0) {
+ log_err(LD_BUG, "Error computing RSA fingerprint");
return -1;
}
- printf("%s %s\n", nickname, buf);
+ if (!(edkey = get_master_identity_key())) {
+ log_err(LD_GENERAL,"Error: missing ed25519 identity key.");
+ return -1;
+ }
+ if (show_rsa) {
+ printf("%s %s\n", nickname, rsa);
+ }
+ if (show_ed25519) {
+ char ed25519[ED25519_BASE64_LEN + 1];
+ digest256_to_base64(ed25519, (const char *) edkey->pubkey);
+ printf("%s %s\n", nickname, ed25519);
+ }
return 0;
}
@@ -907,8 +922,11 @@ sandbox_init_filter(void)
if (options->BridgeAuthoritativeDir)
OPEN_DATADIR_SUFFIX("networkstatus-bridges", ".tmp");
- if (authdir_mode(options))
+ if (authdir_mode(options)) {
OPEN_DATADIR("approved-routers");
+ OPEN_DATADIR_SUFFIX("my-consensus-microdesc", ".tmp");
+ OPEN_DATADIR_SUFFIX("my-consensus-ns", ".tmp");
+ }
if (options->ServerDNSResolvConfFile)
sandbox_cfg_allow_open_filename(&cfg,
@@ -986,6 +1004,11 @@ sandbox_init_filter(void)
if (options->BridgeAuthoritativeDir)
RENAME_SUFFIX("networkstatus-bridges", ".tmp");
+ if (authdir_mode(options)) {
+ RENAME_SUFFIX("my-consensus-microdesc", ".tmp");
+ RENAME_SUFFIX("my-consensus-ns", ".tmp");
+ }
+
#define STAT_DATADIR(name) \
sandbox_cfg_allow_stat_filename(&cfg, get_datadir_fname(name))
@@ -1091,6 +1114,7 @@ sandbox_init_filter(void)
OPEN_DATADIR2_SUFFIX("stats", "buffer-stats", ".tmp");
OPEN_DATADIR2_SUFFIX("stats", "conn-stats", ".tmp");
OPEN_DATADIR2_SUFFIX("stats", "hidserv-stats", ".tmp");
+ OPEN_DATADIR2_SUFFIX("stats", "hidserv-v3-stats", ".tmp");
OPEN_DATADIR("approved-routers");
OPEN_DATADIR_SUFFIX("fingerprint", ".tmp");
@@ -1116,6 +1140,7 @@ sandbox_init_filter(void)
RENAME_SUFFIX2("stats", "buffer-stats", ".tmp");
RENAME_SUFFIX2("stats", "conn-stats", ".tmp");
RENAME_SUFFIX2("stats", "hidserv-stats", ".tmp");
+ RENAME_SUFFIX2("stats", "hidserv-v3-stats", ".tmp");
RENAME_SUFFIX("hashed-fingerprint", ".tmp");
RENAME_SUFFIX("router-stability", ".tmp");
@@ -1320,6 +1345,13 @@ tor_run_main(const tor_main_configuration_t *tor_cfg)
pubsub_connect();
if (get_options()->Sandbox && get_options()->command == CMD_RUN_TOR) {
+#ifdef ENABLE_FRAGILE_HARDENING
+ log_warn(LD_CONFIG, "Sandbox is enabled but this Tor was built using "
+ "fragile compiler hardening. The sandbox may be unable to filter "
+ "requests to open files and directories and its overall "
+ "effectiveness will be reduced.");
+#endif
+
sandbox_cfg_t* cfg = sandbox_init_filter();
if (sandbox_init(cfg)) {
diff --git a/src/app/main/main.h b/src/app/main/main.h
index e6ed978c61..a8fa0959ab 100644
--- a/src/app/main/main.h
+++ b/src/app/main/main.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/app/main/ntmain.c b/src/app/main/ntmain.c
index 5dc0edd591..9f2f52fb2e 100644
--- a/src/app/main/ntmain.c
+++ b/src/app/main/ntmain.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -500,7 +500,8 @@ nt_service_command_line(int *using_default_torrc)
if (!strcmp(backup_argv[i], "--options") ||
!strcmp(backup_argv[i], "-options")) {
while (++i < backup_argc) {
- if (!strcmp(backup_argv[i], "-f"))
+ if (!strcmp(backup_argv[i], "-f") ||
+ !strcmp(backup_argv[i], "--torrc-file"))
*using_default_torrc = 0;
smartlist_add(sl, backup_argv[i]);
}
diff --git a/src/app/main/ntmain.h b/src/app/main/ntmain.h
index c2d6e23da7..46c4625b77 100644
--- a/src/app/main/ntmain.h
+++ b/src/app/main/ntmain.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/app/main/risky_options.c b/src/app/main/risky_options.c
index 747dda766b..ed9eeca224 100644
--- a/src/app/main/risky_options.c
+++ b/src/app/main/risky_options.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/app/main/risky_options.h b/src/app/main/risky_options.h
index 4548ae3efb..f94dd15faa 100644
--- a/src/app/main/risky_options.h
+++ b/src/app/main/risky_options.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -14,4 +14,4 @@
extern const char risky_option_list[];
-#endif
+#endif /* !defined(TOR_RISKY_OPTIONS_H) */
diff --git a/src/app/main/shutdown.c b/src/app/main/shutdown.c
index 4a556333db..a6065db5da 100644
--- a/src/app/main/shutdown.c
+++ b/src/app/main/shutdown.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -45,8 +45,6 @@
#include "feature/nodelist/routerlist.h"
#include "feature/relay/ext_orport.h"
#include "feature/relay/relay_config.h"
-#include "feature/rend/rendcache.h"
-#include "feature/rend/rendclient.h"
#include "feature/stats/bwhist.h"
#include "feature/stats/geoip_stats.h"
#include "feature/stats/rephist.h"
@@ -119,8 +117,6 @@ tor_free_all(int postfork)
networkstatus_free_all();
addressmap_free_all();
dirserv_free_all();
- rend_cache_free_all();
- rend_service_authorization_free_all();
rep_hist_free_all();
bwhist_free_all();
circuit_free_all();
diff --git a/src/app/main/shutdown.h b/src/app/main/shutdown.h
index 623ae9525b..035ced8467 100644
--- a/src/app/main/shutdown.h
+++ b/src/app/main/shutdown.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/app/main/subsysmgr.c b/src/app/main/subsysmgr.c
index 349803cd46..ad2bf95700 100644
--- a/src/app/main/subsysmgr.c
+++ b/src/app/main/subsysmgr.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/app/main/subsysmgr.h b/src/app/main/subsysmgr.h
index ae0b3df469..e5ff7e2b2b 100644
--- a/src/app/main/subsysmgr.h
+++ b/src/app/main/subsysmgr.h
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/app/main/subsystem_list.c b/src/app/main/subsystem_list.c
index cb79909e69..0333077164 100644
--- a/src/app/main/subsystem_list.c
+++ b/src/app/main/subsystem_list.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -14,6 +14,7 @@
#include "lib/cc/torint.h"
#include "core/mainloop/mainloop_sys.h"
+#include "core/or/dos_sys.h"
#include "core/or/or_sys.h"
#include "feature/control/btrack_sys.h"
#include "lib/compress/compress_sys.h"
@@ -64,6 +65,7 @@ const subsys_fns_t *tor_subsystems[] = {
&sys_mainloop,
&sys_or,
+ &sys_dos,
&sys_relay,
&sys_hs,
diff --git a/src/app/main/tor_main.c b/src/app/main/tor_main.c
index 0ee03fd5e9..d12b6cb425 100644
--- a/src/app/main/tor_main.c
+++ b/src/app/main/tor_main.c
@@ -1,6 +1,6 @@
/* Copyright 2001-2004 Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
diff --git a/src/config/README b/src/config/README
index cb2debb88f..4553325e57 100644
--- a/src/config/README
+++ b/src/config/README
@@ -33,3 +33,32 @@ torrc.sample.in:
most people shouldn't mess with.
+==============================
+
+On the geoip format:
+
+Our geoip files are line-oriented. Any empty line, or line starting
+with a #, is ignored.
+
+All other lines are composed of three comma-separated values:
+START,END,CC. For the geoip file, START and END are IPv4 addresses
+as expressed as 32-bit integers (such as 3325256709 to represent
+198.51.100.5). For the geoip6 file, START and END are IPv6
+addresses, with no brackets. In both cases CC is a two-character
+country code.
+
+The semantic meaning of a line START,END,CC is that all addresses
+between START and END _inclusive_ should be mapped to the country code
+CC.
+
+We guarantee that all entries within these files are disjoint --
+that is, there is no address that is matched by more than one
+line. We also guarantee that all entries within these files are
+sorted in numerically ascending order by address.
+
+Thus, one effective search algorithm here is to perform a binary
+search on all the entries in the file.
+
+Note that there _are_ "gaps" in these databases: not every possible
+address maps to a country code. In those cases, Tor reports the
+country as ??.
diff --git a/src/config/mmdb-convert.py b/src/config/mmdb-convert.py
deleted file mode 100644
index 4acfea6c0e..0000000000
--- a/src/config/mmdb-convert.py
+++ /dev/null
@@ -1,471 +0,0 @@
-#!/usr/bin/python
-
-# This software has been dedicated to the public domain under the CC0
-# public domain dedication.
-#
-# To the extent possible under law, the person who associated CC0
-# with mmdb-convert.py has waived all copyright and related or
-# neighboring rights to mmdb-convert.py.
-#
-# You should have received a copy of the CC0 legalcode along with this
-# work in doc/cc0.txt. If not, see
-# <https://creativecommons.org/publicdomain/zero/1.0/>.
-
-# Nick Mathewson is responsible for this kludge, but takes no
-# responsibility for it.
-
-"""This kludge is meant to
- parse mmdb files in sufficient detail to dump out the old format
- that Tor expects. It's also meant to be pure-python.
-
- When given a simplicity/speed tradeoff, it opts for simplicity.
-
- You will not understand the code without understanding the MaxMind-DB
- file format. It is specified at:
- https://github.com/maxmind/MaxMind-DB/blob/master/MaxMind-DB-spec.md.
-
- This isn't so much tested. When it breaks, you get to keep both
- pieces.
-"""
-
-# Future imports for Python 2.7, mandatory in 3.0
-from __future__ import division
-from __future__ import print_function
-from __future__ import unicode_literals
-
-import struct
-import bisect
-import socket
-import binascii
-import sys
-import time
-
-METADATA_MARKER = b'\xab\xcd\xefMaxMind.com'
-
-# Here's some python2/python3 junk. Better solutions wanted.
-try:
- ord(b"1"[0])
-except TypeError:
- def byte_to_int(b):
- "convert a single element of a bytestring to an integer."
- return b
-else:
- byte_to_int = ord
-
-# Here's some more python2/python3 junk. Better solutions wanted.
-try:
- str(b"a", "utf8")
-except TypeError:
- bytesToStr = str
-else:
- def bytesToStr(b):
- "convert a bytestring in utf8 to a string."
- return str(b, 'utf8')
-
-def to_int(s):
- "Parse a big-endian integer from bytestring s."
- result = 0
- for c in s:
- result *= 256
- result += byte_to_int(c)
- return result
-
-def to_int24(s):
- "Parse a pair of big-endian 24-bit integers from bytestring s."
- a, b, c = struct.unpack("!HHH", s)
- return ((a <<8)+(b>>8)), (((b&0xff)<<16)+c)
-
-def to_int32(s):
- "Parse a pair of big-endian 32-bit integers from bytestring s."
- a, b = struct.unpack("!LL", s)
- return a, b
-
-def to_int28(s):
- "Parse a pair of big-endian 28-bit integers from bytestring s."
- a, b = struct.unpack("!LL", s + b'\x00')
- return (((a & 0xf0) << 20) + (a >> 8)), ((a & 0x0f) << 24) + (b >> 8)
-
-class Tree(object):
- "Holds a node in the tree"
- def __init__(self, left, right):
- self.left = left
- self.right = right
-
-def resolve_tree(tree, data):
- """Fill in the left_item and right_item fields for all values in the tree
- so that they point to another Tree, or to a Datum, or to None."""
- d = Datum(None, None, None, None)
- def resolve_item(item):
- "Helper: resolve a single index."
- if item < len(tree):
- return tree[item]
- elif item == len(tree):
- return None
- else:
- d.pos = (item - len(tree) - 16)
- p = bisect.bisect_left(data, d)
- assert data[p].pos == d.pos
- return data[p]
-
- for t in tree:
- t.left_item = resolve_item(t.left)
- t.right_item = resolve_item(t.right)
-
-def parse_search_tree(s, record_size):
- """Given a bytestring and a record size in bits, parse the tree.
- Return a list of nodes."""
- record_bytes = (record_size*2) // 8
- nodes = []
- p = 0
- try:
- to_leftright = { 24: to_int24,
- 28: to_int28,
- 32: to_int32 }[ record_size ]
- except KeyError:
- raise NotImplementedError("Unsupported record size in bits: %d" %
- record_size)
- while p < len(s):
- left, right = to_leftright(s[p:p+record_bytes])
- p += record_bytes
-
- nodes.append( Tree(left, right ) )
-
- return nodes
-
-class Datum(object):
- """Holds a single entry from the Data section"""
- def __init__(self, pos, kind, ln, data):
- self.pos = pos # Position of this record within data section
- self.kind = kind # Type of this record. one of TP_*
- self.ln = ln # Length field, which might be overloaded.
- self.data = data # Raw bytes data.
- self.children = None # Used for arrays and maps.
-
- def __repr__(self):
- return "Datum(%r,%r,%r,%r)" % (self.pos, self.kind, self.ln, self.data)
-
- # Comparison functions used for bsearch
- def __lt__(self, other):
- return self.pos < other.pos
-
- def __gt__(self, other):
- return self.pos > other.pos
-
- def __eq__(self, other):
- return self.pos == other.pos
-
- def build_maps(self):
- """If this is a map or array, fill in its 'map' field if it's a map,
- and the 'map' field of all its children."""
-
- if not hasattr(self, 'nChildren'):
- return
-
- if self.kind == TP_ARRAY:
- del self.nChildren
- for c in self.children:
- c.build_maps()
-
- elif self.kind == TP_MAP:
- del self.nChildren
- self.map = {}
- for i in range(0, len(self.children), 2):
- k = self.children[i].deref()
- v = self.children[i+1].deref()
- v.build_maps()
- if k.kind != TP_UTF8:
- raise ValueError("Bad dictionary key type %d"% k.kind)
- self.map[bytesToStr(k.data)] = v
-
- def int_val(self):
- """If this is an integer type, return its value"""
- assert self.kind in (TP_UINT16, TP_UINT32, TP_UINT64,
- TP_UINT128, TP_SINT32)
- i = to_int(self.data)
- if self.kind == TP_SINT32:
- if i & 0x80000000:
- i = i - 0x100000000
- return i
-
- def deref(self):
- """If this value is a pointer, return its pointed-to-value. Chase
- through multiple layers of pointers if need be. If this isn't
- a pointer, return it."""
- n = 0
- s = self
- while s.kind == TP_PTR:
- s = s.ptr
- n += 1
- assert n < 100
- return s
-
-def resolve_pointers(data):
- """Fill in the ptr field of every pointer in data."""
- search = Datum(None, None, None, None)
- for d in data:
- if d.kind == TP_PTR:
- search.pos = d.ln
- p = bisect.bisect_left(data, search)
- assert data[p].pos == d.ln
- d.ptr = data[p]
-
-TP_PTR = 1
-TP_UTF8 = 2
-TP_DBL = 3
-TP_BYTES = 4
-TP_UINT16 = 5
-TP_UINT32 = 6
-TP_MAP = 7
-TP_SINT32 = 8
-TP_UINT64 = 9
-TP_UINT128 = 10
-TP_ARRAY = 11
-TP_DCACHE = 12
-TP_END = 13
-TP_BOOL = 14
-TP_FLOAT = 15
-
-def get_type_and_len(s):
- """Data parsing helper: decode the type value and much-overloaded 'length'
- field for the value starting at s. Return a 3-tuple of type, length,
- and number of bytes used to encode type-plus-length."""
- c = byte_to_int(s[0])
- tp = c >> 5
- skip = 1
- if tp == 0:
- tp = byte_to_int(s[1])+7
- skip = 2
- ln = c & 31
-
- # I'm sure I don't know what they were thinking here...
- if tp == TP_PTR:
- len_len = (ln >> 3) + 1
- if len_len < 4:
- ln &= 7
- ln <<= len_len * 8
- else:
- ln = 0
- ln += to_int(s[skip:skip+len_len])
- ln += (0, 0, 2048, 526336, 0)[len_len]
- skip += len_len
- elif ln >= 29:
- len_len = ln - 28
- ln = to_int(s[skip:skip+len_len])
- ln += (0, 29, 285, 65821)[len_len]
- skip += len_len
-
- return tp, ln, skip
-
-# Set of types for which 'length' doesn't mean length.
-IGNORE_LEN_TYPES = set([
- TP_MAP, # Length is number of key-value pairs that follow.
- TP_ARRAY, # Length is number of members that follow.
- TP_PTR, # Length is index to pointed-to data element.
- TP_BOOL, # Length is 0 or 1.
- TP_DCACHE, # Length is number of members that follow
-])
-
-def parse_data_section(s):
- """Given a data section encoded in a bytestring, return a list of
- Datum items."""
-
- # Stack of possibly nested containers. We use the 'nChildren' member of
- # the last one to tell how many more items nest directly inside.
- stack = []
-
- # List of all items, including nested ones.
- data = []
-
- # Byte index within the data section.
- pos = 0
-
- while s:
- tp, ln, skip = get_type_and_len(s)
- if tp in IGNORE_LEN_TYPES:
- real_len = 0
- else:
- real_len = ln
-
- d = Datum(pos, tp, ln, s[skip:skip+real_len])
- data.append(d)
- pos += skip+real_len
- s = s[skip+real_len:]
-
- if stack:
- stack[-1].children.append(d)
- stack[-1].nChildren -= 1
- if stack[-1].nChildren == 0:
- del stack[-1]
-
- if d.kind == TP_ARRAY:
- d.nChildren = d.ln
- d.children = []
- stack.append(d)
- elif d.kind == TP_MAP:
- d.nChildren = d.ln * 2
- d.children = []
- stack.append(d)
-
- return data
-
-def parse_mm_file(s):
- """Parse a MaxMind-DB file."""
- try:
- metadata_ptr = s.rindex(METADATA_MARKER)
- except ValueError:
- raise ValueError("No metadata!")
-
- metadata = parse_data_section(s[metadata_ptr+len(METADATA_MARKER):])
-
- if metadata[0].kind != TP_MAP:
- raise ValueError("Bad map")
-
- metadata[0].build_maps()
- mm = metadata[0].map
-
- tree_size = (((mm['record_size'].int_val() * 2) // 8 ) *
- mm['node_count'].int_val())
-
- if s[tree_size:tree_size+16] != b'\x00'*16:
- raise ValueError("Missing section separator!")
-
- tree = parse_search_tree(s[:tree_size], mm['record_size'].int_val())
-
- data = parse_data_section(s[tree_size+16:metadata_ptr])
-
- resolve_pointers(data)
- resolve_tree(tree, data)
-
- for d in data:
- d.build_maps()
-
- return metadata, tree, data
-
-def format_datum(datum):
- """Given a Datum at a leaf of the tree, return the string that we should
- write as its value.
-
- We first try country->iso_code which is the two-character ISO 3166-1
- country code of the country where MaxMind believes the end user is
- located. If there's no such key, we try registered_country->iso_code
- which is the country in which the ISP has registered the IP address.
- Without falling back to registered_country, we'd leave out all ranges
- that MaxMind thinks belong to anonymous proxies, because those ranges
- don't contain country but only registered_country. In short: let's
- fill all A1 entries with what ARIN et. al think.
- """
- try:
- return bytesToStr(datum.map['country'].map['iso_code'].data)
- except KeyError:
- pass
- try:
- return bytesToStr(datum.map['registered_country'].map['iso_code'].data)
- except KeyError:
- pass
- return None
-
-IPV4_PREFIX = "0"*96
-
-def dump_item_ipv4(entries, prefix, val):
- """Dump the information for an IPv4 address to entries, where 'prefix'
- is a string holding a binary prefix for the address, and 'val' is the
- value to dump. If the prefix is not an IPv4 address (it does not start
- with 96 bits of 0), then print nothing.
- """
- if not prefix.startswith(IPV4_PREFIX):
- return
- prefix = prefix[96:]
- v = int(prefix, 2)
- shift = 32 - len(prefix)
- lo = v << shift
- hi = ((v+1) << shift) - 1
- entries.append((lo, hi, val))
-
-def fmt_item_ipv4(entry):
- """Format an IPv4 range with lo and hi addresses in decimal form."""
- return "%d,%d,%s\n"%(entry[0], entry[1], entry[2])
-
-def fmt_ipv6_addr(v):
- """Given a 128-bit integer representing an ipv6 address, return a
- string for that ipv6 address."""
- return socket.inet_ntop(socket.AF_INET6, binascii.unhexlify("%032x"%v))
-
-def fmt_item_ipv6(entry):
- """Format an IPv6 range with lo and hi addresses in hex form."""
- return "%s,%s,%s\n"%(fmt_ipv6_addr(entry[0]),
- fmt_ipv6_addr(entry[1]),
- entry[2])
-
-IPV4_MAPPED_IPV6_PREFIX = "0"*80 + "1"*16
-IPV6_6TO4_PREFIX = "0010000000000010"
-TEREDO_IPV6_PREFIX = "0010000000000001" + "0"*16
-
-def dump_item_ipv6(entries, prefix, val):
- """Dump the information for an IPv6 address prefix to entries, where
- 'prefix' is a string holding a binary prefix for the address,
- and 'val' is the value to dump. If the prefix is an IPv4 address
- (starts with 96 bits of 0), is an IPv4-mapped IPv6 address
- (::ffff:0:0/96), or is in the 6to4 mapping subnet (2002::/16), then
- print nothing.
- """
- if prefix.startswith(IPV4_PREFIX) or \
- prefix.startswith(IPV4_MAPPED_IPV6_PREFIX) or \
- prefix.startswith(IPV6_6TO4_PREFIX) or \
- prefix.startswith(TEREDO_IPV6_PREFIX):
- return
- v = int(prefix, 2)
- shift = 128 - len(prefix)
- lo = v << shift
- hi = ((v+1) << shift) - 1
- entries.append((lo, hi, val))
-
-def dump_tree(entries, node, dump_item, prefix=""):
- """Walk the tree rooted at 'node', and call dump_item on the
- format_datum output of every leaf of the tree."""
-
- if isinstance(node, Tree):
- dump_tree(entries, node.left_item, dump_item, prefix+"0")
- dump_tree(entries, node.right_item, dump_item, prefix+"1")
- elif isinstance(node, Datum):
- assert node.kind == TP_MAP
- code = format_datum(node)
- if code:
- dump_item(entries, prefix, code)
- else:
- assert node == None
-
-GEOIP_FILE_HEADER = """\
-# Last updated based on %s Maxmind GeoLite2 Country
-# wget https://geolite.maxmind.com/download/geoip/database/GeoLite2-Country.mmdb.gz
-# gunzip GeoLite2-Country.mmdb.gz
-# python mmdb-convert.py GeoLite2-Country.mmdb
-"""
-
-def write_geoip_file(filename, metadata, the_tree, dump_item, fmt_item):
- """Write the entries in the_tree to filename."""
- entries = []
- dump_tree(entries, the_tree[0], dump_item)
- fobj = open(filename, 'w')
-
- build_epoch = metadata[0].map['build_epoch'].int_val()
- fobj.write(GEOIP_FILE_HEADER %
- time.strftime('%B %-d %Y', time.gmtime(build_epoch)))
-
- unwritten = None
- for entry in entries:
- if not unwritten:
- unwritten = entry
- elif unwritten[1] + 1 == entry[0] and unwritten[2] == entry[2]:
- unwritten = (unwritten[0], entry[1], unwritten[2])
- else:
- fobj.write(fmt_item(unwritten))
- unwritten = entry
- if unwritten:
- fobj.write(fmt_item(unwritten))
- fobj.close()
-
-content = open(sys.argv[1], 'rb').read()
-metadata, the_tree, _ = parse_mm_file(content)
-
-write_geoip_file('geoip', metadata, the_tree, dump_item_ipv4, fmt_item_ipv4)
-write_geoip_file('geoip6', metadata, the_tree, dump_item_ipv6, fmt_item_ipv6)
diff --git a/src/config/torrc.minimal.in-staging b/src/config/torrc.minimal.in-staging
index 7f43cd324e..667ab294b4 100644
--- a/src/config/torrc.minimal.in-staging
+++ b/src/config/torrc.minimal.in-staging
@@ -224,4 +224,4 @@
## mechanisms like https://bridges.torproject.org/. If you want to run
## a private bridge, for example because you'll give out your bridge
## address manually to your friends, uncomment this line:
-#PublishServerDescriptor 0
+#BridgeDistribution none
diff --git a/src/config/torrc.sample.in b/src/config/torrc.sample.in
index 5d593871dd..edc30d043c 100644
--- a/src/config/torrc.sample.in
+++ b/src/config/torrc.sample.in
@@ -239,7 +239,7 @@
## mechanisms like https://bridges.torproject.org/. If you want to run
## a private bridge, for example because you'll give out your bridge
## address manually to your friends, uncomment this line:
-#PublishServerDescriptor 0
+#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
diff --git a/src/core/crypto/hs_ntor.c b/src/core/crypto/hs_ntor.c
index 07bcdc566c..67da65d8bc 100644
--- a/src/core/crypto/hs_ntor.c
+++ b/src/core/crypto/hs_ntor.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017-2020, The Tor Project, Inc. */
+/* Copyright (c) 2017-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/** \file hs_ntor.c
diff --git a/src/core/crypto/hs_ntor.h b/src/core/crypto/hs_ntor.h
index 9a975dd83f..d5913f6562 100644
--- a/src/core/crypto/hs_ntor.h
+++ b/src/core/crypto/hs_ntor.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017-2020, The Tor Project, Inc. */
+/* Copyright (c) 2017-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/core/crypto/include.am b/src/core/crypto/include.am
index 28b7e22905..2d53b3cb0b 100644
--- a/src/core/crypto/include.am
+++ b/src/core/crypto/include.am
@@ -5,6 +5,7 @@ LIBTOR_APP_A_SOURCES += \
src/core/crypto/onion_crypto.c \
src/core/crypto/onion_fast.c \
src/core/crypto/onion_ntor.c \
+ src/core/crypto/onion_ntor_v3.c \
src/core/crypto/onion_tap.c \
src/core/crypto/relay_crypto.c
@@ -14,5 +15,6 @@ noinst_HEADERS += \
src/core/crypto/onion_crypto.h \
src/core/crypto/onion_fast.h \
src/core/crypto/onion_ntor.h \
+ src/core/crypto/onion_ntor_v3.h \
src/core/crypto/onion_tap.h \
src/core/crypto/relay_crypto.h
diff --git a/src/core/crypto/onion_crypto.c b/src/core/crypto/onion_crypto.c
index 1f34be1cc1..81e4e1b078 100644
--- a/src/core/crypto/onion_crypto.c
+++ b/src/core/crypto/onion_crypto.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -35,14 +35,28 @@
#include "core/crypto/onion_crypto.h"
#include "core/crypto/onion_fast.h"
#include "core/crypto/onion_ntor.h"
+#include "core/crypto/onion_ntor_v3.h"
#include "core/crypto/onion_tap.h"
#include "feature/relay/router.h"
#include "lib/crypt_ops/crypto_dh.h"
#include "lib/crypt_ops/crypto_util.h"
+#include "feature/relay/routerkeys.h"
+#include "core/or/congestion_control_common.h"
+
+#include "core/or/circuitbuild.h"
#include "core/or/crypt_path_st.h"
#include "core/or/extend_info_st.h"
+#include "trunnel/congestion_control.h"
+#include "trunnel/extension.h"
+
+static const uint8_t NTOR3_CIRC_VERIFICATION[] = "circuit extend";
+static const size_t NTOR3_CIRC_VERIFICATION_LEN = 14;
+
+#define NTOR3_VERIFICATION_ARGS \
+ NTOR3_CIRC_VERIFICATION, NTOR3_CIRC_VERIFICATION_LEN
+
/** Return a new server_onion_keys_t object with all of the keys
* and other info we might need to do onion handshakes. (We make a copy of
* our keys for each cpuworker to avoid race conditions with the main thread,
@@ -52,6 +66,7 @@ server_onion_keys_new(void)
{
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());
dup_onion_keys(&keys->onion_key, &keys->last_onion_key);
keys->curve25519_key_map = construct_ntor_key_map();
keys->junk_keypair = tor_malloc_zero(sizeof(curve25519_keypair_t));
@@ -91,6 +106,9 @@ onion_handshake_state_release(onion_handshake_state_t *state)
ntor_handshake_state_free(state->u.ntor);
state->u.ntor = NULL;
break;
+ case ONION_HANDSHAKE_TYPE_NTOR_V3:
+ ntor3_handshake_state_free(state->u.ntor3);
+ break;
default:
/* LCOV_EXCL_START
* This state should not even exist. */
@@ -103,19 +121,23 @@ onion_handshake_state_release(onion_handshake_state_t *state)
/** Perform the first step of a circuit-creation handshake of type <b>type</b>
* (one of ONION_HANDSHAKE_TYPE_*): generate the initial "onion skin" in
- * <b>onion_skin_out</b>, and store any state information in <b>state_out</b>.
+ * <b>onion_skin_out</b> with length of up to <b>onion_skin_out_maxlen</b>,
+ * and store any state information in <b>state_out</b>.
* Return -1 on failure, and the length of the onionskin on acceptance.
*/
int
onion_skin_create(int type,
const extend_info_t *node,
onion_handshake_state_t *state_out,
- uint8_t *onion_skin_out)
+ uint8_t *onion_skin_out,
+ size_t onion_skin_out_maxlen)
{
int r = -1;
switch (type) {
case ONION_HANDSHAKE_TYPE_TAP:
+ if (onion_skin_out_maxlen < TAP_ONIONSKIN_CHALLENGE_LEN)
+ return -1;
if (!node->onion_key)
return -1;
@@ -133,7 +155,9 @@ onion_skin_create(int type,
r = CREATE_FAST_LEN;
break;
case ONION_HANDSHAKE_TYPE_NTOR:
- if (!extend_info_supports_ntor(node))
+ if (onion_skin_out_maxlen < NTOR_ONIONSKIN_LEN)
+ return -1;
+ if (!extend_info_supports_ntor(node))
return -1;
if (onion_skin_ntor_create((const uint8_t*)node->identity_digest,
&node->curve25519_onion_key,
@@ -143,6 +167,37 @@ onion_skin_create(int type,
r = NTOR_ONIONSKIN_LEN;
break;
+ case ONION_HANDSHAKE_TYPE_NTOR_V3:
+ if (!extend_info_supports_ntor_v3(node))
+ return -1;
+ if (ed25519_public_key_is_zero(&node->ed_identity))
+ return -1;
+ size_t msg_len = 0;
+ uint8_t *msg = NULL;
+ if (client_circ_negotiation_message(node, &msg, &msg_len) < 0)
+ return -1;
+ uint8_t *onion_skin = NULL;
+ size_t onion_skin_len = 0;
+ int status = onion_skin_ntor3_create(
+ &node->ed_identity,
+ &node->curve25519_onion_key,
+ NTOR3_VERIFICATION_ARGS,
+ msg, msg_len, /* client message */
+ &state_out->u.ntor3,
+ &onion_skin, &onion_skin_len);
+ tor_free(msg);
+ if (status < 0) {
+ return -1;
+ }
+ if (onion_skin_len > onion_skin_out_maxlen) {
+ tor_free(onion_skin);
+ return -1;
+ }
+ memcpy(onion_skin_out, onion_skin, onion_skin_len);
+ tor_free(onion_skin);
+ r = (int) onion_skin_len;
+ break;
+
default:
/* LCOV_EXCL_START
* We should never try to create an impossible handshake type. */
@@ -158,6 +213,50 @@ onion_skin_create(int type,
return r;
}
+/**
+ * Takes a param request message from the client, compares it to our
+ * consensus parameters, and creates a reply message and output
+ * parameters.
+ *
+ * This function runs in a worker thread, so it can only inspect
+ * arguments and local variables.
+ *
+ * Returns 0 if successful.
+ * Returns -1 on parsing, parameter failure, or reply creation failure.
+ */
+static int
+negotiate_v3_ntor_server_circ_params(const uint8_t *param_request_msg,
+ size_t param_request_len,
+ const circuit_params_t *our_ns_params,
+ circuit_params_t *params_out,
+ uint8_t **resp_msg_out,
+ size_t *resp_msg_len_out)
+{
+ int ret;
+
+ /* Parse request. */
+ ret = congestion_control_parse_ext_request(param_request_msg,
+ param_request_len);
+ if (ret < 0) {
+ goto err;
+ }
+ params_out->cc_enabled = ret && our_ns_params->cc_enabled;
+
+ /* Build the response. */
+ ret = congestion_control_build_ext_response(our_ns_params, params_out,
+ resp_msg_out, resp_msg_len_out);
+ if (ret < 0) {
+ goto err;
+ }
+ params_out->sendme_inc_cells = our_ns_params->sendme_inc_cells;
+
+ /* Success. */
+ ret = 0;
+
+ err:
+ return ret;
+}
+
/* This is the maximum value for keys_out_len passed to
* onion_skin_server_handshake, plus 16. We can make it bigger if needed:
* It just defines how many bytes to stack-allocate. */
@@ -174,14 +273,20 @@ int
onion_skin_server_handshake(int type,
const uint8_t *onion_skin, size_t onionskin_len,
const server_onion_keys_t *keys,
+ const circuit_params_t *our_ns_params,
uint8_t *reply_out,
+ size_t reply_out_maxlen,
uint8_t *keys_out, size_t keys_out_len,
- uint8_t *rend_nonce_out)
+ uint8_t *rend_nonce_out,
+ circuit_params_t *params_out)
{
int r = -1;
+ memset(params_out, 0, sizeof(*params_out));
switch (type) {
case ONION_HANDSHAKE_TYPE_TAP:
+ if (reply_out_maxlen < TAP_ONIONSKIN_REPLY_LEN)
+ return -1;
if (onionskin_len != TAP_ONIONSKIN_CHALLENGE_LEN)
return -1;
if (onion_skin_TAP_server_handshake((const char*)onion_skin,
@@ -193,6 +298,8 @@ onion_skin_server_handshake(int type,
memcpy(rend_nonce_out, reply_out+DH1024_KEY_LEN, DIGEST_LEN);
break;
case ONION_HANDSHAKE_TYPE_FAST:
+ if (reply_out_maxlen < CREATED_FAST_LEN)
+ return -1;
if (onionskin_len != CREATE_FAST_LEN)
return -1;
if (fast_server_handshake(onion_skin, reply_out, keys_out, keys_out_len)<0)
@@ -201,6 +308,8 @@ onion_skin_server_handshake(int type,
memcpy(rend_nonce_out, reply_out+DIGEST_LEN, DIGEST_LEN);
break;
case ONION_HANDSHAKE_TYPE_NTOR:
+ if (reply_out_maxlen < NTOR_REPLY_LEN)
+ return -1;
if (onionskin_len < NTOR_ONIONSKIN_LEN)
return -1;
{
@@ -223,6 +332,71 @@ onion_skin_server_handshake(int type,
r = NTOR_REPLY_LEN;
}
break;
+ case ONION_HANDSHAKE_TYPE_NTOR_V3: {
+ size_t keys_tmp_len = keys_out_len + DIGEST_LEN;
+ tor_assert(keys_tmp_len <= MAX_KEYS_TMP_LEN);
+ uint8_t keys_tmp[MAX_KEYS_TMP_LEN];
+ uint8_t *client_msg = NULL;
+ size_t client_msg_len = 0;
+ uint8_t *reply_msg = NULL;
+ size_t reply_msg_len = 0;
+
+ ntor3_server_handshake_state_t *state = NULL;
+
+ if (onion_skin_ntor3_server_handshake_part1(
+ keys->curve25519_key_map,
+ keys->junk_keypair,
+ &keys->my_ed_identity,
+ onion_skin, onionskin_len,
+ NTOR3_VERIFICATION_ARGS,
+ &client_msg, &client_msg_len,
+ &state) < 0) {
+ return -1;
+ }
+
+ if (negotiate_v3_ntor_server_circ_params(client_msg,
+ client_msg_len,
+ our_ns_params,
+ params_out,
+ &reply_msg,
+ &reply_msg_len) < 0) {
+ ntor3_server_handshake_state_free(state);
+ tor_free(client_msg);
+ return -1;
+ }
+ tor_free(client_msg);
+
+ uint8_t *server_handshake = NULL;
+ size_t server_handshake_len = 0;
+ if (onion_skin_ntor3_server_handshake_part2(
+ state,
+ NTOR3_VERIFICATION_ARGS,
+ reply_msg, reply_msg_len,
+ &server_handshake, &server_handshake_len,
+ keys_tmp, keys_tmp_len) < 0) {
+ tor_free(reply_msg);
+ ntor3_server_handshake_state_free(state);
+ return -1;
+ }
+ tor_free(reply_msg);
+
+ if (server_handshake_len > reply_out_maxlen) {
+ tor_free(server_handshake);
+ ntor3_server_handshake_state_free(state);
+ return -1;
+ }
+
+ memcpy(keys_out, keys_tmp, keys_out_len);
+ memcpy(rend_nonce_out, keys_tmp+keys_out_len, DIGEST_LEN);
+ memcpy(reply_out, server_handshake, server_handshake_len);
+ memwipe(keys_tmp, 0, keys_tmp_len);
+ memwipe(server_handshake, 0, server_handshake_len);
+ tor_free(server_handshake);
+ ntor3_server_handshake_state_free(state);
+
+ r = (int) server_handshake_len;
+ }
+ break;
default:
/* LCOV_EXCL_START
* We should have rejected this far before this point */
@@ -235,6 +409,44 @@ onion_skin_server_handshake(int type,
return r;
}
+/**
+ * Takes a param response message from the exit, compares it to our
+ * consensus parameters for sanity, and creates output parameters
+ * if sane.
+ *
+ * Returns -1 on parsing or insane params, 0 if success.
+ */
+static int
+negotiate_v3_ntor_client_circ_params(const uint8_t *param_response_msg,
+ size_t param_response_len,
+ circuit_params_t *params_out)
+{
+ int ret = congestion_control_parse_ext_response(param_response_msg,
+ param_response_len,
+ params_out);
+ if (ret < 0) {
+ return -1;
+ }
+
+ /* If congestion control came back enabled, but we didn't ask for it
+ * because the consensus said no, close the circuit.
+ *
+ * This is a fatal error condition for the circuit, because it either
+ * means that congestion control was disabled by the consensus
+ * during the handshake, or the exit decided to send us an unsolicited
+ * congestion control response.
+ *
+ * In either case, we cannot proceed on this circuit, and must try a
+ * new one.
+ */
+ if (ret && !congestion_control_enabled()) {
+ return -1;
+ }
+ params_out->cc_enabled = ret;
+
+ return 0;
+}
+
/** Perform the final (client-side) step of a circuit-creation handshake of
* type <b>type</b>, using our state in <b>handshake_state</b> and the
* server's response in <b>reply</b>. On success, generate <b>keys_out_len</b>
@@ -249,11 +461,14 @@ onion_skin_client_handshake(int type,
const uint8_t *reply, size_t reply_len,
uint8_t *keys_out, size_t keys_out_len,
uint8_t *rend_authenticator_out,
+ circuit_params_t *params_out,
const char **msg_out)
{
if (handshake_state->tag != type)
return -1;
+ memset(params_out, 0, sizeof(*params_out));
+
switch (type) {
case ONION_HANDSHAKE_TYPE_TAP:
if (reply_len != TAP_ONIONSKIN_REPLY_LEN) {
@@ -303,6 +518,39 @@ onion_skin_client_handshake(int type,
tor_free(keys_tmp);
}
return 0;
+ case ONION_HANDSHAKE_TYPE_NTOR_V3: {
+ size_t keys_tmp_len = keys_out_len + DIGEST_LEN;
+ uint8_t *keys_tmp = tor_malloc(keys_tmp_len);
+ uint8_t *server_msg = NULL;
+ size_t server_msg_len = 0;
+ int r = onion_ntor3_client_handshake(
+ handshake_state->u.ntor3,
+ reply, reply_len,
+ NTOR3_VERIFICATION_ARGS,
+ keys_tmp, keys_tmp_len,
+ &server_msg, &server_msg_len);
+ if (r < 0) {
+ tor_free(keys_tmp);
+ tor_free(server_msg);
+ return -1;
+ }
+
+ if (negotiate_v3_ntor_client_circ_params(server_msg,
+ server_msg_len,
+ params_out) < 0) {
+ tor_free(keys_tmp);
+ tor_free(server_msg);
+ return -1;
+ }
+ tor_free(server_msg);
+
+ memcpy(keys_out, keys_tmp, keys_out_len);
+ memcpy(rend_authenticator_out, keys_tmp + keys_out_len, DIGEST_LEN);
+ memwipe(keys_tmp, 0, keys_tmp_len);
+ tor_free(keys_tmp);
+
+ return 0;
+ }
default:
log_warn(LD_BUG, "called with unknown handshake state type %d", type);
tor_fragile_assert();
diff --git a/src/core/crypto/onion_crypto.h b/src/core/crypto/onion_crypto.h
index 2665d326a3..cb0188ff54 100644
--- a/src/core/crypto/onion_crypto.h
+++ b/src/core/crypto/onion_crypto.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -12,8 +12,11 @@
#ifndef TOR_ONION_CRYPTO_H
#define TOR_ONION_CRYPTO_H
+#include "lib/crypt_ops/crypto_ed25519.h"
+
typedef struct server_onion_keys_t {
uint8_t my_identity[DIGEST_LEN];
+ ed25519_public_key_t my_ed_identity;
crypto_pk_t *onion_key;
crypto_pk_t *last_onion_key;
struct di_digest256_map_t *curve25519_key_map;
@@ -22,21 +25,37 @@ typedef struct server_onion_keys_t {
void onion_handshake_state_release(onion_handshake_state_t *state);
+/**
+ * Parameters negotiated as part of a circuit handshake.
+ */
+typedef struct circuit_params_t {
+ /** Is true if congestion control is enabled in consensus or param,
+ * as per congestion_control_enabled() result. */
+ bool cc_enabled;
+ /** The number of cells in a sendme increment. Only used if cc_enabled=1. */
+ uint8_t sendme_inc_cells;
+} circuit_params_t;
+
int onion_skin_create(int type,
const extend_info_t *node,
onion_handshake_state_t *state_out,
- uint8_t *onion_skin_out);
+ uint8_t *onion_skin_out,
+ size_t onion_skin_out_maxlen);
int onion_skin_server_handshake(int type,
const uint8_t *onion_skin, size_t onionskin_len,
const server_onion_keys_t *keys,
+ const circuit_params_t *ns_params,
uint8_t *reply_out,
+ size_t reply_out_maxlen,
uint8_t *keys_out, size_t key_out_len,
- uint8_t *rend_nonce_out);
+ uint8_t *rend_nonce_out,
+ circuit_params_t *negotiated_params_out);
int onion_skin_client_handshake(int type,
const onion_handshake_state_t *handshake_state,
const uint8_t *reply, size_t reply_len,
uint8_t *keys_out, size_t key_out_len,
uint8_t *rend_authenticator_out,
+ circuit_params_t *negotiated_params_out,
const char **msg_out);
server_onion_keys_t *server_onion_keys_new(void);
diff --git a/src/core/crypto/onion_fast.c b/src/core/crypto/onion_fast.c
index d760549325..4e454fd402 100644
--- a/src/core/crypto/onion_fast.c
+++ b/src/core/crypto/onion_fast.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/core/crypto/onion_fast.h b/src/core/crypto/onion_fast.h
index da983a56d9..742e2ef7d4 100644
--- a/src/core/crypto/onion_fast.h
+++ b/src/core/crypto/onion_fast.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/core/crypto/onion_ntor.c b/src/core/crypto/onion_ntor.c
index 5a77230d02..092fced1cb 100644
--- a/src/core/crypto/onion_ntor.c
+++ b/src/core/crypto/onion_ntor.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2020, The Tor Project, Inc. */
+/* Copyright (c) 2012-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/core/crypto/onion_ntor.h b/src/core/crypto/onion_ntor.h
index 9473409e40..82eb6c3ad9 100644
--- a/src/core/crypto/onion_ntor.h
+++ b/src/core/crypto/onion_ntor.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2020, The Tor Project, Inc. */
+/* Copyright (c) 2012-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/core/crypto/onion_ntor_v3.c b/src/core/crypto/onion_ntor_v3.c
new file mode 100644
index 0000000000..491c69cf8d
--- /dev/null
+++ b/src/core/crypto/onion_ntor_v3.c
@@ -0,0 +1,760 @@
+/* Copyright (c) 2001 Matej Pfajfar.
+ * Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * @file onion_ntor_v3.c
+ * @brief Implements the version 3 ntor handshake as first specified in
+ * proposal 332.
+ *
+ * The v3 ntor handshake differs from the earlier versions (ntor and hs-ntor)
+ * primarily in that it allows the client to send an authenticated encrypted
+ * message as part of its onion skin, and allows the relay to send and
+ * encrypted authenticated reply as part of its response.
+ *
+ * It also takes a "verification string" -- the handshake cannot succeed
+ * unless both parties use the same value for their verification stream.
+ **/
+
+#define ONION_NTOR_V3_PRIVATE
+
+#include "orconfig.h"
+#include "core/crypto/onion_ntor_v3.h"
+
+#include "lib/arch/bytes.h"
+#include "lib/crypt_ops/crypto_digest.h"
+#include "lib/crypt_ops/crypto_rand.h"
+#include "lib/crypt_ops/crypto_util.h"
+#include "lib/ctime/di_ops.h"
+#include "lib/log/util_bug.h"
+
+#include <string.h>
+
+/* Parameters used to keep the outputs of this handshake from colliding with
+ * others. These are defined in the specification. */
+#define PROTOID "ntor3-curve25519-sha3_256-1"
+#define TWEAK(A) (PROTOID ":" A)
+
+#define T_MSGKDF TWEAK("kdf_phase1")
+#define T_MSGMAC TWEAK("msg_mac")
+#define T_KEY_SEED TWEAK("key_seed")
+#define T_VERIFY TWEAK("verify")
+#define T_FINAL TWEAK("kdf_final")
+#define T_AUTH TWEAK("auth_final")
+
+/**
+ * Add @a len bytes of @a data as input to the provided @a xof.
+ *
+ * (This is provided just for abbreviation).
+ **/
+#define xof_add(xof, data, len) crypto_xof_add_bytes((xof), (data), (len))
+/**
+ * Add @a len bytes of @a data as input to the provided @a xof,
+ * prefixed with an encoding of the length.
+ *
+ * This is equivalent to ENCAP(data) in the spec.
+ **/
+static void
+xof_add_encap(crypto_xof_t *xof, const uint8_t *data, size_t len)
+{
+ uint64_t len64 = tor_htonll(len);
+ xof_add(xof, (uint8_t *)(&len64), 8);
+ xof_add(xof, data, len);
+}
+/**
+ * Add an encapsulated tweak to the provided xof.
+ **/
+#define xof_add_tweak(d, s) xof_add_encap((d), (const uint8_t *)(s), strlen(s))
+
+/**
+ * Add @a len bytes of @a data to the provided @a digest.
+ *
+ * This is provided as an abbreviation, and to get the types right.
+ **/
+static void
+d_add(crypto_digest_t *digest, const uint8_t *data, size_t len)
+{
+ crypto_digest_add_bytes(digest, (const char *)data, len);
+}
+/**
+ * Add @a len bytes of @a data to the provided @a digest, prefixed
+ * with the encoded length.
+ *
+ * This is equivalent to ENCAP(data) from the spec.
+ **/
+static void
+d_add_encap(crypto_digest_t *digest, const uint8_t *data, size_t len)
+{
+ uint64_t len64 = tor_htonll(len);
+ d_add(digest, (const uint8_t *)(&len64), 8);
+ d_add(digest, data, len);
+}
+/**
+ * Add an encapsulated tweak to the provided digest.
+ **/
+#define d_add_tweak(d, s) d_add_encap((d), (const uint8_t *)(s), strlen(s))
+
+/**
+ * Helper: copy @a len bytes of @a data onto *@a ptr, and advance @a ptr
+ * forward by @a len bytes.
+ *
+ * Asserts that @a ptr will not be advanced beyond @a endptr.
+ **/
+static void
+push(uint8_t **ptr, const uint8_t *endptr, const uint8_t *data, size_t len)
+{
+ size_t remaining = endptr - *ptr;
+ tor_assert(len <= remaining);
+ memcpy(*ptr, data, len);
+ *ptr += len;
+}
+
+/**
+ * Helper: Drop storage held by @a state, after wiping it.
+ **/
+void
+ntor3_handshake_state_free_(ntor3_handshake_state_t *state)
+{
+ if (!state)
+ return;
+
+ memwipe(state, 0, sizeof(*state));
+ tor_free(state);
+}
+
+/**
+ * Perform a client-side v3 ntor handshake with a given relay.
+ *
+ * As inputs this function takes the relay's Ed25519 identity (@a relay_id),
+ * the relay's current ntor onion key (@a relay_key), a verification string
+ * (@a verification_len bytes at @a verification), and a message to send
+ * as part of the handshake (@a message_len bytes at @a message).
+ *
+ * The message will be encrypted and authenticated to the relay, but will not
+ * receive the same forward secrecy as the rest of the handshake. We should
+ * not put any super-confidential data in it.
+ *
+ * The handshake will only succeed if the relay uses the same verification
+ * string as we are using.
+ *
+ * As outputs, this function returns 0 on success and -1 on failure. On
+ * success, it sets @a onion_skin_out and @a onion_skin_len_out to a newly
+ * allocated handshake message that the client can send as part of its CREATE2
+ * or EXTEND2 cell. It also sets it sets @a handshake_state_out to a newly
+ * allocated handshake state object; the client needs to use this object to
+ * process the relay's eventual reply.
+ **/
+int
+onion_skin_ntor3_create(const ed25519_public_key_t *relay_id,
+ const curve25519_public_key_t *relay_key,
+ const uint8_t *verification,
+ const size_t verification_len,
+ const uint8_t *message,
+ const size_t message_len,
+ ntor3_handshake_state_t **handshake_state_out,
+ uint8_t **onion_skin_out,
+ size_t *onion_skin_len_out)
+{
+ curve25519_keypair_t client_keypair;
+ if (curve25519_keypair_generate(&client_keypair, 0) < 0) {
+ return -1;
+ }
+ int r = onion_skin_ntor3_create_nokeygen(
+ &client_keypair,
+ relay_id,
+ relay_key,
+ verification,
+ verification_len,
+ message,
+ message_len,
+ handshake_state_out,
+ onion_skin_out,
+ onion_skin_len_out);
+ memwipe(&client_keypair, 0, sizeof(client_keypair));
+ return r;
+}
+
+/**
+ * Like onion_skin_ntor3_create, but do not generate a new ephemeral keypair.
+ * Instead, take the ephemeral keypair (x,X) from @a client_keypair.
+ *
+ * (Having a separate function for this lets us test the code for correct
+ * behavior.)
+ **/
+STATIC int
+onion_skin_ntor3_create_nokeygen(
+ const curve25519_keypair_t *client_keypair,
+ const ed25519_public_key_t *relay_id,
+ const curve25519_public_key_t *relay_key,
+ const uint8_t *verification,
+ const size_t verification_len,
+ const uint8_t *message,
+ const size_t message_len,
+ ntor3_handshake_state_t **handshake_state_out,
+ uint8_t **onion_skin_out,
+ size_t *onion_skin_len_out)
+{
+ *handshake_state_out = NULL;
+ *onion_skin_out = NULL;
+ *onion_skin_len_out = 0;
+
+ // Set up the handshake state object.
+ *handshake_state_out = tor_malloc_zero(sizeof(ntor3_handshake_state_t));
+ memcpy(&(*handshake_state_out)->client_keypair, client_keypair,
+ sizeof(*client_keypair));
+ memcpy(&(*handshake_state_out)->relay_id, relay_id, sizeof(*relay_id));
+ memcpy(&(*handshake_state_out)->relay_key, relay_key, sizeof(*relay_key));
+
+ // Perform the first DH handshake.
+ curve25519_handshake((*handshake_state_out)->bx,
+ &client_keypair->seckey, relay_key);
+ if (safe_mem_is_zero((*handshake_state_out)->bx, CURVE25519_OUTPUT_LEN)) {
+ // Okay to return early here, since our behavior here doesn't
+ // cause a visible timing sidechannel.
+ return -1;
+ }
+
+ // Compute phase1_keys.
+ uint8_t enc_key[CIPHER256_KEY_LEN];
+ uint8_t mac_key[DIGEST256_LEN];
+ {
+ crypto_xof_t *xof = crypto_xof_new();
+ // secret_input_phase1 = Bx | ID | X | B | PROTOID | ENCAP(VER)
+ xof_add_tweak(xof, T_MSGKDF);
+ xof_add(xof, (*handshake_state_out)->bx, CURVE25519_OUTPUT_LEN);
+ xof_add(xof, relay_id->pubkey, ED25519_PUBKEY_LEN);
+ xof_add(xof, client_keypair->pubkey.public_key, CURVE25519_PUBKEY_LEN);
+ xof_add(xof, relay_key->public_key, CURVE25519_PUBKEY_LEN);
+ xof_add(xof, (const uint8_t *)PROTOID, strlen(PROTOID));
+ xof_add_encap(xof, verification, verification_len);
+ crypto_xof_squeeze_bytes(xof, enc_key, sizeof(enc_key));
+ crypto_xof_squeeze_bytes(xof, mac_key, sizeof(mac_key));
+ crypto_xof_free(xof);
+ }
+
+ // Compute encrypted message.
+ uint8_t *encrypted_message = tor_memdup(message, message_len);
+ {
+ crypto_cipher_t *c =
+ crypto_cipher_new_with_bits((const char *)enc_key, 256);
+ crypto_cipher_crypt_inplace(c, (char *)encrypted_message, message_len);
+ crypto_cipher_free(c);
+ }
+
+ // Compute the MAC value.
+ {
+ crypto_digest_t *m = crypto_digest256_new(DIGEST_SHA3_256);
+ d_add_tweak(m, T_MSGMAC);
+ d_add_encap(m, mac_key, sizeof(mac_key));
+ d_add(m, relay_id->pubkey, ED25519_PUBKEY_LEN);
+ d_add(m, relay_key->public_key, CURVE25519_PUBKEY_LEN);
+ d_add(m, client_keypair->pubkey.public_key, CURVE25519_PUBKEY_LEN);
+ d_add(m, encrypted_message, message_len);
+ crypto_digest_get_digest(m,
+ (char *)(*handshake_state_out)->msg_mac,
+ DIGEST256_LEN);
+ crypto_digest_free(m);
+ }
+
+ // Build the onionskin.
+ *onion_skin_len_out = (ED25519_PUBKEY_LEN + CURVE25519_PUBKEY_LEN*2 +
+ DIGEST256_LEN + message_len);
+ *onion_skin_out = tor_malloc(*onion_skin_len_out);
+ {
+ uint8_t *ptr = *onion_skin_out, *end = ptr + *onion_skin_len_out;
+
+ push(&ptr, end, relay_id->pubkey, ED25519_PUBKEY_LEN);
+ push(&ptr, end, relay_key->public_key, CURVE25519_PUBKEY_LEN);
+ push(&ptr, end, client_keypair->pubkey.public_key, CURVE25519_PUBKEY_LEN);
+ push(&ptr, end, encrypted_message, message_len);
+ push(&ptr, end, (*handshake_state_out)->msg_mac, DIGEST256_LEN);
+ tor_assert(ptr == end);
+ }
+
+ memwipe(&enc_key, 0, sizeof(enc_key));
+ memwipe(&mac_key, 0, sizeof(mac_key));
+ memwipe(encrypted_message, 0, message_len);
+ tor_free(encrypted_message);
+
+ return 0;
+}
+
+/**
+ * Complete a client-side v3 ntor handshake.
+ *
+ * Takes a @a handshake_state returned earlier by `onion_skin_ntor3_create()`,
+ * and the relay's reply to that handshake (@a reply_len bytes at @a
+ * handshake_reply). Also takes a verification string (@a verification_len
+ * bytes at @a verification).
+ *
+ * Returns 0 on success and -1 on failure. On success, generates @a key_len
+ * bytes of key material into the provided @a keys_out buffer, and sets @a
+ * message_out to the message that the relay sent in reply to our message (and
+ * sets @a message_out_len to that message's length).
+ **/
+int
+onion_ntor3_client_handshake(const ntor3_handshake_state_t *handshake_state,
+ const uint8_t *handshake_reply,
+ size_t reply_len,
+ const uint8_t *verification,
+ size_t verification_len,
+ uint8_t *keys_out,
+ size_t keys_out_len,
+ uint8_t **message_out,
+ size_t *message_len_out)
+{
+ *message_out = NULL;
+ *message_len_out = 0;
+
+ int problems = 0;
+
+ // Parse the relay's message.
+ curve25519_public_key_t relay_Y;
+ uint8_t relay_auth[DIGEST256_LEN];
+ size_t encrypted_msg_len;
+ const uint8_t *encrypted_msg;
+ {
+ if (reply_len < CURVE25519_PUBKEY_LEN + DIGEST256_LEN) {
+ // Okay to return early here, since the message is completely
+ // ill-formed, so we can't leak anything.
+ ++problems;
+ goto done;
+ }
+ encrypted_msg_len = reply_len - (CURVE25519_PUBKEY_LEN + DIGEST256_LEN);
+
+ memcpy(&relay_Y.public_key, handshake_reply, CURVE25519_PUBKEY_LEN);
+ handshake_reply += CURVE25519_PUBKEY_LEN;
+ memcpy(&relay_auth, handshake_reply, DIGEST256_LEN);
+ handshake_reply += DIGEST256_LEN;
+ encrypted_msg = handshake_reply;
+ }
+
+ // Finish the second diffie hellman handshake.
+ uint8_t yx[CURVE25519_OUTPUT_LEN];
+ curve25519_handshake(yx, &handshake_state->client_keypair.seckey, &relay_Y);
+ problems |= safe_mem_is_zero(yx, sizeof(yx));
+
+ // Compute two tweaked hashes of secret_input.
+ uint8_t key_seed[DIGEST256_LEN], verify[DIGEST256_LEN];
+ {
+ crypto_digest_t *ks = crypto_digest256_new(DIGEST_SHA3_256);
+ crypto_digest_t *v = crypto_digest256_new(DIGEST_SHA3_256);
+ d_add_tweak(ks, T_KEY_SEED);
+ d_add_tweak(v, T_VERIFY);
+#define ADD2(s,len) STMT_BEGIN { \
+ d_add(ks, (s),(len)); d_add(v, (s), (len)); \
+ } STMT_END
+#define ADD2_ENCAP(s,len) STMT_BEGIN { \
+ d_add_encap(ks, (s),(len)); d_add_encap(v, (s), (len)); \
+ } STMT_END
+
+ ADD2(yx, sizeof(yx));
+ ADD2(handshake_state->bx, sizeof(handshake_state->bx));
+ ADD2(handshake_state->relay_id.pubkey, ED25519_PUBKEY_LEN);
+ ADD2(handshake_state->relay_key.public_key, CURVE25519_PUBKEY_LEN);
+ ADD2(handshake_state->client_keypair.pubkey.public_key,
+ CURVE25519_PUBKEY_LEN);
+ ADD2(relay_Y.public_key, CURVE25519_PUBKEY_LEN);
+ ADD2((const uint8_t *)PROTOID, strlen(PROTOID));
+ ADD2_ENCAP(verification, verification_len);
+
+ crypto_digest_get_digest(ks, (char*) key_seed, DIGEST256_LEN);
+ crypto_digest_get_digest(v, (char*) verify, DIGEST256_LEN);
+ crypto_digest_free(ks);
+ crypto_digest_free(v);
+ }
+
+ // compute expected auth value.
+ uint8_t auth_computed[DIGEST256_LEN];
+ {
+ crypto_digest_t *d = crypto_digest256_new(DIGEST_SHA3_256);
+ d_add_tweak(d, T_AUTH);
+ d_add(d, verify, sizeof(verify));
+ d_add(d, handshake_state->relay_id.pubkey, ED25519_PUBKEY_LEN);
+ d_add(d, handshake_state->relay_key.public_key, CURVE25519_PUBKEY_LEN);
+ d_add(d, relay_Y.public_key, CURVE25519_PUBKEY_LEN);
+ d_add(d, handshake_state->client_keypair.pubkey.public_key,
+ CURVE25519_PUBKEY_LEN);
+ d_add(d, handshake_state->msg_mac, DIGEST256_LEN);
+ d_add_encap(d, encrypted_msg, encrypted_msg_len);
+ d_add(d, (const uint8_t*)PROTOID, strlen(PROTOID));
+ d_add(d, (const uint8_t*)"Server", strlen("Server"));
+ crypto_digest_get_digest(d, (char *)auth_computed, DIGEST256_LEN);
+ crypto_digest_free(d);
+ }
+
+ // Check authentication value.
+ problems |= tor_memneq(auth_computed, relay_auth, DIGEST256_LEN);
+
+ // Compute keystream, decrypt message, and return.
+ *message_out = tor_malloc(encrypted_msg_len);
+ *message_len_out = encrypted_msg_len;
+ uint8_t enc_key[CIPHER256_KEY_LEN];
+ {
+ crypto_xof_t *xof = crypto_xof_new();
+ xof_add_tweak(xof, T_FINAL);
+ xof_add(xof, key_seed, sizeof(key_seed));
+ crypto_xof_squeeze_bytes(xof, enc_key, sizeof(enc_key));
+ crypto_xof_squeeze_bytes(xof, (uint8_t *)keys_out, keys_out_len);
+ crypto_xof_free(xof);
+
+ crypto_cipher_t *c =
+ crypto_cipher_new_with_bits((const char *)enc_key, 256);
+ crypto_cipher_decrypt(c, (char *)*message_out,
+ (const char *)encrypted_msg, encrypted_msg_len);
+ crypto_cipher_free(c);
+ }
+
+ done:
+ memwipe(&relay_Y, 0, sizeof(relay_Y));
+ memwipe(&relay_auth, 0, sizeof(relay_auth));
+ memwipe(&yx, 0, sizeof(yx));
+ memwipe(key_seed, 0, sizeof(key_seed));
+ memwipe(verify, 0, sizeof(verify));
+ memwipe(enc_key, 0, sizeof(enc_key));
+ if (problems) {
+ if (*message_out) {
+ memwipe(*message_out, 0, *message_len_out);
+ tor_free(*message_out); // Sets it to NULL.
+ }
+ *message_len_out = 0;
+ crypto_rand((char*)keys_out, keys_out_len); // In case bad code uses it.
+ return -1;
+ }
+
+ return 0;
+}
+
+/**
+ * Wipe a server handshake state, and release the storage it holds.
+ **/
+void
+ntor3_server_handshake_state_free_(ntor3_server_handshake_state_t *state)
+{
+ if (state == NULL)
+ return;
+
+ memwipe(state, 0, sizeof(ntor3_server_handshake_state_t));
+ tor_free(state);
+}
+
+/**
+ * As a relay, start handling a client's v3 ntor handshake.
+ *
+ * This function performs the _first half_ of the handshake, up to the point
+ * where the client's message is decoded. After calling it, the relay should
+ * decide how and whether to reply to the client's message, compose its reply,
+ * and call `onion_skin_ntor3_server_handshake_part2`.
+ *
+ * It takes as input a map of the relay's known onion keys in @a private_keys,
+ * along with a fake @a junk_key to use if there is a complete mismatch. It
+ * takes the relay's ed25519 identity in @a my_id, along with the client's
+ * handshake message (@a client_handshake_len bytes in @a client_handshake),
+ * and a verification string (@a verification_len bytes in @a verification).
+ *
+ * Return 0 on success, and -1 on failure. On success, sets @a
+ * client_message_out to a newly allocated string holding the plaintext of the
+ * message that the client sent as part of its handshake, and @a
+ * client_message_out_len to its length. Also sets @a state_out to a newly
+ * allocated state object holding the intermediate computation for this
+ * handshake.
+ **/
+int
+onion_skin_ntor3_server_handshake_part1(
+ const di_digest256_map_t *private_keys,
+ const curve25519_keypair_t *junk_key,
+ const ed25519_public_key_t *my_id,
+ const uint8_t *client_handshake,
+ size_t client_handshake_len,
+ const uint8_t *verification,
+ size_t verification_len,
+ uint8_t **client_message_out,
+ size_t *client_message_len_out,
+ ntor3_server_handshake_state_t **state_out)
+{
+ *client_message_out = NULL;
+ *client_message_len_out = 0;
+ *state_out = NULL;
+
+ int problems = 0;
+
+ // Initialize state.
+ (*state_out) = tor_malloc_zero(sizeof(ntor3_server_handshake_state_t));
+ memcpy(&(*state_out)->my_id, my_id, sizeof(*my_id));
+
+ const uint8_t *wanted_id; // [ED25519_PUBKEY_LEN]
+ const uint8_t *wanted_key; // [CURVE25519_PUBKEY_LEN]
+ const uint8_t *encrypted_message;
+ size_t encrypted_message_len;
+ // Unpack the client handshake.
+ {
+ const uint8_t *ptr = client_handshake;
+ const uint8_t *end = ptr + client_handshake_len;
+
+ if (client_handshake_len <
+ ED25519_PUBKEY_LEN + CURVE25519_PUBKEY_LEN * 2 + DIGEST256_LEN) {
+ // Okay to end early; the client knows this is unparseable already.
+ ++problems;
+ goto done;
+ }
+ wanted_id = ptr;
+ ptr += ED25519_PUBKEY_LEN;
+ wanted_key = ptr;
+ ptr += CURVE25519_PUBKEY_LEN;
+ memcpy((*state_out)->client_key.public_key, ptr, CURVE25519_PUBKEY_LEN);
+ ptr += CURVE25519_PUBKEY_LEN;
+ size_t remaining = (end-ptr);
+ if (BUG(remaining < DIGEST256_LEN)) {
+ // Okay to end early; this is a bug.
+ ++problems;
+ goto done;
+ }
+ encrypted_message = ptr;
+ encrypted_message_len = remaining - DIGEST256_LEN;
+ ptr += encrypted_message_len;
+ remaining = (end-ptr);
+ tor_assert(remaining == DIGEST256_LEN);
+ memcpy((*state_out)->msg_mac, ptr, DIGEST256_LEN);
+ }
+
+ // Check the identity.
+ problems |= tor_memneq(my_id->pubkey, wanted_id, ED25519_PUBKEY_LEN);
+
+ // Find the correct keypair.
+ const curve25519_keypair_t *keypair =
+ dimap_search(private_keys, wanted_key, (void *)junk_key);
+ tor_assert(keypair);
+ memcpy(&(*state_out)->my_key, &keypair->pubkey,
+ sizeof(curve25519_public_key_t));
+
+ // Do the first diffie hellman handshake.
+ curve25519_handshake((*state_out)->xb,
+ &keypair->seckey, &(*state_out)->client_key);
+ problems |= safe_mem_is_zero((*state_out)->xb, CURVE25519_OUTPUT_LEN);
+
+ // Derive the encryption and mac keys
+ uint8_t enc_key[CIPHER256_KEY_LEN], mac_key[DIGEST256_LEN];
+ {
+ crypto_xof_t *xof = crypto_xof_new();
+ xof_add_tweak(xof, T_MSGKDF);
+ xof_add(xof, (*state_out)->xb, CURVE25519_OUTPUT_LEN);
+ xof_add(xof, wanted_id, ED25519_PUBKEY_LEN);
+ xof_add(xof, (*state_out)->client_key.public_key, CURVE25519_PUBKEY_LEN);
+ xof_add(xof, keypair->pubkey.public_key, CURVE25519_PUBKEY_LEN);
+ xof_add(xof, (const uint8_t *)PROTOID, strlen(PROTOID));
+ xof_add_encap(xof, verification, verification_len);
+ crypto_xof_squeeze_bytes(xof, enc_key, sizeof(enc_key));
+ crypto_xof_squeeze_bytes(xof, mac_key, sizeof(mac_key));
+ crypto_xof_free(xof);
+ }
+
+ // Check the MAC.
+ uint8_t computed_mac[DIGEST256_LEN];
+ {
+ crypto_digest_t *d = crypto_digest256_new(DIGEST_SHA3_256);
+ d_add_tweak(d, T_MSGMAC);
+ d_add_encap(d, mac_key, sizeof(mac_key));
+ d_add(d, my_id->pubkey, ED25519_PUBKEY_LEN);
+ d_add(d, keypair->pubkey.public_key, CURVE25519_PUBKEY_LEN);
+ d_add(d, (*state_out)->client_key.public_key, CURVE25519_PUBKEY_LEN);
+ d_add(d, encrypted_message, encrypted_message_len);
+ crypto_digest_get_digest(d, (char *)computed_mac, DIGEST256_LEN);
+ crypto_digest_free(d);
+ }
+
+ problems |= tor_memneq((*state_out)->msg_mac, computed_mac, DIGEST256_LEN);
+
+ // Decrypt the message.
+ *client_message_out = tor_malloc(encrypted_message_len);
+ *client_message_len_out = encrypted_message_len;
+ {
+ crypto_cipher_t *c =
+ crypto_cipher_new_with_bits((const char *)enc_key, 256);
+ crypto_cipher_decrypt(c, (char *)*client_message_out,
+ (const char *)encrypted_message,
+ encrypted_message_len);
+ crypto_cipher_free(c);
+ }
+
+ done:
+ memwipe(enc_key, 0, sizeof(enc_key));
+ memwipe(mac_key, 0, sizeof(mac_key));
+ memwipe(computed_mac, 0, sizeof(computed_mac));
+ if (problems) {
+ if (*client_message_out) {
+ memwipe(*client_message_out, 0, *client_message_len_out);
+ tor_free(*client_message_out); // Sets it to NULL.
+ }
+ *client_message_len_out = 0;
+ ntor3_server_handshake_state_free(*state_out);
+ return -1;
+ }
+
+ return 0;
+}
+
+/**
+ * Finish the relay side of an ntor v3 handshake.
+ *
+ * The relay calls this function after it has decided to respond to the
+ * client's original encrypted message. This function receives the relay's
+ * message in @a server_message and its length in @a server_message_len, and
+ * completes the handshake.
+ *
+ * Returns 0 on success and -1 on failure. On success, stores the newly
+ * allocated handshake for the relay to send in @a handshake_out, and its
+ * length in @a handshake_len_out. Stores @a keys_out_len bytes of generated
+ * keys in the provided buffer at @a keys_out.
+ **/
+int
+onion_skin_ntor3_server_handshake_part2(
+ const ntor3_server_handshake_state_t *state,
+ const uint8_t *verification,
+ size_t verification_len,
+ const uint8_t *server_message,
+ size_t server_message_len,
+ uint8_t **handshake_out,
+ size_t *handshake_len_out,
+ uint8_t *keys_out,
+ size_t keys_out_len)
+{
+ curve25519_keypair_t relay_keypair;
+ if (curve25519_keypair_generate(&relay_keypair, 0) < 0) {
+ return -1;
+ }
+ int r = onion_skin_ntor3_server_handshake_part2_nokeygen(
+ &relay_keypair,
+ state,
+ verification,
+ verification_len,
+ server_message,
+ server_message_len,
+ handshake_out,
+ handshake_len_out,
+ keys_out,
+ keys_out_len);
+ memwipe(&relay_keypair, 0, sizeof(relay_keypair));
+ return r;
+}
+
+/**
+ * Like `onion_skin_ntor3_server_handshake_part2`, but do not generate
+ * an ephemeral (y,Y) keypair.
+ *
+ * Instead, this function takes that keypair as @a relay_keypair_y.
+ *
+ * (Having a separate function for this lets us test the code for correct
+ * behavior.)
+ **/
+STATIC int
+onion_skin_ntor3_server_handshake_part2_nokeygen(
+ const curve25519_keypair_t *relay_keypair_y,
+ const ntor3_server_handshake_state_t *state,
+ const uint8_t *verification,
+ size_t verification_len,
+ const uint8_t *server_message,
+ size_t server_message_len,
+ uint8_t **handshake_out,
+ size_t *handshake_len_out,
+ uint8_t *keys_out,
+ size_t keys_out_len)
+{
+ *handshake_out = NULL;
+ *handshake_len_out = 0;
+
+ int problems = 0;
+
+ // Second diffie-hellman handshake.
+ uint8_t xy[CURVE25519_OUTPUT_LEN];
+ curve25519_handshake(xy, &relay_keypair_y->seckey, &state->client_key);
+ problems |= safe_mem_is_zero(xy, sizeof(xy));
+
+ // Compute two tweaked hashes of secret_input.
+ uint8_t key_seed[DIGEST256_LEN], verify[DIGEST256_LEN];
+ {
+ crypto_digest_t *ks = crypto_digest256_new(DIGEST_SHA3_256);
+ crypto_digest_t *v = crypto_digest256_new(DIGEST_SHA3_256);
+ d_add_tweak(ks, T_KEY_SEED);
+ d_add_tweak(v, T_VERIFY);
+ ADD2(xy, sizeof(xy));
+ ADD2(state->xb, sizeof(state->xb));
+ ADD2(state->my_id.pubkey, ED25519_PUBKEY_LEN);
+ ADD2(state->my_key.public_key, CURVE25519_PUBKEY_LEN);
+ ADD2(state->client_key.public_key, CURVE25519_PUBKEY_LEN);
+ ADD2(relay_keypair_y->pubkey.public_key, CURVE25519_PUBKEY_LEN);
+ ADD2((const uint8_t *)PROTOID, strlen(PROTOID));
+ ADD2_ENCAP(verification, verification_len);
+ crypto_digest_get_digest(ks, (char*) key_seed, DIGEST256_LEN);
+ crypto_digest_get_digest(v, (char*) verify, DIGEST256_LEN);
+ crypto_digest_free(ks);
+ crypto_digest_free(v);
+ }
+
+ // Compute enc_key and keystream.
+ uint8_t enc_key[CIPHER256_KEY_LEN];
+ {
+ crypto_xof_t *xof = crypto_xof_new();
+ xof_add_tweak(xof, T_FINAL);
+ xof_add(xof, key_seed, sizeof(key_seed));
+ crypto_xof_squeeze_bytes(xof, enc_key, sizeof(enc_key));
+ crypto_xof_squeeze_bytes(xof, keys_out, keys_out_len);
+ crypto_xof_free(xof);
+ }
+
+ // Encrypt message.
+ uint8_t *encrypted_message = tor_memdup(server_message, server_message_len);
+ {
+ crypto_cipher_t *c =
+ crypto_cipher_new_with_bits((const char *)enc_key, 256);
+ crypto_cipher_crypt_inplace(
+ c, (char *)encrypted_message, server_message_len);
+ crypto_cipher_free(c);
+ }
+
+ // Compute AUTH digest.
+ uint8_t auth[DIGEST256_LEN];
+ {
+ crypto_digest_t *d = crypto_digest256_new(DIGEST_SHA3_256);
+ d_add_tweak(d, T_AUTH);
+ d_add(d, verify, sizeof(verify));
+ d_add(d, state->my_id.pubkey, ED25519_PUBKEY_LEN);
+ d_add(d, state->my_key.public_key, CURVE25519_PUBKEY_LEN);
+ d_add(d, relay_keypair_y->pubkey.public_key, CURVE25519_PUBKEY_LEN);
+ d_add(d, state->client_key.public_key, CURVE25519_PUBKEY_LEN);
+ d_add(d, state->msg_mac, DIGEST256_LEN);
+ d_add_encap(d, encrypted_message, server_message_len);
+ d_add(d, (const uint8_t*)PROTOID, strlen(PROTOID));
+ d_add(d, (const uint8_t*)"Server", strlen("Server"));
+ crypto_digest_get_digest(d, (char *)auth, DIGEST256_LEN);
+ crypto_digest_free(d);
+ }
+
+ // Compose the reply.
+ *handshake_len_out = CURVE25519_PUBKEY_LEN + DIGEST256_LEN +
+ server_message_len;
+ *handshake_out = tor_malloc(*handshake_len_out);
+ uint8_t *ptr = *handshake_out, *end = ptr + *handshake_len_out;
+ push(&ptr, end, relay_keypair_y->pubkey.public_key, CURVE25519_PUBKEY_LEN);
+ push(&ptr, end, auth, sizeof(auth));
+ push(&ptr, end, encrypted_message, server_message_len);
+ tor_assert(ptr == end);
+
+ // Clean up and return.
+ memwipe(xy, 0, sizeof(xy));
+ memwipe(key_seed, 0, sizeof(key_seed));
+ memwipe(verify, 0, sizeof(verify));
+ memwipe(enc_key, 0, sizeof(enc_key));
+ memwipe(encrypted_message, 0, server_message_len);
+ tor_free(encrypted_message);
+
+ if (problems) {
+ memwipe(*handshake_out, 0, *handshake_len_out);
+ tor_free(*handshake_out); // Sets it to NULL.
+ *handshake_len_out = 0;
+ crypto_rand((char*)keys_out, keys_out_len); // In case bad code uses it.
+ return -1;
+ }
+ return 0;
+}
diff --git a/src/core/crypto/onion_ntor_v3.h b/src/core/crypto/onion_ntor_v3.h
new file mode 100644
index 0000000000..4449eb237d
--- /dev/null
+++ b/src/core/crypto/onion_ntor_v3.h
@@ -0,0 +1,140 @@
+/* Copyright (c) 2001 Matej Pfajfar.
+ * Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * @file onion_ntor_v3.h
+ * @brief Header for core/crypto/onion_ntor_v3.c
+ **/
+
+#ifndef TOR_CORE_CRYPTO_ONION_NTOR_V3_H
+#define TOR_CORE_CRYPTO_ONION_NTOR_V3_H
+
+#include "lib/cc/torint.h"
+#include "lib/testsupport/testsupport.h"
+#include "lib/crypt_ops/crypto_cipher.h"
+#include "lib/crypt_ops/crypto_curve25519.h"
+#include "lib/crypt_ops/crypto_ed25519.h"
+#include "lib/malloc/malloc.h"
+
+/**
+ * Client-side state held while an ntor v3 handshake is in progress.
+ **/
+typedef struct ntor3_handshake_state_t ntor3_handshake_state_t;
+
+/**
+ * Server-side state held while the relay is handling a client's
+ * encapsulated message, before replying to the v3 handshake.
+ **/
+typedef struct ntor3_server_handshake_state_t ntor3_server_handshake_state_t;
+
+void ntor3_handshake_state_free_(ntor3_handshake_state_t *st);
+#define ntor3_handshake_state_free(ptr) \
+ FREE_AND_NULL(ntor3_handshake_state_t, ntor3_handshake_state_free_, (ptr))
+void ntor3_server_handshake_state_free_(ntor3_server_handshake_state_t *st);
+#define ntor3_server_handshake_state_free(ptr) \
+ FREE_AND_NULL(ntor3_server_handshake_state_t, \
+ ntor3_server_handshake_state_free_, (ptr))
+
+int onion_skin_ntor3_create(const ed25519_public_key_t *relay_id,
+ const curve25519_public_key_t *relay_key,
+ const uint8_t *verification,
+ const size_t verification_len,
+ const uint8_t *message,
+ const size_t message_len,
+ ntor3_handshake_state_t **handshake_state_out,
+ uint8_t **onion_skin_out,
+ size_t *onion_skin_len_out);
+
+int onion_ntor3_client_handshake(
+ const ntor3_handshake_state_t *handshake_state,
+ const uint8_t *handshake_reply,
+ size_t reply_len,
+ const uint8_t *verification,
+ size_t verification_len,
+ uint8_t *keys_out,
+ size_t keys_out_len,
+ uint8_t **message_out,
+ size_t *message_len_out);
+
+struct di_digest256_map_t;
+int onion_skin_ntor3_server_handshake_part1(
+ const struct di_digest256_map_t *private_keys,
+ const curve25519_keypair_t *junk_key,
+ const ed25519_public_key_t *my_id,
+ const uint8_t *client_handshake,
+ size_t client_handshake_len,
+ const uint8_t *verification,
+ size_t verification_len,
+ uint8_t **client_message_out,
+ size_t *client_message_len_out,
+ ntor3_server_handshake_state_t **state_out);
+
+int onion_skin_ntor3_server_handshake_part2(
+ const ntor3_server_handshake_state_t *state,
+ const uint8_t *verification,
+ size_t verification_len,
+ const uint8_t *server_message,
+ size_t server_message_len,
+ uint8_t **handshake_out,
+ size_t *handshake_len_out,
+ uint8_t *keys_out,
+ size_t keys_out_len);
+
+#ifdef ONION_NTOR_V3_PRIVATE
+struct ntor3_handshake_state_t {
+ /** Ephemeral (x,X) keypair. */
+ curve25519_keypair_t client_keypair;
+ /** Relay's ed25519 identity key (ID) */
+ ed25519_public_key_t relay_id;
+ /** Relay's public key (B) */
+ curve25519_public_key_t relay_key;
+ /** Shared secret (Bx). */
+ uint8_t bx[CURVE25519_OUTPUT_LEN];
+ /** MAC of the client's encrypted message data (MAC) */
+ uint8_t msg_mac[DIGEST256_LEN];
+};
+
+struct ntor3_server_handshake_state_t {
+ /** Relay's ed25519 identity key (ID) */
+ ed25519_public_key_t my_id;
+ /** Relay's public key (B) */
+ curve25519_public_key_t my_key;
+ /** Client's public ephemeral key (X). */
+ curve25519_public_key_t client_key;
+
+ /** Shared secret (Xb) */
+ uint8_t xb[CURVE25519_OUTPUT_LEN];
+ /** MAC of the client's encrypted message data */
+ uint8_t msg_mac[DIGEST256_LEN];
+};
+
+STATIC int onion_skin_ntor3_create_nokeygen(
+ const curve25519_keypair_t *client_keypair,
+ const ed25519_public_key_t *relay_id,
+ const curve25519_public_key_t *relay_key,
+ const uint8_t *verification,
+ const size_t verification_len,
+ const uint8_t *message,
+ const size_t message_len,
+ ntor3_handshake_state_t **handshake_state_out,
+ uint8_t **onion_skin_out,
+ size_t *onion_skin_len_out);
+
+STATIC int onion_skin_ntor3_server_handshake_part2_nokeygen(
+ const curve25519_keypair_t *relay_keypair_y,
+ const ntor3_server_handshake_state_t *state,
+ const uint8_t *verification,
+ size_t verification_len,
+ const uint8_t *server_message,
+ size_t server_message_len,
+ uint8_t **handshake_out,
+ size_t *handshake_len_out,
+ uint8_t *keys_out,
+ size_t keys_out_len);
+
+#endif
+
+#endif /* !defined(TOR_CORE_CRYPTO_ONION_NTOR_V3_H) */
diff --git a/src/core/crypto/onion_tap.c b/src/core/crypto/onion_tap.c
index 119f55f206..08ec3ec936 100644
--- a/src/core/crypto/onion_tap.c
+++ b/src/core/crypto/onion_tap.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/core/crypto/onion_tap.h b/src/core/crypto/onion_tap.h
index 78174b1fab..341270c981 100644
--- a/src/core/crypto/onion_tap.h
+++ b/src/core/crypto/onion_tap.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/core/crypto/relay_crypto.c b/src/core/crypto/relay_crypto.c
index 3e6167e0e1..92075d7118 100644
--- a/src/core/crypto/relay_crypto.c
+++ b/src/core/crypto/relay_crypto.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/core/crypto/relay_crypto.h b/src/core/crypto/relay_crypto.h
index 5e36c7678c..6256a100d7 100644
--- a/src/core/crypto/relay_crypto.h
+++ b/src/core/crypto/relay_crypto.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/core/mainloop/connection.c b/src/core/mainloop/connection.c
index c827af7a9a..cf25213cb1 100644
--- a/src/core/mainloop/connection.c
+++ b/src/core/mainloop/connection.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -106,7 +106,6 @@
#include "feature/relay/dns.h"
#include "feature/relay/ext_orport.h"
#include "feature/relay/routermode.h"
-#include "feature/rend/rendclient.h"
#include "feature/rend/rendcommon.h"
#include "feature/stats/connstats.h"
#include "feature/stats/rephist.h"
@@ -118,6 +117,7 @@
#include "lib/cc/ctassert.h"
#include "lib/sandbox/sandbox.h"
#include "lib/net/buffers_net.h"
+#include "lib/net/address.h"
#include "lib/tls/tortls.h"
#include "lib/evloop/compat_libevent.h"
#include "lib/compress/compress.h"
@@ -147,6 +147,8 @@
#include "feature/nodelist/routerinfo_st.h"
#include "core/or/socks_request_st.h"
+#include "core/or/congestion_control_flow.h"
+
/**
* On Windows and Linux we cannot reliably bind() a socket to an
* address and port if: 1) There's already a socket bound to wildcard
@@ -251,13 +253,13 @@ CONST_TO_LISTENER_CONN(const connection_t *c)
}
size_t
-connection_get_inbuf_len(connection_t *conn)
+connection_get_inbuf_len(const connection_t *conn)
{
return conn->inbuf ? buf_datalen(conn->inbuf) : 0;
}
size_t
-connection_get_outbuf_len(connection_t *conn)
+connection_get_outbuf_len(const connection_t *conn)
{
return conn->outbuf ? buf_datalen(conn->outbuf) : 0;
}
@@ -588,7 +590,6 @@ or_connection_new(int type, int socket_family)
/* If we aren't told an address for this connection, we should
* presume it isn't local, and should be rate-limited. */
TO_CONN(or_conn)->always_rate_limit_as_remote = 1;
- connection_or_set_ext_or_identifier(or_conn);
}
return or_conn;
@@ -613,6 +614,11 @@ entry_connection_new(int type, int socket_family)
entry_conn->entry_cfg.ipv4_traffic = 1;
else if (socket_family == AF_INET6)
entry_conn->entry_cfg.ipv6_traffic = 1;
+
+ /* Initialize the read token bucket to the maximum value which is the same as
+ * no rate limiting. */
+ token_bucket_rw_init(&ENTRY_TO_EDGE_CONN(entry_conn)->bucket, INT32_MAX,
+ INT32_MAX, monotime_coarse_get_stamp());
return entry_conn;
}
@@ -624,6 +630,10 @@ edge_connection_new(int type, int socket_family)
edge_connection_t *edge_conn = tor_malloc_zero(sizeof(edge_connection_t));
tor_assert(type == CONN_TYPE_EXIT);
connection_init(time(NULL), TO_CONN(edge_conn), type, socket_family);
+ /* Initialize the read token bucket to the maximum value which is the same as
+ * no rate limiting. */
+ token_bucket_rw_init(&edge_conn->bucket, INT32_MAX, INT32_MAX,
+ monotime_coarse_get_stamp());
return edge_conn;
}
@@ -647,6 +657,9 @@ listener_connection_new(int type, int socket_family)
listener_connection_t *listener_conn =
tor_malloc_zero(sizeof(listener_connection_t));
connection_init(time(NULL), TO_CONN(listener_conn), type, socket_family);
+ /* Listener connections aren't accounted for with note_connection() so do
+ * this explicitly so to count them. */
+ rep_hist_note_conn_opened(false, type, socket_family);
return listener_conn;
}
@@ -898,7 +911,6 @@ connection_free_minimal(connection_t *conn)
}
}
if (CONN_IS_EDGE(conn)) {
- rend_data_free(TO_EDGE_CONN(conn)->rend_data);
hs_ident_edge_conn_free(TO_EDGE_CONN(conn)->hs_ident);
}
if (conn->type == CONN_TYPE_CONTROL) {
@@ -927,7 +939,6 @@ connection_free_minimal(connection_t *conn)
tor_compress_free(dir_conn->compress_state);
dir_conn_clear_spool(dir_conn);
- rend_data_free(dir_conn->rend_data);
hs_ident_dir_conn_free(dir_conn->hs_ident);
if (dir_conn->guard_state) {
/* Cancel before freeing, if it's still there. */
@@ -948,8 +959,6 @@ connection_free_minimal(connection_t *conn)
connection_or_clear_identity(TO_OR_CONN(conn));
}
if (conn->type == CONN_TYPE_OR || conn->type == CONN_TYPE_EXT_OR) {
- connection_or_remove_from_ext_or_id_map(TO_OR_CONN(conn));
- tor_free(TO_OR_CONN(conn)->ext_or_conn_id);
tor_free(TO_OR_CONN(conn)->ext_or_auth_correct_client_hash);
tor_free(TO_OR_CONN(conn)->ext_or_transport);
}
@@ -1152,6 +1161,10 @@ connection_mark_for_close_internal_, (connection_t *conn,
* the number of seconds since last successful write, so
* we get our whole 15 seconds */
conn->timestamp_last_write_allowed = time(NULL);
+
+ /* Note the connection close. */
+ rep_hist_note_conn_closed(conn->from_listener, conn->type,
+ conn->socket_family);
}
/** Find each connection that has hold_open_until_flushed set to
@@ -1243,11 +1256,9 @@ create_unix_sockaddr(const char *listenaddress, char **readable_address,
}
#endif /* defined(HAVE_SYS_UN_H) || defined(RUNNING_DOXYGEN) */
-/** Warn that an accept or a connect has failed because we're running out of
- * TCP sockets we can use on current system. Rate-limit these warnings so
- * that we don't spam the log. */
+/* Log a rate-limited warning about resource exhaustion */
static void
-warn_too_many_conns(void)
+warn_about_resource_exhaution(void)
{
#define WARN_TOO_MANY_CONNS_INTERVAL (6*60*60)
static ratelim_t last_warned = RATELIM_INIT(WARN_TOO_MANY_CONNS_INTERVAL);
@@ -1262,6 +1273,17 @@ warn_too_many_conns(void)
}
}
+/**
+ * A socket failed from file descriptor exhaustion.
+ *
+ * Note down file descriptor exhaustion and log a warning. */
+static inline void
+socket_failed_from_fd_exhaustion(void)
+{
+ rep_hist_note_overload(OVERLOAD_FD_EXHAUSTED);
+ warn_about_resource_exhaution();
+}
+
#ifdef HAVE_SYS_UN_H
#define UNIX_SOCKET_PURPOSE_CONTROL_SOCKET 0
@@ -1477,7 +1499,7 @@ connection_listener_new(const struct sockaddr *listensockaddr,
if (!SOCKET_OK(s)) {
int e = tor_socket_errno(s);
if (ERRNO_IS_RESOURCE_LIMIT(e)) {
- warn_too_many_conns();
+ socket_failed_from_fd_exhaustion();
/*
* We'll call the OOS handler at the error exit, so set the
* exhaustion flag for it.
@@ -1603,7 +1625,7 @@ connection_listener_new(const struct sockaddr *listensockaddr,
if (! SOCKET_OK(s)) {
int e = tor_socket_errno(s);
if (ERRNO_IS_RESOURCE_LIMIT(e)) {
- warn_too_many_conns();
+ socket_failed_from_fd_exhaustion();
/*
* We'll call the OOS handler at the error exit, so set the
* exhaustion flag for it.
@@ -1718,13 +1740,6 @@ connection_listener_new(const struct sockaddr *listensockaddr,
}
}
- /* Force IPv4 and IPv6 traffic on for non-SOCKSPorts.
- * Forcing options on isn't a good idea, see #32994 and #33607. */
- if (type != CONN_TYPE_AP_LISTENER) {
- lis_conn->entry_cfg.ipv4_traffic = 1;
- lis_conn->entry_cfg.ipv6_traffic = 1;
- }
-
if (connection_add(conn) < 0) { /* no space, forget it */
log_warn(LD_NET,"connection_add for listener failed. Giving up.");
goto err;
@@ -1923,7 +1938,7 @@ connection_handle_listener_read(connection_t *conn, int new_type)
connection_check_oos(get_n_open_sockets(), 0);
return 0;
} else if (ERRNO_IS_RESOURCE_LIMIT(e)) {
- warn_too_many_conns();
+ socket_failed_from_fd_exhaustion();
/* Exhaustion; tell the OOS handler */
connection_check_oos(get_n_open_sockets(), 1);
return 0;
@@ -1984,6 +1999,7 @@ connection_handle_listener_read(connection_t *conn, int new_type)
log_notice(LD_APP,
"Denying socks connection from untrusted address %s.",
fmt_and_decorate_addr(&addr));
+ rep_hist_note_conn_rejected(new_type, conn->socket_family);
tor_close_socket(news);
return 0;
}
@@ -1993,6 +2009,7 @@ connection_handle_listener_read(connection_t *conn, int new_type)
if (dir_policy_permits_address(&addr) == 0) {
log_notice(LD_DIRSERV,"Denying dir connection from address %s.",
fmt_and_decorate_addr(&addr));
+ rep_hist_note_conn_rejected(new_type, conn->socket_family);
tor_close_socket(news);
return 0;
}
@@ -2001,6 +2018,7 @@ connection_handle_listener_read(connection_t *conn, int new_type)
/* Assess with the connection DoS mitigation subsystem if this address
* can open a new connection. */
if (dos_conn_addr_get_defense_type(&addr) == DOS_CONN_DEFENSE_CLOSE) {
+ rep_hist_note_conn_rejected(new_type, conn->socket_family);
tor_close_socket(news);
return 0;
}
@@ -2051,6 +2069,9 @@ connection_handle_listener_read(connection_t *conn, int new_type)
tor_assert(0);
};
+ /* We are receiving this connection. */
+ newconn->from_listener = 1;
+
if (connection_add(newconn) < 0) { /* no space, forget it */
connection_free(newconn);
return 0; /* no need to tear down the parent */
@@ -2062,7 +2083,7 @@ connection_handle_listener_read(connection_t *conn, int new_type)
return 0;
}
- note_connection(true /* inbound */, conn->socket_family);
+ note_connection(true /* inbound */, newconn);
return 0;
}
@@ -2186,7 +2207,7 @@ connection_connect_sockaddr,(connection_t *conn,
*/
*socket_error = tor_socket_errno(s);
if (ERRNO_IS_RESOURCE_LIMIT(*socket_error)) {
- warn_too_many_conns();
+ socket_failed_from_fd_exhaustion();
connection_check_oos(get_n_open_sockets(), 1);
} else {
log_warn(LD_NET,"Error creating network socket: %s",
@@ -2208,6 +2229,30 @@ connection_connect_sockaddr,(connection_t *conn,
*/
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
+ * long as the 4-tuple is unique.
+ *
+ * This is needed for relays using OutboundBindAddresses because the port
+ * value in the bind address is set to 0. */
+#ifdef IP_BIND_ADDRESS_NO_PORT
+ static int try_ip_bind_address_no_port = 1;
+ if (bindaddr && try_ip_bind_address_no_port &&
+ setsockopt(s, SOL_IP, IP_BIND_ADDRESS_NO_PORT, &(int){1}, sizeof(int))) {
+ if (errno == EINVAL) {
+ log_notice(LD_NET, "Tor was built with support for "
+ "IP_BIND_ADDRESS_NO_PORT, but the current kernel "
+ "doesn't support it. This might cause Tor to run out "
+ "of ephemeral ports more quickly.");
+ try_ip_bind_address_no_port = 0;
+ } else {
+ log_warn(LD_NET, "Error setting IP_BIND_ADDRESS_NO_PORT on new "
+ "connection: %s", tor_socket_strerror(errno));
+ }
+ }
+#endif
+
if (bindaddr && bind(s, bindaddr, bindaddr_len) < 0) {
*socket_error = tor_socket_errno(s);
log_warn(LD_NET,"Error binding network socket: %s",
@@ -2235,7 +2280,7 @@ connection_connect_sockaddr,(connection_t *conn,
}
}
- note_connection(false /* outbound */, conn->socket_family);
+ note_connection(false /* outbound */, conn);
/* it succeeded. we're connected. */
log_fn(inprogress ? LOG_DEBUG : LOG_INFO, LD_NET,
@@ -3246,7 +3291,7 @@ retry_all_listeners(smartlist_t *new_conns, int close_all_noncontrol)
* we hit those, bail early so tor can stop. */
if (!new_conn) {
log_warn(LD_NET, "Unable to create listener port: %s:%d",
- fmt_addr(&r->new_port->addr), r->new_port->port);
+ fmt_and_decorate_addr(&r->new_port->addr), r->new_port->port);
retval = -1;
break;
}
@@ -3265,7 +3310,8 @@ retry_all_listeners(smartlist_t *new_conns, int close_all_noncontrol)
* any configured port. Kill 'em. */
SMARTLIST_FOREACH_BEGIN(listeners, connection_t *, conn) {
log_notice(LD_NET, "Closing no-longer-configured %s on %s:%d",
- conn_type_to_string(conn->type), conn->address, conn->port);
+ conn_type_to_string(conn->type),
+ fmt_and_decorate_addr(&conn->addr), conn->port);
connection_close_immediate(conn);
connection_mark_for_close(conn);
} SMARTLIST_FOREACH_END(conn);
@@ -3427,6 +3473,16 @@ connection_bucket_read_limit(connection_t *conn, time_t now)
int priority = conn->type != CONN_TYPE_DIR;
ssize_t conn_bucket = -1;
size_t global_bucket_val = token_bucket_rw_get_read(&global_bucket);
+ if (global_bucket_val == 0) {
+ /* We reached our global read limit: count this as an overload.
+ *
+ * The token bucket is always initialized (see connection_bucket_init() and
+ * options_validate_relay_bandwidth()) and hence we can assume that if the
+ * token ever hits zero, it's a limit that got popped and not the bucket
+ * being uninitialized.
+ */
+ rep_hist_note_overload(OVERLOAD_READ);
+ }
if (connection_speaks_cells(conn)) {
or_connection_t *or_conn = TO_OR_CONN(conn);
@@ -3435,6 +3491,19 @@ connection_bucket_read_limit(connection_t *conn, time_t now)
base = get_cell_network_size(or_conn->wide_circ_ids);
}
+ /* Edge connection have their own read bucket due to flow control being able
+ * to set a rate limit for them. However, for exit connections, we still need
+ * to honor the global bucket as well. */
+ if (CONN_IS_EDGE(conn)) {
+ const edge_connection_t *edge_conn = CONST_TO_EDGE_CONN(conn);
+ conn_bucket = token_bucket_rw_get_read(&edge_conn->bucket);
+ if (conn->type == CONN_TYPE_EXIT) {
+ /* Decide between our limit and the global one. */
+ goto end;
+ }
+ return conn_bucket;
+ }
+
if (!connection_is_rate_limited(conn)) {
/* be willing to read on local conns even if our buckets are empty */
return conn_bucket>=0 ? conn_bucket : 1<<14;
@@ -3445,6 +3514,7 @@ connection_bucket_read_limit(connection_t *conn, time_t now)
global_bucket_val = MIN(global_bucket_val, relayed);
}
+ end:
return connection_bucket_get_share(base, priority,
global_bucket_val, conn_bucket);
}
@@ -3457,6 +3527,11 @@ connection_bucket_write_limit(connection_t *conn, time_t now)
int priority = conn->type != CONN_TYPE_DIR;
size_t conn_bucket = buf_datalen(conn->outbuf);
size_t global_bucket_val = token_bucket_rw_get_write(&global_bucket);
+ if (global_bucket_val == 0) {
+ /* We reached our global write limit: We should count this as an overload.
+ * See above function for more information */
+ rep_hist_note_overload(OVERLOAD_WRITE);
+ }
if (!connection_is_rate_limited(conn)) {
/* be willing to write to local conns even if our buckets are empty */
@@ -3617,6 +3692,13 @@ connection_buckets_decrement(connection_t *conn, time_t now,
record_num_bytes_transferred_impl(conn, now, num_read, num_written);
+ /* Edge connection need to decrement the read side of the bucket used by our
+ * congestion control. */
+ if (CONN_IS_EDGE(conn) && num_read > 0) {
+ edge_connection_t *edge_conn = TO_EDGE_CONN(conn);
+ token_bucket_rw_dec(&edge_conn->bucket, num_read, 0);
+ }
+
if (!connection_is_rate_limited(conn))
return; /* local IPs are free */
@@ -3670,14 +3752,16 @@ connection_write_bw_exhausted(connection_t *conn, bool is_global_bw)
void
connection_consider_empty_read_buckets(connection_t *conn)
{
+ int is_global = 1;
const char *reason;
- if (!connection_is_rate_limited(conn))
+ if (CONN_IS_EDGE(conn) &&
+ token_bucket_rw_get_read(&TO_EDGE_CONN(conn)->bucket) <= 0) {
+ reason = "edge connection read bucket exhausted. Pausing.";
+ is_global = false;
+ } else if (!connection_is_rate_limited(conn)) {
return; /* Always okay. */
-
- int is_global = 1;
-
- if (token_bucket_rw_get_read(&global_bucket) <= 0) {
+ } else if (token_bucket_rw_get_read(&global_bucket) <= 0) {
reason = "global read bucket exhausted. Pausing.";
} else if (connection_counts_as_relayed_traffic(conn, approx_time()) &&
token_bucket_rw_get_read(&global_relayed_bucket) <= 0) {
@@ -3687,8 +3771,9 @@ connection_consider_empty_read_buckets(connection_t *conn)
token_bucket_rw_get_read(&TO_OR_CONN(conn)->bucket) <= 0) {
reason = "connection read bucket exhausted. Pausing.";
is_global = false;
- } else
+ } else {
return; /* all good, no need to stop it */
+ }
LOG_FN_CONN(conn, (LOG_DEBUG, LD_NET, "%s", reason));
connection_read_bw_exhausted(conn, is_global);
@@ -3792,6 +3877,10 @@ connection_bucket_refill_single(connection_t *conn, uint32_t now_ts)
or_connection_t *or_conn = TO_OR_CONN(conn);
token_bucket_rw_refill(&or_conn->bucket, now_ts);
}
+
+ if (CONN_IS_EDGE(conn)) {
+ token_bucket_rw_refill(&TO_EDGE_CONN(conn)->bucket, now_ts);
+ }
}
/**
@@ -4529,9 +4618,9 @@ connection_handle_write_impl(connection_t *conn, int force)
!dont_stop_writing) { /* it's done flushing */
if (connection_finished_flushing(conn) < 0) {
/* already marked */
- return -1;
+ goto err;
}
- return 0;
+ goto done;
}
/* Call even if result is 0, since the global write bucket may
@@ -4541,7 +4630,17 @@ connection_handle_write_impl(connection_t *conn, int force)
if (n_read > 0 && connection_is_reading(conn))
connection_consider_empty_read_buckets(conn);
+ done:
+ /* If this is an edge connection with congestion control, check to see
+ * if it is time to send an xon */
+ if (conn_uses_flow_control(conn)) {
+ flow_control_decide_xon(TO_EDGE_CONN(conn), n_written);
+ }
+
return 0;
+
+ err:
+ return -1;
}
/* DOCDOC connection_handle_write */
@@ -4812,34 +4911,6 @@ connection_get_by_type_nonlinked,(int type))
CONN_GET_TEMPLATE(conn, conn->type == type && !conn->linked);
}
-/** Return a connection of type <b>type</b> that has rendquery equal
- * to <b>rendquery</b>, and that is not marked for close. If state
- * is non-zero, conn must be of that state too.
- */
-connection_t *
-connection_get_by_type_state_rendquery(int type, int state,
- const char *rendquery)
-{
- tor_assert(type == CONN_TYPE_DIR ||
- type == CONN_TYPE_AP || type == CONN_TYPE_EXIT);
- tor_assert(rendquery);
-
- CONN_GET_TEMPLATE(conn,
- (conn->type == type &&
- (!state || state == conn->state)) &&
- (
- (type == CONN_TYPE_DIR &&
- TO_DIR_CONN(conn)->rend_data &&
- !rend_cmp_service_ids(rendquery,
- rend_data_get_address(TO_DIR_CONN(conn)->rend_data)))
- ||
- (CONN_IS_EDGE(conn) &&
- TO_EDGE_CONN(conn)->rend_data &&
- !rend_cmp_service_ids(rendquery,
- rend_data_get_address(TO_EDGE_CONN(conn)->rend_data)))
- ));
-}
-
/** Return a new smartlist of dir_connection_t * from get_connection_array()
* that satisfy conn_test on connection_t *conn_var, and dirconn_test on
* dir_connection_t *dirconn_var. conn_var must be of CONN_TYPE_DIR and not
@@ -5829,7 +5900,6 @@ connection_free_all(void)
/* Unlink everything from the identity map. */
connection_or_clear_identity_map();
- connection_or_clear_ext_or_id_map();
/* Clear out our list of broken connections */
clear_broken_connection_map(0);
@@ -5866,7 +5936,8 @@ clock_skew_warning, (const connection_t *conn, long apparent_skew, int trusted,
char *ext_source = NULL, *warn = NULL;
format_time_interval(dbuf, sizeof(dbuf), apparent_skew);
if (conn)
- tor_asprintf(&ext_source, "%s:%s:%d", source, conn->address, conn->port);
+ tor_asprintf(&ext_source, "%s:%s:%d", source,
+ fmt_and_decorate_addr(&conn->addr), conn->port);
else
ext_source = tor_strdup(source);
log_fn(trusted ? LOG_WARN : LOG_INFO, domain,
diff --git a/src/core/mainloop/connection.h b/src/core/mainloop/connection.h
index 9dab28c3d9..8b378b15a4 100644
--- a/src/core/mainloop/connection.h
+++ b/src/core/mainloop/connection.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -274,8 +274,8 @@ void connection_buf_add_compress(const char *string, size_t len,
struct dir_connection_t *conn, int done);
void connection_buf_add_buf(struct connection_t *conn, struct buf_t *buf);
-size_t connection_get_inbuf_len(struct connection_t *conn);
-size_t connection_get_outbuf_len(struct connection_t *conn);
+size_t connection_get_inbuf_len(const struct connection_t *conn);
+size_t connection_get_outbuf_len(const struct connection_t *conn);
struct connection_t *connection_get_by_global_id(uint64_t id);
struct connection_t *connection_get_by_type(int type);
diff --git a/src/core/mainloop/cpuworker.c b/src/core/mainloop/cpuworker.c
index 2ae7e9aaf2..39d4899075 100644
--- a/src/core/mainloop/cpuworker.c
+++ b/src/core/mainloop/cpuworker.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -21,6 +21,8 @@
#include "core/or/channel.h"
#include "core/or/circuitlist.h"
#include "core/or/connection_or.h"
+#include "core/or/congestion_control_common.h"
+#include "core/or/congestion_control_flow.h"
#include "app/config/config.h"
#include "core/mainloop/cpuworker.h"
#include "lib/crypt_ops/crypto_rand.h"
@@ -30,6 +32,7 @@
#include "feature/relay/onion_queue.h"
#include "feature/stats/rephist.h"
#include "feature/relay/router.h"
+#include "feature/nodelist/networkstatus.h"
#include "lib/evloop/workqueue.h"
#include "core/crypto/onion_crypto.h"
@@ -73,8 +76,42 @@ worker_state_free_void(void *arg)
static replyqueue_t *replyqueue = NULL;
static threadpool_t *threadpool = NULL;
-static int total_pending_tasks = 0;
-static int max_pending_tasks = 128;
+static uint32_t total_pending_tasks = 0;
+static uint32_t max_pending_tasks = 128;
+
+/** Return the consensus parameter max pending tasks per CPU. */
+static uint32_t
+get_max_pending_tasks_per_cpu(const networkstatus_t *ns)
+{
+/* Total voodoo. Can we make this more sensible? Maybe, that is why we made it
+ * a consensus parameter so our future self can figure out this magic. */
+#define MAX_PENDING_TASKS_PER_CPU_DEFAULT 64
+#define MAX_PENDING_TASKS_PER_CPU_MIN 1
+#define MAX_PENDING_TASKS_PER_CPU_MAX INT32_MAX
+
+ return networkstatus_get_param(ns, "max_pending_tasks_per_cpu",
+ MAX_PENDING_TASKS_PER_CPU_DEFAULT,
+ MAX_PENDING_TASKS_PER_CPU_MIN,
+ MAX_PENDING_TASKS_PER_CPU_MAX);
+}
+
+/** Set the max pending tasks per CPU worker. This uses the consensus to check
+ * for the allowed number per CPU. The ns parameter can be NULL as in that no
+ * consensus is available at the time of setting this value. */
+static void
+set_max_pending_tasks(const networkstatus_t *ns)
+{
+ max_pending_tasks =
+ get_num_cpus(get_options()) * get_max_pending_tasks_per_cpu(ns);
+}
+
+/** Called when the consensus has changed. */
+void
+cpuworker_consensus_has_changed(const networkstatus_t *ns)
+{
+ tor_assert(ns);
+ set_max_pending_tasks(ns);
+}
/** Initialize the cpuworker subsystem. It is OK to call this more than once
* during Tor's lifetime.
@@ -104,8 +141,17 @@ cpu_init(void)
tor_assert(r == 0);
}
- /* Total voodoo. Can we make this more sensible? */
- max_pending_tasks = get_num_cpus(get_options()) * 64;
+ set_max_pending_tasks(NULL);
+}
+
+/** Return the number of threads configured for our CPU worker. */
+unsigned int
+cpuworker_get_n_threads(void)
+{
+ if (!threadpool) {
+ return 0;
+ }
+ return threadpool_get_n_threads(threadpool);
}
/** Magic numbers to make sure our cpuworker_requests don't grow any
@@ -126,6 +172,11 @@ typedef struct cpuworker_request_t {
/** A create cell for the cpuworker to process. */
create_cell_t create_cell;
+ /**
+ * A copy of this relay's consensus params that are relevant to
+ * the circuit, for use in negotiation. */
+ circuit_params_t circ_ns_params;
+
/* Turn the above into a tagged union if needed. */
} cpuworker_request_t;
@@ -158,6 +209,8 @@ typedef struct cpuworker_reply_t {
uint8_t keys[CPATH_KEY_MATERIAL_LEN];
/** Input to use for authenticating introduce1 cells. */
uint8_t rend_auth_material[DIGEST_LEN];
+ /** Negotiated circuit parameters. */
+ circuit_params_t circ_params;
} cpuworker_reply_t;
typedef struct cpuworker_job_u_t {
@@ -379,6 +432,18 @@ cpuworker_onion_handshake_replyfn(void *work_)
goto done_processing;
}
+ /* If the client asked for congestion control, if our consensus parameter
+ * allowed it to negotiate as enabled, allocate a congestion control obj. */
+ if (rpl.circ_params.cc_enabled) {
+ if (get_options()->SbwsExit) {
+ TO_CIRCUIT(circ)->ccontrol = congestion_control_new(&rpl.circ_params,
+ CC_PATH_SBWS);
+ } else {
+ TO_CIRCUIT(circ)->ccontrol = congestion_control_new(&rpl.circ_params,
+ CC_PATH_EXIT);
+ }
+ }
+
if (onionskin_answer(circ,
&rpl.created_cell,
(const char*)rpl.keys, sizeof(rpl.keys),
@@ -387,6 +452,7 @@ cpuworker_onion_handshake_replyfn(void *work_)
circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_INTERNAL);
goto done_processing;
}
+
log_debug(LD_OR,"onionskin_answer succeeded. Yay.");
done_processing:
@@ -425,9 +491,12 @@ cpuworker_onion_handshake_threadfn(void *state_, void *work_)
n = onion_skin_server_handshake(cc->handshake_type,
cc->onionskin, cc->handshake_len,
onion_keys,
+ &req.circ_ns_params,
cell_out->reply,
+ sizeof(cell_out->reply),
rpl.keys, CPATH_KEY_MATERIAL_LEN,
- rpl.rend_auth_material);
+ rpl.rend_auth_material,
+ &rpl.circ_params);
if (n < 0) {
/* failure */
log_debug(LD_OR,"onion_skin_server_handshake failed.");
@@ -450,6 +519,7 @@ cpuworker_onion_handshake_threadfn(void *state_, void *work_)
}
rpl.success = 1;
}
+
rpl.magic = CPUWORKER_REPLY_MAGIC;
if (req.timed) {
struct timeval tv_diff;
@@ -550,6 +620,11 @@ assign_onionskin_to_cpuworker(or_circuit_t *circ,
if (should_time)
tor_gettimeofday(&req.started_at);
+ /* Copy the current cached consensus params relevant to
+ * circuit negotiation into the CPU worker context */
+ req.circ_ns_params.cc_enabled = congestion_control_enabled();
+ req.circ_ns_params.sendme_inc_cells = congestion_control_sendme_inc();
+
job = tor_malloc_zero(sizeof(cpuworker_job_t));
job->circ = circ;
memcpy(&job->u.request, &req, sizeof(req));
diff --git a/src/core/mainloop/cpuworker.h b/src/core/mainloop/cpuworker.h
index 7e71961750..9eee287c1f 100644
--- a/src/core/mainloop/cpuworker.h
+++ b/src/core/mainloop/cpuworker.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -12,8 +12,13 @@
#ifndef TOR_CPUWORKER_H
#define TOR_CPUWORKER_H
+#include "feature/nodelist/networkstatus_st.h"
+
void cpu_init(void);
void cpuworkers_rotate_keyinfo(void);
+
+void cpuworker_consensus_has_changed(const networkstatus_t *ns);
+
struct workqueue_entry_t;
enum workqueue_reply_t;
enum workqueue_priority_t;
@@ -33,5 +38,7 @@ void cpuworker_log_onionskin_overhead(int severity, int onionskin_type,
const char *onionskin_type_name);
void cpuworker_cancel_circ_handshake(or_circuit_t *circ);
+unsigned int cpuworker_get_n_threads(void);
+
#endif /* !defined(TOR_CPUWORKER_H) */
diff --git a/src/core/mainloop/mainloop.c b/src/core/mainloop/mainloop.c
index 77ab6f26c8..526f8c37af 100644
--- a/src/core/mainloop/mainloop.c
+++ b/src/core/mainloop/mainloop.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -91,8 +91,6 @@
#include "feature/relay/routerkeys.h"
#include "feature/relay/routermode.h"
#include "feature/relay/selftest.h"
-#include "feature/rend/rendcache.h"
-#include "feature/rend/rendservice.h"
#include "feature/stats/geoip_stats.h"
#include "feature/stats/predict_ports.h"
#include "feature/stats/connstats.h"
@@ -643,6 +641,13 @@ connection_start_reading,(connection_t *conn))
if (connection_should_read_from_linked_conn(conn))
connection_start_reading_from_linked_conn(conn);
} else {
+ if (CONN_IS_EDGE(conn) && TO_EDGE_CONN(conn)->xoff_received) {
+ /* We should not get called here if we're waiting for an XON, but
+ * belt-and-suspenders */
+ log_info(LD_NET,
+ "Request to start reading on an edgeconn blocked with XOFF");
+ return;
+ }
if (event_add(conn->read_event, NULL))
log_warn(LD_NET, "Error from libevent setting read event state for %d "
"to watched: %s",
@@ -1148,7 +1153,7 @@ directory_info_has_arrived(time_t now, int from_cache, int suppress_logs)
if (server_mode(options) && !net_is_disabled() && !from_cache &&
(have_completed_a_circuit() || !any_predicted_circuits(now)))
- router_do_reachability_checks(1, 1);
+ router_do_reachability_checks();
}
/** Perform regular maintenance tasks for a single connection. This
@@ -1224,7 +1229,7 @@ run_connection_housekeeping(int i, time_t now)
* mark it now. */
log_info(LD_OR,
"Expiring non-used OR connection to fd %d (%s:%d) [Too old].",
- (int)conn->s, conn->address, conn->port);
+ (int)conn->s, fmt_and_decorate_addr(&conn->addr), conn->port);
if (conn->state == OR_CONN_STATE_CONNECTING)
connection_or_connect_failed(TO_OR_CONN(conn),
END_OR_CONN_REASON_TIMEOUT,
@@ -1234,7 +1239,7 @@ run_connection_housekeeping(int i, time_t now)
if (past_keepalive) {
/* We never managed to actually get this connection open and happy. */
log_info(LD_OR,"Expiring non-open OR connection to fd %d (%s:%d).",
- (int)conn->s,conn->address, conn->port);
+ (int)conn->s, fmt_and_decorate_addr(&conn->addr), conn->port);
connection_or_close_normally(TO_OR_CONN(conn), 0);
}
} else if (we_are_hibernating() &&
@@ -1244,7 +1249,7 @@ run_connection_housekeeping(int i, time_t now)
* flush.*/
log_info(LD_OR,"Expiring non-used OR connection to fd %d (%s:%d) "
"[Hibernating or exiting].",
- (int)conn->s,conn->address, conn->port);
+ (int)conn->s, fmt_and_decorate_addr(&conn->addr), conn->port);
connection_or_close_normally(TO_OR_CONN(conn), 1);
} else if (!have_any_circuits &&
now - or_conn->idle_timeout >=
@@ -1252,7 +1257,7 @@ run_connection_housekeeping(int i, time_t now)
log_info(LD_OR,"Expiring non-used OR connection %"PRIu64" to fd %d "
"(%s:%d) [no circuits for %d; timeout %d; %scanonical].",
(chan->global_identifier),
- (int)conn->s, conn->address, conn->port,
+ (int)conn->s, fmt_and_decorate_addr(&conn->addr), conn->port,
(int)(now - chan->timestamp_last_had_circuits),
or_conn->idle_timeout,
or_conn->is_canonical ? "" : "non");
@@ -1264,14 +1269,14 @@ 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, conn->address, conn->port,
+ (int)conn->s, 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)) {
/* send a padding cell */
log_fn(LOG_DEBUG,LD_OR,"Sending keepalive to (%s:%d)",
- conn->address, conn->port);
+ fmt_and_decorate_addr(&conn->addr), conn->port);
memset(&cell,0,sizeof(cell_t));
cell.command = CELL_PADDING;
connection_or_write_cell_to_buf(&cell, or_conn);
@@ -1295,6 +1300,7 @@ signewnym_impl(time_t now)
circuit_mark_all_dirty_circs_as_unusable();
addressmap_clear_transient();
hs_client_purge_state();
+ purge_vanguards_lite();
time_of_last_signewnym = now;
signewnym_is_pending = 0;
@@ -1372,6 +1378,7 @@ CALLBACK(save_state);
CALLBACK(write_stats_file);
CALLBACK(control_per_second_events);
CALLBACK(second_elapsed);
+CALLBACK(manage_vglite);
#undef CALLBACK
@@ -1394,6 +1401,9 @@ STATIC periodic_event_item_t mainloop_periodic_events[] = {
CALLBACK(second_elapsed, NET_PARTICIPANT,
FL(RUN_ON_DISABLE)),
+ /* Update vanguards-lite once per hour, if we have networking */
+ CALLBACK(manage_vglite, NET_PARTICIPANT, FL(NEED_NET)),
+
/* XXXX Do we have a reason to do this on a callback? Does it do any good at
* all? For now, if we're dormant, we can let our listeners decay. */
CALLBACK(retry_listeners, NET_PARTICIPANT, FL(NEED_NET)),
@@ -1468,8 +1478,7 @@ get_my_roles(const or_options_t *options)
int is_relay = server_mode(options);
int is_dirauth = authdir_mode_v3(options);
int is_bridgeauth = authdir_mode_bridge(options);
- int is_hidden_service = !!hs_service_get_num_services() ||
- !!rend_num_services();
+ int is_hidden_service = !!hs_service_get_num_services();
int is_dirserver = dir_server_mode(options);
int sending_control_events = control_any_per_second_event_enabled();
@@ -1665,6 +1674,21 @@ mainloop_schedule_shutdown(int delay_sec)
mainloop_event_schedule(scheduled_shutdown_ev, &delay_tv);
}
+/**
+ * Update vanguards-lite layer2 nodes, once every 15 minutes
+ */
+static int
+manage_vglite_callback(time_t now, const or_options_t *options)
+{
+ (void)now;
+ (void)options;
+#define VANGUARDS_LITE_INTERVAL (15*60)
+
+ maintain_layer2_guards();
+
+ return VANGUARDS_LITE_INTERVAL;
+}
+
/** Perform regular maintenance tasks. This function gets run once per
* second.
*/
@@ -1823,10 +1847,16 @@ check_network_participation_callback(time_t now, const or_options_t *options)
goto found_activity;
}
+ /* If we aren't allowed to become dormant, then participation doesn't
+ matter */
+ if (! options->DormantTimeoutEnabled) {
+ goto found_activity;
+ }
+
/* If we're running an onion service, we can't become dormant. */
/* XXXX this would be nice to change, so that we can be dormant with a
* service. */
- if (hs_service_get_num_services() || rend_num_services()) {
+ if (hs_service_get_num_services()) {
goto found_activity;
}
@@ -1937,7 +1967,11 @@ write_stats_file_callback(time_t now, const or_options_t *options)
next_time_to_write_stats_files = next_write;
}
if (options->HiddenServiceStatistics) {
- time_t next_write = rep_hist_hs_stats_write(now);
+ time_t next_write = rep_hist_hs_stats_write(now, false);
+ if (next_write && next_write < next_time_to_write_stats_files)
+ next_time_to_write_stats_files = next_write;
+
+ next_write = rep_hist_hs_stats_write(now, true);
if (next_write && next_write < next_time_to_write_stats_files)
next_time_to_write_stats_files = next_write;
}
@@ -2009,7 +2043,6 @@ clean_caches_callback(time_t now, const or_options_t *options)
{
/* Remove old information from rephist and the rend cache. */
rep_history_clean(now - options->RephistTrackTime);
- rend_cache_clean(now, REND_CACHE_TYPE_SERVICE);
hs_cache_clean_as_client(now);
hs_cache_clean_as_dir(now);
microdesc_cache_rebuild(NULL, 0);
@@ -2028,7 +2061,6 @@ rend_cache_failure_clean_callback(time_t now, const or_options_t *options)
/* We don't keep entries that are more than five minutes old so we try to
* clean it as soon as we can since we want to make sure the client waits
* as little as possible for reachability reasons. */
- rend_cache_failure_clean(now);
hs_cache_client_intro_state_clean(now);
return 30;
}
diff --git a/src/core/mainloop/mainloop.h b/src/core/mainloop/mainloop.h
index 1ddfec2162..98d0b3a058 100644
--- a/src/core/mainloop/mainloop.h
+++ b/src/core/mainloop/mainloop.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/core/mainloop/mainloop_pubsub.c b/src/core/mainloop/mainloop_pubsub.c
index 0e982d4c40..1e72ada5f0 100644
--- a/src/core/mainloop/mainloop_pubsub.c
+++ b/src/core/mainloop/mainloop_pubsub.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001, Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/core/mainloop/mainloop_pubsub.h b/src/core/mainloop/mainloop_pubsub.h
index 3698fd8d03..481e0cd585 100644
--- a/src/core/mainloop/mainloop_pubsub.h
+++ b/src/core/mainloop/mainloop_pubsub.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001, Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/core/mainloop/mainloop_state_st.h b/src/core/mainloop/mainloop_state_st.h
index 5649b536f9..461f0220d3 100644
--- a/src/core/mainloop/mainloop_state_st.h
+++ b/src/core/mainloop/mainloop_state_st.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/core/mainloop/mainloop_sys.c b/src/core/mainloop/mainloop_sys.c
index 884bae1c59..b50053fce9 100644
--- a/src/core/mainloop/mainloop_sys.c
+++ b/src/core/mainloop/mainloop_sys.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/core/mainloop/mainloop_sys.h b/src/core/mainloop/mainloop_sys.h
index b3ade33cd1..2fc2d85fc9 100644
--- a/src/core/mainloop/mainloop_sys.h
+++ b/src/core/mainloop/mainloop_sys.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/core/mainloop/netstatus.c b/src/core/mainloop/netstatus.c
index 7367c68219..b833149151 100644
--- a/src/core/mainloop/netstatus.c
+++ b/src/core/mainloop/netstatus.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -154,6 +154,9 @@ netstatus_load_from_state(const mainloop_state_t *state, time_t now)
last_activity = now;
participating_on_network = true;
}
+ if (! get_options()->DormantTimeoutEnabled) {
+ participating_on_network = true;
+ }
reset_user_activity(last_activity);
}
diff --git a/src/core/mainloop/netstatus.h b/src/core/mainloop/netstatus.h
index 5f54e54553..d2070fb87a 100644
--- a/src/core/mainloop/netstatus.h
+++ b/src/core/mainloop/netstatus.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/core/mainloop/periodic.c b/src/core/mainloop/periodic.c
index 29cf8c4831..36ffabfc48 100644
--- a/src/core/mainloop/periodic.c
+++ b/src/core/mainloop/periodic.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2020, The Tor Project, Inc. */
+/* Copyright (c) 2015-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/core/mainloop/periodic.h b/src/core/mainloop/periodic.h
index de556a6bdb..be62b77f23 100644
--- a/src/core/mainloop/periodic.h
+++ b/src/core/mainloop/periodic.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2020, The Tor Project, Inc. */
+/* Copyright (c) 2015-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/core/or/addr_policy_st.h b/src/core/or/addr_policy_st.h
index 08d16ee616..4ced25f708 100644
--- a/src/core/or/addr_policy_st.h
+++ b/src/core/or/addr_policy_st.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/core/or/address_set.c b/src/core/or/address_set.c
index 9bd3cc0f2d..909876d615 100644
--- a/src/core/or/address_set.c
+++ b/src/core/or/address_set.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2018-2020, The Tor Project, Inc. */
+/* Copyright (c) 2018-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/core/or/address_set.h b/src/core/or/address_set.h
index b4d94b65a9..3c5b55cf5f 100644
--- a/src/core/or/address_set.h
+++ b/src/core/or/address_set.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2018-2020, The Tor Project, Inc. */
+/* Copyright (c) 2018-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/core/or/cell_queue_st.h b/src/core/or/cell_queue_st.h
index 0681dba1b8..30a4d028fa 100644
--- a/src/core/or/cell_queue_st.h
+++ b/src/core/or/cell_queue_st.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/core/or/cell_st.h b/src/core/or/cell_st.h
index a640d6a456..77e12c0c2c 100644
--- a/src/core/or/cell_st.h
+++ b/src/core/or/cell_st.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/core/or/channel.c b/src/core/or/channel.c
index 1ac029c152..c46fa93e58 100644
--- a/src/core/or/channel.c
+++ b/src/core/or/channel.c
@@ -1,4 +1,4 @@
-/* * Copyright (c) 2012-2020, The Tor Project, Inc. */
+/* * Copyright (c) 2012-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -71,12 +71,12 @@
#include "core/or/relay.h"
#include "core/or/scheduler.h"
#include "feature/client/entrynodes.h"
+#include "feature/hs/hs_service.h"
#include "feature/nodelist/dirlist.h"
#include "feature/nodelist/networkstatus.h"
#include "feature/nodelist/nodelist.h"
#include "feature/nodelist/routerlist.h"
#include "feature/relay/router.h"
-#include "feature/rend/rendservice.h"
#include "feature/stats/geoip_stats.h"
#include "feature/stats/rephist.h"
#include "lib/evloop/timers.h"
@@ -1897,7 +1897,7 @@ channel_do_open_actions(channel_t *chan)
if (!get_options()->ConnectionPadding) {
/* Disable if torrc disabled */
channelpadding_disable_padding_on_channel(chan);
- } else if (rend_service_allow_non_anonymous_connection(get_options()) &&
+ } else if (hs_service_allow_non_anonymous_connection(get_options()) &&
!networkstatus_get_param(NULL,
CHANNELPADDING_SOS_PARAM,
CHANNELPADDING_SOS_DEFAULT, 0, 1)) {
@@ -2629,24 +2629,42 @@ channel_dump_statistics, (channel_t *chan, int severity))
circuitmux_num_circuits(chan->cmux) : 0);
/* Describe timestamps */
- tor_log(severity, LD_GENERAL,
- " * Channel %"PRIu64 " was last used by a "
- "client at %"PRIu64 " (%"PRIu64 " seconds ago)",
- (chan->global_identifier),
- (uint64_t)(chan->timestamp_client),
- (uint64_t)(now - chan->timestamp_client));
- tor_log(severity, LD_GENERAL,
- " * Channel %"PRIu64 " last received a cell "
- "at %"PRIu64 " (%"PRIu64 " seconds ago)",
- (chan->global_identifier),
- (uint64_t)(chan->timestamp_recv),
- (uint64_t)(now - chan->timestamp_recv));
- tor_log(severity, LD_GENERAL,
- " * Channel %"PRIu64 " last transmitted a cell "
- "at %"PRIu64 " (%"PRIu64 " seconds ago)",
- (chan->global_identifier),
- (uint64_t)(chan->timestamp_xmit),
- (uint64_t)(now - chan->timestamp_xmit));
+ if (chan->timestamp_client == 0) {
+ tor_log(severity, LD_GENERAL,
+ " * Channel %"PRIu64 " was never used by a "
+ "client", (chan->global_identifier));
+ } else {
+ tor_log(severity, LD_GENERAL,
+ " * Channel %"PRIu64 " was last used by a "
+ "client at %"PRIu64 " (%"PRIu64 " seconds ago)",
+ (chan->global_identifier),
+ (uint64_t)(chan->timestamp_client),
+ (uint64_t)(now - chan->timestamp_client));
+ }
+ if (chan->timestamp_recv == 0) {
+ tor_log(severity, LD_GENERAL,
+ " * Channel %"PRIu64 " never received a cell",
+ (chan->global_identifier));
+ } else {
+ tor_log(severity, LD_GENERAL,
+ " * Channel %"PRIu64 " last received a cell "
+ "at %"PRIu64 " (%"PRIu64 " seconds ago)",
+ (chan->global_identifier),
+ (uint64_t)(chan->timestamp_recv),
+ (uint64_t)(now - chan->timestamp_recv));
+ }
+ if (chan->timestamp_xmit == 0) {
+ tor_log(severity, LD_GENERAL,
+ " * Channel %"PRIu64 " never transmitted a cell",
+ (chan->global_identifier));
+ } else {
+ tor_log(severity, LD_GENERAL,
+ " * Channel %"PRIu64 " last transmitted a cell "
+ "at %"PRIu64 " (%"PRIu64 " seconds ago)",
+ (chan->global_identifier),
+ (uint64_t)(chan->timestamp_xmit),
+ (uint64_t)(now - chan->timestamp_xmit));
+ }
/* Describe counters and rates */
tor_log(severity, LD_GENERAL,
diff --git a/src/core/or/channel.h b/src/core/or/channel.h
index a1517aee37..cd867477d1 100644
--- a/src/core/or/channel.h
+++ b/src/core/or/channel.h
@@ -1,4 +1,4 @@
-/* * Copyright (c) 2012-2020, The Tor Project, Inc. */
+/* * Copyright (c) 2012-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/core/or/channelpadding.c b/src/core/or/channelpadding.c
index d4c19491ac..1f559f6c42 100644
--- a/src/core/or/channelpadding.c
+++ b/src/core/or/channelpadding.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -27,8 +27,8 @@
#include "feature/relay/router.h"
#include "feature/relay/routermode.h"
#include "lib/time/compat_time.h"
-#include "feature/rend/rendservice.h"
#include "lib/evloop/timers.h"
+#include "feature/hs/hs_service.h"
#include "core/or/cell_st.h"
#include "core/or/or_connection_st.h"
@@ -744,7 +744,7 @@ channelpadding_decide_to_pad_channel(channel_t *chan)
return CHANNELPADDING_WONTPAD;
}
- if (rend_service_allow_non_anonymous_connection(options) &&
+ if (hs_service_allow_non_anonymous_connection(options) &&
!consensus_nf_pad_single_onion) {
/* If the consensus just changed values, this channel may still
* think padding is enabled. Negotiate it off. */
diff --git a/src/core/or/channelpadding.h b/src/core/or/channelpadding.h
index 9246988cdc..23f4210ab7 100644
--- a/src/core/or/channelpadding.h
+++ b/src/core/or/channelpadding.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/core/or/channeltls.c b/src/core/or/channeltls.c
index dd5e42c47f..9db8e2392d 100644
--- a/src/core/or/channeltls.c
+++ b/src/core/or/channeltls.c
@@ -1,4 +1,4 @@
-/* * Copyright (c) 2012-2020, The Tor Project, Inc. */
+/* * Copyright (c) 2012-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -64,6 +64,7 @@
#include "trunnel/netinfo.h"
#include "core/or/channelpadding.h"
#include "core/or/extendinfo.h"
+#include "core/or/congestion_control_common.h"
#include "core/or/cell_st.h"
#include "core/or/cell_queue_st.h"
@@ -72,7 +73,7 @@
#include "core/or/or_handshake_state_st.h"
#include "feature/nodelist/routerinfo_st.h"
#include "core/or/var_cell_st.h"
-#include "src/feature/relay/relay_find_addr.h"
+#include "feature/relay/relay_find_addr.h"
#include "lib/tls/tortls.h"
#include "lib/tls/x509.h"
@@ -793,7 +794,7 @@ channel_tls_num_cells_writeable_method(channel_t *chan)
cell_network_size = get_cell_network_size(tlschan->conn->wide_circ_ids);
outbuf_len = connection_get_outbuf_len(TO_CONN(tlschan->conn));
/* Get the number of cells */
- n = CEIL_DIV(OR_CONN_HIGHWATER - outbuf_len, cell_network_size);
+ n = CEIL_DIV(or_conn_highwatermark() - outbuf_len, cell_network_size);
if (n < 0) n = 0;
#if SIZEOF_SIZE_T > SIZEOF_INT
if (n > INT_MAX) n = INT_MAX;
diff --git a/src/core/or/channeltls.h b/src/core/or/channeltls.h
index e7010a51fc..67dee94847 100644
--- a/src/core/or/channeltls.h
+++ b/src/core/or/channeltls.h
@@ -1,4 +1,4 @@
-/* * Copyright (c) 2012-2020, The Tor Project, Inc. */
+/* * Copyright (c) 2012-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/core/or/circuit_st.h b/src/core/or/circuit_st.h
index 35d214ce08..be6429438a 100644
--- a/src/core/or/circuit_st.h
+++ b/src/core/or/circuit_st.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -22,6 +22,7 @@
struct hs_token_t;
struct circpad_machine_spec_t;
struct circpad_machine_runtime_t;
+struct congestion_control_t;
/** Number of padding state machines on a circuit. */
#define CIRCPAD_MAX_MACHINES (2)
@@ -244,6 +245,9 @@ struct circuit_t {
* that STOP commands actually correspond to the current machine,
* and not a previous one. */
uint32_t padding_machine_ctr;
+
+ /** Congestion control fields */
+ struct congestion_control_t *ccontrol;
};
#endif /* !defined(CIRCUIT_ST_H) */
diff --git a/src/core/or/circuitbuild.c b/src/core/or/circuitbuild.c
index 78501c0aa2..511df4112b 100644
--- a/src/core/or/circuitbuild.c
+++ b/src/core/or/circuitbuild.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -69,10 +69,10 @@
#include "feature/relay/router.h"
#include "feature/relay/routermode.h"
#include "feature/relay/selftest.h"
-#include "feature/rend/rendcommon.h"
#include "feature/stats/predict_ports.h"
#include "lib/crypt_ops/crypto_rand.h"
#include "lib/trace/events.h"
+#include "core/or/congestion_control_common.h"
#include "core/or/cell_st.h"
#include "core/or/cpath_build_state_st.h"
@@ -82,6 +82,9 @@
#include "core/or/or_circuit_st.h"
#include "core/or/origin_circuit_st.h"
+#include "trunnel/extension.h"
+#include "trunnel/congestion_control.h"
+
static int circuit_send_first_onion_skin(origin_circuit_t *circ);
static int circuit_build_no_more_hops(origin_circuit_t *circ);
static int circuit_send_intermediate_onion_skin(origin_circuit_t *circ,
@@ -842,7 +845,13 @@ circuit_pick_create_handshake(uint8_t *cell_type_out,
* using the TAP handshake, and CREATE2 otherwise. */
if (extend_info_supports_ntor(ei)) {
*cell_type_out = CELL_CREATE2;
- *handshake_type_out = ONION_HANDSHAKE_TYPE_NTOR;
+ /* Only use ntor v3 with exits that support congestion control,
+ * and only when it is enabled. */
+ if (ei->exit_supports_congestion_control &&
+ congestion_control_enabled())
+ *handshake_type_out = ONION_HANDSHAKE_TYPE_NTOR_V3;
+ else
+ *handshake_type_out = ONION_HANDSHAKE_TYPE_NTOR;
} else {
/* XXXX030 Remove support for deciding to use TAP and EXTEND. */
*cell_type_out = CELL_CREATE;
@@ -996,7 +1005,8 @@ circuit_send_first_onion_skin(origin_circuit_t *circ)
len = onion_skin_create(cc.handshake_type,
circ->cpath->extend_info,
&circ->cpath->handshake_state,
- cc.onionskin);
+ cc.onionskin,
+ sizeof(cc.onionskin));
if (len < 0) {
log_warn(LD_CIRC,"onion_skin_create (first hop) failed.");
return - END_CIRC_REASON_INTERNAL;
@@ -1078,7 +1088,7 @@ circuit_build_no_more_hops(origin_circuit_t *circ)
clear_broken_connection_map(1);
if (server_mode(options) &&
!router_all_orports_seem_reachable(options)) {
- router_do_reachability_checks(1, 1);
+ router_do_reachability_checks();
}
}
@@ -1143,7 +1153,8 @@ circuit_send_intermediate_onion_skin(origin_circuit_t *circ,
len = onion_skin_create(ec.create_cell.handshake_type,
hop->extend_info,
&hop->handshake_state,
- ec.create_cell.onionskin);
+ ec.create_cell.onionskin,
+ sizeof(ec.create_cell.onionskin));
if (len < 0) {
log_warn(LD_CIRC,"onion_skin_create failed.");
return - END_CIRC_REASON_INTERNAL;
@@ -1241,6 +1252,7 @@ circuit_finish_handshake(origin_circuit_t *circ,
}
tor_assert(hop->state == CPATH_STATE_AWAITING_KEYS);
+ circuit_params_t params;
{
const char *msg = NULL;
if (onion_skin_client_handshake(hop->handshake_state.tag,
@@ -1248,6 +1260,7 @@ circuit_finish_handshake(origin_circuit_t *circ,
reply->reply, reply->handshake_len,
(uint8_t*)keys, sizeof(keys),
(uint8_t*)hop->rend_circ_nonce,
+ &params,
&msg) < 0) {
if (msg)
log_warn(LD_CIRC,"onion_skin_client_handshake failed: %s", msg);
@@ -1261,6 +1274,40 @@ circuit_finish_handshake(origin_circuit_t *circ,
return -END_CIRC_REASON_TORPROTOCOL;
}
+ if (params.cc_enabled) {
+ int circ_len = circuit_get_cpath_len(circ);
+
+ if (circ_len == DEFAULT_ROUTE_LEN &&
+ circuit_get_cpath_hop(circ, DEFAULT_ROUTE_LEN) == hop) {
+ hop->ccontrol = congestion_control_new(&params, CC_PATH_EXIT);
+ } else if (circ_len == SBWS_ROUTE_LEN &&
+ circuit_get_cpath_hop(circ, SBWS_ROUTE_LEN) == hop) {
+ hop->ccontrol = congestion_control_new(&params, CC_PATH_SBWS);
+ } else {
+ if (circ_len > DEFAULT_ROUTE_LEN) {
+ /* This can happen for unknown reasons; cannibalization codepaths
+ * don't seem able to do it, so there is some magic way that hops can
+ * still get added. Perhaps some cases of circuit pre-build that change
+ * purpose? */
+ log_info(LD_CIRC,
+ "Unexpected path length %d for exit circuit %d, purpose %d",
+ circ_len, circ->global_identifier,
+ TO_CIRCUIT(circ)->purpose);
+ hop->ccontrol = congestion_control_new(&params, CC_PATH_EXIT);
+ } else {
+ /* This is likely directory requests, which should block on orconn
+ * before congestion control, but lets give them the lower sbws
+ * param set anyway just in case. */
+ log_info(LD_CIRC,
+ "Unexpected path length %d for exit circuit %d, purpose %d",
+ circ_len, circ->global_identifier,
+ TO_CIRCUIT(circ)->purpose);
+
+ hop->ccontrol = congestion_control_new(&params, CC_PATH_SBWS);
+ }
+ }
+ }
+
hop->state = CPATH_STATE_OPEN;
log_info(LD_CIRC,"Finished building circuit hop:");
circuit_log_path(LOG_INFO,LD_CIRC,circ);
@@ -1339,16 +1386,13 @@ circuit_truncated(origin_circuit_t *circ, int reason)
* CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT)
*
* - A hidden service connecting to a rendezvous point, which the
- * client picked (CIRCUIT_PURPOSE_S_CONNECT_REND, via
- * rend_service_receive_introduction() and
- * rend_service_relaunch_rendezvous)
+ * client picked (CIRCUIT_PURPOSE_S_CONNECT_REND.
*
* There are currently two situations where we picked the exit node
* ourselves, making DEFAULT_ROUTE_LEN a safe circuit length:
*
* - We are a hidden service connecting to an introduction point
- * (CIRCUIT_PURPOSE_S_ESTABLISH_INTRO, via
- * rend_service_launch_establish_intro())
+ * (CIRCUIT_PURPOSE_S_ESTABLISH_INTRO).
*
* - We are a router testing its own reachabiity
* (CIRCUIT_PURPOSE_TESTING, via router_do_reachability_checks())
@@ -1363,7 +1407,9 @@ route_len_for_purpose(uint8_t purpose, extend_info_t *exit_ei)
int routelen = DEFAULT_ROUTE_LEN;
int known_purpose = 0;
- if (circuit_should_use_vanguards(purpose)) {
+ /* If we're using L3 vanguards, we need longer paths for onion services */
+ if (circuit_purpose_is_hidden_service(purpose) &&
+ get_options()->HSLayer3Nodes) {
/* Clients want an extra hop for rends to avoid linkability.
* Services want it for intro points to avoid publishing their
* layer3 guards. They want it for hsdir posts to use
@@ -1378,14 +1424,6 @@ route_len_for_purpose(uint8_t purpose, extend_info_t *exit_ei)
purpose == CIRCUIT_PURPOSE_S_ESTABLISH_INTRO)
return routelen+1;
- /* If we only have Layer2 vanguards, then we do not need
- * the extra hop for linkabilty reasons (see below).
- * This means all hops can be of the form:
- * S/C - G - L2 - M - R/HSDir/I
- */
- if (get_options()->HSLayer2Nodes && !get_options()->HSLayer3Nodes)
- return routelen+1;
-
/* For connections to hsdirs, clients want two extra hops
* when using layer3 guards, to avoid linkability.
* Same goes for intro points. Note that the route len
@@ -1404,16 +1442,14 @@ route_len_for_purpose(uint8_t purpose, extend_info_t *exit_ei)
return routelen;
switch (purpose) {
- /* These two purposes connect to a router that we chose, so
- * DEFAULT_ROUTE_LEN is safe. */
- case CIRCUIT_PURPOSE_S_ESTABLISH_INTRO:
- /* hidden service connecting to introduction point */
+ /* These purposes connect to a router that we chose, so DEFAULT_ROUTE_LEN
+ * is safe: */
case CIRCUIT_PURPOSE_TESTING:
/* router reachability testing */
known_purpose = 1;
break;
- /* These three purposes connect to a router that someone else
+ /* These purposes connect to a router that someone else
* might have chosen, so add an extra hop to protect anonymity. */
case CIRCUIT_PURPOSE_C_GENERAL:
case CIRCUIT_PURPOSE_C_HSDIR_GET:
@@ -1423,6 +1459,9 @@ route_len_for_purpose(uint8_t purpose, extend_info_t *exit_ei)
/* client connecting to introduction point */
case CIRCUIT_PURPOSE_S_CONNECT_REND:
/* hidden service connecting to rendezvous point */
+ case CIRCUIT_PURPOSE_S_ESTABLISH_INTRO:
+ /* hidden service connecting to intro point. In this case we want an extra
+ hop to avoid linkability attacks by the introduction point. */
known_purpose = 1;
routelen++;
break;
@@ -2023,7 +2062,7 @@ cpath_build_state_to_crn_ipv6_extend_flag(const cpath_build_state_t *state,
}
/** Decide a suitable length for circ's cpath, and pick an exit
- * router (or use <b>exit</b> if provided). Store these in the
+ * router (or use <b>exit_ei</b> if provided). Store these in the
* cpath.
*
* If <b>is_hs_v3_rp_circuit</b> is set, then this exit should be suitable to
@@ -2038,7 +2077,7 @@ onion_pick_cpath_exit(origin_circuit_t *circ, extend_info_t *exit_ei,
if (state->onehop_tunnel) {
log_debug(LD_CIRC, "Launching a one-hop circuit for dir tunnel%s.",
- (rend_allow_non_anonymous_connection(get_options()) ?
+ (hs_service_allow_non_anonymous_connection(get_options()) ?
", or intro or rendezvous connection" : ""));
state->desired_path_len = 1;
} else {
@@ -2068,7 +2107,10 @@ onion_pick_cpath_exit(origin_circuit_t *circ, extend_info_t *exit_ei,
log_warn(LD_CIRC,"Failed to choose an exit server");
return -1;
}
- exit_ei = extend_info_from_node(node, state->onehop_tunnel);
+ exit_ei = extend_info_from_node(node, state->onehop_tunnel,
+ /* for_exit_use */
+ !state->is_internal && TO_CIRCUIT(circ)->purpose ==
+ CIRCUIT_PURPOSE_C_GENERAL);
if (BUG(exit_ei == NULL))
return -1;
}
@@ -2076,7 +2118,7 @@ onion_pick_cpath_exit(origin_circuit_t *circ, extend_info_t *exit_ei,
return 0;
}
-/** Give <b>circ</b> a new exit destination to <b>exit</b>, and add a
+/** Give <b>circ</b> a new exit destination to <b>exit_ei</b>, and add a
* hop to the cpath reflecting this. Don't send the next extend cell --
* the caller will do this if it wants to.
*/
@@ -2118,8 +2160,6 @@ circuit_extend_to_new_exit(origin_circuit_t *circ, extend_info_t *exit_ei)
return -1;
}
- // XXX: Should cannibalized circuits be dirty or not? Not easy to say..
-
return 0;
}
@@ -2265,8 +2305,14 @@ middle_node_must_be_vanguard(const or_options_t *options,
return 0;
}
- /* If we have sticky L2 nodes, and this is an L2 pick, use vanguards */
- if (options->HSLayer2Nodes && cur_len == 1) {
+ /* Don't even bother if the feature is disabled */
+ if (!vanguards_lite_is_enabled()) {
+ return 0;
+ }
+
+ /* If we are a hidden service circuit, always use either vanguards-lite
+ * or HSLayer2Nodes for 2nd hop. */
+ if (cur_len == 1) {
return 1;
}
@@ -2290,7 +2336,8 @@ pick_vanguard_middle_node(const or_options_t *options,
/* Pick the right routerset based on the current hop */
if (cur_len == 1) {
- vanguard_routerset = options->HSLayer2Nodes;
+ vanguard_routerset = options->HSLayer2Nodes ?
+ options->HSLayer2Nodes : get_layer2_guards();
} else if (cur_len == 2) {
vanguard_routerset = options->HSLayer3Nodes;
} else {
@@ -2299,6 +2346,10 @@ pick_vanguard_middle_node(const or_options_t *options,
return NULL;
}
+ if (BUG(!vanguard_routerset)) {
+ return NULL;
+ }
+
node = pick_restricted_middle_node(flags, vanguard_routerset,
options->ExcludeNodes, excluded,
cur_len+1);
@@ -2455,7 +2506,7 @@ onion_extend_cpath(origin_circuit_t *circ)
primary address, for potentially connecting to an IPv6 OR
port. Servers always want the primary (IPv4) address. */
int client = (server_mode(get_options()) == 0);
- info = extend_info_from_node(r, client);
+ info = extend_info_from_node(r, client, false);
/* Clients can fail to find an allowed address */
tor_assert_nonfatal(info || client);
}
@@ -2463,13 +2514,24 @@ onion_extend_cpath(origin_circuit_t *circ)
const node_t *r =
choose_good_middle_server(purpose, state, circ->cpath, cur_len);
if (r) {
- info = extend_info_from_node(r, 0);
+ info = extend_info_from_node(r, 0, false);
}
}
if (!info) {
- log_warn(LD_CIRC,"Failed to find node for hop #%d of our path. Discarding "
- "this circuit.", cur_len+1);
+ /* This can happen on first startup, possibly due to insufficient relays
+ * downloaded to pick vanguards-lite layer2 nodes, or other ephemeral
+ * reasons. It only happens briefly, is hard to reproduce, and then goes
+ * away for ever. :/ */
+ if (!router_have_minimum_dir_info()) {
+ log_info(LD_CIRC,
+ "Failed to find node for hop #%d of our path. Discarding "
+ "this circuit.", cur_len+1);
+ } else {
+ log_notice(LD_CIRC,
+ "Failed to find node for hop #%d of our path. Discarding "
+ "this circuit.", cur_len+1);
+ }
return -1;
}
@@ -2573,3 +2635,25 @@ circuit_upgrade_circuits_from_guard_wait(void)
smartlist_free(to_upgrade);
}
+
+/**
+ * Try to generate a circuit-negotiation message for communication with a
+ * given relay. Assumes we are using ntor v3, or some later version that
+ * supports parameter negotiatoin.
+ *
+ * On success, return 0 and pass back a message in the `out` parameters.
+ * Otherwise, return -1.
+ **/
+int
+client_circ_negotiation_message(const extend_info_t *ei,
+ uint8_t **msg_out,
+ size_t *msg_len_out)
+{
+ tor_assert(ei && msg_out && msg_len_out);
+
+ if (!ei->exit_supports_congestion_control) {
+ return -1;
+ }
+
+ return congestion_control_build_ext_request(msg_out, msg_len_out);
+}
diff --git a/src/core/or/circuitbuild.h b/src/core/or/circuitbuild.h
index 0cd1eb4f45..a66c611132 100644
--- a/src/core/or/circuitbuild.h
+++ b/src/core/or/circuitbuild.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -64,6 +64,10 @@ circuit_deliver_create_cell,(circuit_t *circ,
const struct create_cell_t *create_cell,
int relayed));
+int client_circ_negotiation_message(const extend_info_t *ei,
+ uint8_t **msg_out,
+ size_t *msg_len_out);
+
#ifdef CIRCUITBUILD_PRIVATE
STATIC circid_t get_unique_circ_id_by_chan(channel_t *chan);
STATIC int new_route_len(uint8_t purpose, extend_info_t *exit_ei,
diff --git a/src/core/or/circuitlist.c b/src/core/or/circuitlist.c
index bd36683880..50dc2ee338 100644
--- a/src/core/or/circuitlist.c
+++ b/src/core/or/circuitlist.c
@@ -1,7 +1,7 @@
/* Copyright 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -43,7 +43,6 @@
* For hidden services, we need to be able to look up introduction point
* circuits and rendezvous circuits by cookie, key, etc. These are
* currently handled with linear searches in
- * circuit_get_ready_rend_circuit_by_rend_data(),
* circuit_get_next_by_pk_and_purpose(), and with hash lookups in
* circuit_get_rendezvous() and circuit_get_intro_point().
*
@@ -65,6 +64,7 @@
#include "core/or/circuitpadding.h"
#include "core/or/crypt_path.h"
#include "core/or/extendinfo.h"
+#include "core/or/status.h"
#include "core/or/trace_probes_circuit.h"
#include "core/mainloop/connection.h"
#include "app/config/config.h"
@@ -77,6 +77,7 @@
#include "feature/dircommon/directory.h"
#include "feature/client/entrynodes.h"
#include "core/mainloop/mainloop.h"
+#include "feature/hs/hs_cache.h"
#include "feature/hs/hs_circuit.h"
#include "feature/hs/hs_circuitmap.h"
#include "feature/hs/hs_ident.h"
@@ -88,7 +89,6 @@
#include "core/or/policies.h"
#include "core/or/relay.h"
#include "core/crypto/relay_crypto.h"
-#include "feature/rend/rendclient.h"
#include "feature/rend/rendcommon.h"
#include "feature/stats/predict_ports.h"
#include "feature/stats/bwhist.h"
@@ -101,6 +101,9 @@
#include "lib/compress/compress_zlib.h"
#include "lib/compress/compress_zstd.h"
#include "lib/buf/buffers.h"
+#include "core/or/congestion_control_common.h"
+#include "core/or/congestion_control_st.h"
+#include "lib/math/stats.h"
#include "core/or/ocirc_event.h"
@@ -135,7 +138,6 @@ static smartlist_t *circuits_pending_other_guards = NULL;
* circuit_mark_for_close and which are waiting for circuit_about_to_free. */
static smartlist_t *circuits_pending_close = NULL;
-static void cpath_ref_decref(crypt_path_reference_t *cpath_ref);
static void circuit_about_to_free_atexit(circuit_t *circ);
static void circuit_about_to_free(circuit_t *circ);
@@ -147,6 +149,13 @@ static void circuit_about_to_free(circuit_t *circ);
*/
static int any_opened_circs_cached_val = 0;
+/** Moving average of the cc->cwnd from each closed circuit. */
+double cc_stats_circ_close_cwnd_ma = 0;
+/** Moving average of the cc->cwnd from each closed slow-start circuit. */
+double cc_stats_circ_close_ss_cwnd_ma = 0;
+
+uint64_t cc_stats_circs_closed = 0;
+
/********* END VARIABLES ************/
/* Implement circuit handle helpers. */
@@ -1145,6 +1154,8 @@ circuit_free_(circuit_t *circ)
* hs identifier is freed. */
hs_circ_cleanup_on_free(circ);
+ congestion_control_free(circ->ccontrol);
+
if (CIRCUIT_IS_ORIGIN(circ)) {
origin_circuit_t *ocirc = TO_ORIGIN_CIRCUIT(circ);
mem = ocirc;
@@ -1163,8 +1174,6 @@ circuit_free_(circuit_t *circ)
if (ocirc->build_state) {
extend_info_free(ocirc->build_state->chosen_exit);
- cpath_free(ocirc->build_state->pending_final_cpath);
- cpath_ref_decref(ocirc->build_state->service_pending_final_cpath_ref);
}
tor_free(ocirc->build_state);
@@ -1177,7 +1186,6 @@ circuit_free_(circuit_t *circ)
circuit_clear_cpath(ocirc);
crypto_pk_free(ocirc->intro_key);
- rend_data_free(ocirc->rend_data);
/* Finally, free the identifier of the circuit and nullify it so multiple
* cleanup will work. */
@@ -1354,18 +1362,6 @@ circuit_free_all(void)
HT_CLEAR(chan_circid_map, &chan_circid_map);
}
-/** Release a crypt_path_reference_t*, which may be NULL. */
-static void
-cpath_ref_decref(crypt_path_reference_t *cpath_ref)
-{
- if (cpath_ref != NULL) {
- if (--(cpath_ref->refcount) == 0) {
- cpath_free(cpath_ref->cpath);
- tor_free(cpath_ref);
- }
- }
-}
-
/** A helper function for circuit_dump_by_conn() below. Log a bunch
* of information about circuit <b>circ</b>.
*/
@@ -1684,37 +1680,6 @@ circuit_unlink_all_from_channel(channel_t *chan, int reason)
smartlist_free(detached);
}
-/** Return a circ such that
- * - circ-\>rend_data-\>onion_address is equal to
- * <b>rend_data</b>-\>onion_address,
- * - circ-\>rend_data-\>rend_cookie is equal to
- * <b>rend_data</b>-\>rend_cookie, and
- * - circ-\>purpose is equal to CIRCUIT_PURPOSE_C_REND_READY.
- *
- * Return NULL if no such circuit exists.
- */
-origin_circuit_t *
-circuit_get_ready_rend_circ_by_rend_data(const rend_data_t *rend_data)
-{
- SMARTLIST_FOREACH_BEGIN(circuit_get_global_list(), circuit_t *, circ) {
- if (!circ->marked_for_close &&
- circ->purpose == CIRCUIT_PURPOSE_C_REND_READY) {
- origin_circuit_t *ocirc = TO_ORIGIN_CIRCUIT(circ);
- if (ocirc->rend_data == NULL) {
- continue;
- }
- if (!rend_cmp_service_ids(rend_data_get_address(rend_data),
- rend_data_get_address(ocirc->rend_data)) &&
- tor_memeq(ocirc->rend_data->rend_cookie,
- rend_data->rend_cookie,
- REND_COOKIE_LEN))
- return ocirc;
- }
- }
- SMARTLIST_FOREACH_END(circ);
- return NULL;
-}
-
/** Return the first introduction circuit originating from the global circuit
* list after <b>start</b> or at the start of the list if <b>start</b> is
* NULL. Return NULL if no circuit is found.
@@ -1811,14 +1776,10 @@ circuit_get_next_service_rp_circ(origin_circuit_t *start)
}
/** Return the first circuit originating here in global_circuitlist after
- * <b>start</b> whose purpose is <b>purpose</b>, and where <b>digest</b> (if
- * set) matches the private key digest of the rend data associated with the
- * circuit. Return NULL if no circuit is found. If <b>start</b> is NULL,
- * begin at the start of the list.
- */
+ * <b>start</b> whose purpose is <b>purpose</b>. Return NULL if no circuit is
+ * found. If <b>start</b> is NULL, begin at the start of the list. */
origin_circuit_t *
-circuit_get_next_by_pk_and_purpose(origin_circuit_t *start,
- const uint8_t *digest, uint8_t purpose)
+circuit_get_next_by_purpose(origin_circuit_t *start, uint8_t purpose)
{
int idx;
smartlist_t *lst = circuit_get_global_list();
@@ -1830,7 +1791,6 @@ circuit_get_next_by_pk_and_purpose(origin_circuit_t *start,
for ( ; idx < smartlist_len(lst); ++idx) {
circuit_t *circ = smartlist_get(lst, idx);
- origin_circuit_t *ocirc;
if (circ->marked_for_close)
continue;
@@ -1841,12 +1801,7 @@ circuit_get_next_by_pk_and_purpose(origin_circuit_t *start,
if (BUG(!CIRCUIT_PURPOSE_IS_ORIGIN(circ->purpose))) {
break;
}
- ocirc = TO_ORIGIN_CIRCUIT(circ);
- if (!digest)
- return ocirc;
- if (rend_circuit_pk_digest_eq(ocirc, digest)) {
- return ocirc;
- }
+ return TO_ORIGIN_CIRCUIT(circ);
}
return NULL;
}
@@ -2279,6 +2234,26 @@ 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);
+ /* Update stats. */
+ if (circ->ccontrol) {
+ if (circ->ccontrol->in_slow_start) {
+ /* If we are in slow start, only count the ss cwnd if we've sent
+ * enough data to get RTT measurements such that we have a min
+ * and a max RTT, and they are not the same. This prevents us from
+ * averaging and reporting unused and low-use circuits here */
+ if (circ->ccontrol->max_rtt_usec != circ->ccontrol->min_rtt_usec) {
+ cc_stats_circ_close_ss_cwnd_ma =
+ stats_update_running_avg(cc_stats_circ_close_ss_cwnd_ma,
+ circ->ccontrol->cwnd);
+ }
+ } else {
+ cc_stats_circ_close_cwnd_ma =
+ stats_update_running_avg(cc_stats_circ_close_cwnd_ma,
+ circ->ccontrol->cwnd);
+ }
+ cc_stats_circs_closed++;
+ }
+
if (circuits_pending_close == NULL)
circuits_pending_close = smartlist_new();
@@ -2401,6 +2376,12 @@ circuit_about_to_free(circuit_t *circ)
circuitmux_detach_circuit(or_circ->p_chan->cmux, circ);
circuit_set_p_circid_chan(or_circ, 0, NULL);
}
+
+ if (or_circ->n_cells_discarded_at_end) {
+ time_t age = approx_time() - circ->timestamp_created.tv_sec;
+ note_circ_closed_for_unrecognized_cells(
+ age, or_circ->n_cells_discarded_at_end);
+ }
} else {
origin_circuit_t *ocirc = TO_ORIGIN_CIRCUIT(circ);
edge_connection_t *conn;
@@ -2644,8 +2625,10 @@ conns_compare_by_buffer_age_(const void **a_, const void **b_)
/** We're out of memory for cells, having allocated <b>current_allocation</b>
* bytes' worth. Kill the 'worst' circuits until we're under
- * FRACTION_OF_DATA_TO_RETAIN_ON_OOM of our maximum usage. */
-void
+ * FRACTION_OF_DATA_TO_RETAIN_ON_OOM of our maximum usage.
+ *
+ * Return the number of bytes removed. */
+size_t
circuits_handle_oom(size_t current_allocation)
{
smartlist_t *circlist;
@@ -2655,6 +2638,7 @@ circuits_handle_oom(size_t current_allocation)
size_t mem_recovered=0;
int n_circuits_killed=0;
int n_dirconns_killed=0;
+ int n_edgeconns_killed = 0;
uint32_t now_ts;
log_notice(LD_GENERAL, "We're low on memory (cell queues total alloc:"
" %"TOR_PRIuSZ" buffer total alloc: %" TOR_PRIuSZ ","
@@ -2670,13 +2654,12 @@ circuits_handle_oom(size_t current_allocation)
tor_zlib_get_total_allocation(),
tor_zstd_get_total_allocation(),
tor_lzma_get_total_allocation(),
- rend_cache_get_total_allocation());
-
+ hs_cache_get_total_allocation());
{
size_t mem_target = (size_t)(get_options()->MaxMemInQueues *
FRACTION_OF_DATA_TO_RETAIN_ON_OOM);
if (current_allocation <= mem_target)
- return;
+ return 0;
mem_to_recover = current_allocation - mem_target;
}
@@ -2722,12 +2705,19 @@ circuits_handle_oom(size_t current_allocation)
if (conn_age < circ->age_tmp) {
break;
}
- if (conn->type == CONN_TYPE_DIR && conn->linked_conn == NULL) {
+ /* Also consider edge connections so we don't accumulate bytes on the
+ * outbuf due to a malicious destination holding off the read on us. */
+ if ((conn->type == CONN_TYPE_DIR && conn->linked_conn == NULL) ||
+ CONN_IS_EDGE(conn)) {
if (!conn->marked_for_close)
connection_mark_for_close(conn);
mem_recovered += single_conn_free_bytes(conn);
- ++n_dirconns_killed;
+ if (conn->type == CONN_TYPE_DIR) {
+ ++n_dirconns_killed;
+ } else {
+ ++n_edgeconns_killed;
+ }
if (mem_recovered >= mem_to_recover)
goto done_recovering_mem;
@@ -2755,14 +2745,16 @@ circuits_handle_oom(size_t current_allocation)
} SMARTLIST_FOREACH_END(circ);
done_recovering_mem:
-
log_notice(LD_GENERAL, "Removed %"TOR_PRIuSZ" bytes by killing %d circuits; "
"%d circuits remain alive. Also killed %d non-linked directory "
- "connections.",
+ "connections. Killed %d edge connections",
mem_recovered,
n_circuits_killed,
smartlist_len(circlist) - n_circuits_killed,
- n_dirconns_killed);
+ n_dirconns_killed,
+ n_edgeconns_killed);
+
+ return mem_recovered;
}
/** Verify that circuit <b>c</b> has all of its invariants
diff --git a/src/core/or/circuitlist.h b/src/core/or/circuitlist.h
index bd4a117e26..541a708de2 100644
--- a/src/core/or/circuitlist.h
+++ b/src/core/or/circuitlist.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -60,9 +60,7 @@
* to becoming open, or they are open and have sent the
* establish_rendezvous cell but haven't received an ack.
* circuits that are c_rend_ready are open and have received a
- * rend ack, but haven't heard from the service yet. if they have a
- * buildstate->pending_final_cpath then they're expecting a
- * cell from the service, else they're not.
+ * rend ack, but haven't heard from the service yet.
* circuits that are c_rend_ready_intro_acked are open, and
* some intro circ has sent its intro and received an ack.
* circuits that are c_rend_joined are open, have heard from
@@ -163,6 +161,11 @@
((p) == CIRCUIT_PURPOSE_C_GENERAL || \
(p) == CIRCUIT_PURPOSE_C_HSDIR_GET)
+/** Stats. */
+extern double cc_stats_circ_close_cwnd_ma;
+extern double cc_stats_circ_close_ss_cwnd_ma;
+extern uint64_t cc_stats_circs_closed;
+
/** Convert a circuit_t* to a pointer to the enclosing or_circuit_t. Assert
* if the cast is impossible. */
or_circuit_t *TO_OR_CIRCUIT(circuit_t *);
@@ -207,10 +210,8 @@ int circuit_id_in_use_on_channel(circid_t circ_id, channel_t *chan);
circuit_t *circuit_get_by_edge_conn(edge_connection_t *conn);
void circuit_unlink_all_from_channel(channel_t *chan, int reason);
origin_circuit_t *circuit_get_by_global_id(uint32_t id);
-origin_circuit_t *circuit_get_ready_rend_circ_by_rend_data(
- const rend_data_t *rend_data);
-origin_circuit_t *circuit_get_next_by_pk_and_purpose(origin_circuit_t *start,
- const uint8_t *digest, uint8_t purpose);
+origin_circuit_t *circuit_get_next_by_purpose(origin_circuit_t *start,
+ uint8_t purpose);
origin_circuit_t *circuit_get_next_intro_circ(const origin_circuit_t *start,
bool want_client_circ);
origin_circuit_t *circuit_get_next_service_rp_circ(origin_circuit_t *start);
@@ -236,7 +237,7 @@ int circuit_count_pending_on_channel(channel_t *chan);
MOCK_DECL(void, assert_circuit_ok,(const circuit_t *c));
void circuit_free_all(void);
-void circuits_handle_oom(size_t current_allocation);
+size_t circuits_handle_oom(size_t current_allocation);
void circuit_clear_testing_cell_stats(circuit_t *circ);
diff --git a/src/core/or/circuitmux.c b/src/core/or/circuitmux.c
index be54ae6ec6..6f8761ca39 100644
--- a/src/core/or/circuitmux.c
+++ b/src/core/or/circuitmux.c
@@ -1,4 +1,4 @@
-/* * Copyright (c) 2012-2020, The Tor Project, Inc. */
+/* * Copyright (c) 2012-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/core/or/circuitmux.h b/src/core/or/circuitmux.h
index 5e41ccc6ca..502b248f28 100644
--- a/src/core/or/circuitmux.h
+++ b/src/core/or/circuitmux.h
@@ -1,4 +1,4 @@
-/* * Copyright (c) 2012-2020, The Tor Project, Inc. */
+/* * Copyright (c) 2012-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/core/or/circuitmux_ewma.c b/src/core/or/circuitmux_ewma.c
index 0dcd22e8a7..adf256ab05 100644
--- a/src/core/or/circuitmux_ewma.c
+++ b/src/core/or/circuitmux_ewma.c
@@ -1,4 +1,4 @@
-/* * Copyright (c) 2012-2020, The Tor Project, Inc. */
+/* * Copyright (c) 2012-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -45,7 +45,10 @@
/*** EWMA parameter #defines ***/
/** How long does a tick last (seconds)? */
-#define EWMA_TICK_LEN 10
+#define EWMA_TICK_LEN_DEFAULT 10
+#define EWMA_TICK_LEN_MIN 1
+#define EWMA_TICK_LEN_MAX 600
+static int ewma_tick_len = EWMA_TICK_LEN_DEFAULT;
/** The default per-tick scale factor, if it hasn't been overridden by a
* consensus or a configuration setting. zero means "disabled". */
@@ -148,7 +151,7 @@ cell_ewma_get_tick(void)
monotime_coarse_get(&now);
int32_t msec_diff = monotime_coarse_diff_msec32(&start_of_current_tick,
&now);
- return current_tick_num + msec_diff / (1000*EWMA_TICK_LEN);
+ return current_tick_num + msec_diff / (1000*ewma_tick_len);
}
/**
@@ -527,15 +530,15 @@ cell_ewma_get_current_tick_and_fraction(double *remainder_out)
monotime_coarse_get(&now);
int32_t msec_diff = monotime_coarse_diff_msec32(&start_of_current_tick,
&now);
- if (msec_diff > (1000*EWMA_TICK_LEN)) {
- unsigned ticks_difference = msec_diff / (1000*EWMA_TICK_LEN);
+ if (msec_diff > (1000*ewma_tick_len)) {
+ unsigned ticks_difference = msec_diff / (1000*ewma_tick_len);
monotime_coarse_add_msec(&start_of_current_tick,
&start_of_current_tick,
- ticks_difference * 1000 * EWMA_TICK_LEN);
+ ticks_difference * 1000 * ewma_tick_len);
current_tick_num += ticks_difference;
- msec_diff %= 1000*EWMA_TICK_LEN;
+ msec_diff %= 1000*ewma_tick_len;
}
- *remainder_out = ((double)msec_diff) / (1.0e3 * EWMA_TICK_LEN);
+ *remainder_out = ((double)msec_diff) / (1.0e3 * ewma_tick_len);
return current_tick_num;
}
@@ -605,15 +608,20 @@ cmux_ewma_set_options(const or_options_t *options,
/* Both options and consensus can be NULL. This assures us to either get a
* valid configured value or the default one. */
halflife = get_circuit_priority_halflife(options, consensus, &source);
+ ewma_tick_len = networkstatus_get_param(consensus,
+ "CircuitPriorityTickSecs",
+ EWMA_TICK_LEN_DEFAULT,
+ EWMA_TICK_LEN_MIN,
+ EWMA_TICK_LEN_MAX);
/* convert halflife into halflife-per-tick. */
- halflife /= EWMA_TICK_LEN;
+ halflife /= ewma_tick_len;
/* compute per-tick scale factor. */
ewma_scale_factor = exp(LOG_ONEHALF / halflife);
log_info(LD_OR,
"Enabled cell_ewma algorithm because of value in %s; "
"scale factor is %f per %d seconds",
- source, ewma_scale_factor, EWMA_TICK_LEN);
+ source, ewma_scale_factor, ewma_tick_len);
}
/** Return the multiplier necessary to convert the value of a cell sent in
diff --git a/src/core/or/circuitmux_ewma.h b/src/core/or/circuitmux_ewma.h
index e41cf9e0f0..93805532ef 100644
--- a/src/core/or/circuitmux_ewma.h
+++ b/src/core/or/circuitmux_ewma.h
@@ -1,4 +1,4 @@
-/* * Copyright (c) 2012-2020, The Tor Project, Inc. */
+/* * Copyright (c) 2012-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/core/or/circuitpadding.c b/src/core/or/circuitpadding.c
index 6dfe94de01..99dc5f9d83 100644
--- a/src/core/or/circuitpadding.c
+++ b/src/core/or/circuitpadding.c
@@ -2967,6 +2967,8 @@ signed_error_t
circpad_handle_padding_negotiate(circuit_t *circ, cell_t *cell)
{
int retval = 0;
+ /* Should we send back a STOP cell? */
+ bool respond_with_stop = true;
circpad_negotiate_t *negotiate;
if (CIRCUIT_IS_ORIGIN(circ)) {
@@ -2992,6 +2994,12 @@ circpad_handle_padding_negotiate(circuit_t *circ, cell_t *cell)
negotiate->machine_type, negotiate->machine_ctr);
goto done;
}
+
+ /* If we reached this point we received a STOP command from an old or
+ unknown machine. Don't reply with our own STOP since there is no one to
+ handle it on the other end */
+ respond_with_stop = false;
+
if (negotiate->machine_ctr <= circ->padding_machine_ctr) {
log_info(LD_CIRC, "Received STOP command for old machine %u, ctr %u",
negotiate->machine_type, negotiate->machine_ctr);
@@ -3023,10 +3031,13 @@ circpad_handle_padding_negotiate(circuit_t *circ, cell_t *cell)
retval = -1;
done:
- circpad_padding_negotiated(circ, negotiate->machine_type,
- negotiate->command,
- (retval == 0) ? CIRCPAD_RESPONSE_OK : CIRCPAD_RESPONSE_ERR,
- negotiate->machine_ctr);
+ if (respond_with_stop) {
+ circpad_padding_negotiated(circ, negotiate->machine_type,
+ negotiate->command,
+ (retval == 0) ? CIRCPAD_RESPONSE_OK : CIRCPAD_RESPONSE_ERR,
+ negotiate->machine_ctr);
+ }
+
circpad_negotiate_free(negotiate);
return retval;
diff --git a/src/core/or/circuitpadding.h b/src/core/or/circuitpadding.h
index 3d2929cf74..306d178684 100644
--- a/src/core/or/circuitpadding.h
+++ b/src/core/or/circuitpadding.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2020, The Tor Project, Inc. */
+ * Copyright (c) 2017-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/core/or/circuitstats.c b/src/core/or/circuitstats.c
index 51bd9e1208..f55771c79e 100644
--- a/src/core/or/circuitstats.c
+++ b/src/core/or/circuitstats.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -34,8 +34,6 @@
#include "lib/crypt_ops/crypto_rand.h"
#include "core/mainloop/mainloop.h"
#include "feature/nodelist/networkstatus.h"
-#include "feature/rend/rendclient.h"
-#include "feature/rend/rendservice.h"
#include "feature/relay/router.h"
#include "app/config/statefile.h"
#include "core/or/circuitlist.h"
@@ -44,6 +42,7 @@
#include "lib/time/tvdiff.h"
#include "lib/encoding/confline.h"
#include "feature/dirauth/authmode.h"
+#include "feature/hs/hs_service.h"
#include "feature/relay/relay_periodic.h"
#include "core/or/crypt_path_st.h"
@@ -146,8 +145,8 @@ circuit_build_times_disabled_(const or_options_t *options,
*
* If we fix both of these issues someday, we should test
* these modes with LearnCircuitBuildTimeout on again. */
- int single_onion_disabled = rend_service_allow_non_anonymous_connection(
- options);
+ int single_onion_disabled = hs_service_allow_non_anonymous_connection(
+ options);
if (consensus_disabled || config_disabled || dirauth_disabled ||
state_disabled || single_onion_disabled) {
@@ -203,10 +202,10 @@ circuit_build_times_max_timeouts(void)
* Retrieve and bounds-check the cbtnummodes consensus parameter.
*
* Effect: This value governs how many modes to use in the weighted
- * average calculation of Pareto parameter Xm. A value of 3 introduces
- * some bias (2-5% of CDF) under ideal conditions, but allows for better
- * performance in the event that a client chooses guard nodes of radically
- * different performance characteristics.
+ * average calculation of Pareto parameter Xm. Analysis of pairs of
+ * geographically near, far, and mixed guaeds has shown that a value of
+ * 10 introduces some allows for the actual timeout rate to be within
+ * 2-7% of the cutoff quantile, for quantiles between 60-80%.
*/
static int32_t
circuit_build_times_default_num_xm_modes(void)
@@ -851,58 +850,49 @@ circuit_build_times_create_histogram(const circuit_build_times_t *cbt,
* Return the Pareto start-of-curve parameter Xm.
*
* Because we are not a true Pareto curve, we compute this as the
- * weighted average of the N most frequent build time bins. N is either
- * 1 if we don't have enough circuit build time data collected, or
- * determined by the consensus parameter cbtnummodes (default 3).
+ * weighted average of the 10 most frequent build time bins. This
+ * heuristic allowed for the actual timeout rate to be closest
+ * to the chosen quantile cutoff, for quantiles 60-80%, out of
+ * many variant approaches (see #40157 for analysis).
*/
-static build_time_t
+STATIC build_time_t
circuit_build_times_get_xm(circuit_build_times_t *cbt)
{
- build_time_t i, nbins;
+ build_time_t nbins = 0;
build_time_t *nth_max_bin;
- int32_t bin_counts=0;
- build_time_t ret = 0;
- uint32_t *histogram = circuit_build_times_create_histogram(cbt, &nbins);
- int n=0;
+ build_time_t xm_total = 0;
+ build_time_t Xm = 0;
+ int32_t xm_counts=0;
int num_modes = circuit_build_times_default_num_xm_modes();
+ uint32_t *histogram = circuit_build_times_create_histogram(cbt, &nbins);
tor_assert(nbins > 0);
tor_assert(num_modes > 0);
- // Only use one mode if < 1000 buildtimes. Not enough data
- // for multiple.
- if (cbt->total_build_times < CBT_NCIRCUITS_TO_OBSERVE)
- num_modes = 1;
-
nth_max_bin = tor_calloc(num_modes, sizeof(build_time_t));
- /* Determine the N most common build times */
- for (i = 0; i < nbins; i++) {
- if (histogram[i] >= histogram[nth_max_bin[0]]) {
- nth_max_bin[0] = i;
- }
-
- for (n = 1; n < num_modes; n++) {
- if (histogram[i] >= histogram[nth_max_bin[n]] &&
- (!histogram[nth_max_bin[n-1]]
- || histogram[i] < histogram[nth_max_bin[n-1]])) {
+ /* Determine the N most common build times, by selecting the
+ * nth largest mode, counting it, and removing it from the histogram. */
+ for (int n = 0; n < num_modes; n++) {
+ /* Get nth mode */
+ for (build_time_t i = 0; i < nbins; i++) {
+ if (histogram[i] > histogram[nth_max_bin[n]]) {
nth_max_bin[n] = i;
}
}
- }
- for (n = 0; n < num_modes; n++) {
- bin_counts += histogram[nth_max_bin[n]];
- ret += CBT_BIN_TO_MS(nth_max_bin[n])*histogram[nth_max_bin[n]];
- log_info(LD_CIRC, "Xm mode #%d: %u %u", n, CBT_BIN_TO_MS(nth_max_bin[n]),
- histogram[nth_max_bin[n]]);
+ /* Update average */
+ xm_counts += histogram[nth_max_bin[n]];
+ xm_total += CBT_BIN_TO_MS(nth_max_bin[n])*histogram[nth_max_bin[n]];
+
+ /* Prevent from re-counting this value */
+ histogram[nth_max_bin[n]] = 0;
}
- /* bin_counts can become zero if all of our last CBT_NCIRCUITS_TO_OBSERVE
+ /* xm_counts can become zero if all of our last CBT_NCIRCUITS_TO_OBSERVE
* circuits were abandoned before they completed. This shouldn't happen,
* though. We should have reset/re-learned a lower timeout first. */
- if (bin_counts == 0) {
- ret = 0;
+ if (xm_counts == 0) {
log_warn(LD_CIRC,
"No valid circuit build time data out of %d times, %u modes, "
"have_timeout=%d, %lfms", cbt->total_build_times, num_modes,
@@ -910,15 +900,13 @@ circuit_build_times_get_xm(circuit_build_times_t *cbt)
goto done;
}
- tor_assert(bin_counts > 0);
-
- ret /= bin_counts;
+ Xm = xm_total / xm_counts;
done:
tor_free(histogram);
tor_free(nth_max_bin);
- return ret;
+ return Xm;
}
/**
@@ -1008,43 +996,6 @@ circuit_build_times_shuffle_and_store_array(circuit_build_times_t *cbt,
}
/**
- * Filter old synthetic timeouts that were created before the
- * new right-censored Pareto calculation was deployed.
- *
- * Once all clients before 0.2.1.13-alpha are gone, this code
- * will be unused.
- */
-static int
-circuit_build_times_filter_timeouts(circuit_build_times_t *cbt)
-{
- int num_filtered=0, i=0;
- double timeout_rate = 0;
- build_time_t max_timeout = 0;
-
- timeout_rate = circuit_build_times_timeout_rate(cbt);
- max_timeout = (build_time_t)cbt->close_ms;
-
- for (i = 0; i < CBT_NCIRCUITS_TO_OBSERVE; i++) {
- if (cbt->circuit_build_times[i] > max_timeout) {
- build_time_t replaced = cbt->circuit_build_times[i];
- num_filtered++;
- cbt->circuit_build_times[i] = CBT_BUILD_ABANDONED;
-
- log_debug(LD_CIRC, "Replaced timeout %d with %d", replaced,
- cbt->circuit_build_times[i]);
- }
- }
-
- log_info(LD_CIRC,
- "We had %d timeouts out of %d build times, "
- "and filtered %d above the max of %u",
- (int)(cbt->total_build_times*timeout_rate),
- cbt->total_build_times, num_filtered, max_timeout);
-
- return num_filtered;
-}
-
-/**
* Load histogram from <b>state</b>, shuffling the resulting array
* after we do so. Use this result to estimate parameters and
* calculate the timeout.
@@ -1169,10 +1120,6 @@ circuit_build_times_parse_state(circuit_build_times_t *cbt,
circuit_build_times_set_timeout(cbt);
- if (!state->CircuitBuildAbandonedCount && cbt->total_build_times) {
- circuit_build_times_filter_timeouts(cbt);
- }
-
done:
tor_free(loaded_times);
return err ? -1 : 0;
@@ -1193,7 +1140,6 @@ circuit_build_times_update_alpha(circuit_build_times_t *cbt)
build_time_t *x=cbt->circuit_build_times;
double a = 0;
int n=0,i=0,abandoned_count=0;
- build_time_t max_time=0;
/* https://en.wikipedia.org/wiki/Pareto_distribution#Parameter_estimation */
/* We sort of cheat here and make our samples slightly more pareto-like
@@ -1213,14 +1159,13 @@ circuit_build_times_update_alpha(circuit_build_times_t *cbt)
if (x[i] < cbt->Xm) {
a += tor_mathlog(cbt->Xm);
+ n++;
} else if (x[i] == CBT_BUILD_ABANDONED) {
abandoned_count++;
} else {
a += tor_mathlog(x[i]);
- if (x[i] > max_time)
- max_time = x[i];
+ n++;
}
- n++;
}
/*
@@ -1229,30 +1174,23 @@ circuit_build_times_update_alpha(circuit_build_times_t *cbt)
* performs this same check, and resets state if it hits it. If we
* hit it at runtime, something serious has gone wrong.
*/
- if (n!=cbt->total_build_times) {
+ if (n!=cbt->total_build_times-abandoned_count) {
log_err(LD_CIRC, "Discrepancy in build times count: %d vs %d", n,
cbt->total_build_times);
}
- tor_assert(n==cbt->total_build_times);
-
- if (max_time <= 0) {
- /* This can happen if Xm is actually the *maximum* value in the set.
- * It can also happen if we've abandoned every single circuit somehow.
- * In either case, tell the caller not to compute a new build timeout. */
- log_warn(LD_BUG,
- "Could not determine largest build time (%d). "
- "Xm is %dms and we've abandoned %d out of %d circuits.", max_time,
- cbt->Xm, abandoned_count, n);
- return 0;
- }
-
- a += abandoned_count*tor_mathlog(max_time);
+ tor_assert_nonfatal(n==cbt->total_build_times-abandoned_count);
+ /* This is the "Maximum Likelihood Estimator" for parameter alpha of a Pareto
+ * Distribution. See:
+ * https://en.wikipedia.org/wiki/Pareto_distribution#Estimation_of_parameters
+ *
+ * The division in the estimator is done with subtraction outside the ln(),
+ * with the sum occurring in the for loop above.
+ *
+ * This done is to avoid the precision issues of logs of small values.
+ */
a -= n*tor_mathlog(cbt->Xm);
- // Estimator comes from Eq #4 in:
- // "Bayesian estimation based on trimmed samples from Pareto populations"
- // by Arturo J. Fernández. We are right-censored only.
- a = (n-abandoned_count)/a;
+ a = n/a;
cbt->alpha = a;
@@ -1661,9 +1599,8 @@ circuit_build_times_network_check_changed(circuit_build_times_t *cbt)
log_notice(LD_CIRC,
"Your network connection speed appears to have changed. Resetting "
- "timeout to %lds after %d timeouts and %d buildtimes.",
- tor_lround(cbt->timeout_ms/1000), timeout_count,
- total_build_times);
+ "timeout to %ldms after %d timeouts and %d buildtimes.",
+ tor_lround(cbt->timeout_ms), timeout_count, total_build_times);
return 1;
}
@@ -1829,7 +1766,7 @@ circuit_build_times_set_timeout(circuit_build_times_t *cbt)
return;
if (cbt->timeout_ms < circuit_build_times_min_timeout()) {
- log_info(LD_CIRC, "Set buildtimeout to low value %fms. Setting to %dms",
+ log_notice(LD_CIRC, "Set buildtimeout to low value %fms. Setting to %dms",
cbt->timeout_ms, circuit_build_times_min_timeout());
cbt->timeout_ms = circuit_build_times_min_timeout();
if (cbt->close_ms < cbt->timeout_ms) {
@@ -1847,9 +1784,9 @@ circuit_build_times_set_timeout(circuit_build_times_t *cbt)
log_info(LD_CIRC,
"Based on %d circuit times, it looks like we don't need to "
"wait so long for circuits to finish. We will now assume a "
- "circuit is too slow to use after waiting %ld seconds.",
+ "circuit is too slow to use after waiting %ld milliseconds.",
cbt->total_build_times,
- tor_lround(cbt->timeout_ms/1000));
+ tor_lround(cbt->timeout_ms));
log_info(LD_CIRC,
"Circuit timeout data: %fms, %fms, Xm: %d, a: %f, r: %f",
cbt->timeout_ms, cbt->close_ms, cbt->Xm, cbt->alpha,
@@ -1858,18 +1795,18 @@ circuit_build_times_set_timeout(circuit_build_times_t *cbt)
log_info(LD_CIRC,
"Based on %d circuit times, it looks like we need to wait "
"longer for circuits to finish. We will now assume a "
- "circuit is too slow to use after waiting %ld seconds.",
+ "circuit is too slow to use after waiting %ld milliseconds.",
cbt->total_build_times,
- tor_lround(cbt->timeout_ms/1000));
+ tor_lround(cbt->timeout_ms));
log_info(LD_CIRC,
"Circuit timeout data: %fms, %fms, Xm: %d, a: %f, r: %f",
cbt->timeout_ms, cbt->close_ms, cbt->Xm, cbt->alpha,
timeout_rate);
} else {
log_info(LD_CIRC,
- "Set circuit build timeout to %lds (%fms, %fms, Xm: %d, a: %f,"
+ "Set circuit build timeout to %ldms (%fms, %fms, Xm: %d, a: %f,"
" r: %f) based on %d circuit times",
- tor_lround(cbt->timeout_ms/1000),
+ tor_lround(cbt->timeout_ms),
cbt->timeout_ms, cbt->close_ms, cbt->Xm, cbt->alpha, timeout_rate,
cbt->total_build_times);
}
diff --git a/src/core/or/circuitstats.h b/src/core/or/circuitstats.h
index 930e0a9ba3..c175f7e4a0 100644
--- a/src/core/or/circuitstats.h
+++ b/src/core/or/circuitstats.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -56,10 +56,10 @@ void circuit_build_times_reset(circuit_build_times_t *cbt);
#define CBT_NCIRCUITS_TO_OBSERVE 1000
/** Width of the histogram bins in milliseconds */
-#define CBT_BIN_WIDTH ((build_time_t)50)
+#define CBT_BIN_WIDTH ((build_time_t)10)
/** Number of modes to use in the weighted-avg computation of Xm */
-#define CBT_DEFAULT_NUM_XM_MODES 3
+#define CBT_DEFAULT_NUM_XM_MODES 10
#define CBT_MIN_NUM_XM_MODES 1
#define CBT_MAX_NUM_XM_MODES 20
@@ -79,7 +79,7 @@ void circuit_build_times_reset(circuit_build_times_t *cbt);
* How long to wait before actually closing circuits that take too long to
* build in terms of CDF quantile.
*/
-#define CBT_DEFAULT_CLOSE_QUANTILE 95
+#define CBT_DEFAULT_CLOSE_QUANTILE 99
#define CBT_MIN_CLOSE_QUANTILE CBT_MIN_QUANTILE_CUTOFF
#define CBT_MAX_CLOSE_QUANTILE CBT_MAX_QUANTILE_CUTOFF
@@ -120,8 +120,8 @@ double circuit_build_times_quantile_cutoff(void);
#define CBT_MAX_TEST_FREQUENCY INT32_MAX
/** Lowest allowable value for CircuitBuildTimeout in milliseconds */
-#define CBT_DEFAULT_TIMEOUT_MIN_VALUE (1500)
-#define CBT_MIN_TIMEOUT_MIN_VALUE 500
+#define CBT_DEFAULT_TIMEOUT_MIN_VALUE (CBT_BIN_WIDTH)
+#define CBT_MIN_TIMEOUT_MIN_VALUE CBT_BIN_WIDTH
#define CBT_MAX_TIMEOUT_MIN_VALUE INT32_MAX
/** Initial circuit build timeout in milliseconds */
@@ -142,6 +142,7 @@ STATIC int circuit_build_times_update_alpha(circuit_build_times_t *cbt);
/* Network liveness functions */
STATIC int circuit_build_times_network_check_changed(
circuit_build_times_t *cbt);
+STATIC build_time_t circuit_build_times_get_xm(circuit_build_times_t *cbt);
#endif /* defined(CIRCUITSTATS_PRIVATE) */
#ifdef TOR_UNIT_TESTS
diff --git a/src/core/or/circuituse.c b/src/core/or/circuituse.c
index 059e43ec47..dbeea10821 100644
--- a/src/core/or/circuituse.c
+++ b/src/core/or/circuituse.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -58,9 +58,6 @@
#include "feature/nodelist/routerlist.h"
#include "feature/relay/routermode.h"
#include "feature/relay/selftest.h"
-#include "feature/rend/rendclient.h"
-#include "feature/rend/rendcommon.h"
-#include "feature/rend/rendservice.h"
#include "feature/stats/predict_ports.h"
#include "lib/math/fp.h"
#include "lib/time/tvdiff.h"
@@ -84,16 +81,6 @@ static int
circuit_matches_with_rend_stream(const edge_connection_t *edge_conn,
const origin_circuit_t *origin_circ)
{
- /* Check if this is a v2 rendezvous circ/stream */
- if ((edge_conn->rend_data && !origin_circ->rend_data) ||
- (!edge_conn->rend_data && origin_circ->rend_data) ||
- (edge_conn->rend_data && origin_circ->rend_data &&
- rend_cmp_service_ids(rend_data_get_address(edge_conn->rend_data),
- rend_data_get_address(origin_circ->rend_data)))) {
- /* this circ is not for this conn */
- return 0;
- }
-
/* Check if this is a v3 rendezvous circ/stream */
if ((edge_conn->hs_ident && !origin_circ->hs_ident) ||
(!edge_conn->hs_ident && origin_circ->hs_ident) ||
@@ -146,11 +133,6 @@ circuit_is_acceptable(const origin_circuit_t *origin_circ,
return 0;
}
- /* If this is a timed-out hidden service circuit, skip it. */
- if (origin_circ->hs_circ_has_timed_out) {
- return 0;
- }
-
if (purpose == CIRCUIT_PURPOSE_C_GENERAL ||
purpose == CIRCUIT_PURPOSE_C_HSDIR_GET ||
purpose == CIRCUIT_PURPOSE_S_HSDIR_POST ||
@@ -347,7 +329,6 @@ circuit_get_best(const entry_connection_t *conn,
{
origin_circuit_t *best=NULL;
struct timeval now;
- int intro_going_on_but_too_old = 0;
tor_assert(conn);
@@ -366,15 +347,6 @@ circuit_get_best(const entry_connection_t *conn,
continue;
origin_circ = TO_ORIGIN_CIRCUIT(circ);
- /* Log an info message if we're going to launch a new intro circ in
- * parallel */
- if (purpose == CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT &&
- !must_be_open && origin_circ->hs_circ_has_timed_out &&
- !circ->marked_for_close) {
- intro_going_on_but_too_old = 1;
- continue;
- }
-
if (!circuit_is_acceptable(origin_circ,conn,must_be_open,purpose,
need_uptime,need_internal, (time_t)now.tv_sec))
continue;
@@ -387,11 +359,6 @@ circuit_get_best(const entry_connection_t *conn,
}
SMARTLIST_FOREACH_END(circ);
- if (!best && intro_going_on_but_too_old)
- log_info(LD_REND|LD_CIRC, "There is an intro circuit being created "
- "right now, but it has already taken quite a while. Starting "
- "one in parallel.");
-
return best;
}
@@ -463,8 +430,9 @@ circuit_expire_building(void)
* circuit_build_times_get_initial_timeout() if we haven't computed
* custom timeouts yet */
struct timeval general_cutoff, begindir_cutoff, fourhop_cutoff,
- close_cutoff, extremely_old_cutoff, hs_extremely_old_cutoff,
- cannibalized_cutoff, c_intro_cutoff, s_intro_cutoff, stream_cutoff;
+ close_cutoff, extremely_old_cutoff,
+ cannibalized_cutoff, c_intro_cutoff, s_intro_cutoff, stream_cutoff,
+ c_rend_ready_cutoff;
const or_options_t *options = get_options();
struct timeval now;
cpath_build_state_t *build_state;
@@ -544,13 +512,19 @@ circuit_expire_building(void)
/* Server intro circs have an extra round trip */
SET_CUTOFF(s_intro_cutoff, get_circuit_build_timeout_ms() * (9/6.0) + 1000);
+ /* For circuit purpose set to: CIRCUIT_PURPOSE_C_REND_READY_INTRO_ACKED.
+ *
+ * The cutoff of such circuit is very high because we end up in this state if
+ * once the INTRODUCE_ACK is received which could be before the service
+ * receives the INTRODUCE2 cell. The worst case is a full 3-hop latency
+ * (intro -> service), 4-hop circuit creation latency (service -> RP), and
+ * finally a 7-hop latency for the RENDEZVOUS2 cell to arrive (service ->
+ * client). */
+ SET_CUTOFF(c_rend_ready_cutoff, get_circuit_build_timeout_ms() * 3 + 1000);
+
SET_CUTOFF(close_cutoff, get_circuit_build_close_time_ms());
SET_CUTOFF(extremely_old_cutoff, get_circuit_build_close_time_ms()*2 + 1000);
- SET_CUTOFF(hs_extremely_old_cutoff,
- MAX(get_circuit_build_close_time_ms()*2 + 1000,
- options->SocksTimeout * 1000));
-
bool fixed_time = circuit_build_times_disabled(get_options());
SMARTLIST_FOREACH_BEGIN(circuit_get_global_list(), circuit_t *,victim) {
@@ -581,8 +555,12 @@ circuit_expire_building(void)
cutoff = c_intro_cutoff;
else if (victim->purpose == CIRCUIT_PURPOSE_S_ESTABLISH_INTRO)
cutoff = s_intro_cutoff;
- else if (victim->purpose == CIRCUIT_PURPOSE_C_ESTABLISH_REND)
- cutoff = stream_cutoff;
+ else if (victim->purpose == CIRCUIT_PURPOSE_S_CONNECT_REND) {
+ /* Service connecting to a rendezvous point is a four hop circuit. We set
+ * it explicitly here because this function is a clusterf***. */
+ cutoff = fourhop_cutoff;
+ } else if (victim->purpose == CIRCUIT_PURPOSE_C_REND_READY_INTRO_ACKED)
+ cutoff = c_rend_ready_cutoff;
else if (victim->purpose == CIRCUIT_PURPOSE_PATH_BIAS_TESTING)
cutoff = close_cutoff;
else if (TO_ORIGIN_CIRCUIT(victim)->has_opened &&
@@ -593,9 +571,6 @@ circuit_expire_building(void)
else
cutoff = general_cutoff;
- if (TO_ORIGIN_CIRCUIT(victim)->hs_circ_has_timed_out)
- cutoff = hs_extremely_old_cutoff;
-
if (timercmp(&victim->timestamp_began, &cutoff, OP_GT))
continue; /* it's still young, leave it alone */
@@ -689,8 +664,7 @@ circuit_expire_building(void)
/* c_rend_ready circs measure age since timestamp_dirty,
* because that's set when they switch purposes
*/
- if (TO_ORIGIN_CIRCUIT(victim)->rend_data ||
- TO_ORIGIN_CIRCUIT(victim)->hs_ident ||
+ if (TO_ORIGIN_CIRCUIT(victim)->hs_ident ||
victim->timestamp_dirty > cutoff.tv_sec)
continue;
break;
@@ -768,51 +742,29 @@ circuit_expire_building(void)
}
}
- /* If this is a hidden service client circuit which is far enough along in
- * connecting to its destination, and we haven't already flagged it as
- * 'timed out', flag it so we'll launch another intro or rend circ, but
- * don't mark it for close yet.
- *
- * (Circs flagged as 'timed out' are given a much longer timeout
- * period above, so we won't close them in the next call to
- * circuit_expire_building.) */
- if (!(TO_ORIGIN_CIRCUIT(victim)->hs_circ_has_timed_out)) {
- switch (victim->purpose) {
- case CIRCUIT_PURPOSE_C_REND_READY:
- /* We only want to spare a rend circ iff it has been specified in an
- * INTRODUCE1 cell sent to a hidden service. */
- if (!hs_circ_is_rend_sent_in_intro1(CONST_TO_ORIGIN_CIRCUIT(victim))) {
- break;
- }
- FALLTHROUGH;
- case CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT:
- case CIRCUIT_PURPOSE_C_REND_READY_INTRO_ACKED:
- /* If we have reached this line, we want to spare the circ for now. */
- log_info(LD_CIRC,"Marking circ %u (state %d:%s, purpose %d) "
- "as timed-out HS circ",
- (unsigned)victim->n_circ_id,
- victim->state, circuit_state_to_string(victim->state),
- victim->purpose);
- TO_ORIGIN_CIRCUIT(victim)->hs_circ_has_timed_out = 1;
+ /* Special checks for onion service circuits. */
+ switch (victim->purpose) {
+ case CIRCUIT_PURPOSE_C_REND_READY:
+ /* We only want to spare a rend circ iff it has been specified in an
+ * INTRODUCE1 cell sent to a hidden service. */
+ if (hs_circ_is_rend_sent_in_intro1(CONST_TO_ORIGIN_CIRCUIT(victim))) {
continue;
- default:
- break;
}
- }
-
- /* If this is a service-side rendezvous circuit which is far
- * enough along in connecting to its destination, consider sparing
- * it. */
- if (!(TO_ORIGIN_CIRCUIT(victim)->hs_circ_has_timed_out) &&
- victim->purpose == CIRCUIT_PURPOSE_S_CONNECT_REND) {
- log_info(LD_CIRC,"Marking circ %u (state %d:%s, purpose %d) "
- "as timed-out HS circ; relaunching rendezvous attempt.",
+ break;
+ case CIRCUIT_PURPOSE_S_CONNECT_REND:
+ /* The connection to the rendezvous point has timed out, close it and
+ * retry if possible. */
+ log_info(LD_CIRC,"Rendezvous circ %u (state %d:%s, purpose %d) "
+ "as timed-out, closing it. Relaunching rendezvous attempt.",
(unsigned)victim->n_circ_id,
victim->state, circuit_state_to_string(victim->state),
victim->purpose);
- TO_ORIGIN_CIRCUIT(victim)->hs_circ_has_timed_out = 1;
- hs_circ_retry_service_rendezvous_point(TO_ORIGIN_CIRCUIT(victim));
- continue;
+ /* We'll close as a timeout the victim circuit. The rendezvous point
+ * won't keep both circuits, it only keeps the newest (for the same
+ * cookie). */
+ break;
+ default:
+ break;
}
if (victim->n_chan)
@@ -897,7 +849,7 @@ circuit_log_ancient_one_hop_circuits(int age)
continue;
/* Single Onion Services deliberately make long term one-hop intro
* and rendezvous connections. Don't log the established ones. */
- if (rend_service_allow_non_anonymous_connection(options) &&
+ if (hs_service_allow_non_anonymous_connection(options) &&
(circ->purpose == CIRCUIT_PURPOSE_S_INTRO ||
circ->purpose == CIRCUIT_PURPOSE_S_REND_JOINED))
continue;
@@ -1142,7 +1094,7 @@ needs_exit_circuits(time_t now, int *needs_uptime, int *needs_capacity)
STATIC int
needs_hs_server_circuits(time_t now, int num_uptime_internal)
{
- if (!rend_num_services() && !hs_service_get_num_services()) {
+ if (!hs_service_get_num_services()) {
/* No services, we don't need anything. */
goto no_need;
}
@@ -1218,25 +1170,6 @@ needs_circuits_for_build(int num)
return 0;
}
-/**
- * Launch the appropriate type of predicted circuit for hidden
- * services, depending on our options.
- */
-static void
-circuit_launch_predicted_hs_circ(int flags)
-{
- /* K.I.S.S. implementation of bug #23101: If we are using
- * vanguards or pinned middles, pre-build a specific purpose
- * for HS circs. */
- if (circuit_should_use_vanguards(CIRCUIT_PURPOSE_HS_VANGUARDS)) {
- circuit_launch(CIRCUIT_PURPOSE_HS_VANGUARDS, flags);
- } else {
- /* If no vanguards, then no HS-specific prebuilt circuits are needed.
- * Normal GENERAL circs are fine */
- circuit_launch(CIRCUIT_PURPOSE_C_GENERAL, flags);
- }
-}
-
/** Determine how many circuits we have open that are clean,
* Make sure it's enough for all the upcoming behaviors we predict we'll have.
* But put an upper bound on the total number of circuits.
@@ -1290,7 +1223,7 @@ circuit_predict_and_launch_new(void)
"Have %d clean circs (%d internal), need another internal "
"circ for my hidden service.",
num, num_internal);
- circuit_launch_predicted_hs_circ(flags);
+ circuit_launch(CIRCUIT_PURPOSE_HS_VANGUARDS, flags);
return;
}
@@ -1309,7 +1242,10 @@ circuit_predict_and_launch_new(void)
" another hidden service circ.",
num, num_uptime_internal, num_internal);
- circuit_launch_predicted_hs_circ(flags);
+ /* Always launch vanguards purpose circuits for HS clients,
+ * for vanguards-lite. This prevents us from cannibalizing
+ * to build these circuits (and thus not use vanguards). */
+ circuit_launch(CIRCUIT_PURPOSE_HS_VANGUARDS, flags);
return;
}
@@ -1661,8 +1597,9 @@ circuit_testing_opened(origin_circuit_t *circ)
} else if (circuit_enough_testing_circs()) {
router_perform_bandwidth_test(NUM_PARALLEL_TESTING_CIRCS, time(NULL));
have_performed_bandwidth_test = 1;
- } else
- router_do_reachability_checks(1, 0);
+ } else {
+ router_do_reachability_checks();
+ }
}
/** A testing circuit has failed to build. Take whatever stats we want. */
@@ -2014,14 +1951,6 @@ circuit_purpose_is_hs_vanguards(const uint8_t purpose)
return (purpose == CIRCUIT_PURPOSE_HS_VANGUARDS);
}
-/** Return true iff the given circuit is an HS v2 circuit. */
-bool
-circuit_is_hs_v2(const circuit_t *circ)
-{
- return (CIRCUIT_IS_ORIGIN(circ) &&
- (CONST_TO_ORIGIN_CIRCUIT(circ)->rend_data != NULL));
-}
-
/** Return true iff the given circuit is an HS v3 circuit. */
bool
circuit_is_hs_v3(const circuit_t *circ)
@@ -2043,16 +1972,12 @@ circuit_is_hs_v3(const circuit_t *circ)
int
circuit_should_use_vanguards(uint8_t purpose)
{
- const or_options_t *options = get_options();
-
- /* Only hidden service circuits use vanguards */
- if (!circuit_purpose_is_hidden_service(purpose))
- return 0;
-
- /* Pinned middles are effectively vanguards */
- if (options->HSLayer2Nodes || options->HSLayer3Nodes)
+ /* All hidden service circuits use either vanguards or
+ * vanguards-lite. */
+ if (circuit_purpose_is_hidden_service(purpose))
return 1;
+ /* Everything else is a normal circuit */
return 0;
}
@@ -2090,13 +2015,11 @@ circuit_should_cannibalize_to_build(uint8_t purpose_to_build,
return 0;
}
- /* For vanguards, the server-side intro circ is not cannibalized
- * because we pre-build 4 hop HS circuits, and it only needs a 3 hop
- * circuit. It is also long-lived, so it is more important that
- * it have lower latency than get built fast.
+ /* The server-side intro circ is not cannibalized because it only
+ * needs a 3 hop circuit. It is also long-lived, so it is more
+ * important that it have lower latency than get built fast.
*/
- if (circuit_should_use_vanguards(purpose_to_build) &&
- purpose_to_build == CIRCUIT_PURPOSE_S_ESTABLISH_INTRO) {
+ if (purpose_to_build == CIRCUIT_PURPOSE_S_ESTABLISH_INTRO) {
return 0;
}
@@ -2448,19 +2371,12 @@ circuit_get_open_circ_or_launch(entry_connection_t *conn,
extend_info = hs_client_get_random_intro_from_edge(edge_conn);
if (!extend_info) {
log_info(LD_REND, "No intro points: re-fetching service descriptor.");
- if (edge_conn->rend_data) {
- rend_client_refetch_v2_renddesc(edge_conn->rend_data);
- } else {
- hs_client_refetch_hsdesc(&edge_conn->hs_ident->identity_pk);
- }
+ hs_client_refetch_hsdesc(&edge_conn->hs_ident->identity_pk);
connection_ap_mark_as_waiting_for_renddesc(conn);
return 0;
}
- log_info(LD_REND,"Chose %s as intro point for '%s'.",
- extend_info_describe(extend_info),
- (edge_conn->rend_data) ?
- safe_str_client(rend_data_get_address(edge_conn->rend_data)) :
- "service");
+ log_info(LD_REND,"Chose %s as intro point for service",
+ extend_info_describe(extend_info));
}
/* If we have specified a particular exit node for our
@@ -2477,7 +2393,8 @@ circuit_get_open_circ_or_launch(entry_connection_t *conn,
/* We might want to connect to an IPv6 bridge for loading
descriptors so we use the preferred address rather than
the primary. */
- extend_info = extend_info_from_node(r, conn->want_onehop ? 1 : 0);
+ extend_info = extend_info_from_node(r, conn->want_onehop ? 1 : 0,
+ desired_circuit_purpose == CIRCUIT_PURPOSE_C_GENERAL);
if (!extend_info) {
log_warn(LD_CIRC,"Could not make a one-hop connection to %s. "
"Discarding this circuit.", conn->chosen_exit_name);
@@ -2512,7 +2429,9 @@ circuit_get_open_circ_or_launch(entry_connection_t *conn,
digest,
NULL, /* Ed25519 ID */
NULL, NULL, /* onion keys */
- &addr, conn->socks_request->port);
+ &addr, conn->socks_request->port,
+ NULL,
+ false);
} else { /* ! (want_onehop && conn->chosen_exit_name[0] == '$') */
/* We will need an onion key for the router, and we
* don't have one. Refuse or relax requirements. */
@@ -2584,10 +2503,7 @@ circuit_get_open_circ_or_launch(entry_connection_t *conn,
rep_hist_note_used_internal(time(NULL), need_uptime, 1);
if (circ) {
const edge_connection_t *edge_conn = ENTRY_TO_EDGE_CONN(conn);
- if (edge_conn->rend_data) {
- /* write the service_id into circ */
- circ->rend_data = rend_data_dup(edge_conn->rend_data);
- } else if (edge_conn->hs_ident) {
+ if (edge_conn->hs_ident) {
circ->hs_ident =
hs_ident_circuit_new(&edge_conn->hs_ident->identity_pk);
}
@@ -2733,6 +2649,13 @@ consider_recording_trackhost(const entry_connection_t *conn,
const or_options_t *options = get_options();
char *new_address = NULL;
char fp[HEX_DIGEST_LEN+1];
+ uint64_t stream_id = 0;
+
+ if (BUG(!conn)) {
+ return;
+ }
+
+ stream_id = ENTRY_TO_CONN(conn)->global_identifier;
/* Search the addressmap for this conn's destination. */
/* If they're not in the address map.. */
@@ -2756,7 +2679,7 @@ consider_recording_trackhost(const entry_connection_t *conn,
addressmap_register(conn->socks_request->address, new_address,
time(NULL) + options->TrackHostExitsExpire,
- ADDRMAPSRC_TRACKEXIT, 0, 0);
+ ADDRMAPSRC_TRACKEXIT, 0, 0, stream_id);
}
/** Attempt to attach the connection <b>conn</b> to <b>circ</b>, and send a
@@ -2796,8 +2719,9 @@ connection_ap_handshake_attach_chosen_circuit(entry_connection_t *conn,
tor_assert(conn->socks_request);
if (conn->socks_request->command == SOCKS_COMMAND_CONNECT) {
- if (!conn->use_begindir)
+ if (!conn->use_begindir) {
consider_recording_trackhost(conn, circ);
+ }
if (connection_ap_handshake_send_begin(conn) < 0)
return -1;
} else {
@@ -2826,13 +2750,9 @@ connection_ap_get_nonrend_circ_purpose(const entry_connection_t *conn)
if (base_conn->linked_conn &&
base_conn->linked_conn->type == CONN_TYPE_DIR) {
/* Set a custom purpose for hsdir activity */
- if (base_conn->linked_conn->purpose == DIR_PURPOSE_UPLOAD_RENDDESC_V2 ||
- base_conn->linked_conn->purpose == DIR_PURPOSE_UPLOAD_HSDESC) {
+ if (base_conn->linked_conn->purpose == DIR_PURPOSE_UPLOAD_HSDESC) {
return CIRCUIT_PURPOSE_S_HSDIR_POST;
- } else if (base_conn->linked_conn->purpose
- == DIR_PURPOSE_FETCH_RENDDESC_V2 ||
- base_conn->linked_conn->purpose
- == DIR_PURPOSE_FETCH_HSDESC) {
+ } else if (base_conn->linked_conn->purpose == DIR_PURPOSE_FETCH_HSDESC) {
return CIRCUIT_PURPOSE_C_HSDIR_GET;
}
}
diff --git a/src/core/or/circuituse.h b/src/core/or/circuituse.h
index 028fe4aa48..c737ff1c9d 100644
--- a/src/core/or/circuituse.h
+++ b/src/core/or/circuituse.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -76,7 +76,6 @@ bool circuit_purpose_is_hs_client(const uint8_t purpose);
bool circuit_purpose_is_hs_service(const uint8_t purpose);
bool circuit_purpose_is_hs_vanguards(const uint8_t purpose);
-bool circuit_is_hs_v2(const circuit_t *circ);
bool circuit_is_hs_v3(const circuit_t *circ);
int circuit_should_use_vanguards(uint8_t);
diff --git a/src/core/or/command.c b/src/core/or/command.c
index a8b93dc9a0..cad7a173b6 100644
--- a/src/core/or/command.c
+++ b/src/core/or/command.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -331,6 +331,13 @@ command_process_create_cell(cell_t *cell, channel_t *chan)
return;
}
+ /* Mark whether this circuit used TAP in case we need to use this
+ * information for onion service statistics later on. */
+ if (create_cell->handshake_type == ONION_HANDSHAKE_TYPE_FAST ||
+ create_cell->handshake_type == ONION_HANDSHAKE_TYPE_TAP) {
+ circ->used_legacy_circuit_handshake = true;
+ }
+
if (!channel_is_client(chan)) {
/* remember create types we've seen, but don't remember them from
* clients, to be extra conservative about client statistics. */
@@ -353,15 +360,19 @@ command_process_create_cell(cell_t *cell, channel_t *chan)
uint8_t rend_circ_nonce[DIGEST_LEN];
int len;
created_cell_t created_cell;
+ circuit_params_t params;
memset(&created_cell, 0, sizeof(created_cell));
len = onion_skin_server_handshake(ONION_HANDSHAKE_TYPE_FAST,
create_cell->onionskin,
create_cell->handshake_len,
NULL,
+ NULL,
created_cell.reply,
+ sizeof(created_cell.reply),
keys, CPATH_KEY_MATERIAL_LEN,
- rend_circ_nonce);
+ rend_circ_nonce,
+ &params);
tor_free(create_cell);
if (len < 0) {
log_warn(LD_OR,"Failed to generate key material. Closing.");
@@ -556,7 +567,7 @@ command_process_relay_cell(cell_t *cell, channel_t *chan)
}
if ((reason = circuit_receive_relay_cell(cell, circ, direction)) < 0) {
- log_fn(LOG_PROTOCOL_WARN,LD_PROTOCOL,"circuit_receive_relay_cell "
+ log_fn(LOG_DEBUG,LD_PROTOCOL,"circuit_receive_relay_cell "
"(%s) failed. Closing.",
direction==CELL_DIRECTION_OUT?"forward":"backward");
/* Always emit a bandwidth event for closed circs */
@@ -587,11 +598,27 @@ command_process_relay_cell(cell_t *cell, channel_t *chan)
}
/* If this is a cell in an RP circuit, count it as part of the
- hidden service stats */
+ onion service stats */
if (options->HiddenServiceStatistics &&
!CIRCUIT_IS_ORIGIN(circ) &&
- TO_OR_CIRCUIT(circ)->circuit_carries_hs_traffic_stats) {
- rep_hist_seen_new_rp_cell();
+ CONST_TO_OR_CIRCUIT(circ)->circuit_carries_hs_traffic_stats) {
+ /** We need to figure out of this is a v2 or v3 RP circuit to count it
+ * appropriately. v2 services always use the TAP legacy handshake to
+ * connect to the RP; we use this feature to distinguish between v2/v3. */
+ bool is_v2 = false;
+ if (CONST_TO_OR_CIRCUIT(circ)->used_legacy_circuit_handshake) {
+ is_v2 = true;
+ } else if (CONST_TO_OR_CIRCUIT(circ)->rend_splice) {
+ /* If this is a client->RP circuit we need to check the spliced circuit
+ * (which is the service->RP circuit) to see if it was using TAP and
+ * hence if it's a v2 circuit. That's because client->RP circuits can
+ * still use ntor even on v2; but service->RP will always use TAP. */
+ const or_circuit_t *splice = CONST_TO_OR_CIRCUIT(circ)->rend_splice;
+ if (splice->used_legacy_circuit_handshake) {
+ is_v2 = true;
+ }
+ }
+ rep_hist_seen_new_rp_cell(is_v2);
}
}
diff --git a/src/core/or/command.h b/src/core/or/command.h
index 14ebb4a339..dfe363d53c 100644
--- a/src/core/or/command.h
+++ b/src/core/or/command.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/core/or/congestion_control_common.c b/src/core/or/congestion_control_common.c
new file mode 100644
index 0000000000..f5b7740bed
--- /dev/null
+++ b/src/core/or/congestion_control_common.c
@@ -0,0 +1,1570 @@
+/* Copyright (c) 2021, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file congestion_control_common.c
+ * \brief Common code used by all congestion control algorithms.
+ */
+
+#define TOR_CONGESTION_CONTROL_COMMON_PRIVATE
+
+#include "core/or/or.h"
+
+#include "core/crypto/onion_crypto.h"
+#include "core/or/circuitlist.h"
+#include "core/or/crypt_path.h"
+#include "core/or/or_circuit_st.h"
+#include "core/or/origin_circuit_st.h"
+#include "core/or/channel.h"
+#include "core/mainloop/connection.h"
+#include "core/or/sendme.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/trace_probes_cc.h"
+#include "lib/time/compat_time.h"
+#include "feature/nodelist/networkstatus.h"
+#include "app/config/config.h"
+
+#include "trunnel/congestion_control.h"
+#include "trunnel/extension.h"
+
+/* Consensus parameter defaults.
+ *
+ * More details for each of the parameters can be found in proposal 324,
+ * section 6.5 including tuning notes. */
+#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_ALWAYS (CC_ALG_VEGAS)
+
+#define CWND_INC_DFLT (TLS_RECORD_MAX_CELLS)
+#define CWND_INC_PCT_SS_DFLT (100)
+#define CWND_INC_RATE_DFLT (1)
+
+#define CWND_MIN_DFLT (2*SENDME_INC_DFLT)
+#define CWND_MAX_DFLT (INT32_MAX)
+
+#define BWE_SENDME_MIN_DFLT (5)
+
+#define N_EWMA_CWND_PCT_DFLT (50)
+#define N_EWMA_MAX_DFLT (10)
+#define N_EWMA_SS_DFLT (2)
+
+#define RTT_RESET_PCT_DFLT (100)
+
+/* BDP algorithms for each congestion control algorithms use the piecewise
+ * estimattor. See section 3.1.4 of proposal 324. */
+#define WESTWOOD_BDP_ALG BDP_ALG_PIECEWISE
+#define VEGAS_BDP_MIX_ALG BDP_ALG_PIECEWISE
+#define NOLA_BDP_ALG BDP_ALG_PIECEWISE
+
+/* Indicate OR connection buffer limitations used to stop or start accepting
+ * cells in its outbuf.
+ *
+ * These watermarks are historical to tor in a sense that they've been used
+ * almost from the genesis point. And were likely defined to fit the bounds of
+ * TLS records of 16KB which would be around 32 cells.
+ *
+ * These are defaults of the consensus parameter "orconn_high" and "orconn_low"
+ * values. */
+#define OR_CONN_HIGHWATER_DFLT (32*1024)
+#define OR_CONN_LOWWATER_DFLT (16*1024)
+
+/* Low and high values of circuit cell queue sizes. They are used to tell when
+ * to start or stop reading on the streams attached on the circuit.
+ *
+ * These are defaults of the consensus parameters "cellq_high" and "cellq_low".
+ */
+#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);
+
+/* Number of times the RTT value was reset. For MetricsPort. */
+static uint64_t num_rtt_reset;
+
+/* Number of times the clock was stalled. For MetricsPort. */
+static uint64_t num_clock_stalls;
+
+/* Consensus parameters cached. The non static ones are extern. */
+static uint32_t cwnd_max = CWND_MAX_DFLT;
+int32_t cell_queue_high = CELL_QUEUE_HIGH_DFLT;
+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;
+
+/**
+ * Number of cwnd worth of sendme acks to smooth RTT and BDP with,
+ * using N_EWMA */
+static uint8_t n_ewma_cwnd_pct;
+
+/**
+ * Maximum number N for the N-count EWMA averaging of RTT and BDP.
+ */
+static uint8_t n_ewma_max;
+
+/**
+ * Maximum number N for the N-count EWMA averaging of RTT in Slow Start.
+ */
+static uint8_t n_ewma_ss;
+
+/**
+ * Minimum number of sendmes before we begin BDP estimates
+ */
+static uint8_t bwe_sendme_min;
+
+/**
+ * Percentage of the current RTT to use when reseting the minimum RTT
+ * for a circuit. (RTT is reset when the cwnd hits cwnd_min).
+ */
+static uint8_t rtt_reset_pct;
+
+/** Metric to count the number of congestion control circuits **/
+uint64_t cc_stats_circs_created = 0;
+
+/** Return the number of RTT reset that have been done. */
+uint64_t
+congestion_control_get_num_rtt_reset(void)
+{
+ return num_rtt_reset;
+}
+
+/** Return the number of clock stalls that have been done. */
+uint64_t
+congestion_control_get_num_clock_stalls(void)
+{
+ return num_clock_stalls;
+}
+
+/**
+ * Update global congestion control related consensus parameter values,
+ * every consensus update.
+ */
+void
+congestion_control_new_consensus_params(const networkstatus_t *ns)
+{
+#define CELL_QUEUE_HIGH_MIN (1)
+#define CELL_QUEUE_HIGH_MAX (1000)
+ cell_queue_high = networkstatus_get_param(ns, "cellq_high",
+ CELL_QUEUE_HIGH_DFLT,
+ CELL_QUEUE_HIGH_MIN,
+ CELL_QUEUE_HIGH_MAX);
+
+#define CELL_QUEUE_LOW_MIN (1)
+#define CELL_QUEUE_LOW_MAX (1000)
+ cell_queue_low = networkstatus_get_param(ns, "cellq_low",
+ CELL_QUEUE_LOW_DFLT,
+ CELL_QUEUE_LOW_MIN,
+ CELL_QUEUE_LOW_MAX);
+
+#define OR_CONN_HIGHWATER_MIN (CELL_PAYLOAD_SIZE)
+#define OR_CONN_HIGHWATER_MAX (INT32_MAX)
+ or_conn_highwater =
+ networkstatus_get_param(ns, "orconn_high",
+ OR_CONN_HIGHWATER_DFLT,
+ OR_CONN_HIGHWATER_MIN,
+ OR_CONN_HIGHWATER_MAX);
+
+#define OR_CONN_LOWWATER_MIN (CELL_PAYLOAD_SIZE)
+#define OR_CONN_LOWWATER_MAX (INT32_MAX)
+ or_conn_lowwater =
+ networkstatus_get_param(ns, "orconn_low",
+ OR_CONN_LOWWATER_DFLT,
+ OR_CONN_LOWWATER_MIN,
+ OR_CONN_LOWWATER_MAX);
+
+#define CWND_MAX_MIN 500
+#define CWND_MAX_MAX (INT32_MAX)
+ cwnd_max =
+ networkstatus_get_param(NULL, "cc_cwnd_max",
+ CWND_MAX_DFLT,
+ CWND_MAX_MIN,
+ CWND_MAX_MAX);
+
+#define RTT_RESET_PCT_MIN (0)
+#define RTT_RESET_PCT_MAX (100)
+ rtt_reset_pct =
+ networkstatus_get_param(NULL, "cc_rtt_reset_pct",
+ RTT_RESET_PCT_DFLT,
+ RTT_RESET_PCT_MIN,
+ RTT_RESET_PCT_MAX);
+
+#define SENDME_INC_MIN 1
+#define SENDME_INC_MAX (255)
+ cc_sendme_inc =
+ networkstatus_get_param(NULL, "cc_sendme_inc",
+ SENDME_INC_DFLT,
+ SENDME_INC_MIN,
+ SENDME_INC_MAX);
+
+#define CC_ALG_MIN 0
+#define CC_ALG_MAX (NUM_CC_ALGS-1)
+ cc_alg =
+ networkstatus_get_param(NULL, "cc_alg",
+ CC_ALG_DFLT,
+ CC_ALG_MIN,
+ CC_ALG_MAX);
+
+#define BWE_SENDME_MIN_MIN 2
+#define BWE_SENDME_MIN_MAX (20)
+ bwe_sendme_min =
+ networkstatus_get_param(NULL, "cc_bwe_min",
+ BWE_SENDME_MIN_DFLT,
+ BWE_SENDME_MIN_MIN,
+ BWE_SENDME_MIN_MAX);
+
+#define N_EWMA_CWND_PCT_MIN 1
+#define N_EWMA_CWND_PCT_MAX (255)
+ n_ewma_cwnd_pct =
+ networkstatus_get_param(NULL, "cc_ewma_cwnd_pct",
+ N_EWMA_CWND_PCT_DFLT,
+ N_EWMA_CWND_PCT_MIN,
+ N_EWMA_CWND_PCT_MAX);
+
+#define N_EWMA_MAX_MIN 2
+#define N_EWMA_MAX_MAX (INT32_MAX)
+ n_ewma_max =
+ networkstatus_get_param(NULL, "cc_ewma_max",
+ N_EWMA_MAX_DFLT,
+ N_EWMA_MAX_MIN,
+ N_EWMA_MAX_MAX);
+
+#define N_EWMA_SS_MIN 2
+#define N_EWMA_SS_MAX (INT32_MAX)
+ n_ewma_ss =
+ networkstatus_get_param(NULL, "cc_ewma_ss",
+ N_EWMA_SS_DFLT,
+ N_EWMA_SS_MIN,
+ N_EWMA_SS_MAX);
+}
+
+/**
+ * Set congestion control parameters on a circuit's congestion
+ * control object based on values from the consensus.
+ *
+ * cc_alg is the negotiated congestion control algorithm.
+ *
+ * sendme_inc is the number of packaged cells that a sendme cell
+ * acks. This parameter will come from circuit negotiation.
+ */
+static void
+congestion_control_init_params(congestion_control_t *cc,
+ const circuit_params_t *params,
+ cc_path_t path)
+{
+ const or_options_t *opts = get_options();
+ cc->sendme_inc = params->sendme_inc_cells;
+
+#define CWND_INIT_MIN SENDME_INC_DFLT
+#define CWND_INIT_MAX (10000)
+ cc->cwnd =
+ networkstatus_get_param(NULL, "cc_cwnd_init",
+ CIRCWINDOW_INIT,
+ CWND_INIT_MIN,
+ CWND_INIT_MAX);
+
+#define CWND_INC_PCT_SS_MIN 1
+#define CWND_INC_PCT_SS_MAX (500)
+ cc->cwnd_inc_pct_ss =
+ networkstatus_get_param(NULL, "cc_cwnd_inc_pct_ss",
+ CWND_INC_PCT_SS_DFLT,
+ CWND_INC_PCT_SS_MIN,
+ CWND_INC_PCT_SS_MAX);
+
+#define CWND_INC_MIN 1
+#define CWND_INC_MAX (1000)
+ cc->cwnd_inc =
+ networkstatus_get_param(NULL, "cc_cwnd_inc",
+ CWND_INC_DFLT,
+ CWND_INC_MIN,
+ CWND_INC_MAX);
+
+#define CWND_INC_RATE_MIN 1
+#define CWND_INC_RATE_MAX (250)
+ cc->cwnd_inc_rate =
+ networkstatus_get_param(NULL, "cc_cwnd_inc_rate",
+ CWND_INC_RATE_DFLT,
+ CWND_INC_RATE_MIN,
+ CWND_INC_RATE_MAX);
+
+#define CWND_MIN_MIN SENDME_INC_DFLT
+#define CWND_MIN_MAX (1000)
+ cc->cwnd_min =
+ networkstatus_get_param(NULL, "cc_cwnd_min",
+ CWND_MIN_DFLT,
+ CWND_MIN_MIN,
+ CWND_MIN_MAX);
+
+ /* If the consensus says to use OG sendme, but torrc has
+ * always-enabled, use the default "always" alg (vegas),
+ * else use cached conensus alg. */
+ if (cc_alg == CC_ALG_SENDME && opts->AlwaysCongestionControl) {
+ cc->cc_alg = CC_ALG_DFLT_ALWAYS;
+ } else {
+ 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) {
+ congestion_control_vegas_set_params(cc, path);
+ } else if (cc->cc_alg == CC_ALG_NOLA) {
+ congestion_control_nola_set_params(cc);
+ }
+}
+
+/** Returns true if congestion control is enabled in the most recent
+ * consensus, or if __AlwaysCongestionControl is set to true.
+ *
+ * Note that this function (and many many other functions) should not
+ * be called from the CPU worker threads when handling congestion
+ * control negotiation. Relevant values are marshaled into the
+ * `circuit_params_t` struct, in order to be used in worker threads
+ * without touching global state. Use those values in CPU worker
+ * threads, instead of calling this function.
+ *
+ * The danger is still present, in your time, as it was in ours.
+ */
+bool
+congestion_control_enabled(void)
+{
+ const or_options_t *opts = NULL;
+
+ tor_assert_nonfatal_once(in_main_thread());
+
+ opts = get_options();
+
+ /* If the user has set "__AlwaysCongesttionControl",
+ * then always try to negotiate congestion control, regardless
+ * of consensus param. This is to be used for testing and sbws.
+ *
+ * Note that we do *not* allow disabling congestion control
+ * if the consensus says to use it, as this is bad for queueing
+ * and fairness. */
+ if (opts->AlwaysCongestionControl)
+ return 1;
+
+ return cc_alg != CC_ALG_SENDME;
+}
+
+/**
+ * For unit tests only: set the cached consensus cc alg to
+ * specified value.
+ */
+void
+congestion_control_set_cc_enabled(void)
+{
+ cc_alg = CC_ALG_VEGAS;
+}
+
+/**
+ * Allocate and initialize fields in congestion control object.
+ *
+ * cc_alg is the negotiated congestion control algorithm.
+ *
+ * sendme_inc is the number of packaged cells that a sendme cell
+ * acks. This parameter will come from circuit negotiation.
+ */
+static void
+congestion_control_init(congestion_control_t *cc,
+ const circuit_params_t *params,
+ 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);
+
+ cc->next_cc_event = CWND_UPDATE_RATE(cc);
+}
+
+/** Allocate and initialize a new congestion control object */
+congestion_control_t *
+congestion_control_new(const circuit_params_t *params, cc_path_t path)
+{
+ congestion_control_t *cc = tor_malloc_zero(sizeof(congestion_control_t));
+
+ congestion_control_init(cc, params, path);
+
+ cc_stats_circs_created++;
+
+ return cc;
+}
+
+/**
+ * Free a congestion control object and its associated state.
+ */
+void
+congestion_control_free_(congestion_control_t *cc)
+{
+ if (!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);
+}
+
+/**
+ * Enqueue a u64 timestamp to the end of a queue of timestamps.
+ */
+static inline void
+enqueue_timestamp(smartlist_t *timestamps_u64, uint64_t timestamp_usec)
+{
+ uint64_t *timestamp_ptr = tor_malloc(sizeof(uint64_t));
+ *timestamp_ptr = timestamp_usec;
+
+ smartlist_add(timestamps_u64, timestamp_ptr);
+}
+
+/**
+ * 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.
+ */
+static inline uint64_t
+dequeue_timestamp(smartlist_t *timestamps_u64_usecs)
+{
+ uint64_t *timestamp_ptr = smartlist_get(timestamps_u64_usecs, 0);
+ uint64_t timestamp_u64;
+
+ if (BUG(!timestamp_ptr)) {
+ log_err(LD_CIRC, "Congestion control timestamp list became empty!");
+ return 0;
+ }
+
+ timestamp_u64 = *timestamp_ptr;
+ smartlist_del_keeporder(timestamps_u64_usecs, 0);
+ tor_free(timestamp_ptr);
+
+ return timestamp_u64;
+}
+
+/**
+ * Returns the number N of N-count EWMA, for averaging RTT and BDP over
+ * N SENDME acks.
+ *
+ * This N is bracketed between a divisor of the number of acks in a CWND
+ * and a max value. It is always at least 2.
+ */
+static inline uint64_t
+n_ewma_count(const congestion_control_t *cc)
+{
+ uint64_t ewma_cnt = 0;
+
+ if (cc->in_slow_start) {
+ /* In slow-start, we check the Vegas condition every sendme,
+ * so much lower ewma counts are needed. */
+ ewma_cnt = n_ewma_ss;
+ } else {
+ /* After slow-start, we check the Vegas condition only once per
+ * CWND, so it is better to average over longer periods. */
+ ewma_cnt = MIN(CWND_UPDATE_RATE(cc)*n_ewma_cwnd_pct/100,
+ n_ewma_max);
+ }
+ ewma_cnt = MAX(ewma_cnt, 2);
+ return ewma_cnt;
+}
+
+/**
+ * Get a package window from either old sendme logic, or congestion control.
+ *
+ * A package window is how many cells you can still send.
+ */
+int
+congestion_control_get_package_window(const circuit_t *circ,
+ const crypt_path_t *cpath)
+{
+ int package_window;
+ congestion_control_t *cc;
+
+ tor_assert(circ);
+
+ if (cpath) {
+ package_window = cpath->package_window;
+ cc = cpath->ccontrol;
+ } else {
+ package_window = circ->package_window;
+ cc = circ->ccontrol;
+ }
+
+ if (!cc) {
+ return package_window;
+ } else {
+ /* Inflight can be above cwnd if cwnd was just reduced */
+ if (cc->inflight > cc->cwnd)
+ return 0;
+ /* In the extremely unlikely event that cwnd-inflight is larger than
+ * INT32_MAX, just return that cap, so old code doesn't explode. */
+ else if (cc->cwnd - cc->inflight > INT32_MAX)
+ return INT32_MAX;
+ else
+ return (int)(cc->cwnd - cc->inflight);
+ }
+}
+
+/**
+ * Returns the number of cells that are acked by every sendme.
+ */
+int
+sendme_get_inc_count(const circuit_t *circ, const crypt_path_t *layer_hint)
+{
+ int sendme_inc = CIRCWINDOW_INCREMENT;
+ congestion_control_t *cc = NULL;
+
+ if (layer_hint) {
+ cc = layer_hint->ccontrol;
+ } else {
+ cc = circ->ccontrol;
+ }
+
+ if (cc) {
+ sendme_inc = cc->sendme_inc;
+ }
+
+ return sendme_inc;
+}
+
+/** Return true iff the next cell we send will result in the other endpoint
+ * sending a SENDME.
+ *
+ * We are able to know that because the package or inflight window value minus
+ * one cell (the possible SENDME cell) should be a multiple of the
+ * cells-per-sendme increment value (set via consensus parameter, negotiated
+ * for the circuit, and passed in as sendme_inc).
+ *
+ * This function is used when recording a cell digest and this is done quite
+ * low in the stack when decrypting or encrypting a cell. The window is only
+ * updated once the cell is actually put in the outbuf.
+ */
+bool
+circuit_sent_cell_for_sendme(const circuit_t *circ,
+ const crypt_path_t *layer_hint)
+{
+ congestion_control_t *cc;
+ int window;
+
+ tor_assert(circ);
+
+ if (layer_hint) {
+ window = layer_hint->package_window;
+ cc = layer_hint->ccontrol;
+ } else {
+ window = circ->package_window;
+ cc = circ->ccontrol;
+ }
+
+ /* If we are using congestion control and the alg is not
+ * old-school 'fixed', then use cc->inflight to determine
+ * when sendmes will be sent */
+ if (cc) {
+ if (!cc->inflight)
+ return false;
+
+ /* This check must be +1 because this function is called *before*
+ * inflight is incremented for the sent cell */
+ if ((cc->inflight+1) % cc->sendme_inc != 0)
+ return false;
+
+ return true;
+ }
+
+ /* At the start of the window, no SENDME will be expected. */
+ if (window == CIRCWINDOW_START) {
+ return false;
+ }
+
+ /* Are we at the limit of the increment and if not, we don't expect next
+ * cell is a SENDME.
+ *
+ * We test against the window minus 1 because when we are looking if the
+ * next cell is a SENDME, the window (either package or deliver) hasn't been
+ * decremented just yet so when this is called, we are currently processing
+ * the "window - 1" cell.
+ */
+ if (((window - 1) % CIRCWINDOW_INCREMENT) != 0) {
+ return false;
+ }
+
+ /* Next cell is expected to be a SENDME. */
+ return true;
+}
+
+/**
+ * Call-in to tell congestion control code that this circuit sent a cell.
+ *
+ * This updates the 'inflight' counter, and if this is a cell that will
+ * cause the other end to send a SENDME, record the current time in a list
+ * of pending timestamps, so that we can later compute the circuit RTT when
+ * the SENDME comes back. */
+void
+congestion_control_note_cell_sent(congestion_control_t *cc,
+ const circuit_t *circ,
+ const crypt_path_t *cpath)
+{
+ tor_assert(circ);
+ tor_assert(cc);
+
+ /* Is this the last cell before a SENDME? The idea is that if the
+ * package_window reaches a multiple of the increment, after this cell, we
+ * should expect a SENDME. Note that this function must be called *before*
+ * we account for the sent cell. */
+ if (!circuit_sent_cell_for_sendme(circ, cpath)) {
+ cc->inflight++;
+ return;
+ }
+
+ cc->inflight++;
+
+ /* Record this cell time for RTT computation when SENDME arrives */
+ enqueue_timestamp(cc->sendme_pending_timestamps,
+ monotime_absolute_usec());
+}
+
+/**
+ * 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.
+ *
+ * Returns true if circuit estimates were successfully updated, false
+ * otherwise.
+ */
+bool
+congestion_control_update_circuit_estimates(congestion_control_t *cc,
+ const circuit_t *circ,
+ const crypt_path_t *layer_hint)
+{
+ 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);
+}
+
+/**
+ * Returns true if we have enough time data to use heuristics
+ * to compare RTT to a baseline.
+ */
+static bool
+time_delta_should_use_heuristics(const congestion_control_t *cc)
+{
+ /* If we have exited slow start and also have an EWMA RTT, we
+ * should have processed at least a cwnd worth of RTTs */
+ if (!cc->in_slow_start && cc->ewma_rtt_usec) {
+ 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;
+
+/**
+ * Returns true if the monotime delta is 0, or is significantly
+ * different than the previous delta. Either case indicates
+ * that the monotime time source stalled or jumped.
+ *
+ * Also caches the clock state in the is_monotime_clock_broken flag,
+ * so we can also provide a is_monotime_clock_reliable() function,
+ * used by flow control rate timing.
+ */
+static bool
+time_delta_stalled_or_jumped(const congestion_control_t *cc,
+ uint64_t old_delta, uint64_t new_delta)
+{
+#define DELTA_DISCREPENCY_RATIO_MAX 5000
+ /* If we have a 0 new_delta, that is definitely a monotime stall */
+ if (new_delta == 0) {
+ static ratelim_t stall_info_limit = RATELIM_INIT(60);
+ log_fn_ratelim(&stall_info_limit, LOG_INFO, LD_CIRC,
+ "Congestion control cannot measure RTT due to monotime stall.");
+
+ is_monotime_clock_broken = true;
+ return true;
+ }
+
+ /*
+ * For the heuristic cases, we need at least a few timestamps,
+ * to average out any previous partial stalls or jumps. So until
+ * that point, let's just assume its OK.
+ */
+ if (!time_delta_should_use_heuristics(cc)) {
+ return false;
+ }
+
+ /* If old_delta is significantly larger than new_delta, then
+ * this means that the monotime clock could have recently
+ * stopped moving forward. However, use the cache for this
+ * value, because it may also be caused by network activity,
+ * or by a previous clock jump that was not detected.
+ *
+ * So if we have not gotten a 0-delta recently, we will
+ * still allow this new low RTT, but just yell about it. */
+ if (old_delta > new_delta * DELTA_DISCREPENCY_RATIO_MAX) {
+ static ratelim_t dec_notice_limit = RATELIM_INIT(300);
+ log_fn_ratelim(&dec_notice_limit, LOG_NOTICE, LD_CIRC,
+ "Sudden decrease in circuit RTT (%"PRIu64" vs %"PRIu64
+ "), likely due to clock jump.",
+ new_delta/1000, old_delta/1000);
+
+ return is_monotime_clock_broken;
+ }
+
+ /* If new_delta is significantly larger than old_delta, then
+ * this means that the monotime clock suddenly jumped forward.
+ * However, do not cache this value, because it may also be caused
+ * by network activity.
+ */
+ if (new_delta > old_delta * DELTA_DISCREPENCY_RATIO_MAX) {
+ static ratelim_t dec_notice_limit = RATELIM_INIT(300);
+ log_fn_ratelim(&dec_notice_limit, LOG_PROTOCOL_WARN, LD_CIRC,
+ "Sudden increase in circuit RTT (%"PRIu64" vs %"PRIu64
+ "), likely due to clock jump or suspended remote endpoint.",
+ new_delta/1000, old_delta/1000);
+
+ return true;
+ }
+
+ /* All good! Update cached status, too */
+ is_monotime_clock_broken = false;
+
+ return false;
+}
+
+/**
+ * Is the monotime clock stalled according to any circuits?
+ */
+bool
+is_monotime_clock_reliable(void)
+{
+ return !is_monotime_clock_broken;
+}
+
+/**
+ * Called when we get a SENDME. Updates circuit RTT by pulling off a
+ * timestamp of when we sent the CIRCWINDOW_INCREMENT-th cell from
+ * the queue of such timestamps, and comparing that to current time.
+ *
+ * Also updates min, max, and EWMA of RTT.
+ *
+ * Returns the current circuit RTT in usecs, or 0 if it could not be
+ * measured (due to clock jump, stall, etc).
+ */
+static uint64_t
+congestion_control_update_circuit_rtt(congestion_control_t *cc,
+ uint64_t now_usec)
+{
+ uint64_t rtt, ewma_cnt;
+ uint64_t sent_at_timestamp;
+
+ tor_assert(cc);
+
+ /* Get the time that we sent the cell that resulted in the other
+ * end sending this sendme. Use this to calculate RTT */
+ sent_at_timestamp = dequeue_timestamp(cc->sendme_pending_timestamps);
+
+ rtt = now_usec - sent_at_timestamp;
+
+ /* Do not update RTT at all if it looks fishy */
+ if (time_delta_stalled_or_jumped(cc, cc->ewma_rtt_usec, rtt)) {
+ num_clock_stalls++; /* Accounting */
+ return 0;
+ }
+
+ ewma_cnt = n_ewma_count(cc);
+
+ cc->ewma_rtt_usec = n_count_ewma(rtt, cc->ewma_rtt_usec, ewma_cnt);
+
+ if (rtt > cc->max_rtt_usec) {
+ cc->max_rtt_usec = rtt;
+ }
+
+ if (cc->min_rtt_usec == 0) {
+ // If we do not have a min_rtt yet, use current ewma
+ cc->min_rtt_usec = cc->ewma_rtt_usec;
+ } else if (cc->cwnd == cc->cwnd_min && !cc->in_slow_start) {
+ // Raise min rtt if cwnd hit cwnd_min. This gets us out of a wedge state
+ // if we hit cwnd_min due to an abnormally low rtt.
+ uint64_t new_rtt = percent_max_mix(cc->ewma_rtt_usec, cc->min_rtt_usec,
+ rtt_reset_pct);
+
+ static ratelim_t rtt_notice_limit = RATELIM_INIT(300);
+ log_fn_ratelim(&rtt_notice_limit, LOG_NOTICE, LD_CIRC,
+ "Resetting circ RTT from %"PRIu64" to %"PRIu64" due to low cwnd",
+ cc->min_rtt_usec/1000, new_rtt/1000);
+
+ cc->min_rtt_usec = new_rtt;
+ num_rtt_reset++; /* Accounting */
+ } else if (cc->ewma_rtt_usec < cc->min_rtt_usec) {
+ // Using the EWMA for min instead of current RTT helps average out
+ // effects from other conns
+ cc->min_rtt_usec = cc->ewma_rtt_usec;
+ }
+
+ return rtt;
+}
+
+/**
+ * Called when we get a SENDME. Updates the bandwidth-delay-product (BDP)
+ * estimates of a circuit. Several methods of computing BDP are used,
+ * depending on scenario. While some congestion control algorithms only
+ * use one of these methods, we update them all because it's quick and easy.
+ *
+ * - now_usec is the current monotime in usecs.
+ * - curr_rtt_usec is the current circuit RTT in usecs. It may be 0 if no
+ * RTT could bemeasured.
+ *
+ * Returns true if we were able to update BDP, false otherwise.
+ */
+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;
+ } 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;
+ }
+
+ /* If we have no EWMA RTT, it is because monotime has been stalled
+ * or messed up the entire time so far. Set our BDP estimates directly
+ * to current cwnd */
+ if (!cc->ewma_rtt_usec) {
+ uint64_t cwnd = cc->cwnd;
+
+ tor_assert_nonfatal(cc->cwnd <= cwnd_max);
+
+ /* If the channel is blocked, keep subtracting off the chan_q
+ * until we hit the min cwnd. */
+ if (blocked_on_chan) {
+ /* Cast is fine because we're less than int32 */
+ if (chan_q >= (int64_t)cwnd) {
+ log_notice(LD_CIRC,
+ "Clock stall with large chanq: %d %"PRIu64, chan_q, cwnd);
+ cwnd = cc->cwnd_min;
+ } else {
+ cwnd = MAX(cwnd - chan_q, cc->cwnd_min);
+ }
+ cc->blocked_chan = 1;
+ } else {
+ 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;
+
+ static ratelim_t dec_notice_limit = RATELIM_INIT(300);
+ log_fn_ratelim(&dec_notice_limit, LOG_NOTICE, LD_CIRC,
+ "Our clock has been stalled for the entire lifetime of a circuit. "
+ "Performance may be sub-optimal.");
+
+ return blocked_on_chan;
+ }
+
+ /* Congestion window based BDP will respond to changes in RTT only, and is
+ * relative to cwnd growth. It is useful for correcting for BDP
+ * overestimation, but if BDP is higher than the current cwnd, it will
+ * underestimate it.
+ *
+ * We multiply here first to avoid precision issues from min_RTT being
+ * 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;
+ }
+
+ /* The orconn is blocked; use smaller of inflight vs SENDME */
+ if (blocked_on_chan) {
+ log_info(LD_CIRC, "CC: Streams blocked on circ channel. Chanq: %d",
+ chan_q);
+
+ /* A blocked channel is an immediate congestion signal, but it still
+ * happens only once per cwnd */
+ if (!cc->blocked_chan) {
+ 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 */
+ if (cc->blocked_chan) {
+ cc->blocked_chan = 0;
+ cc->next_cc_event = 0;
+ 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) {
+ if (CIRCUIT_IS_ORIGIN(circ)) {
+ log_info(LD_CIRC,
+ "CC: Circuit %d "
+ "SENDME RTT: %"PRIu64", %"PRIu64", %"PRIu64", %"PRIu64", "
+ "BDP estimates: "
+ "%"PRIu64", "
+ "%"PRIu64", "
+ "%"PRIu64", "
+ "%"PRIu64", "
+ "%"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]
+ );
+ } else {
+ log_info(LD_CIRC,
+ "CC: Circuit %"PRIu64":%d "
+ "SENDME RTT: %"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]
+ );
+ }
+ }
+
+ /* We updated BDP this round if either we had a blocked channel, or
+ * 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);
+ }
+ return ret;
+}
+
+/**
+ * Dispatch the sendme to the appropriate congestion control algorithm.
+ */
+int
+congestion_control_dispatch_cc_alg(congestion_control_t *cc,
+ const circuit_t *circ,
+ const crypt_path_t *layer_hint)
+{
+ 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);
+ }
+
+ if (cc->cwnd > cwnd_max) {
+ static ratelim_t cwnd_limit = RATELIM_INIT(60);
+ log_fn_ratelim(&cwnd_limit, LOG_NOTICE, LD_CIRC,
+ "Congestion control cwnd %"PRIu64" exceeds max %d, clamping.",
+ cc->cwnd, cwnd_max);
+ cc->cwnd = cwnd_max;
+ }
+
+ return ret;
+}
+
+/**
+ * Build an extension field request to negotiate congestion control.
+ *
+ * If congestion control is enabled, field TRUNNEL_EXT_TYPE_CC_FIELD_REQUEST
+ * is created in msg_out. It is a single 0-length field that signifies that we
+ * want to use congestion control. The length of msg_out is provided via
+ * msg_len_out.
+ *
+ * If congestion control is not enabled, a payload with 0 extensions is created
+ * and returned.
+ *
+ * If there is a failure building the request, -1 is returned, else 0.
+ *
+ * *msg_out must be freed if the return value is 0.
+ */
+int
+congestion_control_build_ext_request(uint8_t **msg_out, size_t *msg_len_out)
+{
+ uint8_t *request = NULL;
+ trn_extension_t *ext = NULL;
+ trn_extension_field_t *field = NULL;
+
+ ext = trn_extension_new();
+
+ /* With congestion control enabled, add the request, else it is an empty
+ * request in the payload. */
+
+ if (congestion_control_enabled()) {
+ /* Build the extension field that will hold the CC field. */
+ field = trn_extension_field_new();
+ trn_extension_field_set_field_type(field,
+ TRUNNEL_EXT_TYPE_CC_FIELD_REQUEST);
+
+ /* No payload indicating a request to use congestion control. */
+ trn_extension_field_set_field_len(field, 0);
+
+ /* Build final extension. */
+ trn_extension_add_fields(ext, field);
+ trn_extension_set_num(ext, 1);
+ }
+
+ /* Encode extension. */
+ ssize_t ret = trn_extension_encoded_len(ext);
+ if (BUG(ret < 0)) {
+ goto err;
+ }
+ size_t request_len = ret;
+ request = tor_malloc_zero(request_len);
+ ret = trn_extension_encode(request, request_len, ext);
+ if (BUG(ret < 0)) {
+ tor_free(request);
+ goto err;
+ }
+ *msg_out = request;
+ *msg_len_out = request_len;
+
+ /* Free everything, we've encoded the request now. */
+ ret = 0;
+
+ err:
+ trn_extension_free(ext);
+ return (int)ret;
+}
+
+/**
+ * Parse a congestion control ntorv3 request payload for extensions.
+ *
+ * On parsing failure, -1 is returned.
+ *
+ * If congestion control request is present, return 1. If it is not present,
+ * return 0.
+ *
+ * WARNING: Called from CPU worker! Must not access any global state.
+ */
+int
+congestion_control_parse_ext_request(const uint8_t *msg, const size_t msg_len)
+{
+ ssize_t ret = 0;
+ trn_extension_t *ext = NULL;
+ size_t num_fields = 0;
+
+ /* Parse extension from payload. */
+ ret = trn_extension_parse(&ext, msg, msg_len);
+ if (ret < 0) {
+ goto end;
+ }
+
+ /* No extension implies no support for congestion control. In this case, we
+ * simply return 0 to indicate CC is disabled. */
+ if ((num_fields = trn_extension_get_num(ext)) == 0) {
+ ret = 0;
+ goto end;
+ }
+
+ /* Go over all fields. If any field is TRUNNEL_EXT_TYPE_CC_FIELD_REQUEST,
+ * then congestion control is enabled. Ignore unknown fields. */
+ for (size_t f = 0; f < num_fields; f++) {
+ const trn_extension_field_t *field = trn_extension_get_fields(ext, f);
+ if (field == NULL) {
+ ret = -1;
+ goto end;
+ }
+
+ /* For congestion control to be enabled, we only need the field type. */
+ if (trn_extension_field_get_field_type(field) ==
+ TRUNNEL_EXT_TYPE_CC_FIELD_REQUEST) {
+ ret = 1;
+ break;
+ }
+ }
+
+ end:
+ trn_extension_free(ext);
+ return (int)ret;
+}
+
+/**
+ * Given our observed parameters for circuits and congestion control,
+ * as well as the parameters for the resulting circuit, build a response
+ * payload using extension fields into *msg_out, with length specified in
+ * *msg_out_len.
+ *
+ * If congestion control will be enabled, the extension field for
+ * TRUNNEL_EXT_TYPE_CC_FIELD_RESPONSE will contain the sendme_inc value.
+ *
+ * If congestion control won't be enabled, an extension payload with 0
+ * fields will be created.
+ *
+ * Return 0 if an extension payload was created in *msg_out, and -1 on
+ * error.
+ *
+ * *msg_out must be freed if the return value is 0.
+ *
+ * WARNING: Called from CPU worker! Must not access any global state.
+ */
+int
+congestion_control_build_ext_response(const circuit_params_t *our_params,
+ const circuit_params_t *circ_params,
+ uint8_t **msg_out, size_t *msg_len_out)
+{
+ ssize_t ret;
+ uint8_t *request = NULL;
+ trn_extension_t *ext = NULL;
+ trn_extension_field_t *field = NULL;
+ trn_extension_field_cc_t *cc_field = NULL;
+
+ tor_assert(our_params);
+ tor_assert(circ_params);
+ tor_assert(msg_out);
+ tor_assert(msg_len_out);
+
+ ext = trn_extension_new();
+
+ if (circ_params->cc_enabled) {
+ /* Build the extension field that will hold the CC field. */
+ field = trn_extension_field_new();
+ trn_extension_field_set_field_type(field,
+ TRUNNEL_EXT_TYPE_CC_FIELD_RESPONSE);
+
+ /* Build the congestion control field response. */
+ cc_field = trn_extension_field_cc_new();
+ trn_extension_field_cc_set_sendme_inc(cc_field,
+ our_params->sendme_inc_cells);
+
+ ret = trn_extension_field_cc_encoded_len(cc_field);
+ if (BUG(ret <= 0)) {
+ trn_extension_field_free(field);
+ goto err;
+ }
+ size_t field_len = ret;
+ trn_extension_field_set_field_len(field, field_len);
+ trn_extension_field_setlen_field(field, field_len);
+
+ uint8_t *field_array = trn_extension_field_getarray_field(field);
+ ret = trn_extension_field_cc_encode(field_array,
+ trn_extension_field_getlen_field(field), cc_field);
+ if (BUG(ret <= 0)) {
+ trn_extension_field_free(field);
+ goto err;
+ }
+
+ /* Build final extension. */
+ trn_extension_add_fields(ext, field);
+ trn_extension_set_num(ext, 1);
+ }
+
+ /* Encode extension. */
+ ret = trn_extension_encoded_len(ext);
+ if (BUG(ret < 0)) {
+ goto err;
+ }
+ size_t request_len = ret;
+ request = tor_malloc_zero(request_len);
+ ret = trn_extension_encode(request, request_len, ext);
+ if (BUG(ret < 0)) {
+ tor_free(request);
+ goto err;
+ }
+ *msg_out = request;
+ *msg_len_out = request_len;
+
+ /* We've just encoded the extension, clean everything. */
+ ret = 0;
+
+ err:
+ trn_extension_free(ext);
+ trn_extension_field_cc_free(cc_field);
+ return (int)ret;
+}
+
+/** Return true iff the given sendme increment is within the acceptable
+ * margins. */
+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
+ * 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) {
+ return false;
+ }
+ return true;
+}
+
+/** Return 1 if CC is enabled which also will set the SENDME increment into our
+ * params_out. Return 0 if CC is disabled. Else, return -1 on error. */
+int
+congestion_control_parse_ext_response(const uint8_t *msg,
+ const size_t msg_len,
+ circuit_params_t *params_out)
+{
+ ssize_t ret = 0;
+ size_t num_fields = 0;
+ trn_extension_t *ext = NULL;
+ trn_extension_field_cc_t *cc_field = NULL;
+
+ /* 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
+ * 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
+
+ /* Parse extension from payload. */
+ ret = trn_extension_parse(&ext, msg, msg_len);
+ if (ret < 0) {
+ goto end;
+ }
+
+ if ((num_fields = trn_extension_get_num(ext)) == 0) {
+ ret = 0;
+ goto end;
+ }
+
+ /* Go over all fields. If any field is TRUNNEL_EXT_TYPE_CC_FIELD_RESPONSE,
+ * then congestion control is enabled. Ignore unknown fields. */
+ for (size_t f = 0; f < num_fields; f++) {
+ const trn_extension_field_t *field = trn_extension_get_fields(ext, f);
+ if (field == NULL) {
+ ret = -1;
+ goto end;
+ }
+
+ /* Only examine TRUNNEL_EXT_TYPE_CC_FIELD_RESPONSE; ignore other fields */
+ if (trn_extension_field_get_field_type(field) ==
+ TRUNNEL_EXT_TYPE_CC_FIELD_RESPONSE) {
+
+ /* Parse the field into the congestion control field. */
+ ret = trn_extension_field_cc_parse(&cc_field,
+ trn_extension_field_getconstarray_field(field),
+ trn_extension_field_getlen_field(field));
+ if (ret < 0) {
+ goto end;
+ }
+
+ uint8_t sendme_inc_cells =
+ trn_extension_field_cc_get_sendme_inc(cc_field);
+ if (!congestion_control_validate_sendme_increment(sendme_inc_cells)) {
+ ret = -1;
+ goto end;
+ }
+
+ /* All good. Get value and break */
+ params_out->sendme_inc_cells = sendme_inc_cells;
+ ret = 1;
+ break;
+ }
+ }
+
+ end:
+ trn_extension_free(ext);
+ trn_extension_field_cc_free(cc_field);
+
+ return (int)ret;
+}
+
+/**
+ * Returns a formatted string of fields containing congestion
+ * control information, for the CIRC_BW control port event.
+ *
+ * An origin circuit can have a ccontrol object directly on it,
+ * if it is an onion service, or onion client. Exit-bound clients
+ * will have the ccontrol on the cpath associated with their exit
+ * (the last one in the cpath list).
+ *
+ * WARNING: This function does not support leaky-pipe topology. It
+ * is to be used for control port information only.
+ */
+char *
+congestion_control_get_control_port_fields(const origin_circuit_t *circ)
+{
+ const congestion_control_t *ccontrol = NULL;
+ char *ret = NULL;
+ int len;
+
+ if (TO_CIRCUIT(circ)->ccontrol) {
+ ccontrol = TO_CIRCUIT(circ)->ccontrol;
+ } else if (circ->cpath && circ->cpath->prev->ccontrol) {
+ /* Get ccontrol for last hop (exit) if it exists */
+ ccontrol = circ->cpath->prev->ccontrol;
+ }
+
+ if (!ccontrol)
+ return NULL;
+
+ len = tor_asprintf(&ret,
+ " SS=%d CWND=%"PRIu64" RTT=%"PRIu64" MIN_RTT=%"PRIu64,
+ ccontrol->in_slow_start, ccontrol->cwnd,
+ ccontrol->ewma_rtt_usec/1000,
+ ccontrol->min_rtt_usec/1000);
+ if (len < 0) {
+ log_warn(LD_BUG, "Unable to format event for controller.");
+ return NULL;
+ }
+
+ return ret;
+}
diff --git a/src/core/or/congestion_control_common.h b/src/core/or/congestion_control_common.h
new file mode 100644
index 0000000000..fa8f67bb8b
--- /dev/null
+++ b/src/core/or/congestion_control_common.h
@@ -0,0 +1,190 @@
+/* Copyright (c) 2019-2021, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file congestion_control_common.h
+ * \brief Public APIs for congestion control
+ **/
+
+#ifndef TOR_CONGESTION_CONTROL_COMMON_H
+#define TOR_CONGESTION_CONTROL_COMMON_H
+
+#include "core/crypto/onion_crypto.h"
+#include "core/or/crypt_path_st.h"
+#include "core/or/circuit_st.h"
+
+/* The maximum whole number of cells that can fit in a
+ * full TLS record. This is 31. */
+#define TLS_RECORD_MAX_CELLS ((16 * 1024) / CELL_MAX_NETWORK_SIZE)
+
+typedef struct congestion_control_t congestion_control_t;
+
+/**
+ * Specifies the path type to help choose congestion control
+ * parameters. Since these paths are different lengths, they
+ * will need different queue parameters. */
+typedef enum {
+ CC_PATH_EXIT = 0,
+ CC_PATH_ONION = 1,
+ CC_PATH_ONION_SOS = 2,
+ CC_PATH_ONION_VG = 3,
+ CC_PATH_SBWS = 4,
+} cc_path_t;
+
+/** The length of a path for sbws measurement */
+#define SBWS_ROUTE_LEN 2
+
+/** Wrapper for the free function, set the CC pointer to NULL after free */
+#define congestion_control_free(cc) \
+ FREE_AND_NULL(congestion_control_t, congestion_control_free_, cc)
+
+void congestion_control_free_(congestion_control_t *cc);
+
+struct circuit_params_t;
+congestion_control_t *congestion_control_new(
+ const struct circuit_params_t *params,
+ cc_path_t path);
+
+int congestion_control_dispatch_cc_alg(congestion_control_t *cc,
+ const circuit_t *circ,
+ const crypt_path_t *layer_hint);
+
+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 *);
+
+int congestion_control_get_package_window(const circuit_t *,
+ const crypt_path_t *);
+
+int sendme_get_inc_count(const circuit_t *, const crypt_path_t *);
+bool circuit_sent_cell_for_sendme(const circuit_t *, const crypt_path_t *);
+bool is_monotime_clock_reliable(void);
+
+void congestion_control_new_consensus_params(const networkstatus_t *ns);
+
+bool congestion_control_enabled(void);
+
+int congestion_control_build_ext_request(uint8_t **msg_out,
+ size_t *msg_len_out);
+int congestion_control_parse_ext_request(const uint8_t *msg,
+ const size_t msg_len);
+int congestion_control_build_ext_response(const circuit_params_t *our_params,
+ const circuit_params_t *circ_params,
+ uint8_t **msg_out,
+ size_t *msg_len_out);
+int congestion_control_parse_ext_response(const uint8_t *msg,
+ const size_t msg_len,
+ circuit_params_t *params_out);
+bool congestion_control_validate_sendme_increment(uint8_t sendme_inc);
+char *congestion_control_get_control_port_fields(const origin_circuit_t *);
+
+uint64_t congestion_control_get_num_rtt_reset(void);
+uint64_t congestion_control_get_num_clock_stalls(void);
+
+extern uint64_t cc_stats_circs_created;
+
+/* Ugh, C.. these are private. Use the getter instead, when
+ * external to the congestion control code. */
+extern uint32_t or_conn_highwater;
+extern uint32_t or_conn_lowwater;
+extern int32_t cell_queue_high;
+extern int32_t cell_queue_low;
+extern uint8_t cc_sendme_inc;
+
+/** Stop writing on an orconn when its outbuf is this large */
+static inline uint32_t
+or_conn_highwatermark(void)
+{
+ return or_conn_highwater;
+}
+
+/** Resume writing on an orconn when its outbuf is less than this */
+static inline uint32_t
+or_conn_lowwatermark(void)
+{
+ return or_conn_lowwater;
+}
+
+/** Stop reading on edge connections when we have this many cells
+ * waiting on the appropriate queue. */
+static inline int32_t
+cell_queue_highwatermark(void)
+{
+ return cell_queue_high;
+}
+
+/** Start reading from edge connections again when we get down to this many
+ * cells. */
+static inline int32_t
+cell_queue_lowwatermark(void)
+{
+ return cell_queue_low;
+}
+
+/** Returns the sendme inc rate cached from the most recent consensus */
+static inline uint8_t
+congestion_control_sendme_inc(void)
+{
+ return cc_sendme_inc;
+}
+
+/**
+ * Compute an N-count EWMA, aka N-EWMA. N-EWMA is defined as:
+ * EWMA = alpha*value + (1-alpha)*EWMA_prev
+ * with alpha = 2/(N+1).
+ *
+ * This works out to:
+ * EWMA = value*2/(N+1) + EMA_prev*(N-1)/(N+1)
+ * = (value*2 + EWMA_prev*(N-1))/(N+1)
+ */
+static inline uint64_t
+n_count_ewma(uint64_t curr, uint64_t prev, uint64_t N)
+{
+ if (prev == 0)
+ return curr;
+ else
+ return (2*curr + (N-1)*prev)/(N+1);
+}
+
+/**
+ * Helper function that gives us a percentile weighted-average between
+ * two values. The pct_max argument specifies the percentage weight of the
+ * maximum of a and b, when computing this weighted-average.
+ *
+ * This also allows this function to be used as either MIN() or a MAX()
+ * by this parameterization. It is MIN() when pct_max==0;
+ * it is MAX() when pct_max==100; it is avg() when pct_max==50; it is a
+ * weighted-average for values in between.
+ */
+static inline uint64_t
+percent_max_mix(uint64_t a, uint64_t b, uint8_t pct_max)
+{
+ uint64_t max = MAX(a, b);
+ uint64_t min = MIN(a, b);
+
+ if (BUG(pct_max > 100)) {
+ return max;
+ }
+
+ return pct_max*max/100 + (100-pct_max)*min/100;
+}
+
+/* Private section starts. */
+#ifdef TOR_CONGESTION_CONTROL_PRIVATE
+
+/*
+ * Unit tests declaractions.
+ */
+#ifdef TOR_UNIT_TESTS
+
+void congestion_control_set_cc_enabled(void);
+
+#endif /* defined(TOR_UNIT_TESTS) */
+
+#endif /* defined(TOR_CONGESTION_CONTROL_PRIVATE) */
+
+#endif /* !defined(TOR_CONGESTION_CONTROL_COMMON_H) */
diff --git a/src/core/or/congestion_control_flow.c b/src/core/or/congestion_control_flow.c
new file mode 100644
index 0000000000..90b1927ef9
--- /dev/null
+++ b/src/core/or/congestion_control_flow.c
@@ -0,0 +1,751 @@
+/* Copyright (c) 2019-2021, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file congestion_control_flow.c
+ * \brief Code that implements flow control for congestion controlled
+ * circuits.
+ */
+
+#define TOR_CONGESTION_CONTROL_FLOW_PRIVATE
+
+#include "core/or/or.h"
+
+#include "core/or/relay.h"
+#include "core/mainloop/connection.h"
+#include "core/or/connection_edge.h"
+#include "core/mainloop/mainloop.h"
+#include "core/or/congestion_control_common.h"
+#include "core/or/congestion_control_flow.h"
+#include "core/or/congestion_control_st.h"
+#include "core/or/circuitlist.h"
+#include "core/or/trace_probes_cc.h"
+#include "feature/nodelist/networkstatus.h"
+#include "trunnel/flow_control_cells.h"
+#include "feature/control/control_events.h"
+#include "lib/math/stats.h"
+
+#include "core/or/connection_st.h"
+#include "core/or/cell_st.h"
+#include "app/config/config.h"
+
+/** Cache consensus parameters */
+static uint32_t xoff_client;
+static uint32_t xoff_exit;
+
+static uint32_t xon_change_pct;
+static uint32_t xon_ewma_cnt;
+static uint32_t xon_rate_bytes;
+
+/** Metricsport stats */
+uint64_t cc_stats_flow_num_xoff_sent;
+uint64_t cc_stats_flow_num_xon_sent;
+double cc_stats_flow_xoff_outbuf_ma = 0;
+double cc_stats_flow_xon_outbuf_ma = 0;
+
+/* In normal operation, we can get a burst of up to 32 cells before returning
+ * to libevent to flush the outbuf. This is a heuristic from hardcoded values
+ * and strange logic in connection_bucket_get_share(). */
+#define MAX_EXPECTED_CELL_BURST 32
+
+/* The following three are for dropmark rate limiting. They define when we
+ * scale down our XON, XOFF, and xmit byte counts. Early scaling is beneficial
+ * because it limits the ability of spurious XON/XOFF to be sent after large
+ * amounts of data without XON/XOFF. At these limits, after 10MB of data (or
+ * more), an adversary can only inject (log2(10MB)-log2(200*500))*100 ~= 1000
+ * cells of fake XOFF/XON before the xmit byte count will be halved enough to
+ * triggering a limit. */
+#define XON_COUNT_SCALE_AT 200
+#define XOFF_COUNT_SCALE_AT 200
+#define ONE_MEGABYTE (UINT64_C(1) << 20)
+#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.
+ *
+ * More details for each of the parameters can be found in proposal 324,
+ * section 6.5 including tuning notes.
+ */
+void
+flow_control_new_consensus_params(const networkstatus_t *ns)
+{
+#define CC_XOFF_CLIENT_DFLT 500
+#define CC_XOFF_CLIENT_MIN 1
+#define CC_XOFF_CLIENT_MAX 10000
+ xoff_client = networkstatus_get_param(ns, "cc_xoff_client",
+ CC_XOFF_CLIENT_DFLT,
+ CC_XOFF_CLIENT_MIN,
+ CC_XOFF_CLIENT_MAX)*RELAY_PAYLOAD_SIZE;
+
+#define CC_XOFF_EXIT_DFLT 500
+#define CC_XOFF_EXIT_MIN 1
+#define CC_XOFF_EXIT_MAX 10000
+ xoff_exit = networkstatus_get_param(ns, "cc_xoff_exit",
+ CC_XOFF_EXIT_DFLT,
+ CC_XOFF_EXIT_MIN,
+ CC_XOFF_EXIT_MAX)*RELAY_PAYLOAD_SIZE;
+
+#define CC_XON_CHANGE_PCT_DFLT 25
+#define CC_XON_CHANGE_PCT_MIN 1
+#define CC_XON_CHANGE_PCT_MAX 99
+ xon_change_pct = networkstatus_get_param(ns, "cc_xon_change_pct",
+ CC_XON_CHANGE_PCT_DFLT,
+ CC_XON_CHANGE_PCT_MIN,
+ CC_XON_CHANGE_PCT_MAX);
+
+#define CC_XON_RATE_BYTES_DFLT (500)
+#define CC_XON_RATE_BYTES_MIN (1)
+#define CC_XON_RATE_BYTES_MAX (5000)
+ xon_rate_bytes = networkstatus_get_param(ns, "cc_xon_rate",
+ CC_XON_RATE_BYTES_DFLT,
+ CC_XON_RATE_BYTES_MIN,
+ CC_XON_RATE_BYTES_MAX)*RELAY_PAYLOAD_SIZE;
+
+#define CC_XON_EWMA_CNT_DFLT (2)
+#define CC_XON_EWMA_CNT_MIN (2)
+#define CC_XON_EWMA_CNT_MAX (100)
+ xon_ewma_cnt = networkstatus_get_param(ns, "cc_xon_ewma_cnt",
+ CC_XON_EWMA_CNT_DFLT,
+ CC_XON_EWMA_CNT_MIN,
+ CC_XON_EWMA_CNT_MAX);
+}
+
+/**
+ * Send an XOFF for this stream, and note that we sent one
+ */
+static void
+circuit_send_stream_xoff(edge_connection_t *stream)
+{
+ xoff_cell_t xoff;
+ uint8_t payload[CELL_PAYLOAD_SIZE];
+ ssize_t xoff_size;
+
+ memset(&xoff, 0, sizeof(xoff));
+ memset(payload, 0, sizeof(payload));
+
+ xoff_cell_set_version(&xoff, 0);
+
+ if ((xoff_size = xoff_cell_encode(payload, CELL_PAYLOAD_SIZE, &xoff)) < 0) {
+ log_warn(LD_BUG, "Failed to encode xon cell");
+ return;
+ }
+
+ if (connection_edge_send_command(stream, RELAY_COMMAND_XOFF,
+ (char*)payload, (size_t)xoff_size) == 0) {
+ stream->xoff_sent = true;
+ cc_stats_flow_num_xoff_sent++;
+
+ /* If this is an entry conn, notify control port */
+ if (TO_CONN(stream)->type == CONN_TYPE_AP) {
+ control_event_stream_status(TO_ENTRY_CONN(TO_CONN(stream)),
+ STREAM_EVENT_XOFF_SENT,
+ 0);
+ }
+ }
+}
+
+/**
+ * Compute the recent drain rate (write rate) for this edge
+ * connection and return it, in KB/sec (1000 bytes/sec).
+ *
+ * Returns 0 if the monotime clock is busted.
+ */
+static inline uint32_t
+compute_drain_rate(const edge_connection_t *stream)
+{
+ if (BUG(!is_monotime_clock_reliable())) {
+ log_warn(LD_BUG, "Computing drain rate with stalled monotime clock");
+ return 0;
+ }
+
+ uint64_t delta = monotime_absolute_usec() - stream->drain_start_usec;
+
+ if (delta == 0) {
+ log_warn(LD_BUG, "Computing stream drain rate with zero time delta");
+ return 0;
+ }
+
+ /* Overflow checks */
+ if (stream->prev_drained_bytes > INT32_MAX/1000 || /* Intermediate */
+ stream->prev_drained_bytes/delta > INT32_MAX/1000) { /* full value */
+ return INT32_MAX;
+ }
+
+ /* kb/sec = bytes/usec * 1000 usec/msec * 1000 msec/sec * kb/1000bytes */
+ return MAX(1, (uint32_t)(stream->prev_drained_bytes * 1000)/delta);
+}
+
+/**
+ * Send an XON for this stream, with appropriate advisory rate information.
+ *
+ * Reverts the xoff sent status, and stores the rate information we sent,
+ * in case it changes.
+ */
+static void
+circuit_send_stream_xon(edge_connection_t *stream)
+{
+ xon_cell_t xon;
+ uint8_t payload[CELL_PAYLOAD_SIZE];
+ ssize_t xon_size;
+
+ memset(&xon, 0, sizeof(xon));
+ memset(payload, 0, sizeof(payload));
+
+ xon_cell_set_version(&xon, 0);
+ xon_cell_set_kbps_ewma(&xon, stream->ewma_drain_rate);
+
+ if ((xon_size = xon_cell_encode(payload, CELL_PAYLOAD_SIZE, &xon)) < 0) {
+ log_warn(LD_BUG, "Failed to encode xon cell");
+ return;
+ }
+
+ /* Store the advisory rate information, to send advisory updates if
+ * it changes */
+ stream->ewma_rate_last_sent = stream->ewma_drain_rate;
+
+ if (connection_edge_send_command(stream, RELAY_COMMAND_XON, (char*)payload,
+ (size_t)xon_size) == 0) {
+ /* Revert the xoff sent status, so we can send another one if need be */
+ stream->xoff_sent = false;
+
+ cc_stats_flow_num_xon_sent++;
+
+ /* If it's an entry conn, notify control port */
+ if (TO_CONN(stream)->type == CONN_TYPE_AP) {
+ control_event_stream_status(TO_ENTRY_CONN(TO_CONN(stream)),
+ STREAM_EVENT_XON_SENT,
+ 0);
+ }
+ }
+}
+
+/**
+ * Process a stream XOFF, parsing it, and then stopping reading on
+ * the edge connection.
+ *
+ * Record that we have received an xoff, so we know not to resume
+ * reading on this edge conn until we get an XON.
+ *
+ * Returns false if the XOFF did not validate; true if it does.
+ */
+bool
+circuit_process_stream_xoff(edge_connection_t *conn,
+ const crypt_path_t *layer_hint,
+ const cell_t *cell)
+{
+ (void)cell;
+ bool retval = true;
+
+ if (BUG(!conn)) {
+ log_fn(LOG_PROTOCOL_WARN, LD_EDGE,
+ "Got XOFF on invalid stream?");
+ return false;
+ }
+
+ /* Make sure this XOFF came from the right hop */
+ if (layer_hint && layer_hint != conn->cpath_layer) {
+ log_fn(LOG_PROTOCOL_WARN, LD_EDGE,
+ "Got XOFF from wrong hop.");
+ return false;
+ }
+
+ if (edge_get_ccontrol(conn) == NULL) {
+ log_fn(LOG_PROTOCOL_WARN, LD_EDGE,
+ "Got XOFF for non-congestion control circuit");
+ return false;
+ }
+
+ if (conn->xoff_received) {
+ log_fn(LOG_PROTOCOL_WARN, LD_EDGE,
+ "Got multiple XOFF on connection");
+ return false;
+ }
+
+ /* If we are near the max, scale everything down */
+ if (conn->num_xoff_recv == XOFF_COUNT_SCALE_AT) {
+ log_info(LD_EDGE, "Scaling down for XOFF count: %d %d %d",
+ conn->total_bytes_xmit,
+ conn->num_xoff_recv,
+ conn->num_xon_recv);
+ conn->total_bytes_xmit /= 2;
+ conn->num_xoff_recv /= 2;
+ conn->num_xon_recv /= 2;
+ }
+
+ conn->num_xoff_recv++;
+
+ /* Client-side check to make sure that XOFF is not sent too early,
+ * for dropmark attacks. The main sidechannel risk is early cells,
+ * but we also check to make sure that we have not received more XOFFs
+ * than could have been generated by the bytes we sent.
+ */
+ if (TO_CONN(conn)->type == CONN_TYPE_AP || conn->hs_ident != NULL) {
+ uint32_t limit = 0;
+ if (conn->hs_ident)
+ limit = xoff_client;
+ else
+ limit = xoff_exit;
+
+ if (conn->total_bytes_xmit < limit*conn->num_xoff_recv) {
+ log_fn(LOG_PROTOCOL_WARN, LD_EDGE,
+ "Got extra XOFF for bytes sent. Got %d, expected max %d",
+ conn->num_xoff_recv, conn->total_bytes_xmit/limit);
+ /* We still process this, because the only dropmark defenses
+ * in C tor are via the vanguards addon's use of the read valid
+ * cells. So just signal that we think this is not valid protocol
+ * data and proceed. */
+ retval = false;
+ }
+ }
+
+ log_info(LD_EDGE, "Got XOFF!");
+ connection_stop_reading(TO_CONN(conn));
+ conn->xoff_received = true;
+
+ /* If this is an entry conn, notify control port */
+ if (TO_CONN(conn)->type == CONN_TYPE_AP) {
+ control_event_stream_status(TO_ENTRY_CONN(TO_CONN(conn)),
+ STREAM_EVENT_XOFF_RECV,
+ 0);
+ }
+
+ return retval;
+}
+
+/**
+ * Process a stream XON, and if it validates, clear the xoff
+ * flag and resume reading on this edge connection.
+ *
+ * Also, use provided rate information to rate limit
+ * reading on this edge (or packagaing from it onto
+ * the circuit), to avoid XON/XOFF chatter.
+ *
+ * Returns true if the XON validates, false otherwise.
+ */
+bool
+circuit_process_stream_xon(edge_connection_t *conn,
+ const crypt_path_t *layer_hint,
+ const cell_t *cell)
+{
+ xon_cell_t *xon;
+ bool retval = true;
+
+ if (BUG(!conn)) {
+ log_fn(LOG_PROTOCOL_WARN, LD_EDGE,
+ "Got XON on invalid stream?");
+ return false;
+ }
+
+ /* Make sure this XON came from the right hop */
+ if (layer_hint && layer_hint != conn->cpath_layer) {
+ log_fn(LOG_PROTOCOL_WARN, LD_EDGE,
+ "Got XON from wrong hop.");
+ return false;
+ }
+
+ if (edge_get_ccontrol(conn) == NULL) {
+ log_fn(LOG_PROTOCOL_WARN, LD_EDGE,
+ "Got XON for non-congestion control circuit");
+ return false;
+ }
+
+ if (xon_cell_parse(&xon, cell->payload+RELAY_HEADER_SIZE,
+ CELL_PAYLOAD_SIZE-RELAY_HEADER_SIZE) < 0) {
+ log_fn(LOG_PROTOCOL_WARN, LD_EDGE,
+ "Received malformed XON cell.");
+ return false;
+ }
+
+ /* If we are near the max, scale everything down */
+ if (conn->num_xon_recv == XON_COUNT_SCALE_AT) {
+ log_info(LD_EDGE, "Scaling down for XON count: %d %d %d",
+ conn->total_bytes_xmit,
+ conn->num_xoff_recv,
+ conn->num_xon_recv);
+ conn->total_bytes_xmit /= 2;
+ conn->num_xoff_recv /= 2;
+ conn->num_xon_recv /= 2;
+ }
+
+ conn->num_xon_recv++;
+
+ /* Client-side check to make sure that XON is not sent too early,
+ * for dropmark attacks. The main sidechannel risk is early cells,
+ * but we also check to see that we did not get more XONs than make
+ * sense for the number of bytes we sent.
+ */
+ if (TO_CONN(conn)->type == CONN_TYPE_AP || conn->hs_ident != NULL) {
+ uint32_t limit = 0;
+
+ if (conn->hs_ident)
+ limit = MIN(xoff_client, xon_rate_bytes);
+ else
+ limit = MIN(xoff_exit, xon_rate_bytes);
+
+ if (conn->total_bytes_xmit < limit*conn->num_xon_recv) {
+ log_fn(LOG_PROTOCOL_WARN, LD_EDGE,
+ "Got extra XON for bytes sent. Got %d, expected max %d",
+ conn->num_xon_recv, conn->total_bytes_xmit/limit);
+
+ /* We still process this, because the only dropmark defenses
+ * in C tor are via the vanguards addon's use of the read valid
+ * cells. So just signal that we think this is not valid protocol
+ * data and proceed. */
+ retval = false;
+ }
+ }
+
+ log_info(LD_EDGE, "Got XON: %d", xon->kbps_ewma);
+
+ /* Adjust the token bucket of this edge connection with the drain rate in
+ * the XON. Rate is in bytes from kilobit (kpbs). */
+ uint64_t rate = ((uint64_t) xon_cell_get_kbps_ewma(xon) * 1000);
+ if (rate == 0 || INT32_MAX < rate) {
+ /* No rate. */
+ rate = INT32_MAX;
+ }
+ token_bucket_rw_adjust(&conn->bucket, (uint32_t) rate, (uint32_t) rate);
+
+ if (conn->xoff_received) {
+ /* Clear the fact that we got an XOFF, so that this edge can
+ * start and stop reading normally */
+ conn->xoff_received = false;
+ connection_start_reading(TO_CONN(conn));
+ }
+
+ /* If this is an entry conn, notify control port */
+ if (TO_CONN(conn)->type == CONN_TYPE_AP) {
+ control_event_stream_status(TO_ENTRY_CONN(TO_CONN(conn)),
+ STREAM_EVENT_XON_RECV,
+ 0);
+ }
+
+ xon_cell_free(xon);
+
+ return retval;
+}
+
+/**
+ * Called from sendme_stream_data_received(), when data arrives
+ * from a circuit to our edge's outbuf, to decide if we need to send
+ * an XOFF.
+ *
+ * Returns the amount of cells remaining until the buffer is full, at
+ * which point it sends an XOFF, and returns 0.
+ *
+ * Returns less than 0 if we have queued more than a congestion window
+ * worth of data and need to close the circuit.
+ */
+int
+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)) {
+ log_err(LD_BUG, "Flow control called for non-congestion control circuit");
+ return -1;
+ }
+
+ /* Onion services and clients are typically localhost edges, so they
+ * need different buffering limits than exits do */
+ if (TO_CONN(stream)->type == CONN_TYPE_AP || stream->hs_ident != NULL) {
+ buffer_limit_xoff = xoff_client;
+ } else {
+ buffer_limit_xoff = xoff_exit;
+ }
+
+ if (total_buffered > buffer_limit_xoff) {
+ if (!stream->xoff_sent) {
+ log_info(LD_EDGE, "Sending XOFF: %"TOR_PRIuSZ" %d",
+ total_buffered, buffer_limit_xoff);
+ tor_trace(TR_SUBSYS(cc), TR_EV(flow_decide_xoff_sending), stream);
+
+ cc_stats_flow_xoff_outbuf_ma =
+ stats_update_running_avg(cc_stats_flow_xoff_outbuf_ma,
+ total_buffered);
+
+ circuit_send_stream_xoff(stream);
+
+ /* Clear the drain rate. It is considered wrong if we
+ * got all the way to XOFF */
+ stream->ewma_drain_rate = 0;
+ }
+ }
+
+ /* If the outbuf has accumulated more than the expected burst limit of
+ * cells, then assume it is not draining, and call decide_xon. We must
+ * do this because writes only happen when the socket unblocks, so
+ * may not otherwise notice accumulation of data in the outbuf for
+ * advisory XONs. */
+ if (total_buffered > MAX_EXPECTED_CELL_BURST*RELAY_PAYLOAD_SIZE) {
+ flow_control_decide_xon(stream, 0);
+ }
+
+ /* Flow control always takes more data; we rely on the oomkiller to
+ * handle misbehavior. */
+ return 0;
+}
+
+/**
+ * Returns true if the stream's drain rate has changed significantly.
+ *
+ * Returns false if the monotime clock is stalled, or if we have
+ * no previous drain rate information.
+ */
+static bool
+stream_drain_rate_changed(const edge_connection_t *stream)
+{
+ if (!is_monotime_clock_reliable()) {
+ return false;
+ }
+
+ if (!stream->ewma_rate_last_sent) {
+ return false;
+ }
+
+ if (stream->ewma_drain_rate >
+ (100+(uint64_t)xon_change_pct)*stream->ewma_rate_last_sent/100) {
+ return true;
+ }
+
+ if (stream->ewma_drain_rate <
+ (100-(uint64_t)xon_change_pct)*stream->ewma_rate_last_sent/100) {
+ return true;
+ }
+
+ return false;
+}
+
+/**
+ * Called whenever we drain an edge connection outbuf by writing on
+ * its socket, to decide if it is time to send an xon.
+ *
+ * The n_written parameter tells us how many bytes we have written
+ * this time, which is used to compute the advisory drain rate fields.
+ */
+void
+flow_control_decide_xon(edge_connection_t *stream, size_t n_written)
+{
+ size_t total_buffered = connection_get_outbuf_len(TO_CONN(stream));
+
+ /* Bounds check the number of drained bytes, and scale */
+ if (stream->drained_bytes >= UINT32_MAX - n_written) {
+ /* Cut the bytes in half, and move the start time up halfway to now
+ * (if we have one). */
+ stream->drained_bytes /= 2;
+
+ if (stream->drain_start_usec) {
+ uint64_t now = monotime_absolute_usec();
+
+ stream->drain_start_usec = now - (now-stream->drain_start_usec)/2;
+ }
+ }
+
+ /* Accumulate drained bytes since last rate computation */
+ stream->drained_bytes += n_written;
+
+ tor_trace(TR_SUBSYS(cc), TR_EV(flow_decide_xon), stream, n_written);
+
+ /* Check for bad monotime clock and bytecount wrap */
+ if (!is_monotime_clock_reliable()) {
+ /* If the monotime clock ever goes wrong, the safest thing to do
+ * is just clear our short-term rate info and wait for the clock to
+ * become reliable again.. */
+ stream->drain_start_usec = 0;
+ stream->drained_bytes = 0;
+ } else {
+ /* If we have no drain start timestamp, and we still have
+ * remaining buffer, start the buffering counter */
+ if (!stream->drain_start_usec && total_buffered > 0) {
+ log_debug(LD_EDGE, "Began edge buffering: %d %d %"TOR_PRIuSZ,
+ stream->ewma_rate_last_sent,
+ stream->ewma_drain_rate,
+ total_buffered);
+ tor_trace(TR_SUBSYS(cc), TR_EV(flow_decide_xon_drain_start),
+ stream);
+ stream->drain_start_usec = monotime_absolute_usec();
+ stream->drained_bytes = 0;
+ }
+ }
+
+ if (stream->drain_start_usec) {
+ /* If we have spent enough time in a queued state, update our drain
+ * rate. */
+ if (stream->drained_bytes > xon_rate_bytes) {
+ /* No previous drained bytes means it is the first time we are computing
+ * it so use the value we just drained onto the socket as a baseline. It
+ * won't be accurate but it will be a start towards the right value.
+ *
+ * We have to do this in order to have a drain rate else we could be
+ * sending a drain rate of 0 in an XON which would be undesirable and
+ * basically like sending an XOFF. */
+ if (stream->prev_drained_bytes == 0) {
+ stream->prev_drained_bytes = stream->drained_bytes;
+ }
+ uint32_t drain_rate = compute_drain_rate(stream);
+ /* Once the drain rate has been computed, note how many bytes we just
+ * drained so it can be used at the next calculation. We do this here
+ * because it gets reset once the rate is changed. */
+ stream->prev_drained_bytes = stream->drained_bytes;
+
+ if (drain_rate) {
+ stream->ewma_drain_rate =
+ (uint32_t)n_count_ewma(drain_rate,
+ stream->ewma_drain_rate,
+ xon_ewma_cnt);
+ log_debug(LD_EDGE, "Updating drain rate: %d %d %"TOR_PRIuSZ,
+ drain_rate,
+ stream->ewma_drain_rate,
+ total_buffered);
+ tor_trace(TR_SUBSYS(cc), TR_EV(flow_decide_xon_drain_update),
+ stream, drain_rate);
+ /* Reset recent byte counts. This prevents us from sending advisory
+ * XONs more frequent than every xon_rate_bytes. */
+ stream->drained_bytes = 0;
+ stream->drain_start_usec = 0;
+ }
+ }
+ }
+
+ /* If we don't have an XOFF outstanding, consider updating an
+ * old rate */
+ if (!stream->xoff_sent) {
+ if (stream_drain_rate_changed(stream)) {
+ /* If we are still buffering and the rate changed, update
+ * advisory XON */
+ log_info(LD_EDGE, "Sending rate-change XON: %d %d %"TOR_PRIuSZ,
+ stream->ewma_rate_last_sent,
+ stream->ewma_drain_rate,
+ total_buffered);
+ tor_trace(TR_SUBSYS(cc), TR_EV(flow_decide_xon_rate_change), stream);
+
+ cc_stats_flow_xon_outbuf_ma =
+ stats_update_running_avg(cc_stats_flow_xon_outbuf_ma,
+ total_buffered);
+
+ circuit_send_stream_xon(stream);
+ }
+ } else if (total_buffered == 0) {
+ log_info(LD_EDGE, "Sending XON: %d %d %"TOR_PRIuSZ,
+ stream->ewma_rate_last_sent,
+ stream->ewma_drain_rate,
+ total_buffered);
+ tor_trace(TR_SUBSYS(cc), TR_EV(flow_decide_xon_partial_drain), stream);
+ circuit_send_stream_xon(stream);
+ }
+
+ /* If the buffer has fully emptied, clear the drain timestamp,
+ * so we can total only bytes drained while outbuf is 0. */
+ if (total_buffered == 0) {
+ stream->drain_start_usec = 0;
+
+ /* After we've spent 'xon_rate_bytes' with the queue fully drained,
+ * double any rate we sent. */
+ if (stream->drained_bytes >= xon_rate_bytes &&
+ stream->ewma_rate_last_sent) {
+ stream->ewma_drain_rate = MIN(INT32_MAX, 2*stream->ewma_drain_rate);
+
+ log_debug(LD_EDGE,
+ "Queue empty for xon_rate_limit bytes: %d %d",
+ stream->ewma_rate_last_sent,
+ stream->ewma_drain_rate);
+ tor_trace(TR_SUBSYS(cc), TR_EV(flow_decide_xon_drain_doubled), stream);
+ /* Resetting the drained bytes count. We need to keep its value as a
+ * previous so the drain rate calculation takes into account what was
+ * actually drain the last time. */
+ stream->prev_drained_bytes = stream->drained_bytes;
+ stream->drained_bytes = 0;
+ }
+ }
+
+ return;
+}
+
+/**
+ * Note that we packaged some data on this stream. Used to enforce
+ * client-side dropmark limits
+ */
+void
+flow_control_note_sent_data(edge_connection_t *stream, size_t len)
+{
+ /* If we are near the max, scale everything down */
+ if (stream->total_bytes_xmit >= TOTAL_XMIT_SCALE_AT-len) {
+ log_info(LD_EDGE, "Scaling down for flow control xmit bytes:: %d %d %d",
+ stream->total_bytes_xmit,
+ stream->num_xoff_recv,
+ stream->num_xon_recv);
+
+ stream->total_bytes_xmit /= 2;
+ stream->num_xoff_recv /= 2;
+ stream->num_xon_recv /= 2;
+ }
+
+ stream->total_bytes_xmit += len;
+}
+
+/** Returns true if an edge connection uses flow control */
+bool
+edge_uses_flow_control(const edge_connection_t *stream)
+{
+ bool ret = (stream->on_circuit && stream->on_circuit->ccontrol) ||
+ (stream->cpath_layer && stream->cpath_layer->ccontrol);
+
+ /* All circuits with congestion control use flow control */
+ 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)
+{
+ bool ret = false;
+
+ if (CONN_IS_EDGE(conn)) {
+ edge_connection_t *edge = TO_EDGE_CONN(conn);
+
+ if (edge_uses_flow_control(edge)) {
+ ret = true;
+ }
+ }
+
+ return ret;
+}
+
diff --git a/src/core/or/congestion_control_flow.h b/src/core/or/congestion_control_flow.h
new file mode 100644
index 0000000000..5c735cce23
--- /dev/null
+++ b/src/core/or/congestion_control_flow.h
@@ -0,0 +1,54 @@
+/* Copyright (c) 2019-2021, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file congestion_control_flow.h
+ * \brief APIs for stream flow control on congestion controlled circuits.
+ **/
+
+#ifndef TOR_CONGESTION_CONTROL_FLOW_H
+#define TOR_CONGESTION_CONTROL_FLOW_H
+
+#include "core/or/crypt_path_st.h"
+#include "core/or/circuit_st.h"
+#include "core/or/edge_connection_st.h"
+
+void flow_control_new_consensus_params(const struct networkstatus_t *);
+
+bool circuit_process_stream_xoff(edge_connection_t *conn,
+ const crypt_path_t *layer_hint,
+ const cell_t *cell);
+bool circuit_process_stream_xon(edge_connection_t *conn,
+ const crypt_path_t *layer_hint,
+ const cell_t *cell);
+
+int flow_control_decide_xoff(edge_connection_t *stream);
+void flow_control_decide_xon(edge_connection_t *stream, size_t n_written);
+
+void flow_control_note_sent_data(edge_connection_t *stream, size_t len);
+
+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;
+extern double cc_stats_flow_xoff_outbuf_ma;
+extern double cc_stats_flow_xon_outbuf_ma;
+
+/* Private section starts. */
+#ifdef TOR_CONGESTION_CONTROL_FLOW_PRIVATE
+
+/*
+ * Unit tests declaractions.
+ */
+#ifdef TOR_UNIT_TESTS
+
+#endif /* defined(TOR_UNIT_TESTS) */
+
+#endif /* defined(TOR_CONGESTION_CONTROL_FLOW_PRIVATE) */
+
+#endif /* !defined(TOR_CONGESTION_CONTROL_FLOW_H) */
diff --git a/src/core/or/congestion_control_nola.c b/src/core/or/congestion_control_nola.c
new file mode 100644
index 0000000000..d8ad69a78c
--- /dev/null
+++ b/src/core/or/congestion_control_nola.c
@@ -0,0 +1,139 @@
+/* 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
new file mode 100644
index 0000000000..9c7d6e0635
--- /dev/null
+++ b/src/core/or/congestion_control_nola.h
@@ -0,0 +1,33 @@
+/* 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
new file mode 100644
index 0000000000..0cc4e43938
--- /dev/null
+++ b/src/core/or/congestion_control_st.h
@@ -0,0 +1,276 @@
+/* Copyright (c) 2019-2021, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file congestion_control_st.h
+ * \brief Structure definitions for congestion control.
+ **/
+
+#ifndef CONGESTION_CONTROL_ST_H
+#define CONGESTION_CONTROL_ST_H
+
+#include "core/or/crypt_path_st.h"
+#include "core/or/circuit_st.h"
+
+/** Signifies which sendme algorithm to use */
+typedef enum {
+ /** OG Tor fixed-sized circ and stream windows. It sucks, but it is important
+ * to make sure that the new algs can compete with the old garbage. */
+ CC_ALG_SENDME = 0,
+
+ /**
+ * Prop#324 TOR_WESTWOOD - Deliberately aggressive. Westwood may not even
+ * converge to fairness in some cases because max RTT will also increase
+ * on congestion, which boosts the Westwood RTT congestion threshold. So it
+ * can cause runaway queue bloat, which may or may not lead to a robot
+ * uprising... Ok that's Westworld, not Westwood. Still, we need to test
+ * Vegas and NOLA against something more aggressive to ensure they do not
+ * starve in the presence of cheaters. We also need to make sure cheaters
+ * trigger the oomkiller in those cases.
+ */
+ CC_ALG_WESTWOOD = 1,
+
+ /**
+ * Prop#324 TOR_VEGAS - TCP Vegas-style BDP tracker. Because Vegas backs off
+ * whenever it detects queue delay, it can be beaten out by more aggressive
+ * algs. However, in live network testing, it seems to do just fine against
+ * current SENDMEs. It outperforms Westwood and does not stall. */
+ CC_ALG_VEGAS = 2,
+
+ /**
+ * 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. */
+ CC_ALG_NOLA = 3,
+} cc_alg_t;
+
+/* Total number of CC algs in cc_alg_t enum */
+#define NUM_CC_ALGS (CC_ALG_NOLA+1)
+
+/** Signifies how we estimate circuit BDP */
+typedef enum {
+ /* CWND-based BDP will respond to changes in RTT only, and is relative
+ * to cwnd growth. So in slow-start, this will under-estimate BDP */
+ BDP_ALG_CWND_RTT = 0,
+
+ /* Sendme-based BDP will quickly measure BDP in less than
+ * a cwnd worth of data when in use. So it should be good for slow-start.
+ * But if the link goes idle, it will be vastly lower than true BDP. Thus,
+ * this estimate gets reset when the cwnd is not fully utilized. */
+ BDP_ALG_SENDME_RATE = 1,
+
+ /* Inflight BDP is similar to the cwnd estimator, except it uses
+ * packets inflight minus local circuit queues instead of current cwnd.
+ * Because it is strictly less than or equal to the cwnd, it will cause
+ * the cwnd to drift downward. It is only used if the local OR connection
+ * is blocked. */
+ BDP_ALG_INFLIGHT_RTT = 2,
+
+ /* The Piecewise BDP estimator uses the CWND estimator before there
+ * are sufficient SENDMEs to calculate the SENDME estimator. At that
+ * point, it uses the SENDME estimator, unless the local OR connection
+ * becomes blocked. In that case, it switches to the inflight estimator. */
+ BDP_ALG_PIECEWISE = 3,
+
+} bdp_alg_t;
+
+/** 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 */
+ uint32_t ss_cwnd_cap;
+ /** The maximum slow-start cwnd */
+ uint32_t ss_cwnd_max;
+ /** The queue use allowed before we exit slow start */
+ uint16_t gamma;
+ /** The queue use below which we increment cwnd */
+ uint16_t alpha;
+ /** The queue use above which we decrement cwnd */
+ uint16_t beta;
+ /** The queue use at which we cap cwnd in steady state */
+ uint16_t delta;
+ /** Weighted average (percent) between cwnd estimator and
+ * piecewise estimator. */
+ 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 {
+ /**
+ * Smartlist of uint64_t monotime usec timestamps of when we sent a data
+ * cell that is pending a sendme. FIFO queue that is managed similar to
+ * 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];
+
+ /** Congestion window */
+ uint64_t cwnd;
+
+ /** Number of cells in-flight (sent but awaiting SENDME ack). */
+ uint64_t inflight;
+
+ /**
+ * For steady-state: the number of sendme acks until we will acknowledge
+ * a congestion event again. It starts out as the number of sendme acks
+ * in a congestion window and is decremented each ack. When this reaches
+ * 0, it means we should examine our congestion algorithm conditions.
+ * In this way, we only react to one congestion event per congestion window.
+ *
+ * It is also reset to 0 immediately whenever the circuit's orconn is
+ * blocked, and when a previously blocked orconn is unblocked.
+ */
+ uint16_t next_cc_event;
+
+ /** Counts down until we process a cwnd worth of SENDME acks.
+ * Used to track full cwnd status. */
+ uint16_t next_cwnd_event;
+
+ /** Are we in slow start? */
+ bool in_slow_start;
+
+ /** Has the cwnd become full since last cwnd update? */
+ bool cwnd_full;
+
+ /** Is the local channel blocked on us? That's a congestion signal */
+ bool blocked_chan;
+
+ /* The following parameters are cached from consensus values upon
+ * circuit setup. */
+
+ /** Percent of cwnd to increment by during slow start */
+ uint16_t cwnd_inc_pct_ss;
+
+ /** Number of cells to increment cwnd by during steady state */
+ uint16_t cwnd_inc;
+
+ /** Minimum congestion window (must be at least sendme_inc) */
+ uint16_t cwnd_min;
+
+ /**
+ * Number of times per congestion window to update based on congestion
+ * signals */
+ uint8_t cwnd_inc_rate;
+
+ /**
+ * Number of cells to ack with every sendme. Taken from consensus parameter
+ * and negotiation during circuit setup. */
+ uint8_t sendme_inc;
+
+ /** Which congestion control algorithm to use. Taken from
+ * consensus parameter and negotiation during circuit setup. */
+ cc_alg_t cc_alg;
+
+ /** Which algorithm to estimate circuit bandwidth with. Taken from
+ * 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;
+ };
+};
+
+/**
+ * Returns the number of sendme acks we will receive before we update cwnd.
+ *
+ * Congestion control literature recommends only one update of cwnd per
+ * cwnd worth of acks. However, we can also tune this to be more frequent
+ * by increasing the 'cc_cwnd_inc_rate' consensus parameter. This tuning
+ * only applies after slow start.
+ *
+ * If this returns 0 due to high cwnd_inc_rate, the calling code will
+ * update every sendme ack.
+ */
+static inline uint64_t CWND_UPDATE_RATE(const struct congestion_control_t *cc)
+{
+ /* We add cwnd_inc_rate*sendme_inc/2 to round to nearest integer number
+ * of acks */
+
+ if (cc->in_slow_start) {
+ return 1;
+ } else {
+ return ((cc->cwnd + cc->cwnd_inc_rate*cc->sendme_inc/2)
+ / (cc->cwnd_inc_rate*cc->sendme_inc));
+ }
+}
+
+/**
+ * Gives us the number of SENDMEs in a CWND, rounded.
+ */
+static inline uint64_t SENDME_PER_CWND(const struct congestion_control_t *cc)
+{
+ /* We add cwnd_inc_rate*sendme_inc/2 to round to nearest integer number
+ * of acks */
+ return ((cc->cwnd + cc->sendme_inc/2)/cc->sendme_inc);
+}
+
+/**
+ * Returns the amount to increment the congestion window each update,
+ * during slow start.
+ *
+ * Congestion control literature recommends either doubling the cwnd
+ * every cwnd during slow start, or some similar exponential growth
+ * (such as 50% more every cwnd, for Vegas).
+ *
+ * This is controlled by a consensus parameter 'cwnd_inc_pct_ss', which
+ * allows us to specify the percent of the current consensus window
+ * to update by.
+ */
+static inline uint64_t CWND_INC_SS(const struct congestion_control_t *cc)
+{
+ return (cc->cwnd_inc_pct_ss*cc->cwnd/100);
+}
+
+/**
+ * Returns the amount to increment (and for Vegas, also decrement) the
+ * congestion window by, every update period.
+ *
+ * This is controlled by the cc_cwnd_inc consensus parameter.
+ */
+#define CWND_INC(cc) ((cc)->cwnd_inc)
+
+#endif /* !defined(CONGESTION_CONTROL_ST_H) */
diff --git a/src/core/or/congestion_control_vegas.c b/src/core/or/congestion_control_vegas.c
new file mode 100644
index 0000000000..b82c685d51
--- /dev/null
+++ b/src/core/or/congestion_control_vegas.c
@@ -0,0 +1,619 @@
+/* Copyright (c) 2019-2021, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file congestion_control_vegas.c
+ * \brief Code that implements the TOR_VEGAS congestion control algorithm
+ * from Proposal #324.
+ */
+
+#define TOR_CONGESTION_CONTROL_VEGAS_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_vegas.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"
+#include "lib/math/stats.h"
+
+#define OUTBUF_CELLS (2*TLS_RECORD_MAX_CELLS)
+
+#define SS_CWND_MAX_DFLT (5000)
+
+/* sbws circs are two hops, so params are based on 2 outbufs of cells */
+#define VEGAS_ALPHA_SBWS_DFLT (2*OUTBUF_CELLS-TLS_RECORD_MAX_CELLS)
+#define VEGAS_BETA_SBWS_DFLT (2*OUTBUF_CELLS+TLS_RECORD_MAX_CELLS)
+#define VEGAS_GAMMA_SBWS_DFLT (2*OUTBUF_CELLS)
+#define VEGAS_DELTA_SBWS_DFLT (4*OUTBUF_CELLS)
+#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_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)
+
+/* 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)
+
+/**
+ * Number of sendme_incs between cwnd and inflight for cwnd to be
+ * still considered full */
+#define VEGAS_CWND_FULL_GAP_DFLT (1)
+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)
+static int cc_vegas_cwnd_full_minpct = VEGAS_CWND_FULL_MINPCT_DFLT;
+
+/**
+ * Param to decide when to reset the cwnd.
+ */
+#define VEGAS_CWND_FULL_PER_CWND_DFLT (1)
+static int cc_cwnd_full_per_cwnd = VEGAS_CWND_FULL_PER_CWND_DFLT;
+
+/** Moving average of the cc->cwnd from each circuit exiting slowstart. */
+double cc_stats_vegas_exit_ss_cwnd_ma = 0;
+double cc_stats_vegas_exit_ss_bdp_ma = 0;
+double cc_stats_vegas_exit_ss_inc_ma = 0;
+double cc_stats_vegas_gamma_drop_ma = 0;
+double cc_stats_vegas_delta_drop_ma = 0;
+double cc_stats_vegas_ss_csig_blocked_ma = 0;
+double cc_stats_vegas_csig_blocked_ma = 0;
+double cc_stats_vegas_csig_alpha_ma = 0;
+double cc_stats_vegas_csig_beta_ma = 0;
+double cc_stats_vegas_csig_delta_ma = 0;
+
+double cc_stats_vegas_ss_queue_ma = 0;
+double cc_stats_vegas_queue_ma = 0;
+double cc_stats_vegas_bdp_ma = 0;
+
+/** Stats on how many times we reached "delta" param. */
+uint64_t cc_stats_vegas_above_delta = 0;
+/** Stats on how many times we reached "ss_cwnd_max" param. */
+uint64_t cc_stats_vegas_above_ss_cwnd_max = 0;
+uint64_t cc_stats_vegas_below_ss_inc_floor = 0;
+uint64_t cc_stats_vegas_circ_exited_ss = 0;
+
+/**
+ * The original TCP Vegas congestion window BDP estimator.
+ */
+static inline uint64_t
+vegas_bdp(const congestion_control_t *cc)
+{
+ return cc->bdp[BDP_ALG_CWND_RTT];
+}
+
+/**
+ * Cache Vegas consensus parameters.
+ */
+void
+congestion_control_vegas_set_params(congestion_control_t *cc,
+ cc_path_t path)
+{
+ tor_assert(cc->cc_alg == CC_ALG_VEGAS);
+ const char *alpha_str = NULL, *beta_str = NULL, *gamma_str = NULL;
+ const char *delta_str = NULL, *sscap_str = NULL;
+ int alpha, beta, gamma, delta, ss_cwnd_cap;
+
+ switch (path) {
+ case CC_PATH_SBWS:
+ alpha_str = "cc_vegas_alpha_sbws";
+ beta_str = "cc_vegas_beta_sbws";
+ gamma_str = "cc_vegas_gamma_sbws";
+ delta_str = "cc_vegas_delta_sbws";
+ sscap_str = "cc_sscap_sbws";
+ alpha = VEGAS_ALPHA_SBWS_DFLT;
+ beta = VEGAS_BETA_SBWS_DFLT;
+ gamma = VEGAS_GAMMA_SBWS_DFLT;
+ delta = VEGAS_DELTA_SBWS_DFLT;
+ ss_cwnd_cap = VEGAS_SSCAP_SBWS_DFLT;
+ break;
+ case CC_PATH_EXIT:
+ case CC_PATH_ONION_SOS:
+ alpha_str = "cc_vegas_alpha_exit";
+ beta_str = "cc_vegas_beta_exit";
+ gamma_str = "cc_vegas_gamma_exit";
+ delta_str = "cc_vegas_delta_exit";
+ sscap_str = "cc_sscap_exit";
+ alpha = VEGAS_ALPHA_EXIT_DFLT;
+ beta = VEGAS_BETA_EXIT_DFLT;
+ gamma = VEGAS_GAMMA_EXIT_DFLT;
+ delta = VEGAS_DELTA_EXIT_DFLT;
+ ss_cwnd_cap = VEGAS_SSCAP_EXIT_DFLT;
+ break;
+ case CC_PATH_ONION:
+ case CC_PATH_ONION_VG:
+ alpha_str = "cc_vegas_alpha_onion";
+ beta_str = "cc_vegas_beta_onion";
+ gamma_str = "cc_vegas_gamma_onion";
+ delta_str = "cc_vegas_delta_onion";
+ sscap_str = "cc_sscap_onion";
+ alpha = VEGAS_ALPHA_ONION_DFLT;
+ beta = VEGAS_BETA_ONION_DFLT;
+ gamma = VEGAS_GAMMA_ONION_DFLT;
+ delta = VEGAS_DELTA_ONION_DFLT;
+ ss_cwnd_cap = VEGAS_SSCAP_ONION_DFLT;
+ break;
+ default:
+ tor_assert(0);
+ break;
+ }
+
+ cc->vegas_params.ss_cwnd_cap =
+ networkstatus_get_param(NULL, sscap_str,
+ ss_cwnd_cap,
+ 100,
+ INT32_MAX);
+
+ cc->vegas_params.ss_cwnd_max =
+ networkstatus_get_param(NULL, "cc_ss_max",
+ SS_CWND_MAX_DFLT,
+ 500,
+ INT32_MAX);
+
+ cc->vegas_params.alpha =
+ networkstatus_get_param(NULL, alpha_str,
+ alpha,
+ 0,
+ 1000);
+
+ cc->vegas_params.beta =
+ networkstatus_get_param(NULL, beta_str,
+ beta,
+ 0,
+ 1000);
+
+ cc->vegas_params.gamma =
+ networkstatus_get_param(NULL, gamma_str,
+ gamma,
+ 0,
+ 1000);
+
+ cc->vegas_params.delta =
+ networkstatus_get_param(NULL, delta_str,
+ delta,
+ 0,
+ INT32_MAX);
+
+ cc_vegas_cwnd_full_minpct =
+ networkstatus_get_param(NULL, "cc_cwnd_full_minpct",
+ VEGAS_CWND_FULL_MINPCT_DFLT,
+ 0,
+ 100);
+
+ cc_vegas_cwnd_full_gap =
+ networkstatus_get_param(NULL, "cc_cwnd_full_gap",
+ VEGAS_CWND_FULL_GAP_DFLT,
+ 0,
+ INT16_MAX);
+
+ cc_cwnd_full_per_cwnd =
+ networkstatus_get_param(NULL, "cc_cwnd_full_per_cwnd",
+ VEGAS_CWND_FULL_PER_CWND_DFLT,
+ 0,
+ 1);
+}
+
+/**
+ * Common log function for tracking all vegas state.
+ */
+static void
+congestion_control_vegas_log(const circuit_t *circ,
+ const congestion_control_t *cc)
+{
+ uint64_t queue_use = cc->cwnd - vegas_bdp(cc);
+
+ if (CIRCUIT_IS_ORIGIN(circ) &&
+ circ->purpose == CIRCUIT_PURPOSE_S_REND_JOINED) {
+ log_info(LD_CIRC,
+ "CC: TOR_VEGAS Onion Circuit %d "
+ "RTT: %"PRIu64", %"PRIu64", %"PRIu64", "
+ "CWND: %"PRIu64", "
+ "INFL: %"PRIu64", "
+ "VBDP: %"PRIu64", "
+ "QUSE: %"PRIu64", "
+ "BWE: %"PRIu64", "
+ "SS: %d",
+ CONST_TO_ORIGIN_CIRCUIT(circ)->global_identifier,
+ cc->min_rtt_usec/1000,
+ cc->ewma_rtt_usec/1000,
+ cc->max_rtt_usec/1000,
+ cc->cwnd,
+ cc->inflight,
+ vegas_bdp(cc),
+ queue_use,
+ cc->cwnd*CELL_MAX_NETWORK_SIZE*1000/
+ MAX(cc->min_rtt_usec,cc->ewma_rtt_usec),
+ cc->in_slow_start
+ );
+ } else {
+ log_info(LD_CIRC,
+ "CC: TOR_VEGAS "
+ "RTT: %"PRIu64", %"PRIu64", %"PRIu64", "
+ "CWND: %"PRIu64", "
+ "INFL: %"PRIu64", "
+ "VBDP: %"PRIu64", "
+ "QUSE: %"PRIu64", "
+ "BWE: %"PRIu64", "
+ "SS: %d",
+ cc->min_rtt_usec/1000,
+ cc->ewma_rtt_usec/1000,
+ cc->max_rtt_usec/1000,
+ cc->cwnd,
+ cc->inflight,
+ vegas_bdp(cc),
+ queue_use,
+ cc->cwnd*CELL_MAX_NETWORK_SIZE*1000/
+ MAX(cc->min_rtt_usec,cc->ewma_rtt_usec),
+ cc->in_slow_start
+ );
+ }
+}
+
+/**
+ * Implements RFC3742: Limited Slow Start.
+ * https://datatracker.ietf.org/doc/html/rfc3742#section-2
+ */
+static inline uint64_t
+rfc3742_ss_inc(const congestion_control_t *cc)
+{
+ if (cc->cwnd <= cc->vegas_params.ss_cwnd_cap) {
+ /* If less than the cap, round and always grow by at least 1 sendme_inc. */
+ return ((uint64_t)cc->cwnd_inc_pct_ss*cc->sendme_inc + 50)/100;
+ } else {
+ // K = int(cwnd/(0.5 max_ssthresh));
+ // => K = 2*cwnd/max_ssthresh
+ // cwnd += int(MSS/K);
+ // => cwnd += MSS*max_ssthresh/(2*cwnd)
+ // Return at least 1 for inc.
+ return MAX(
+ ((uint64_t)cc->sendme_inc*cc->vegas_params.ss_cwnd_cap + cc->cwnd)/
+ (2*cc->cwnd),
+ 1);
+ }
+}
+
+/**
+ * Exit Vegas slow start.
+ *
+ * This function sets our slow-start state to 0, and emits logs
+ * and control port information signifying end of slow start.
+ * It also schedules the next CWND update for steady-state.
+ */
+static void
+congestion_control_vegas_exit_slow_start(const circuit_t *circ,
+ congestion_control_t *cc)
+{
+ congestion_control_vegas_log(circ, cc);
+ cc->in_slow_start = 0;
+ congestion_control_vegas_log(circ, cc);
+
+ /* Update metricsport metrics */
+ cc_stats_vegas_exit_ss_cwnd_ma =
+ stats_update_running_avg(cc_stats_vegas_exit_ss_cwnd_ma,
+ cc->cwnd);
+ cc_stats_vegas_exit_ss_bdp_ma =
+ stats_update_running_avg(cc_stats_vegas_exit_ss_bdp_ma,
+ vegas_bdp(cc));
+ cc_stats_vegas_exit_ss_inc_ma =
+ stats_update_running_avg(cc_stats_vegas_exit_ss_inc_ma,
+ rfc3742_ss_inc(cc));
+ cc_stats_vegas_circ_exited_ss++;
+
+ /* 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));
+ }
+}
+
+/**
+ * Returns true if the congestion window is considered full.
+ *
+ * We allow a number of sendme_incs gap in case buffering issues
+ * with edge conns cause the window to occasionally be not quite
+ * full. This can happen if several SENDMEs arrive before we
+ * return to the eventloop to fill the inbuf on edge connections.
+ */
+static inline bool
+cwnd_became_full(const congestion_control_t *cc)
+{
+ if (cc->inflight + cc_vegas_cwnd_full_gap*cc->sendme_inc >= cc->cwnd) {
+ return true;
+ } else {
+ return false;
+ }
+}
+
+/**
+ * Returns true if the congestion window is no longer full.
+ *
+ * This functions as a low watermark, below which we stop
+ * allowing cwnd increments.
+ */
+static inline bool
+cwnd_became_nonfull(const congestion_control_t *cc)
+{
+ /* Use multiply form to avoid division */
+ if (100*cc->inflight < cc_vegas_cwnd_full_minpct * cc->cwnd) {
+ return true;
+ } else {
+ return false;
+ }
+}
+
+/**
+ * Decide if it is time to reset the cwnd_full status.
+ *
+ * If cc_cwnd_full_per_cwnd=1, we reset cwnd_full once per congestion
+ * window, ie:
+ * next_cwnd_event == SENDME_PER_CWND(cc)
+ *
+ * Otherwise, we reset cwnd_full whenever there is an update of
+ * the congestion window, ie:
+ * next_cc_event == CWND_UPDATE_RATE(cc)
+ */
+static inline bool
+cwnd_full_reset(const congestion_control_t *cc)
+{
+ if (cc_cwnd_full_per_cwnd) {
+ return (cc->next_cwnd_event == SENDME_PER_CWND(cc));
+ } else {
+ return (cc->next_cc_event == CWND_UPDATE_RATE(cc));
+ }
+}
+
+/**
+ * Process a SENDME and update the congestion window according to the
+ * rules specified in TOR_VEGAS of Proposal #324.
+ *
+ * Essentially, this algorithm attempts to measure queue lengths on
+ * the circuit by subtracting the bandwidth-delay-product estimate
+ * from the current congestion window.
+ *
+ * If the congestion window is larger than the bandwidth-delay-product,
+ * then data is assumed to be queuing. We reduce the congestion window
+ * in that case.
+ *
+ * If the congestion window is smaller than the bandwidth-delay-product,
+ * then there is spare bandwidth capacity on the circuit. We increase the
+ * congestion window in that case.
+ *
+ * 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_vegas_process_sendme(congestion_control_t *cc,
+ const circuit_t *circ,
+ const crypt_path_t *layer_hint)
+{
+ uint64_t queue_use;
+
+ tor_assert(cc && cc->cc_alg == CC_ALG_VEGAS);
+ tor_assert(circ);
+
+ /* Update ack counter until next congestion signal event is allowed */
+ if (cc->next_cc_event)
+ cc->next_cc_event--;
+
+ /* Update ack counter until a full cwnd is processed */
+ if (cc->next_cwnd_event)
+ 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)) {
+ cc->inflight = cc->inflight - cc->sendme_inc;
+ return 0;
+ }
+
+ /* The queue use is the amount in which our cwnd is above BDP;
+ * if it is below, then 0 queue use. */
+ if (vegas_bdp(cc) > cc->cwnd)
+ queue_use = 0; // This should not happen anymore..
+ else
+ queue_use = cc->cwnd - vegas_bdp(cc);
+
+ /* Update the full state */
+ if (cwnd_became_full(cc))
+ cc->cwnd_full = 1;
+ else if (cwnd_became_nonfull(cc))
+ cc->cwnd_full = 0;
+
+ if (cc->in_slow_start) {
+ if (queue_use < cc->vegas_params.gamma && !cc->blocked_chan) {
+ /* If the congestion window is not fully in use, skip any
+ * increment of cwnd in slow start */
+ if (cc->cwnd_full) {
+ /* Get the "Limited Slow Start" increment */
+ uint64_t inc = rfc3742_ss_inc(cc);
+ cc->cwnd += inc;
+
+ // Check if inc is less than what we would do in steady-state
+ // avoidance. Note that this is likely never to happen
+ // in practice, but we keep this block and the metrics to make
+ // sure.
+ if (inc*SENDME_PER_CWND(cc) <= CWND_INC(cc)*cc->cwnd_inc_rate) {
+ congestion_control_vegas_exit_slow_start(circ, cc);
+
+ cc_stats_vegas_below_ss_inc_floor++;
+
+ /* We exited slow start without being blocked */
+ cc_stats_vegas_ss_csig_blocked_ma =
+ stats_update_running_avg(cc_stats_vegas_ss_csig_blocked_ma,
+ 0);
+ }
+ }
+ } else {
+ uint64_t old_cwnd = cc->cwnd;
+
+ /* Congestion signal: Set cwnd to gamma threshhold */
+ cc->cwnd = vegas_bdp(cc) + cc->vegas_params.gamma;
+
+ /* Compute the percentage we experience a blocked csig vs RTT sig */
+ if (cc->blocked_chan) {
+ cc_stats_vegas_ss_csig_blocked_ma =
+ stats_update_running_avg(cc_stats_vegas_ss_csig_blocked_ma,
+ 100);
+ } else {
+ uint64_t cwnd_diff = (old_cwnd > cc->cwnd ? old_cwnd - cc->cwnd : 0);
+
+ cc_stats_vegas_ss_csig_blocked_ma =
+ stats_update_running_avg(cc_stats_vegas_ss_csig_blocked_ma,
+ 0);
+
+ /* Account the amount we reduced the cwnd by for the gamma cutoff */
+ cc_stats_vegas_gamma_drop_ma =
+ stats_update_running_avg(cc_stats_vegas_gamma_drop_ma,
+ cwnd_diff);
+ }
+
+ congestion_control_vegas_exit_slow_start(circ, cc);
+ }
+
+ if (cc->cwnd >= cc->vegas_params.ss_cwnd_max) {
+ cc->cwnd = cc->vegas_params.ss_cwnd_max;
+ congestion_control_vegas_exit_slow_start(circ, cc);
+ cc_stats_vegas_above_ss_cwnd_max++;
+ }
+
+ cc_stats_vegas_ss_queue_ma =
+ stats_update_running_avg(cc_stats_vegas_ss_queue_ma,
+ queue_use);
+ /* After slow start, We only update once per window */
+ } else if (cc->next_cc_event == 0) {
+ if (queue_use > cc->vegas_params.delta) {
+ uint64_t old_cwnd = cc->cwnd;
+ uint64_t cwnd_diff;
+
+ /* If we are above the delta threshhold, drop cwnd down to the
+ * delta threshhold. */
+ cc->cwnd = vegas_bdp(cc) + cc->vegas_params.delta - CWND_INC(cc);
+
+ /* Account the amount we reduced the cwnd by for the gamma cutoff */
+ cwnd_diff = (old_cwnd > cc->cwnd ? old_cwnd - cc->cwnd : 0);
+ cc_stats_vegas_delta_drop_ma =
+ stats_update_running_avg(cc_stats_vegas_delta_drop_ma,
+ cwnd_diff);
+
+ cc_stats_vegas_above_delta++;
+
+ /* Percentage metrics: Add 100% delta, 0 for other two */
+ cc_stats_vegas_csig_alpha_ma =
+ stats_update_running_avg(cc_stats_vegas_csig_alpha_ma,
+ 0);
+ cc_stats_vegas_csig_beta_ma =
+ stats_update_running_avg(cc_stats_vegas_csig_beta_ma,
+ 0);
+ cc_stats_vegas_csig_delta_ma =
+ stats_update_running_avg(cc_stats_vegas_csig_delta_ma,
+ 100);
+ } else if (queue_use > cc->vegas_params.beta || cc->blocked_chan) {
+ cc->cwnd -= CWND_INC(cc);
+
+ /* Compute the percentage we experience a blocked csig vs RTT sig */
+ if (cc->blocked_chan) {
+ cc_stats_vegas_csig_blocked_ma =
+ stats_update_running_avg(cc_stats_vegas_csig_blocked_ma,
+ 100);
+ } else {
+ cc_stats_vegas_csig_blocked_ma =
+ stats_update_running_avg(cc_stats_vegas_csig_blocked_ma,
+ 0);
+ }
+
+ /* Percentage counters: Add 100% beta, 0 for other two */
+ cc_stats_vegas_csig_alpha_ma =
+ stats_update_running_avg(cc_stats_vegas_csig_alpha_ma,
+ 0);
+ cc_stats_vegas_csig_beta_ma =
+ stats_update_running_avg(cc_stats_vegas_csig_beta_ma,
+ 100);
+ cc_stats_vegas_csig_delta_ma =
+ stats_update_running_avg(cc_stats_vegas_csig_delta_ma,
+ 0);
+ } else if (cc->cwnd_full &&
+ queue_use < cc->vegas_params.alpha) {
+ cc->cwnd += CWND_INC(cc);
+
+ /* Percentage counters: Add 100% alpha, 0 for other two */
+ cc_stats_vegas_csig_alpha_ma =
+ stats_update_running_avg(cc_stats_vegas_csig_alpha_ma,
+ 100);
+ cc_stats_vegas_csig_beta_ma =
+ stats_update_running_avg(cc_stats_vegas_csig_beta_ma,
+ 0);
+ cc_stats_vegas_csig_delta_ma =
+ stats_update_running_avg(cc_stats_vegas_csig_delta_ma,
+ 0);
+ } else {
+ /* Percentage counters: No signal this round. Add 0% to all */
+ cc_stats_vegas_csig_alpha_ma =
+ stats_update_running_avg(cc_stats_vegas_csig_alpha_ma,
+ 0);
+ cc_stats_vegas_csig_beta_ma =
+ stats_update_running_avg(cc_stats_vegas_csig_beta_ma,
+ 0);
+ cc_stats_vegas_csig_delta_ma =
+ stats_update_running_avg(cc_stats_vegas_csig_delta_ma,
+ 0);
+ }
+
+ /* cwnd can never fall below 1 increment */
+ cc->cwnd = MAX(cc->cwnd, cc->cwnd_min);
+
+ congestion_control_vegas_log(circ, cc);
+
+ /* Update metrics */
+ cc_stats_vegas_queue_ma =
+ stats_update_running_avg(cc_stats_vegas_queue_ma,
+ queue_use);
+ cc_stats_vegas_bdp_ma =
+ stats_update_running_avg(cc_stats_vegas_bdp_ma,
+ vegas_bdp(cc));
+
+ /* Log if we're above the ss_cap */
+ if (cc->cwnd >= cc->vegas_params.ss_cwnd_max) {
+ log_info(LD_CIRC,
+ "CC: TOR_VEGAS above ss_max in steady state for circ %d: %"PRIu64,
+ circ->purpose, cc->cwnd);
+ }
+ }
+
+ /* Reset event counters */
+ if (cc->next_cwnd_event == 0) {
+ cc->next_cwnd_event = SENDME_PER_CWND(cc);
+ }
+ if (cc->next_cc_event == 0) {
+ cc->next_cc_event = CWND_UPDATE_RATE(cc);
+ }
+
+ /* Decide if enough time has passed to reset the cwnd utilization */
+ if (cwnd_full_reset(cc))
+ cc->cwnd_full = 0;
+
+ /* Update inflight with ack */
+ cc->inflight = cc->inflight - cc->sendme_inc;
+
+ return 0;
+}
diff --git a/src/core/or/congestion_control_vegas.h b/src/core/or/congestion_control_vegas.h
new file mode 100644
index 0000000000..84070664c8
--- /dev/null
+++ b/src/core/or/congestion_control_vegas.h
@@ -0,0 +1,55 @@
+/* Copyright (c) 2019-2021, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file congestion_control_vegas.h
+ * \brief Private-ish APIs for the TOR_VEGAS congestion control algorithm
+ **/
+
+#ifndef TOR_CONGESTION_CONTROL_VEGAS_H
+#define TOR_CONGESTION_CONTROL_VEGAS_H
+
+#include "core/or/crypt_path_st.h"
+#include "core/or/circuit_st.h"
+
+extern double cc_stats_vegas_exit_ss_cwnd_ma;
+extern double cc_stats_vegas_exit_ss_bdp_ma;
+extern double cc_stats_vegas_exit_ss_inc_ma;
+extern double cc_stats_vegas_gamma_drop_ma;
+extern double cc_stats_vegas_delta_drop_ma;
+extern double cc_stats_vegas_ss_csig_blocked_ma;
+extern double cc_stats_vegas_csig_blocked_ma;
+extern uint64_t cc_stats_vegas_above_delta;
+extern uint64_t cc_stats_vegas_above_ss_cwnd_max;
+
+extern double cc_stats_vegas_csig_alpha_ma;
+extern double cc_stats_vegas_csig_beta_ma;
+extern double cc_stats_vegas_csig_delta_ma;
+
+extern double cc_stats_vegas_ss_queue_ma;
+extern double cc_stats_vegas_queue_ma;
+extern double cc_stats_vegas_bdp_ma;
+
+extern uint64_t cc_stats_vegas_below_ss_inc_floor;
+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);
+void congestion_control_vegas_set_params(struct congestion_control_t *cc,
+ cc_path_t path);
+
+/* Private section starts. */
+#ifdef TOR_CONGESTION_CONTROL_VEGAS_PRIVATE
+
+/*
+ * Unit tests declaractions.
+ */
+#ifdef TOR_UNIT_TESTS
+
+#endif /* defined(TOR_UNIT_TESTS) */
+
+#endif /* defined(TOR_CONGESTION_CONTROL_VEGAS_PRIVATE) */
+
+#endif /* !defined(TOR_CONGESTION_CONTROL_VEGAS_H) */
diff --git a/src/core/or/congestion_control_westwood.c b/src/core/or/congestion_control_westwood.c
new file mode 100644
index 0000000000..d28ddf3442
--- /dev/null
+++ b/src/core/or/congestion_control_westwood.c
@@ -0,0 +1,241 @@
+/* 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
new file mode 100644
index 0000000000..c6fd596df4
--- /dev/null
+++ b/src/core/or/congestion_control_westwood.h
@@ -0,0 +1,33 @@
+/* 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 504980c9fd..7dd0935b47 100644
--- a/src/core/or/connection_edge.c
+++ b/src/core/or/connection_edge.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -69,6 +69,8 @@
#include "core/or/circuituse.h"
#include "core/or/circuitpadding.h"
#include "core/or/connection_edge.h"
+#include "core/or/congestion_control_flow.h"
+#include "core/or/circuitstats.h"
#include "core/or/connection_or.h"
#include "core/or/extendinfo.h"
#include "core/or/policies.h"
@@ -96,9 +98,7 @@
#include "feature/relay/dns.h"
#include "feature/relay/router.h"
#include "feature/relay/routermode.h"
-#include "feature/rend/rendclient.h"
#include "feature/rend/rendcommon.h"
-#include "feature/rend/rendservice.h"
#include "feature/stats/predict_ports.h"
#include "feature/stats/rephist.h"
#include "lib/buf/buffers.h"
@@ -166,6 +166,7 @@ static int connection_ap_process_natd(entry_connection_t *conn);
static int connection_exit_connect_dir(edge_connection_t *exitconn);
static int consider_plaintext_ports(entry_connection_t *conn, uint16_t port);
static int connection_ap_supports_optimistic_data(const entry_connection_t *);
+static bool network_reentry_is_allowed(void);
/**
* Cast a `connection_t *` to an `edge_connection_t *`.
@@ -252,24 +253,9 @@ connection_mark_unattached_ap_,(entry_connection_t *conn, int endreason,
int line, const char *file))
{
connection_t *base_conn = ENTRY_TO_CONN(conn);
- edge_connection_t *edge_conn = ENTRY_TO_EDGE_CONN(conn);
tor_assert(base_conn->type == CONN_TYPE_AP);
ENTRY_TO_EDGE_CONN(conn)->edge_has_sent_end = 1; /* no circ yet */
- /* If this is a rendezvous stream and it is failing without ever
- * being attached to a circuit, assume that an attempt to connect to
- * the destination hidden service has just ended.
- *
- * XXXX This condition doesn't limit to only streams failing
- * without ever being attached. That sloppiness should be harmless,
- * but we should fix it someday anyway. */
- if ((edge_conn->on_circuit != NULL || edge_conn->edge_has_sent_end) &&
- connection_edge_is_rendezvous_stream(edge_conn)) {
- if (edge_conn->rend_data) {
- rend_client_note_connection_attempt_ended(edge_conn->rend_data);
- }
- }
-
if (base_conn->marked_for_close) {
/* This call will warn as appropriate. */
connection_mark_for_close_(base_conn, line, file);
@@ -646,20 +632,39 @@ connection_half_edge_add(const edge_connection_t *conn,
half_conn->stream_id = conn->stream_id;
- // How many sendme's should I expect?
- half_conn->sendmes_pending =
- (STREAMWINDOW_START-conn->package_window)/STREAMWINDOW_INCREMENT;
-
// Is there a connected cell pending?
half_conn->connected_pending = conn->base_.state ==
AP_CONN_STATE_CONNECT_WAIT;
- /* Data should only arrive if we're not waiting on a resolved cell.
- * It can arrive after waiting on connected, because of optimistic
- * data. */
- if (conn->base_.state != AP_CONN_STATE_RESOLVE_WAIT) {
- // How many more data cells can arrive on this id?
- half_conn->data_pending = conn->deliver_window;
+ if (edge_uses_flow_control(conn)) {
+ /* If the edge uses the new congestion control flow control, we must use
+ * time-based limits on half-edge activity. */
+ uint64_t timeout_usec = (uint64_t)(get_circuit_build_timeout_ms()*1000);
+ half_conn->used_ccontrol = 1;
+
+ /* If this is an onion service circuit, double the CBT as an approximate
+ * value for the other half of the circuit */
+ if (conn->hs_ident) {
+ timeout_usec *= 2;
+ }
+
+ /* The stream should stop seeing any use after the larger of the circuit
+ * RTT and the overall circuit build timeout */
+ half_conn->end_ack_expected_usec = MAX(timeout_usec,
+ edge_get_max_rtt(conn)) +
+ monotime_absolute_usec();
+ } else {
+ // How many sendme's should I expect?
+ half_conn->sendmes_pending =
+ (STREAMWINDOW_START-conn->package_window)/STREAMWINDOW_INCREMENT;
+
+ /* Data should only arrive if we're not waiting on a resolved cell.
+ * It can arrive after waiting on connected, because of optimistic
+ * data. */
+ if (conn->base_.state != AP_CONN_STATE_RESOLVE_WAIT) {
+ // How many more data cells can arrive on this id?
+ half_conn->data_pending = conn->deliver_window;
+ }
}
insert_at = smartlist_bsearch_idx(circ->half_streams, &half_conn->stream_id,
@@ -720,6 +725,12 @@ connection_half_edge_is_valid_data(const smartlist_t *half_conns,
if (!half)
return 0;
+ if (half->used_ccontrol) {
+ if (monotime_absolute_usec() > half->end_ack_expected_usec)
+ return 0;
+ return 1;
+ }
+
if (half->data_pending > 0) {
half->data_pending--;
return 1;
@@ -772,6 +783,10 @@ connection_half_edge_is_valid_sendme(const smartlist_t *half_conns,
if (!half)
return 0;
+ /* congestion control edges don't use sendmes */
+ if (half->used_ccontrol)
+ return 0;
+
if (half->sendmes_pending > 0) {
half->sendmes_pending--;
return 1;
@@ -1301,15 +1316,6 @@ connection_ap_rescan_and_attach_pending(void)
connection_ap_attach_pending(1);
}
-#ifdef DEBUGGING_17659
-#define UNMARK() do { \
- entry_conn->marked_pending_circ_line = 0; \
- entry_conn->marked_pending_circ_file = 0; \
- } while (0)
-#else /* !defined(DEBUGGING_17659) */
-#define UNMARK() do { } while (0)
-#endif /* defined(DEBUGGING_17659) */
-
/** Tell any AP streams that are listed as waiting for a new circuit to try
* again. If there is an available circuit for a stream, attach it. Otherwise,
* launch a new circuit.
@@ -1338,21 +1344,18 @@ connection_ap_attach_pending(int retry)
connection_t *conn = ENTRY_TO_CONN(entry_conn);
tor_assert(conn && entry_conn);
if (conn->marked_for_close) {
- UNMARK();
continue;
}
if (conn->magic != ENTRY_CONNECTION_MAGIC) {
log_warn(LD_BUG, "%p has impossible magic value %u.",
entry_conn, (unsigned)conn->magic);
- UNMARK();
continue;
}
if (conn->state != AP_CONN_STATE_CIRCUIT_WAIT) {
- log_warn(LD_BUG, "%p is no longer in circuit_wait. Its current state "
- "is %s. Why is it on pending_entry_connections?",
- entry_conn,
- conn_state_to_string(conn->type, conn->state));
- UNMARK();
+ /* The connection_ap_handshake_attach_circuit() call, for onion service,
+ * can lead to more than one connections in the "pending" list to change
+ * state and so it is OK to get here. Ignore it because this connection
+ * won't be in pending_entry_connections list after this point. */
continue;
}
@@ -1377,7 +1380,6 @@ connection_ap_attach_pending(int retry)
/* If we got here, then we either closed the connection, or
* we attached it. */
- UNMARK();
} SMARTLIST_FOREACH_END(entry_conn);
smartlist_free(pending);
@@ -1448,7 +1450,6 @@ connection_ap_mark_as_non_pending_circuit(entry_connection_t *entry_conn)
{
if (PREDICT_UNLIKELY(NULL == pending_entry_connections))
return;
- UNMARK();
smartlist_remove(pending_entry_connections, entry_conn);
}
@@ -1962,14 +1963,14 @@ connection_ap_handshake_rewrite(entry_connection_t *conn,
}
}
-/** We just received a SOCKS request in <b>conn</b> to an onion address of type
- * <b>addresstype</b>. Start connecting to the onion service. */
+/** We just received a SOCKS request in <b>conn</b> to a v3 onion. Start
+ * connecting to the onion service. */
static int
connection_ap_handle_onion(entry_connection_t *conn,
socks_request_t *socks,
- origin_circuit_t *circ,
- hostname_type_t addresstype)
+ origin_circuit_t *circ)
{
+ int retval;
time_t now = approx_time();
connection_t *base_conn = ENTRY_TO_CONN(conn);
@@ -2005,102 +2006,38 @@ connection_ap_handle_onion(entry_connection_t *conn,
return -1;
}
- /* Interface: Regardless of HS version after the block below we should have
- set onion_address, rend_cache_lookup_result, and descriptor_is_usable. */
- const char *onion_address = NULL;
- int rend_cache_lookup_result = -ENOENT;
int descriptor_is_usable = 0;
- if (addresstype == ONION_V2_HOSTNAME) { /* it's a v2 hidden service */
- rend_cache_entry_t *entry = NULL;
- /* Look up if we have client authorization configured for this hidden
- * service. If we do, associate it with the rend_data. */
- rend_service_authorization_t *client_auth =
- rend_client_lookup_service_authorization(socks->address);
-
- const uint8_t *cookie = NULL;
- rend_auth_type_t auth_type = REND_NO_AUTH;
- if (client_auth) {
- log_info(LD_REND, "Using previously configured client authorization "
- "for hidden service request.");
- auth_type = client_auth->auth_type;
- cookie = client_auth->descriptor_cookie;
- }
+ /* Create HS conn identifier with HS pubkey */
+ hs_ident_edge_conn_t *hs_conn_ident =
+ tor_malloc_zero(sizeof(hs_ident_edge_conn_t));
- /* Fill in the rend_data field so we can start doing a connection to
- * a hidden service. */
- rend_data_t *rend_data = ENTRY_TO_EDGE_CONN(conn)->rend_data =
- rend_data_client_create(socks->address, NULL, (char *) cookie,
- auth_type);
- if (rend_data == NULL) {
- return -1;
- }
- onion_address = rend_data_get_address(rend_data);
- log_info(LD_REND,"Got a hidden service request for ID '%s'",
- safe_str_client(onion_address));
-
- rend_cache_lookup_result = rend_cache_lookup_entry(onion_address,-1,
- &entry);
- if (!rend_cache_lookup_result && entry) {
- descriptor_is_usable = rend_client_any_intro_points_usable(entry);
- }
- } else { /* it's a v3 hidden service */
- tor_assert(addresstype == ONION_V3_HOSTNAME);
- const hs_descriptor_t *cached_desc = NULL;
- int retval;
- /* Create HS conn identifier with HS pubkey */
- hs_ident_edge_conn_t *hs_conn_ident =
- tor_malloc_zero(sizeof(hs_ident_edge_conn_t));
-
- retval = hs_parse_address(socks->address, &hs_conn_ident->identity_pk,
- NULL, NULL);
- if (retval < 0) {
- log_warn(LD_GENERAL, "failed to parse hs address");
- tor_free(hs_conn_ident);
- return -1;
- }
- ENTRY_TO_EDGE_CONN(conn)->hs_ident = hs_conn_ident;
-
- onion_address = socks->address;
-
- /* Check the v3 desc cache */
- cached_desc = hs_cache_lookup_as_client(&hs_conn_ident->identity_pk);
- if (cached_desc) {
- rend_cache_lookup_result = 0;
- descriptor_is_usable =
- hs_client_any_intro_points_usable(&hs_conn_ident->identity_pk,
- cached_desc);
- log_info(LD_GENERAL, "Found %s descriptor in cache for %s. %s.",
- (descriptor_is_usable) ? "usable" : "unusable",
- safe_str_client(onion_address),
- (descriptor_is_usable) ? "Not fetching." : "Refetching.");
- } else {
- rend_cache_lookup_result = -ENOENT;
- }
+ retval = hs_parse_address(socks->address, &hs_conn_ident->identity_pk,
+ NULL, NULL);
+ if (retval < 0) {
+ log_warn(LD_GENERAL, "failed to parse hs address");
+ tor_free(hs_conn_ident);
+ return -1;
}
+ ENTRY_TO_EDGE_CONN(conn)->hs_ident = hs_conn_ident;
- /* Lookup the given onion address. If invalid, stop right now.
- * Otherwise, we might have it in the cache or not. */
+ /* Check the v3 desc cache */
+ const hs_descriptor_t *cached_desc = NULL;
unsigned int refetch_desc = 0;
- if (rend_cache_lookup_result < 0) {
- switch (-rend_cache_lookup_result) {
- case EINVAL:
- /* We should already have rejected this address! */
- log_warn(LD_BUG,"Invalid service name '%s'",
- safe_str_client(onion_address));
- connection_mark_unattached_ap(conn, END_STREAM_REASON_TORPROTOCOL);
- return -1;
- case ENOENT:
- /* We didn't have this; we should look it up. */
- log_info(LD_REND, "No descriptor found in our cache for %s. Fetching.",
- safe_str_client(onion_address));
- refetch_desc = 1;
- break;
- default:
- log_warn(LD_BUG, "Unknown cache lookup error %d",
- rend_cache_lookup_result);
- return -1;
- }
+ cached_desc = hs_cache_lookup_as_client(&hs_conn_ident->identity_pk);
+ if (cached_desc) {
+ descriptor_is_usable =
+ hs_client_any_intro_points_usable(&hs_conn_ident->identity_pk,
+ cached_desc);
+ log_info(LD_GENERAL, "Found %s descriptor in cache for %s. %s.",
+ (descriptor_is_usable) ? "usable" : "unusable",
+ safe_str_client(socks->address),
+ (descriptor_is_usable) ? "Not fetching." : "Refetching.");
+ } else {
+ /* We couldn't find this descriptor; we should look it up. */
+ log_info(LD_REND, "No descriptor found in our cache for %s. Fetching.",
+ safe_str_client(socks->address));
+ refetch_desc = 1;
}
/* Help predict that we'll want to do hidden service circuits in the
@@ -2115,33 +2052,25 @@ connection_ap_handle_onion(entry_connection_t *conn,
edge_connection_t *edge_conn = ENTRY_TO_EDGE_CONN(conn);
connection_ap_mark_as_non_pending_circuit(conn);
base_conn->state = AP_CONN_STATE_RENDDESC_WAIT;
- if (addresstype == ONION_V2_HOSTNAME) {
- tor_assert(edge_conn->rend_data);
- rend_client_refetch_v2_renddesc(edge_conn->rend_data);
- /* Whatever the result of the refetch, we don't go further. */
+ tor_assert(edge_conn->hs_ident);
+ /* Attempt to fetch the hsv3 descriptor. Check the retval to see how it
+ * went and act accordingly. */
+ int ret = hs_client_refetch_hsdesc(&edge_conn->hs_ident->identity_pk);
+ switch (ret) {
+ case HS_CLIENT_FETCH_MISSING_INFO:
+ /* Keeping the connection in descriptor wait state is fine because
+ * once we get enough dirinfo or a new live consensus, the HS client
+ * subsystem is notified and every connection in that state will
+ * trigger a fetch for the service key. */
+ case HS_CLIENT_FETCH_LAUNCHED:
+ case HS_CLIENT_FETCH_PENDING:
+ case HS_CLIENT_FETCH_HAVE_DESC:
return 0;
- } else {
- tor_assert(addresstype == ONION_V3_HOSTNAME);
- tor_assert(edge_conn->hs_ident);
- /* Attempt to fetch the hsv3 descriptor. Check the retval to see how it
- * went and act accordingly. */
- int ret = hs_client_refetch_hsdesc(&edge_conn->hs_ident->identity_pk);
- switch (ret) {
- case HS_CLIENT_FETCH_MISSING_INFO:
- /* Keeping the connection in descriptor wait state is fine because
- * once we get enough dirinfo or a new live consensus, the HS client
- * subsystem is notified and every connection in that state will
- * trigger a fetch for the service key. */
- case HS_CLIENT_FETCH_LAUNCHED:
- case HS_CLIENT_FETCH_PENDING:
- case HS_CLIENT_FETCH_HAVE_DESC:
- return 0;
- case HS_CLIENT_FETCH_ERROR:
- case HS_CLIENT_FETCH_NO_HSDIRS:
- case HS_CLIENT_FETCH_NOT_ALLOWED:
- /* Can't proceed further and better close the SOCKS request. */
- return -1;
- }
+ case HS_CLIENT_FETCH_ERROR:
+ case HS_CLIENT_FETCH_NO_HSDIRS:
+ case HS_CLIENT_FETCH_NOT_ALLOWED:
+ /* Can't proceed further and better close the SOCKS request. */
+ return -1;
}
}
@@ -2216,7 +2145,7 @@ connection_ap_handshake_rewrite_and_attach(entry_connection_t *conn,
}
/* If this is a .exit hostname, strip off the .name.exit part, and
- * see whether we're willing to connect there, and and otherwise handle the
+ * see whether we're willing to connect there, and otherwise handle the
* .exit address.
*
* We'll set chosen_exit_name and/or close the connection as appropriate.
@@ -2320,7 +2249,7 @@ connection_ap_handshake_rewrite_and_attach(entry_connection_t *conn,
}
/* Now, we handle everything that isn't a .onion address. */
- if (addresstype != ONION_V2_HOSTNAME && addresstype != ONION_V3_HOSTNAME) {
+ if (addresstype != ONION_V3_HOSTNAME) {
/* Not a hidden-service request. It's either a hostname or an IP,
* possibly with a .exit that we stripped off. We're going to check
* if we're allowed to connect/resolve there, and then launch the
@@ -2506,6 +2435,25 @@ connection_ap_handshake_rewrite_and_attach(entry_connection_t *conn,
* address. */
conn->entry_cfg.ipv6_traffic = 0;
}
+
+ /* Next, yet another check: we know it's a direct IP address. Is it
+ * the IP address of a known relay and its ORPort, or of a directory
+ * authority and its OR or Dir Port? If so, and if a consensus param
+ * says to, then exit relays will refuse this request (see ticket
+ * 2667 for details). Let's just refuse it locally right now, to
+ * save time and network load but also to give the user a more
+ * useful log message. */
+ if (!network_reentry_is_allowed() &&
+ nodelist_reentry_contains(&addr, socks->port)) {
+ log_warn(LD_APP, "Not attempting connection to %s:%d because "
+ "the network would reject it. Are you trying to send "
+ "Tor traffic over Tor? This traffic can be harmful to "
+ "the Tor network. If you really need it, try using "
+ "a bridge as a workaround.",
+ safe_str_client(socks->address), socks->port);
+ connection_mark_unattached_ap(conn, END_STREAM_REASON_TORPROTOCOL);
+ return -1;
+ }
}
}
@@ -2586,24 +2534,9 @@ connection_ap_handshake_rewrite_and_attach(entry_connection_t *conn,
return 0;
} else {
/* If we get here, it's a request for a .onion address! */
- tor_assert(addresstype == ONION_V2_HOSTNAME ||
- addresstype == ONION_V3_HOSTNAME);
+ tor_assert(addresstype == ONION_V3_HOSTNAME);
tor_assert(!automap);
-
- if (addresstype == ONION_V2_HOSTNAME) {
- static bool log_once = false;
- if (!log_once) {
- log_warn(LD_PROTOCOL,
- "Warning! You've just connected to a v2 onion address. These "
- "addresses are deprecated for security reasons, and are no "
- "longer supported in Tor. Please encourage the site operator "
- "to upgrade. For more information see "
- "https://blog.torproject.org/v2-deprecation-timeline");
- log_once = true;
- }
- }
-
- return connection_ap_handle_onion(conn, socks, circ, addresstype);
+ return connection_ap_handle_onion(conn, socks, circ);
}
return 0; /* unreached but keeps the compiler happy */
@@ -3540,22 +3473,30 @@ tell_controller_about_resolved_result(entry_connection_t *conn,
int ttl,
time_t expires)
{
+ uint64_t stream_id = 0;
+
+ if (BUG(!conn)) {
+ return;
+ }
+
+ stream_id = ENTRY_TO_CONN(conn)->global_identifier;
+
expires = time(NULL) + ttl;
if (answer_type == RESOLVED_TYPE_IPV4 && answer_len >= 4) {
char *cp = tor_dup_ip(ntohl(get_uint32(answer)));
if (cp)
control_event_address_mapped(conn->socks_request->address,
- cp, expires, NULL, 0);
+ cp, expires, NULL, 0, stream_id);
tor_free(cp);
} else if (answer_type == RESOLVED_TYPE_HOSTNAME && answer_len < 256) {
char *cp = tor_strndup(answer, answer_len);
control_event_address_mapped(conn->socks_request->address,
- cp, expires, NULL, 0);
+ cp, expires, NULL, 0, stream_id);
tor_free(cp);
} else {
control_event_address_mapped(conn->socks_request->address,
"<error>", time(NULL)+ttl,
- "error=yes", 0);
+ "error=yes", 0, stream_id);
}
}
@@ -3902,13 +3843,7 @@ handle_hs_exit_conn(circuit_t *circ, edge_connection_t *conn)
conn->base_.address = tor_strdup("(rendezvous)");
conn->base_.state = EXIT_CONN_STATE_CONNECTING;
- /* The circuit either has an hs identifier for v3+ or a rend_data for legacy
- * service. */
- if (origin_circ->rend_data) {
- conn->rend_data = rend_data_dup(origin_circ->rend_data);
- tor_assert(connection_edge_is_rendezvous_stream(conn));
- ret = rend_service_set_connection_addr_port(conn, origin_circ);
- } else if (origin_circ->hs_ident) {
+ if (origin_circ->hs_ident) {
/* Setup the identifier to be the one for the circuit service. */
conn->hs_ident =
hs_ident_edge_conn_new(&origin_circ->hs_ident->identity_pk);
@@ -4200,6 +4135,9 @@ connection_exit_begin_resolve(cell_t *cell, or_circuit_t *circ)
if (rh.length > RELAY_PAYLOAD_SIZE)
return -1;
+ /* Note the RESOLVE stream as seen. */
+ rep_hist_note_exit_stream(RELAY_COMMAND_RESOLVE);
+
/* This 'dummy_conn' only exists to remember the stream ID
* associated with the resolve request; and to make the
* implementation of dns.c more uniform. (We really only need to
@@ -4287,6 +4225,7 @@ connection_exit_connect(edge_connection_t *edge_conn)
log_info(LD_EXIT,"%s failed exit policy%s. Closing.",
connection_describe(conn),
why_failed_exit_policy);
+ rep_hist_note_conn_rejected(conn->type, conn->socket_family);
connection_edge_end(edge_conn, END_STREAM_REASON_EXITPOLICY);
circuit_detach_stream(circuit_get_by_edge_conn(edge_conn), edge_conn);
connection_free(conn);
@@ -4314,12 +4253,17 @@ connection_exit_connect(edge_connection_t *edge_conn)
nodelist_reentry_contains(&conn->addr, conn->port)) {
log_info(LD_EXIT, "%s tried to connect back to a known relay address. "
"Closing.", connection_describe(conn));
+ rep_hist_note_conn_rejected(conn->type, conn->socket_family);
connection_edge_end(edge_conn, END_STREAM_REASON_CONNECTREFUSED);
circuit_detach_stream(circuit_get_by_edge_conn(edge_conn), edge_conn);
connection_free(conn);
return;
}
+ /* Note the BEGIN stream as seen. We do this after the Exit policy check in
+ * order to only account for valid streams. */
+ rep_hist_note_exit_stream(RELAY_COMMAND_BEGIN);
+
#ifdef HAVE_SYS_UN_H
if (conn->socket_family != AF_UNIX) {
#else
@@ -4415,6 +4359,9 @@ connection_exit_connect_dir(edge_connection_t *exitconn)
log_info(LD_EXIT, "Opening local connection for anonymized directory exit");
+ /* Note the BEGIN_DIR stream as seen. */
+ rep_hist_note_exit_stream(RELAY_COMMAND_BEGIN_DIR);
+
exitconn->base_.state = EXIT_CONN_STATE_OPEN;
dirconn = dir_connection_new(tor_addr_family(&exitconn->base_.addr));
@@ -4471,10 +4418,8 @@ int
connection_edge_is_rendezvous_stream(const edge_connection_t *conn)
{
tor_assert(conn);
- /* It should not be possible to set both of these structs */
- tor_assert_nonfatal(!(conn->rend_data && conn->hs_ident));
- if (conn->rend_data || conn->hs_ident) {
+ if (conn->hs_ident) {
return 1;
}
return 0;
diff --git a/src/core/or/connection_edge.h b/src/core/or/connection_edge.h
index 802ca071cd..1816f2a463 100644
--- a/src/core/or/connection_edge.h
+++ b/src/core/or/connection_edge.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -80,7 +80,6 @@ typedef enum hostname_type_t {
BAD_HOSTNAME,
EXIT_HOSTNAME,
NORMAL_HOSTNAME,
- ONION_V2_HOSTNAME,
ONION_V3_HOSTNAME,
} hostname_type_t;
diff --git a/src/core/or/connection_or.c b/src/core/or/connection_or.c
index 3b380c6145..dd93628654 100644
--- a/src/core/or/connection_or.c
+++ b/src/core/or/connection_or.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -65,7 +65,9 @@
#include "core/or/scheduler.h"
#include "feature/nodelist/torcert.h"
#include "core/or/channelpadding.h"
+#include "core/or/congestion_control_common.h"
#include "feature/dirauth/authmode.h"
+#include "feature/hs/hs_service.h"
#include "core/or/cell_st.h"
#include "core/or/cell_queue_st.h"
@@ -639,7 +641,7 @@ connection_or_flushed_some(or_connection_t *conn)
/* If we're under the low water mark, add cells until we're just over the
* high water mark. */
datalen = connection_get_outbuf_len(TO_CONN(conn));
- if (datalen < OR_CONN_LOWWATER) {
+ if (datalen < or_conn_lowwatermark()) {
/* Let the scheduler know */
scheduler_channel_wants_writes(TLS_CHAN_TO_BASE(conn->chan));
}
@@ -663,9 +665,9 @@ connection_or_num_cells_writeable(or_connection_t *conn)
* used to trigger when to start writing after we've stopped.
*/
datalen = connection_get_outbuf_len(TO_CONN(conn));
- if (datalen < OR_CONN_HIGHWATER) {
+ if (datalen < or_conn_highwatermark()) {
cell_network_size = get_cell_network_size(conn->wide_circ_ids);
- n = CEIL_DIV(OR_CONN_HIGHWATER - datalen, cell_network_size);
+ n = CEIL_DIV(or_conn_highwatermark() - datalen, cell_network_size);
}
return n;
@@ -690,6 +692,11 @@ connection_or_finished_flushing(or_connection_t *conn)
/* PROXY_HAPROXY gets connected by receiving an ack. */
if (conn->proxy_type == PROXY_HAPROXY) {
tor_assert(TO_CONN(conn)->proxy_state == PROXY_HAPROXY_WAIT_FOR_FLUSH);
+ IF_BUG_ONCE(buf_datalen(TO_CONN(conn)->inbuf) != 0) {
+ /* This should be impossible; we're not even reading. */
+ connection_or_close_for_error(conn, 0);
+ return -1;
+ }
TO_CONN(conn)->proxy_state = PROXY_CONNECTED;
if (connection_tls_start_handshake(conn, 0) < 0) {
@@ -1317,6 +1324,13 @@ note_or_connect_failed(const or_connection_t *or_conn)
tor_assert(or_conn);
+ if (or_conn->potentially_used_for_bootstrapping) {
+ /* Don't cache connection failures for connections we initiated ourself.
+ * If these direct connections fail, we're supposed to recognize that
+ * the destination is down and stop trying. See ticket 40499. */
+ return;
+ }
+
ocf = or_connect_failure_find(or_conn);
if (ocf == NULL) {
ocf = or_connect_failure_new(or_conn);
@@ -1982,7 +1996,8 @@ connection_or_client_learned_peer_id(or_connection_t *conn,
conn->identity_digest);
const int is_authority_fingerprint = router_digest_is_trusted_dir(
conn->identity_digest);
- const int non_anonymous_mode = rend_non_anonymous_mode_enabled(options);
+ const int non_anonymous_mode =
+ hs_service_non_anonymous_mode_enabled(options);
int severity;
const char *extra_log = "";
diff --git a/src/core/or/connection_or.h b/src/core/or/connection_or.h
index 8cbe8c028b..2132f9a072 100644
--- a/src/core/or/connection_or.h
+++ b/src/core/or/connection_or.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/core/or/connection_st.h b/src/core/or/connection_st.h
index 082420c4bc..d3a230daa0 100644
--- a/src/core/or/connection_st.h
+++ b/src/core/or/connection_st.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -87,6 +87,10 @@ struct connection_t {
/** True iff we've called connection_close_immediate() on this linked
* 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
+ * connection. */
+ unsigned int from_listener:1;
/** CONNECT/SOCKS proxy client handshake state (for outgoing connections). */
unsigned int proxy_state:4;
diff --git a/src/core/or/cpath_build_state_st.h b/src/core/or/cpath_build_state_st.h
index eb8e97edc5..2dc682de81 100644
--- a/src/core/or/cpath_build_state_st.h
+++ b/src/core/or/cpath_build_state_st.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -30,11 +30,6 @@ 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;
- /** The crypt_path_t to append after rendezvous: used for rendezvous. */
- crypt_path_t *pending_final_cpath;
- /** A ref-counted reference to the crypt_path_t to append after
- * rendezvous; used on the service side. */
- crypt_path_reference_t *service_pending_final_cpath_ref;
/** 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/crypt_path.c b/src/core/or/crypt_path.c
index e1bbd81251..7673bc306f 100644
--- a/src/core/or/crypt_path.c
+++ b/src/core/or/crypt_path.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2019-2020, The Tor Project, Inc. */
+ * Copyright (c) 2019-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -15,10 +15,6 @@
* some more effort:
*
* - circuit_list_path_impl()
- * - Functions dealing with cpaths in HSv2 create_rend_cpath() and
- * create_rend_cpath_legacy()
- * - The cpath related parts of rend_service_receive_introduction() and
- * rend_client_send_introduction().
**/
#define CRYPT_PATH_PRIVATE
@@ -31,6 +27,7 @@
#include "core/or/circuitbuild.h"
#include "core/or/circuitlist.h"
#include "core/or/extendinfo.h"
+#include "core/or/congestion_control_common.h"
#include "lib/crypt_ops/crypto_dh.h"
#include "lib/crypt_ops/crypto_util.h"
@@ -169,6 +166,7 @@ cpath_free(crypt_path_t *victim)
onion_handshake_state_release(&victim->handshake_state);
crypto_dh_free(victim->rend_dh_handshake_state);
extend_info_free(victim->extend_info);
+ congestion_control_free(victim->ccontrol);
memwipe(victim, 0xBB, sizeof(crypt_path_t)); /* poison memory */
tor_free(victim);
diff --git a/src/core/or/crypt_path_reference_st.h b/src/core/or/crypt_path_reference_st.h
index 71f9cb8c36..b5f7ce3b84 100644
--- a/src/core/or/crypt_path_reference_st.h
+++ b/src/core/or/crypt_path_reference_st.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/core/or/crypt_path_st.h b/src/core/or/crypt_path_st.h
index 2b69728a6d..fdc6b6fbb2 100644
--- a/src/core/or/crypt_path_st.h
+++ b/src/core/or/crypt_path_st.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -21,14 +21,19 @@ struct fast_handshake_state_t;
struct ntor_handshake_state_t;
struct crypto_dh_t;
struct onion_handshake_state_t {
+ /** One of `ONION_HANDSHAKE_TYPE_*`. Determines which member of the union
+ * is accessible. */
uint16_t tag;
union {
struct fast_handshake_state_t *fast;
struct crypto_dh_t *tap;
struct ntor_handshake_state_t *ntor;
+ struct ntor3_handshake_state_t *ntor3;
} u;
};
+struct congestion_control_t;
+
/** Macro to encapsulate private members of a struct.
*
* Renames 'x' to 'x_crypt_path_private_field'.
@@ -80,6 +85,9 @@ struct crypt_path_t {
int deliver_window; /**< How many cells are we willing to deliver originating
* at this step? */
+ /** Congestion control info */
+ struct congestion_control_t *ccontrol;
+
/*********************** Private members ****************************/
/** Private member: Cryptographic state used for encrypting and
diff --git a/src/core/or/destroy_cell_queue_st.h b/src/core/or/destroy_cell_queue_st.h
index aa28289be5..224c82ad9d 100644
--- a/src/core/or/destroy_cell_queue_st.h
+++ b/src/core/or/destroy_cell_queue_st.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/core/or/dos.c b/src/core/or/dos.c
index 41bf303ffe..5bf7d148d7 100644
--- a/src/core/or/dos.c
+++ b/src/core/or/dos.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2018-2020, The Tor Project, Inc. */
+/* Copyright (c) 2018-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/*
@@ -23,7 +23,9 @@
#include "lib/crypt_ops/crypto_rand.h"
#include "core/or/dos.h"
+#include "core/or/dos_sys.h"
+#include "core/or/dos_options_st.h"
#include "core/or/or_connection_st.h"
/*
@@ -47,6 +49,7 @@ static int32_t dos_cc_defense_time_period;
/* Keep some stats for the heartbeat so we can report out. */
static uint64_t cc_num_rejected_cells;
static uint32_t cc_num_marked_addrs;
+static uint32_t cc_num_marked_addrs_max_queue;
/*
* Concurrent connection denial of service mitigation.
@@ -61,9 +64,18 @@ static unsigned int dos_conn_enabled = 0;
* They are initialized with the hardcoded default values. */
static uint32_t dos_conn_max_concurrent_count;
static dos_conn_defense_type_t dos_conn_defense_type;
+static uint32_t dos_conn_connect_rate = DOS_CONN_CONNECT_RATE_DEFAULT;
+static uint32_t dos_conn_connect_burst = DOS_CONN_CONNECT_BURST_DEFAULT;
+static int32_t dos_conn_connect_defense_time_period =
+ DOS_CONN_CONNECT_DEFENSE_TIME_PERIOD_DEFAULT;
/* Keep some stats for the heartbeat so we can report out. */
static uint64_t conn_num_addr_rejected;
+static uint64_t conn_num_addr_connect_rejected;
+
+/** Consensus parameter: How many times a client IP is allowed to hit the
+ * circ_max_cell_queue_size_out limit before being marked. */
+static uint32_t dos_num_circ_max_outq;
/*
* General interface of the denial of service mitigation subsystem.
@@ -72,13 +84,29 @@ static uint64_t conn_num_addr_rejected;
/* Keep stats for the heartbeat. */
static uint64_t num_single_hop_client_refused;
+/** Return the consensus parameter for the outbound circ_max_cell_queue_size
+ * limit. */
+static uint32_t
+get_param_dos_num_circ_max_outq(const networkstatus_t *ns)
+{
+#define DOS_NUM_CIRC_MAX_OUTQ_DEFAULT 3
+#define DOS_NUM_CIRC_MAX_OUTQ_MIN 0
+#define DOS_NUM_CIRC_MAX_OUTQ_MAX INT32_MAX
+
+ /* Update the circuit max cell queue size from the consensus. */
+ return networkstatus_get_param(ns, "dos_num_circ_max_outq",
+ DOS_NUM_CIRC_MAX_OUTQ_DEFAULT,
+ DOS_NUM_CIRC_MAX_OUTQ_MIN,
+ DOS_NUM_CIRC_MAX_OUTQ_MAX);
+}
+
/* Return true iff the circuit creation mitigation is enabled. We look at the
* consensus for this else a default value is returned. */
MOCK_IMPL(STATIC unsigned int,
get_param_cc_enabled, (const networkstatus_t *ns))
{
- if (get_options()->DoSCircuitCreationEnabled != -1) {
- return get_options()->DoSCircuitCreationEnabled;
+ if (dos_get_options()->DoSCircuitCreationEnabled != -1) {
+ return dos_get_options()->DoSCircuitCreationEnabled;
}
return !!networkstatus_get_param(ns, "DoSCircuitCreationEnabled",
@@ -90,8 +118,8 @@ get_param_cc_enabled, (const networkstatus_t *ns))
STATIC uint32_t
get_param_cc_min_concurrent_connection(const networkstatus_t *ns)
{
- if (get_options()->DoSCircuitCreationMinConnections) {
- return get_options()->DoSCircuitCreationMinConnections;
+ if (dos_get_options()->DoSCircuitCreationMinConnections) {
+ return dos_get_options()->DoSCircuitCreationMinConnections;
}
return networkstatus_get_param(ns, "DoSCircuitCreationMinConnections",
DOS_CC_MIN_CONCURRENT_CONN_DEFAULT,
@@ -104,8 +132,8 @@ static uint32_t
get_param_cc_circuit_rate(const networkstatus_t *ns)
{
/* This is in seconds. */
- if (get_options()->DoSCircuitCreationRate) {
- return get_options()->DoSCircuitCreationRate;
+ if (dos_get_options()->DoSCircuitCreationRate) {
+ return dos_get_options()->DoSCircuitCreationRate;
}
return networkstatus_get_param(ns, "DoSCircuitCreationRate",
DOS_CC_CIRCUIT_RATE_DEFAULT,
@@ -117,8 +145,8 @@ get_param_cc_circuit_rate(const networkstatus_t *ns)
STATIC uint32_t
get_param_cc_circuit_burst(const networkstatus_t *ns)
{
- if (get_options()->DoSCircuitCreationBurst) {
- return get_options()->DoSCircuitCreationBurst;
+ if (dos_get_options()->DoSCircuitCreationBurst) {
+ return dos_get_options()->DoSCircuitCreationBurst;
}
return networkstatus_get_param(ns, "DoSCircuitCreationBurst",
DOS_CC_CIRCUIT_BURST_DEFAULT,
@@ -129,8 +157,8 @@ get_param_cc_circuit_burst(const networkstatus_t *ns)
static uint32_t
get_param_cc_defense_type(const networkstatus_t *ns)
{
- if (get_options()->DoSCircuitCreationDefenseType) {
- return get_options()->DoSCircuitCreationDefenseType;
+ if (dos_get_options()->DoSCircuitCreationDefenseType) {
+ return dos_get_options()->DoSCircuitCreationDefenseType;
}
return networkstatus_get_param(ns, "DoSCircuitCreationDefenseType",
DOS_CC_DEFENSE_TYPE_DEFAULT,
@@ -143,8 +171,8 @@ static int32_t
get_param_cc_defense_time_period(const networkstatus_t *ns)
{
/* Time in seconds. */
- if (get_options()->DoSCircuitCreationDefenseTimePeriod) {
- return get_options()->DoSCircuitCreationDefenseTimePeriod;
+ if (dos_get_options()->DoSCircuitCreationDefenseTimePeriod) {
+ return dos_get_options()->DoSCircuitCreationDefenseTimePeriod;
}
return networkstatus_get_param(ns, "DoSCircuitCreationDefenseTimePeriod",
DOS_CC_DEFENSE_TIME_PERIOD_DEFAULT,
@@ -156,8 +184,8 @@ get_param_cc_defense_time_period(const networkstatus_t *ns)
MOCK_IMPL(STATIC unsigned int,
get_param_conn_enabled, (const networkstatus_t *ns))
{
- if (get_options()->DoSConnectionEnabled != -1) {
- return get_options()->DoSConnectionEnabled;
+ if (dos_get_options()->DoSConnectionEnabled != -1) {
+ return dos_get_options()->DoSConnectionEnabled;
}
return !!networkstatus_get_param(ns, "DoSConnectionEnabled",
DOS_CONN_ENABLED_DEFAULT, 0, 1);
@@ -168,8 +196,8 @@ get_param_conn_enabled, (const networkstatus_t *ns))
STATIC uint32_t
get_param_conn_max_concurrent_count(const networkstatus_t *ns)
{
- if (get_options()->DoSConnectionMaxConcurrentCount) {
- return get_options()->DoSConnectionMaxConcurrentCount;
+ if (dos_get_options()->DoSConnectionMaxConcurrentCount) {
+ return dos_get_options()->DoSConnectionMaxConcurrentCount;
}
return networkstatus_get_param(ns, "DoSConnectionMaxConcurrentCount",
DOS_CONN_MAX_CONCURRENT_COUNT_DEFAULT,
@@ -180,14 +208,55 @@ get_param_conn_max_concurrent_count(const networkstatus_t *ns)
static uint32_t
get_param_conn_defense_type(const networkstatus_t *ns)
{
- if (get_options()->DoSConnectionDefenseType) {
- return get_options()->DoSConnectionDefenseType;
+ if (dos_get_options()->DoSConnectionDefenseType) {
+ return dos_get_options()->DoSConnectionDefenseType;
}
return networkstatus_get_param(ns, "DoSConnectionDefenseType",
DOS_CONN_DEFENSE_TYPE_DEFAULT,
DOS_CONN_DEFENSE_NONE, DOS_CONN_DEFENSE_MAX);
}
+/* Return the connection connect rate parameters either from the configuration
+ * file or, if not found, consensus parameter. */
+static uint32_t
+get_param_conn_connect_rate(const networkstatus_t *ns)
+{
+ if (dos_get_options()->DoSConnectionConnectRate) {
+ return dos_get_options()->DoSConnectionConnectRate;
+ }
+ return networkstatus_get_param(ns, "DoSConnectionConnectRate",
+ DOS_CONN_CONNECT_RATE_DEFAULT,
+ 1, INT32_MAX);
+}
+
+/* Return the connection connect burst parameters either from the
+ * configuration file or, if not found, consensus parameter. */
+STATIC uint32_t
+get_param_conn_connect_burst(const networkstatus_t *ns)
+{
+ if (dos_get_options()->DoSConnectionConnectBurst) {
+ return dos_get_options()->DoSConnectionConnectBurst;
+ }
+ return networkstatus_get_param(ns, "DoSConnectionConnectBurst",
+ DOS_CONN_CONNECT_BURST_DEFAULT,
+ 1, INT32_MAX);
+}
+
+/* Return the connection connect defense time period from the configuration
+ * file or, if not found, the consensus parameter. */
+static int32_t
+get_param_conn_connect_defense_time_period(const networkstatus_t *ns)
+{
+ /* Time in seconds. */
+ if (dos_get_options()->DoSConnectionConnectDefenseTimePeriod) {
+ return dos_get_options()->DoSConnectionConnectDefenseTimePeriod;
+ }
+ return networkstatus_get_param(ns, "DoSConnectionConnectDefenseTimePeriod",
+ DOS_CONN_CONNECT_DEFENSE_TIME_PERIOD_DEFAULT,
+ DOS_CONN_CONNECT_DEFENSE_TIME_PERIOD_MIN,
+ INT32_MAX);
+}
+
/* Set circuit creation parameters located in the consensus or their default
* if none are present. Called at initialization or when the consensus
* changes. */
@@ -206,6 +275,13 @@ set_dos_parameters(const networkstatus_t *ns)
dos_conn_enabled = get_param_conn_enabled(ns);
dos_conn_max_concurrent_count = get_param_conn_max_concurrent_count(ns);
dos_conn_defense_type = get_param_conn_defense_type(ns);
+ dos_conn_connect_rate = get_param_conn_connect_rate(ns);
+ dos_conn_connect_burst = get_param_conn_connect_burst(ns);
+ dos_conn_connect_defense_time_period =
+ get_param_conn_connect_defense_time_period(ns);
+
+ /* Circuit. */
+ dos_num_circ_max_outq = get_param_dos_num_circ_max_outq(ns);
}
/* Free everything for the circuit creation DoS mitigation subsystem. */
@@ -347,7 +423,7 @@ cc_has_exhausted_circuits(const dos_client_stats_t *stats)
{
tor_assert(stats);
return stats->cc_stats.circuit_bucket == 0 &&
- stats->concurrent_count >= dos_cc_min_concurrent_conn;
+ stats->conn_stats.concurrent_count >= dos_cc_min_concurrent_conn;
}
/* Mark client address by setting a timestamp in the stats object which tells
@@ -403,6 +479,20 @@ cc_channel_addr_is_marked(channel_t *chan)
/* Concurrent connection private API. */
+/* Mark client connection stats by setting a timestamp which tells us until
+ * when it is marked as positively detected. */
+static void
+conn_mark_client(conn_client_stats_t *stats)
+{
+ tor_assert(stats);
+
+ /* We add a random offset of a maximum of half the defense time so it is
+ * less predictable and thus more difficult to game. */
+ stats->marked_until_ts =
+ approx_time() + dos_conn_connect_defense_time_period +
+ crypto_rand_int_range(1, dos_conn_connect_defense_time_period / 2);
+}
+
/* Free everything for the connection DoS mitigation subsystem. */
static void
conn_free_all(void)
@@ -422,6 +512,63 @@ conn_consensus_has_changed(const networkstatus_t *ns)
}
}
+/** Called when a new client connection has arrived. The following will update
+ * the client connection statistics.
+ *
+ * The addr is used for logging purposes only.
+ *
+ * If the connect counter reaches its limit, it is marked. */
+static void
+conn_update_on_connect(conn_client_stats_t *stats, const tor_addr_t *addr)
+{
+ tor_assert(stats);
+ tor_assert(addr);
+
+ /* Update concurrent count for this new connect. */
+ stats->concurrent_count++;
+
+ /* Refill connect connection count. */
+ token_bucket_ctr_refill(&stats->connect_count, (uint32_t) approx_time());
+
+ /* Decrement counter for this new connection. */
+ if (token_bucket_ctr_get(&stats->connect_count) > 0) {
+ token_bucket_ctr_dec(&stats->connect_count, 1);
+ }
+
+ /* Assess connect counter. Mark it if counter is down to 0 and we haven't
+ * marked it before or it was reset. This is to avoid to re-mark it over and
+ * over again extending continuously the blocked time. */
+ if (token_bucket_ctr_get(&stats->connect_count) == 0 &&
+ stats->marked_until_ts == 0) {
+ conn_mark_client(stats);
+ }
+
+ log_debug(LD_DOS, "Client address %s has now %u concurrent connections. "
+ "Remaining %" TOR_PRIuSZ "/sec connections are allowed.",
+ fmt_addr(addr), stats->concurrent_count,
+ token_bucket_ctr_get(&stats->connect_count));
+}
+
+/** Called when a client connection is closed. The following will update
+ * the client connection statistics.
+ *
+ * The addr is used for logging purposes only. */
+static void
+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. */
+ if (BUG(stats->concurrent_count == 0)) {
+ return;
+ }
+
+ stats->concurrent_count--;
+ log_debug(LD_DOS, "Client address %s has lost a connection. Concurrent "
+ "connections are now at %u",
+ fmt_addr(addr), stats->concurrent_count);
+}
+
/* General private API */
/* Return true iff we have at least one DoS detection enabled. This is used to
@@ -434,6 +581,48 @@ dos_is_enabled(void)
/* Circuit creation public API. */
+/** Return the number of rejected circuits. */
+uint64_t
+dos_get_num_cc_rejected(void)
+{
+ return cc_num_rejected_cells;
+}
+
+/** Return the number of marked addresses. */
+uint32_t
+dos_get_num_cc_marked_addr(void)
+{
+ return cc_num_marked_addrs;
+}
+
+/** Return the number of marked addresses due to max queue limit reached. */
+uint32_t
+dos_get_num_cc_marked_addr_maxq(void)
+{
+ return cc_num_marked_addrs_max_queue;
+}
+
+/** Return number of concurrent connections rejected. */
+uint64_t
+dos_get_num_conn_addr_rejected(void)
+{
+ return conn_num_addr_rejected;
+}
+
+/** Return the number of connection rejected. */
+uint64_t
+dos_get_num_conn_addr_connect_rejected(void)
+{
+ return conn_num_addr_connect_rejected;
+}
+
+/** Return the number of single hop refused. */
+uint64_t
+dos_get_num_single_hop_refused(void)
+{
+ return num_single_hop_client_refused;
+}
+
/* Called when a CREATE cell is received from the given channel. */
void
dos_cc_new_create_cell(channel_t *chan)
@@ -547,9 +736,20 @@ dos_conn_addr_get_defense_type(const tor_addr_t *addr)
goto end;
}
+ /* Is this address marked as making too many client connections? */
+ if (entry->dos_stats.conn_stats.marked_until_ts >= approx_time()) {
+ conn_num_addr_connect_rejected++;
+ return dos_conn_defense_type;
+ }
+ /* Reset it to 0 here so that if the marked timestamp has expired that is
+ * we've gone beyond it, we have to reset it so the detection can mark it
+ * again in the future. */
+ entry->dos_stats.conn_stats.marked_until_ts = 0;
+
/* Need to be above the maximum concurrent connection count to trigger a
* defense. */
- if (entry->dos_stats.concurrent_count > dos_conn_max_concurrent_count) {
+ if (entry->dos_stats.conn_stats.concurrent_count >
+ dos_conn_max_concurrent_count) {
conn_num_addr_rejected++;
return dos_conn_defense_type;
}
@@ -574,7 +774,7 @@ dos_geoip_entry_about_to_free(const clientmap_entry_t *geoip_ent)
/* The count is down to 0 meaning no connections right now, we can safely
* clear the geoip entry from the cache. */
- if (geoip_ent->dos_stats.concurrent_count == 0) {
+ if (geoip_ent->dos_stats.conn_stats.concurrent_count == 0) {
goto end;
}
@@ -595,6 +795,85 @@ dos_geoip_entry_about_to_free(const clientmap_entry_t *geoip_ent)
return;
}
+/** A new geoip client entry has been allocated, initialize its DoS object. */
+void
+dos_geoip_entry_init(clientmap_entry_t *geoip_ent)
+{
+ tor_assert(geoip_ent);
+
+ /* Initialize the connection count counter with the rate and burst
+ * parameters taken either from configuration or consensus.
+ *
+ * We do this even if the DoS connection detection is not enabled because it
+ * 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());
+}
+
+/** Note that the given channel has sent outbound the maximum amount of cell
+ * allowed on the next channel. */
+void
+dos_note_circ_max_outq(const channel_t *chan)
+{
+ tor_addr_t addr;
+ clientmap_entry_t *entry;
+
+ tor_assert(chan);
+
+ /* Skip everything if circuit creation defense is disabled. */
+ if (!dos_cc_enabled) {
+ goto end;
+ }
+
+ /* Must be a client connection else we ignore. */
+ if (!channel_is_client(chan)) {
+ goto end;
+ }
+ /* Without an IP address, nothing can work. */
+ if (!channel_get_addr_if_possible(chan, &addr)) {
+ goto end;
+ }
+
+ /* We are only interested in client connection from the geoip cache. */
+ entry = geoip_lookup_client(&addr, NULL, GEOIP_CLIENT_CONNECT);
+ if (entry == NULL) {
+ goto end;
+ }
+
+ /* Is the client marked? If yes, just ignore. */
+ if (entry->dos_stats.cc_stats.marked_until_ts >= approx_time()) {
+ goto end;
+ }
+
+ /* If max outq parameter is 0, it means disabled, just ignore. */
+ if (dos_num_circ_max_outq == 0) {
+ goto end;
+ }
+
+ entry->dos_stats.num_circ_max_cell_queue_size++;
+
+ /* This is the detection. If we have reached the maximum amount of times a
+ * client IP is allowed to reach this limit, mark client. */
+ if (entry->dos_stats.num_circ_max_cell_queue_size >=
+ dos_num_circ_max_outq) {
+ /* Only account for this marked address if this is the first time we block
+ * it else our counter is inflated with non unique entries. */
+ if (entry->dos_stats.cc_stats.marked_until_ts == 0) {
+ cc_num_marked_addrs_max_queue++;
+ }
+ log_info(LD_DOS, "Detected outbound max circuit queue from addr: %s",
+ fmt_addr(&addr));
+ cc_mark_client(&entry->dos_stats.cc_stats);
+
+ /* Reset after being marked so once unmarked, we start back clean. */
+ entry->dos_stats.num_circ_max_cell_queue_size = 0;
+ }
+
+ end:
+ return;
+}
+
/* Note down that we've just refused a single hop client. This increments a
* counter later used for the heartbeat. */
void
@@ -613,8 +892,8 @@ dos_should_refuse_single_hop_client(void)
return 0;
}
- if (get_options()->DoSRefuseSingleHopClientRendezvous != -1) {
- return get_options()->DoSRefuseSingleHopClientRendezvous;
+ if (dos_get_options()->DoSRefuseSingleHopClientRendezvous != -1) {
+ return dos_get_options()->DoSRefuseSingleHopClientRendezvous;
}
return (int) networkstatus_get_param(NULL,
@@ -626,55 +905,57 @@ dos_should_refuse_single_hop_client(void)
void
dos_log_heartbeat(void)
{
- char *conn_msg = NULL;
- char *cc_msg = NULL;
- char *single_hop_client_msg = NULL;
- char *circ_stats_msg = NULL;
- char *hs_dos_intro2_msg = NULL;
+ smartlist_t *elems = smartlist_new();
/* Stats number coming from relay.c append_cell_to_circuit_queue(). */
- tor_asprintf(&circ_stats_msg,
- " %" PRIu64 " circuits killed with too many cells.",
- stats_n_circ_max_cell_reached);
+ smartlist_add_asprintf(elems,
+ "%" PRIu64 " circuits killed with too many cells",
+ stats_n_circ_max_cell_reached);
if (dos_cc_enabled) {
- tor_asprintf(&cc_msg,
- " %" PRIu64 " circuits rejected,"
- " %" PRIu32 " marked addresses.",
- cc_num_rejected_cells, cc_num_marked_addrs);
+ smartlist_add_asprintf(elems,
+ "%" PRIu64 " circuits rejected, "
+ "%" PRIu32 " marked addresses, "
+ "%" PRIu32 " marked addresses for max queue",
+ cc_num_rejected_cells, cc_num_marked_addrs,
+ cc_num_marked_addrs_max_queue);
+ } else {
+ smartlist_add_asprintf(elems, "[DoSCircuitCreationEnabled disabled]");
}
if (dos_conn_enabled) {
- tor_asprintf(&conn_msg,
- " %" PRIu64 " connections closed.",
- conn_num_addr_rejected);
+ smartlist_add_asprintf(elems,
+ "%" PRIu64 " same address concurrent "
+ "connections rejected", conn_num_addr_rejected);
+ smartlist_add_asprintf(elems,
+ "%" PRIu64 " connections rejected",
+ conn_num_addr_connect_rejected);
+ } else {
+ smartlist_add_asprintf(elems, "[DoSConnectionEnabled disabled]");
}
if (dos_should_refuse_single_hop_client()) {
- tor_asprintf(&single_hop_client_msg,
- " %" PRIu64 " single hop clients refused.",
- num_single_hop_client_refused);
+ smartlist_add_asprintf(elems,
+ "%" PRIu64 " single hop clients refused",
+ num_single_hop_client_refused);
+ } else {
+ smartlist_add_asprintf(elems,
+ "[DoSRefuseSingleHopClientRendezvous disabled]");
}
/* HS DoS stats. */
- tor_asprintf(&hs_dos_intro2_msg,
- " %" PRIu64 " INTRODUCE2 rejected.",
- hs_dos_get_intro2_rejected_count());
+ smartlist_add_asprintf(elems,
+ "%" PRIu64 " INTRODUCE2 rejected",
+ hs_dos_get_intro2_rejected_count());
+
+ char *msg = smartlist_join_strings(elems, ", ", 0, NULL);
log_notice(LD_HEARTBEAT,
- "DoS mitigation since startup:%s%s%s%s%s",
- circ_stats_msg,
- (cc_msg != NULL) ? cc_msg : " [cc not enabled]",
- (conn_msg != NULL) ? conn_msg : " [conn not enabled]",
- (single_hop_client_msg != NULL) ? single_hop_client_msg : "",
- (hs_dos_intro2_msg != NULL) ? hs_dos_intro2_msg : "");
-
- tor_free(conn_msg);
- tor_free(cc_msg);
- tor_free(single_hop_client_msg);
- tor_free(circ_stats_msg);
- tor_free(hs_dos_intro2_msg);
- return;
+ "Heartbeat: DoS mitigation since startup: %s.", msg);
+
+ tor_free(msg);
+ SMARTLIST_FOREACH(elems, char *, e, tor_free(e));
+ smartlist_free(elems);
}
/* Called when a new client connection has been established on the given
@@ -709,11 +990,11 @@ dos_new_client_conn(or_connection_t *or_conn, const char *transport_name)
goto end;
}
- entry->dos_stats.concurrent_count++;
+ /* Update stats from this new connect. */
+ conn_update_on_connect(&entry->dos_stats.conn_stats,
+ &TO_CONN(or_conn)->addr);
+
or_conn->tracked_for_dos_mitigation = 1;
- log_debug(LD_DOS, "Client address %s has now %u concurrent connections.",
- fmt_addr(&TO_CONN(or_conn)->addr),
- entry->dos_stats.concurrent_count);
end:
return;
@@ -743,18 +1024,8 @@ dos_close_client_conn(const or_connection_t *or_conn)
goto end;
}
- /* 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. */
- if (BUG(entry->dos_stats.concurrent_count == 0)) {
- goto end;
- }
-
- entry->dos_stats.concurrent_count--;
- log_debug(LD_DOS, "Client address %s has lost a connection. Concurrent "
- "connections are now at %u",
- fmt_addr(&TO_CONN(or_conn)->addr),
- entry->dos_stats.concurrent_count);
+ /* Update stats from this new close. */
+ conn_update_on_close(&entry->dos_stats.conn_stats, &TO_CONN(or_conn)->addr);
end:
return;
diff --git a/src/core/or/dos.h b/src/core/or/dos.h
index b3eca058b8..4a2227f132 100644
--- a/src/core/or/dos.h
+++ b/src/core/or/dos.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2018-2020, The Tor Project, Inc. */
+/* Copyright (c) 2018-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/*
@@ -9,7 +9,11 @@
#ifndef TOR_DOS_H
#define TOR_DOS_H
-/* Structure that keeps stats of client connection per-IP. */
+#include "core/or/or.h"
+
+#include "lib/evloop/token_bucket.h"
+
+/* Structure that keeps stats of circuit creation per client connection IP. */
typedef struct cc_client_stats_t {
/* Number of allocated circuits remaining for this address. It is
* decremented every time a new circuit is seen for this client address and
@@ -28,17 +32,35 @@ typedef struct cc_client_stats_t {
time_t marked_until_ts;
} cc_client_stats_t;
+/* Structure that keeps stats of client connection per-IP. */
+typedef struct conn_client_stats_t {
+ /* Concurrent connection count from the specific address. 2^32 - 1 is most
+ * likely way too big for the amount of allowed file descriptors. */
+ uint32_t concurrent_count;
+
+ /* Connect count from the specific address. We use a token bucket here to
+ * track the rate and burst of connections from the same IP address.*/
+ token_bucket_ctr_t connect_count;
+
+ /* The client address attempted too many connections, per the connect_count
+ * rules, and thus is marked so defense(s) can be applied. It is
+ * synchronized using the approx_time(). */
+ time_t marked_until_ts;
+} conn_client_stats_t;
+
/* This object is a top level object that contains everything related to the
* per-IP client DoS mitigation. Because it is per-IP, it is used in the geoip
* clientmap_entry_t object. */
typedef struct dos_client_stats_t {
- /* Concurrent connection count from the specific address. 2^32 is most
- * likely way too big for the amount of allowed file descriptors. */
- uint32_t concurrent_count;
+ /* Client connection statistics. */
+ conn_client_stats_t conn_stats;
/* Circuit creation statistics. This is only used if the circuit creation
* subsystem has been enabled (dos_cc_enabled). */
cc_client_stats_t cc_stats;
+
+ /** Number of times the circ_max_cell_queue_size limit has been reached. */
+ uint32_t num_circ_max_cell_queue_size;
} dos_client_stats_t;
/* General API. */
@@ -51,6 +73,7 @@ void dos_free_all(void);
void dos_consensus_has_changed(const networkstatus_t *ns);
int dos_enabled(void);
void dos_log_heartbeat(void);
+void dos_geoip_entry_init(struct clientmap_entry_t *geoip_ent);
void dos_geoip_entry_about_to_free(const struct clientmap_entry_t *geoip_ent);
void dos_new_client_conn(or_connection_t *or_conn,
@@ -59,6 +82,14 @@ void dos_close_client_conn(const or_connection_t *or_conn);
int dos_should_refuse_single_hop_client(void);
void dos_note_refuse_single_hop_client(void);
+void dos_note_circ_max_outq(const channel_t *chan);
+
+uint32_t dos_get_num_cc_marked_addr(void);
+uint32_t dos_get_num_cc_marked_addr_maxq(void);
+uint64_t dos_get_num_cc_rejected(void);
+uint64_t dos_get_num_conn_addr_rejected(void);
+uint64_t dos_get_num_conn_addr_connect_rejected(void);
+uint64_t dos_get_num_single_hop_refused(void);
/*
* Circuit creation DoS mitigation subsystemn interface.
@@ -102,6 +133,16 @@ dos_cc_defense_type_t dos_cc_get_defense_type(channel_t *chan);
#define DOS_CONN_MAX_CONCURRENT_COUNT_DEFAULT 100
/* DoSConnectionDefenseType maps to the dos_conn_defense_type_t enum. */
#define DOS_CONN_DEFENSE_TYPE_DEFAULT DOS_CONN_DEFENSE_CLOSE
+/* DoSConnectionConnectRate default. Per second. */
+#define DOS_CONN_CONNECT_RATE_DEFAULT 20
+/* DoSConnectionConnectBurst default. Per second. */
+#define DOS_CONN_CONNECT_BURST_DEFAULT 40
+/* DoSConnectionConnectDefenseTimePeriod default. Set to 24 hours. */
+#define DOS_CONN_CONNECT_DEFENSE_TIME_PERIOD_DEFAULT (24 * 60 * 60)
+/* DoSCircuitCreationDefenseTimePeriod minimum value. Because we add a random
+ * offset to the marked timestamp, we need the minimum value to be non zero.
+ * We consider that 10 seconds is an acceptable lower bound. */
+#define DOS_CONN_CONNECT_DEFENSE_TIME_PERIOD_MIN (10)
/* Type of defense that we can use for the concurrent connection DoS
* mitigation. */
@@ -125,6 +166,7 @@ STATIC uint32_t get_param_conn_max_concurrent_count(
STATIC uint32_t get_param_cc_circuit_burst(const networkstatus_t *ns);
STATIC uint32_t get_param_cc_min_concurrent_connection(
const networkstatus_t *ns);
+STATIC uint32_t get_param_conn_connect_burst(const networkstatus_t *ns);
STATIC uint64_t get_circuit_rate_per_second(void);
STATIC void cc_stats_refill_bucket(cc_client_stats_t *stats,
diff --git a/src/core/or/dos_config.c b/src/core/or/dos_config.c
new file mode 100644
index 0000000000..9457b0224e
--- /dev/null
+++ b/src/core/or/dos_config.c
@@ -0,0 +1,29 @@
+/* Copyright (c) 2021-2021, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * @file dos_config.c
+ * @brief Code to interpret the user's configuration of DoS module.
+ **/
+
+#include "core/or/dos_config.h"
+#include "core/or/dos_options_st.h"
+
+/* Declare the options field table for dos_options */
+#define CONF_CONTEXT TABLE
+#include "core/or/dos_options.inc"
+#undef CONF_CONTEXT
+
+/** Magic number for dos_options_t. */
+#define DOS_OPTIONS_MAGIC 0x91716151
+
+/**
+ * Declare the configuration options for the dos module.
+ **/
+const config_format_t dos_options_fmt = {
+ .size = sizeof(dos_options_t),
+ .magic = { "dos_options_t",
+ DOS_OPTIONS_MAGIC,
+ offsetof(dos_options_t, magic) },
+ .vars = dos_options_t_vars,
+};
diff --git a/src/core/or/dos_config.h b/src/core/or/dos_config.h
new file mode 100644
index 0000000000..3fc5bb5293
--- /dev/null
+++ b/src/core/or/dos_config.h
@@ -0,0 +1,16 @@
+/* Copyright (c) 2021-2021, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * @file dos_config.h
+ * @brief Header for core/or/dos_config.c
+ **/
+
+#ifndef TOR_CORE_OR_DOS_CONFIG_H
+#define TOR_CORE_OR_DOS_CONFIG_H
+
+#include "lib/conf/conftypes.h"
+
+extern const struct config_format_t dos_options_fmt;
+
+#endif /* !defined(TOR_CORE_OR_DOS_CONFIG_H) */
diff --git a/src/core/or/dos_options.inc b/src/core/or/dos_options.inc
new file mode 100644
index 0000000000..9baa7a35b8
--- /dev/null
+++ b/src/core/or/dos_options.inc
@@ -0,0 +1,59 @@
+/* Copyright (c) 2021, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * @file dos_options.inc
+ * @brief Declare configuration options for the DoS module.
+ **/
+
+BEGIN_CONF_STRUCT(dos_options_t)
+
+/** Autobool: Is the DoS connection mitigation subsystem enabled? */
+CONF_VAR(DoSConnectionEnabled, AUTOBOOL, 0, "auto")
+
+/** Autobool: Is the circuit creation DoS mitigation subsystem enabled? */
+CONF_VAR(DoSCircuitCreationEnabled, AUTOBOOL, 0, "auto")
+
+/** Minimum concurrent connection needed from one single address before any
+ * defense is used. */
+CONF_VAR(DoSCircuitCreationMinConnections, POSINT, 0, "0")
+
+/** Circuit rate used to refill the token bucket. */
+CONF_VAR(DoSCircuitCreationRate, POSINT, 0, "0")
+
+/** Maximum allowed burst of circuits. Reaching that value, the address is
+ * detected as malicious and a defense might be used. */
+CONF_VAR(DoSCircuitCreationBurst, POSINT, 0, "0")
+
+/** When an address is marked as malicious, what defense should be used
+ * against it. See the dos_cc_defense_type_t enum. */
+CONF_VAR(DoSCircuitCreationDefenseType, INT, 0, "0")
+
+/** For how much time (in seconds) the defense is applicable for a malicious
+ * address. A random time delta is added to the defense time of an address
+ * which will be between 1 second and half of this value. */
+CONF_VAR(DoSCircuitCreationDefenseTimePeriod, INTERVAL, 0, "0")
+
+/** Maximum concurrent connection allowed per address. */
+CONF_VAR(DoSConnectionMaxConcurrentCount, POSINT, 0, "0")
+
+/** When an address is reaches the maximum count, what defense should be
+ * used against it. See the dos_conn_defense_type_t enum. */
+CONF_VAR(DoSConnectionDefenseType, INT, 0, "0")
+
+/** Autobool: Do we refuse single hop client rendezvous? */
+CONF_VAR(DoSRefuseSingleHopClientRendezvous, AUTOBOOL, 0, "auto")
+
+/** Allowed burst of client connection allowed per address. */
+CONF_VAR(DoSConnectionConnectBurst, POSINT, 0, "0")
+
+/** Allowed rate of client connection allowed per address. */
+CONF_VAR(DoSConnectionConnectRate, POSINT, 0, "0")
+
+/** For how much time (in seconds) the connection connect rate defense is
+* applicable for a malicious address. A random time delta is added to the
+* defense time of an address which will be between 1 second and half of this
+* value. */
+CONF_VAR(DoSConnectionConnectDefenseTimePeriod, INTERVAL, 0, "0")
+
+END_CONF_STRUCT(dos_options_t)
diff --git a/src/core/or/dos_options_st.h b/src/core/or/dos_options_st.h
new file mode 100644
index 0000000000..1cbe87da03
--- /dev/null
+++ b/src/core/or/dos_options_st.h
@@ -0,0 +1,20 @@
+/* Copyright (c) 2021-2021, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * @file dos_options_st.h
+ * @brief Structure dos_options_t to hold options for the DoS subsystem.
+ **/
+
+#ifndef TOR_CORE_OR_DOS_OPTIONS_ST_H
+#define TOR_CORE_OR_DOS_OPTIONS_ST_H
+
+#include "lib/conf/confdecl.h"
+
+#define CONF_CONTEXT STRUCT
+#include "core/or/dos_options.inc"
+#undef CONF_CONTEXT
+
+typedef struct dos_options_t dos_options_t;
+
+#endif /* !defined(TOR_CORE_OR_DOS_OPTIONS_ST_H) */
diff --git a/src/core/or/dos_sys.c b/src/core/or/dos_sys.c
new file mode 100644
index 0000000000..03a9ee9140
--- /dev/null
+++ b/src/core/or/dos_sys.c
@@ -0,0 +1,60 @@
+/* Copyright (c) 2021-2021, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * @file dos_sys.c
+ * @brief Subsystem definitions for DOS module.
+ **/
+
+#include "core/or/or.h"
+
+#include "lib/subsys/subsys.h"
+
+#include "core/or/dos_config.h"
+#include "core/or/dos_sys.h"
+
+#include "core/or/dos_options_st.h"
+
+static const dos_options_t *global_dos_options;
+
+static int
+subsys_dos_initialize(void)
+{
+ return 0;
+}
+
+static void
+subsys_dos_shutdown(void)
+{
+ global_dos_options = NULL;
+}
+
+const dos_options_t *
+dos_get_options(void)
+{
+ tor_assert(global_dos_options);
+ return global_dos_options;
+}
+
+static int
+dos_set_options(void *arg)
+{
+ dos_options_t *opts = arg;
+ global_dos_options = opts;
+ return 0;
+}
+
+const struct subsys_fns_t sys_dos = {
+ SUBSYS_DECLARE_LOCATION(),
+
+ .name = "dos",
+ .supported = true,
+ .level = DOS_SUBSYS_LEVEL,
+
+ .initialize = subsys_dos_initialize,
+ .shutdown = subsys_dos_shutdown,
+
+ /* Configuration Options. */
+ .options_format = &dos_options_fmt,
+ .set_options = dos_set_options,
+};
diff --git a/src/core/or/dos_sys.h b/src/core/or/dos_sys.h
new file mode 100644
index 0000000000..8a5364fba5
--- /dev/null
+++ b/src/core/or/dos_sys.h
@@ -0,0 +1,25 @@
+/* Copyright (c) 2021-2021, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * @file dos_sys.h
+ * @brief Header for core/or/dos_sys.c
+ **/
+
+#ifndef TOR_CORE_OR_DOS_SYS_H
+#define TOR_CORE_OR_DOS_SYS_H
+
+struct dos_options_t;
+const struct dos_options_t *dos_get_options(void);
+
+extern const struct subsys_fns_t sys_dos;
+
+/**
+ * Subsystem level for the metrics system.
+ *
+ * Defined here so that it can be shared between the real and stub
+ * definitions.
+ **/
+#define DOS_SUBSYS_LEVEL (21)
+
+#endif /* !defined(TOR_CORE_OR_DOS_SYS_H) */
diff --git a/src/core/or/edge_connection_st.h b/src/core/or/edge_connection_st.h
index 9b2f031b9d..942991f139 100644
--- a/src/core/or/edge_connection_st.h
+++ b/src/core/or/edge_connection_st.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -15,6 +15,7 @@
#include "core/or/or.h"
#include "core/or/connection_st.h"
+#include "lib/evloop/token_bucket.h"
/** Subtype of connection_t for an "edge connection" -- that is, an entry (ap)
* connection, or an exit. */
@@ -33,9 +34,6 @@ struct edge_connection_t {
/** A pointer to which node in the circ this conn exits at. Set for AP
* connections and for hidden service exit connections. */
struct crypt_path_t *cpath_layer;
- /** What rendezvous service are we querying for (if an AP) or providing (if
- * an exit)? */
- rend_data_t *rend_data;
/* Hidden service connection identifier for edge connections. Used by the HS
* client-side code to identify client SOCKS connections and by the
@@ -76,6 +74,60 @@ struct edge_connection_t {
* that's going away and being used on channels instead. We still tag
* edge connections with dirreq_id from circuits, so it's copied here. */
uint64_t dirreq_id;
+
+ /* The following are flow control fields */
+
+ /** Used for rate limiting the read side of this edge connection when
+ * congestion control is enabled on its circuit. The XON cell ewma_drain_rate
+ * parameter is used to set the bucket limits. */
+ token_bucket_rw_t bucket;
+
+ /**
+ * Monotime timestamp of the last time we sent a flow control message
+ * for this edge, used to compute advisory rates */
+ uint64_t drain_start_usec;
+
+ /**
+ * Number of bytes written since we either emptied our buffers,
+ * or sent an advisory drate rate. Can wrap, buf if so,
+ * we must reset the usec timestamp above. (Or make this u64, idk).
+ */
+ uint32_t drained_bytes;
+ uint32_t prev_drained_bytes;
+
+ /**
+ * N_EWMA of the drain rate of writes on this edge conn
+ * while buffers were present.
+ */
+ uint32_t ewma_drain_rate;
+
+ /**
+ * The ewma drain rate the last time we sent an xon.
+ */
+ uint32_t ewma_rate_last_sent;
+
+ /**
+ * The following fields are used to count the total bytes sent on this
+ * stream, and compare them to the number of XON and XOFFs received, so
+ * that clients can check rate limits of XOFF/XON to prevent dropmark
+ * attacks. */
+ uint32_t total_bytes_xmit;
+
+ /** Number of XOFFs received */
+ uint8_t num_xoff_recv;
+
+ /** Number of XONs received */
+ uint8_t num_xon_recv;
+
+ /**
+ * Flag that tells us if an XOFF has been sent; cleared when we send an XON.
+ * Used to avoid sending multiple */
+ uint8_t xoff_sent : 1;
+
+ /** Flag that tells us if an XOFF has been received; cleared when we get
+ * an XON. Used to ensure that this edge keeps reads on its edge socket
+ * disabled. */
+ uint8_t xoff_received : 1;
};
#endif /* !defined(EDGE_CONNECTION_ST_H) */
diff --git a/src/core/or/entry_connection_st.h b/src/core/or/entry_connection_st.h
index 495ffd85dd..500de7521b 100644
--- a/src/core/or/entry_connection_st.h
+++ b/src/core/or/entry_connection_st.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/core/or/entry_port_cfg_st.h b/src/core/or/entry_port_cfg_st.h
index ef1095086d..05c2f4a0be 100644
--- a/src/core/or/entry_port_cfg_st.h
+++ b/src/core/or/entry_port_cfg_st.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/core/or/extend_info_st.h b/src/core/or/extend_info_st.h
index 757c6a1771..2ab0beb7e6 100644
--- a/src/core/or/extend_info_st.h
+++ b/src/core/or/extend_info_st.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -38,6 +38,10 @@ struct extend_info_t {
crypto_pk_t *onion_key;
/** Ntor onion key for this hop. */
curve25519_public_key_t curve25519_onion_key;
+ /** True if this hop is to be used as an _exit_,
+ * and it also supports supports NtorV3 _and_ negotiation
+ * of congestion control parameters */
+ bool exit_supports_congestion_control;
};
#endif /* !defined(EXTEND_INFO_ST_H) */
diff --git a/src/core/or/extendinfo.c b/src/core/or/extendinfo.c
index 22e5b664bb..ca623f09ce 100644
--- a/src/core/or/extendinfo.c
+++ b/src/core/or/extendinfo.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -35,7 +35,9 @@ extend_info_new(const char *nickname,
const ed25519_public_key_t *ed_id,
crypto_pk_t *onion_key,
const curve25519_public_key_t *ntor_key,
- const tor_addr_t *addr, uint16_t port)
+ const tor_addr_t *addr, uint16_t port,
+ const protover_summary_flags_t *pv,
+ bool for_exit_use)
{
extend_info_t *info = tor_malloc_zero(sizeof(extend_info_t));
if (rsa_id_digest)
@@ -56,6 +58,12 @@ extend_info_new(const char *nickname,
if (addr) {
extend_info_add_orport(info, addr, port);
}
+
+ if (pv && for_exit_use) {
+ info->exit_supports_congestion_control =
+ pv->supports_congestion_control;
+ }
+
return info;
}
@@ -89,7 +97,8 @@ extend_info_add_orport(extend_info_t *ei,
* and IP version config.
**/
extend_info_t *
-extend_info_from_node(const node_t *node, int for_direct_connect)
+extend_info_from_node(const node_t *node, int for_direct_connect,
+ bool for_exit)
{
crypto_pk_t *rsa_pubkey = NULL;
extend_info_t *info = NULL;
@@ -149,7 +158,9 @@ extend_info_from_node(const node_t *node, int for_direct_connect)
rsa_pubkey,
curve_pubkey,
&ap.addr,
- ap.port);
+ ap.port,
+ &node->ri->pv,
+ for_exit);
} else if (valid_addr && node->rs && node->md) {
info = extend_info_new(node->rs->nickname,
node->identity,
@@ -157,7 +168,9 @@ extend_info_from_node(const node_t *node, int for_direct_connect)
rsa_pubkey,
curve_pubkey,
&ap.addr,
- ap.port);
+ ap.port,
+ &node->rs->pv,
+ for_exit);
}
crypto_pk_free(rsa_pubkey);
@@ -210,6 +223,15 @@ extend_info_supports_ntor(const extend_info_t* ei)
CURVE25519_PUBKEY_LEN);
}
+/** Return true if we can use the Ntor v3 handshake with `ei` */
+int
+extend_info_supports_ntor_v3(const extend_info_t *ei)
+{
+ tor_assert(ei);
+ return extend_info_supports_ntor(ei) &&
+ ei->exit_supports_congestion_control;
+}
+
/* Does ei have an onion key which it would prefer to use?
* Currently, we prefer ntor keys*/
int
diff --git a/src/core/or/extendinfo.h b/src/core/or/extendinfo.h
index 0049dd0189..6d1f20597b 100644
--- a/src/core/or/extendinfo.h
+++ b/src/core/or/extendinfo.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -17,8 +17,11 @@ extend_info_t *extend_info_new(const char *nickname,
const struct ed25519_public_key_t *ed_id,
crypto_pk_t *onion_key,
const struct curve25519_public_key_t *ntor_key,
- const tor_addr_t *addr, uint16_t port);
-extend_info_t *extend_info_from_node(const node_t *r, int for_direct_connect);
+ const tor_addr_t *addr, uint16_t port,
+ const struct protover_summary_flags_t *pv,
+ bool for_exit_use);
+extend_info_t *extend_info_from_node(const node_t *r, int for_direct_connect,
+ bool for_exit);
extend_info_t *extend_info_dup(extend_info_t *info);
void extend_info_free_(extend_info_t *info);
#define extend_info_free(info) \
@@ -26,6 +29,7 @@ void extend_info_free_(extend_info_t *info);
int extend_info_addr_is_allowed(const tor_addr_t *addr);
int extend_info_supports_tap(const extend_info_t* ei);
int extend_info_supports_ntor(const extend_info_t* ei);
+int extend_info_supports_ntor_v3(const extend_info_t *ei);
int extend_info_has_preferred_onion_key(const extend_info_t* ei);
bool extend_info_has_orport(const extend_info_t *ei,
const tor_addr_t *addr, uint16_t port);
diff --git a/src/core/or/half_edge_st.h b/src/core/or/half_edge_st.h
index c6b6e518fc..642d8e1ea5 100644
--- a/src/core/or/half_edge_st.h
+++ b/src/core/or/half_edge_st.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -31,6 +31,18 @@ typedef struct half_edge_t {
* our deliver window */
int data_pending;
+ /**
+ * Monotime timestamp of when the other end should have successfully
+ * shut down the stream and stop sending data, based on the larger
+ * of circuit RTT and CBT. Used if 'used_ccontrol' is true, to expire
+ * the half_edge at this monotime timestamp. */
+ uint64_t end_ack_expected_usec;
+
+ /**
+ * Did this edge use congestion control? If so, use
+ * timer instead of pending data approach */
+ int used_ccontrol : 1;
+
/** Is there a connected cell pending? */
int connected_pending : 1;
} half_edge_t;
diff --git a/src/core/or/include.am b/src/core/or/include.am
index 7c42268c46..b08f8509cc 100644
--- a/src/core/or/include.am
+++ b/src/core/or/include.am
@@ -18,6 +18,8 @@ LIBTOR_APP_A_SOURCES += \
src/core/or/connection_edge.c \
src/core/or/connection_or.c \
src/core/or/dos.c \
+ src/core/or/dos_config.c \
+ src/core/or/dos_sys.c \
src/core/or/extendinfo.c \
src/core/or/onion.c \
src/core/or/ocirc_event.c \
@@ -26,13 +28,17 @@ LIBTOR_APP_A_SOURCES += \
src/core/or/orconn_event.c \
src/core/or/policies.c \
src/core/or/protover.c \
- src/core/or/protover_rust.c \
src/core/or/reasons.c \
src/core/or/relay.c \
src/core/or/scheduler.c \
src/core/or/scheduler_kist.c \
src/core/or/scheduler_vanilla.c \
src/core/or/sendme.c \
+ src/core/or/congestion_control_common.c \
+ src/core/or/congestion_control_vegas.c \
+ src/core/or/congestion_control_nola.c \
+ src/core/or/congestion_control_westwood.c \
+ src/core/or/congestion_control_flow.c \
src/core/or/status.c \
src/core/or/versions.c
@@ -55,6 +61,7 @@ noinst_HEADERS += \
src/core/or/circuitpadding_machines.h \
src/core/or/circuituse.h \
src/core/or/command.h \
+ src/core/or/congestion_control_st.h \
src/core/or/connection_edge.h \
src/core/or/connection_or.h \
src/core/or/connection_st.h \
@@ -64,6 +71,10 @@ noinst_HEADERS += \
src/core/or/crypt_path_st.h \
src/core/or/destroy_cell_queue_st.h \
src/core/or/dos.h \
+ src/core/or/dos_config.h \
+ src/core/or/dos_options.inc \
+ src/core/or/dos_options_st.h \
+ src/core/or/dos_sys.h \
src/core/or/edge_connection_st.h \
src/core/or/extendinfo.h \
src/core/or/half_edge_st.h \
@@ -71,6 +82,7 @@ noinst_HEADERS += \
src/core/or/entry_port_cfg_st.h \
src/core/or/extend_info_st.h \
src/core/or/listener_connection_st.h \
+ src/core/or/lttng_cc.inc \
src/core/or/lttng_circuit.inc \
src/core/or/onion.h \
src/core/or/or.h \
@@ -91,6 +103,11 @@ noinst_HEADERS += \
src/core/or/relay_crypto_st.h \
src/core/or/scheduler.h \
src/core/or/sendme.h \
+ src/core/or/congestion_control_flow.h \
+ src/core/or/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/server_port_cfg_st.h \
src/core/or/socks_request_st.h \
src/core/or/status.h \
@@ -100,7 +117,9 @@ noinst_HEADERS += \
if USE_TRACING_INSTRUMENTATION_LTTNG
LIBTOR_APP_A_SOURCES += \
+ src/core/or/trace_probes_cc.c \
src/core/or/trace_probes_circuit.c
noinst_HEADERS += \
+ src/core/or/trace_probes_cc.h \
src/core/or/trace_probes_circuit.h
endif
diff --git a/src/core/or/listener_connection_st.h b/src/core/or/listener_connection_st.h
index 78175ea061..5cc3fa2afd 100644
--- a/src/core/or/listener_connection_st.h
+++ b/src/core/or/listener_connection_st.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/core/or/lttng_cc.inc b/src/core/or/lttng_cc.inc
new file mode 100644
index 0000000000..de06fa026f
--- /dev/null
+++ b/src/core/or/lttng_cc.inc
@@ -0,0 +1,166 @@
+/* Copyright (c) 2021, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file lttng_cc.inc
+ * \brief LTTng tracing probe declaration for the congestion control subsystem.
+ * It is in this .inc file due to the non C standard syntax and the way
+ * we guard the header with the LTTng specific
+ * TRACEPOINT_HEADER_MULTI_READ.
+ **/
+
+#include "orconfig.h"
+
+/* We only build the following if LTTng instrumentation has been enabled. */
+#ifdef USE_TRACING_INSTRUMENTATION_LTTNG
+
+/* The following defines are LTTng-UST specific. */
+#undef TRACEPOINT_PROVIDER
+#define TRACEPOINT_PROVIDER tor_cc
+
+#undef TRACEPOINT_INCLUDE
+#define TRACEPOINT_INCLUDE "./src/core/or/lttng_cc.inc"
+
+#if !defined(LTTNG_CC_INC) || defined(TRACEPOINT_HEADER_MULTI_READ)
+#define LTTNG_CC_INC
+
+#include <lttng/tracepoint.h>
+
+/*
+ * Flow Control
+ */
+
+/* Emitted every time the flow_control_decide_xon() function is called. */
+TRACEPOINT_EVENT(tor_cc, flow_decide_xon,
+ TP_ARGS(const edge_connection_t *, stream, size_t, n_written),
+ TP_FIELDS(
+ ctf_integer(uint64_t, stream_id, TO_CONN(stream)->global_identifier)
+ ctf_integer(size_t, written_bytes, n_written)
+ ctf_integer(uint32_t, drained_bytes_current, stream->drained_bytes)
+ ctf_integer(uint32_t, drained_bytes_previous, stream->prev_drained_bytes)
+ ctf_integer(uint32_t, ewma_drain_rate_last, stream->ewma_rate_last_sent)
+ ctf_integer(uint32_t, ewma_drain_rate_current, stream->ewma_drain_rate)
+ ctf_integer(size_t, outbuf_len,
+ connection_get_outbuf_len(TO_CONN(stream)))
+ )
+)
+
+/* Emitted when flow control starts measuring the drain rate. */
+TRACEPOINT_EVENT(tor_cc, flow_decide_xon_drain_start,
+ TP_ARGS(const edge_connection_t *, stream),
+ TP_FIELDS(
+ ctf_integer(uint64_t, stream_id, TO_CONN(stream)->global_identifier)
+ ctf_integer(uint32_t, drained_bytes_current, stream->drained_bytes)
+ ctf_integer(uint32_t, drained_bytes_previous, stream->prev_drained_bytes)
+ ctf_integer(uint32_t, ewma_drain_rate_last, stream->ewma_rate_last_sent)
+ ctf_integer(uint32_t, ewma_drain_rate_current, stream->ewma_drain_rate)
+ ctf_integer(size_t, outbuf_len,
+ connection_get_outbuf_len(TO_CONN(stream)))
+ )
+)
+
+/* Emitted when the drain rate is updated. The new_drain_rate value is what was
+ * just computed. */
+TRACEPOINT_EVENT(tor_cc, flow_decide_xon_drain_update,
+ TP_ARGS(const edge_connection_t *, stream, uint32_t, drain_rate),
+ TP_FIELDS(
+ ctf_integer(uint64_t, stream_id, TO_CONN(stream)->global_identifier)
+ ctf_integer(uint32_t, drained_bytes_current, stream->drained_bytes)
+ ctf_integer(uint32_t, drained_bytes_previous, stream->prev_drained_bytes)
+ ctf_integer(uint32_t, new_drain_rate, drain_rate)
+ ctf_integer(uint32_t, ewma_drain_rate_last, stream->ewma_rate_last_sent)
+ ctf_integer(uint32_t, ewma_drain_rate_current, stream->ewma_drain_rate)
+ ctf_integer(size_t, outbuf_len,
+ connection_get_outbuf_len(TO_CONN(stream)))
+ )
+)
+
+/* Emitted when an XON cell is sent due to a notice in a drain rate change. */
+TRACEPOINT_EVENT(tor_cc, flow_decide_xon_rate_change,
+ TP_ARGS(const edge_connection_t *, stream),
+ TP_FIELDS(
+ ctf_integer(uint64_t, stream_id, TO_CONN(stream)->global_identifier)
+ ctf_integer(uint32_t, drained_bytes_current, stream->drained_bytes)
+ ctf_integer(uint32_t, drained_bytes_previous, stream->prev_drained_bytes)
+ ctf_integer(uint32_t, ewma_drain_rate_last, stream->ewma_rate_last_sent)
+ ctf_integer(uint32_t, ewma_drain_rate_current, stream->ewma_drain_rate)
+ ctf_integer(size_t, outbuf_len,
+ connection_get_outbuf_len(TO_CONN(stream)))
+ )
+)
+
+/* Emitted when an XON cell is sent because we partially or fully drained the
+ * edge connection buffer. */
+TRACEPOINT_EVENT(tor_cc, flow_decide_xon_partial_drain,
+ TP_ARGS(const edge_connection_t *, stream),
+ TP_FIELDS(
+ ctf_integer(uint64_t, stream_id, TO_CONN(stream)->global_identifier)
+ ctf_integer(uint32_t, drained_bytes_current, stream->drained_bytes)
+ ctf_integer(uint32_t, drained_bytes_previous, stream->prev_drained_bytes)
+ ctf_integer(uint32_t, ewma_drain_rate_last, stream->ewma_rate_last_sent)
+ ctf_integer(uint32_t, ewma_drain_rate_current, stream->ewma_drain_rate)
+ ctf_integer(size_t, outbuf_len,
+ connection_get_outbuf_len(TO_CONN(stream)))
+ )
+)
+
+/* Emitted when we double the drain rate which is an attempt to see if we can
+ * speed things up. */
+TRACEPOINT_EVENT(tor_cc, flow_decide_xon_drain_doubled,
+ TP_ARGS(const edge_connection_t *, stream),
+ TP_FIELDS(
+ ctf_integer(uint64_t, stream_id, TO_CONN(stream)->global_identifier)
+ ctf_integer(uint32_t, drained_bytes_current, stream->drained_bytes)
+ ctf_integer(uint32_t, drained_bytes_previous, stream->prev_drained_bytes)
+ ctf_integer(uint32_t, ewma_drain_rate_last, stream->ewma_rate_last_sent)
+ ctf_integer(uint32_t, ewma_drain_rate_current, stream->ewma_drain_rate)
+ ctf_integer(size_t, outbuf_len,
+ connection_get_outbuf_len(TO_CONN(stream)))
+ )
+)
+
+/* XOFF */
+
+/* Emitted when we send an XOFF cell. */
+TRACEPOINT_EVENT(tor_cc, flow_decide_xoff_sending,
+ TP_ARGS(const edge_connection_t *, stream),
+ TP_FIELDS(
+ ctf_integer(uint64_t, stream_id, TO_CONN(stream)->global_identifier)
+ ctf_integer(uint32_t, drained_bytes_current, stream->drained_bytes)
+ ctf_integer(uint32_t, drained_bytes_previous, stream->prev_drained_bytes)
+ ctf_integer(uint32_t, ewma_drain_rate_last, stream->ewma_rate_last_sent)
+ ctf_integer(uint32_t, ewma_drain_rate_current, stream->ewma_drain_rate)
+ ctf_integer(size_t, outbuf_len,
+ connection_get_outbuf_len(TO_CONN(stream)))
+ )
+)
+
+/*
+ * Congestion Control
+ */
+
+/* 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),
+ TP_FIELDS(
+ ctf_integer(uint64_t, circuit_ptr, circ)
+ ctf_integer(uint32_t, n_circ_id, circ->n_circ_id)
+ ctf_integer(uint64_t, min_rtt_usec, cc->min_rtt_usec)
+ 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)
+ )
+)
+
+#endif /* LTTNG_CC_INC || TRACEPOINT_HEADER_MULTI_READ */
+
+/* Must be included after the probes declaration. */
+#include <lttng/tracepoint-event.h>
+
+#endif /* USE_TRACING_INSTRUMENTATION_LTTNG */
diff --git a/src/core/or/ocirc_event.c b/src/core/or/ocirc_event.c
index fa16459175..4e432b1d84 100644
--- a/src/core/or/ocirc_event.c
+++ b/src/core/or/ocirc_event.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2007-2020, The Tor Project, Inc. */
+/* Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/core/or/ocirc_event.h b/src/core/or/ocirc_event.h
index 10307a3664..e9a98929e1 100644
--- a/src/core/or/ocirc_event.h
+++ b/src/core/or/ocirc_event.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2007-2020, The Tor Project, Inc. */
+/* Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/core/or/onion.c b/src/core/or/onion.c
index a3b5c6922d..0bdd2a6d35 100644
--- a/src/core/or/onion.c
+++ b/src/core/or/onion.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -88,6 +88,10 @@ check_create_cell(const create_cell_t *cell, int unknown_ok)
if (cell->handshake_len != NTOR_ONIONSKIN_LEN)
return -1;
break;
+ case ONION_HANDSHAKE_TYPE_NTOR_V3:
+ /* ntor v3 has variable length fields that are checked
+ * elsewhere. Fall through to always valid here. */
+ break;
default:
if (! unknown_ok)
return -1;
@@ -521,6 +525,11 @@ create_cell_format_impl(cell_t *cell_out, const create_cell_t *cell_in,
switch (cell_in->cell_type) {
case CELL_CREATE:
+ if (BUG(cell_in->handshake_type == ONION_HANDSHAKE_TYPE_NTOR_V3)) {
+ log_warn(LD_BUG, "Create cells cannot contain ntorv3.");
+ return -1;
+ }
+
if (cell_in->handshake_type == ONION_HANDSHAKE_TYPE_NTOR) {
memcpy(p, NTOR_CREATE_MAGIC, 16);
p += 16;
@@ -619,6 +628,11 @@ extend_cell_format(uint8_t *command_out, uint16_t *len_out,
switch (cell_in->cell_type) {
case RELAY_COMMAND_EXTEND:
{
+ if (BUG(cell_in->create_cell.handshake_type ==
+ ONION_HANDSHAKE_TYPE_NTOR_V3)) {
+ log_warn(LD_BUG, "Extend cells cannot contain ntorv3!");
+ return -1;
+ }
*command_out = RELAY_COMMAND_EXTEND;
*len_out = 6 + TAP_ONIONSKIN_CHALLENGE_LEN + DIGEST_LEN;
set_uint32(p, tor_addr_to_ipv4n(&cell_in->orport_ipv4.addr));
diff --git a/src/core/or/onion.h b/src/core/or/onion.h
index 0dac21ab6b..bba2e38411 100644
--- a/src/core/or/onion.h
+++ b/src/core/or/onion.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/core/or/or.h b/src/core/or/or.h
index d80c41371e..dc8f516f0a 100644
--- a/src/core/or/or.h
+++ b/src/core/or/or.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -210,6 +210,9 @@ struct curve25519_public_key_t;
#define RELAY_COMMAND_PADDING_NEGOTIATE 41
#define RELAY_COMMAND_PADDING_NEGOTIATED 42
+#define RELAY_COMMAND_XOFF 43
+#define RELAY_COMMAND_XON 44
+
/* Reasons why an OR connection is closed. */
#define END_OR_CONN_REASON_DONE 1
#define END_OR_CONN_REASON_REFUSED 2 /* connection refused */
@@ -328,70 +331,11 @@ struct curve25519_public_key_t;
* passed through from a destroy or truncate cell. */
#define END_CIRC_REASON_FLAG_REMOTE 512
-/** Length of 'y' portion of 'y.onion' URL. */
-#define REND_SERVICE_ID_LEN_BASE32 16
-
-/** Length of 'y.onion' including '.onion' URL. */
-#define REND_SERVICE_ADDRESS_LEN (16+1+5)
-
-/** Length of a binary-encoded rendezvous service ID. */
-#define REND_SERVICE_ID_LEN 10
-
-/** Time period for which a v2 descriptor will be valid. */
-#define REND_TIME_PERIOD_V2_DESC_VALIDITY (24*60*60)
-
-/** Time period within which two sets of v2 descriptors will be uploaded in
- * parallel. */
-#define REND_TIME_PERIOD_OVERLAPPING_V2_DESCS (60*60)
-
-/** Number of non-consecutive replicas (i.e. distributed somewhere
- * in the ring) for a descriptor. */
-#define REND_NUMBER_OF_NON_CONSECUTIVE_REPLICAS 2
-
-/** Number of consecutive replicas for a descriptor. */
-#define REND_NUMBER_OF_CONSECUTIVE_REPLICAS 3
-
-/** Length of v2 descriptor ID (32 base32 chars = 160 bits). */
+/** Length of v2 descriptor ID (32 base32 chars = 160 bits).
+ *
+ * XXX: It is still used by v3 code but should be renamed or maybe removed. */
#define REND_DESC_ID_V2_LEN_BASE32 BASE32_DIGEST_LEN
-/** Length of the base32-encoded secret ID part of versioned hidden service
- * descriptors. */
-#define REND_SECRET_ID_PART_LEN_BASE32 BASE32_DIGEST_LEN
-
-/** Length of the base32-encoded hash of an introduction point's
- * identity key. */
-#define REND_INTRO_POINT_ID_LEN_BASE32 BASE32_DIGEST_LEN
-
-/** Length of the descriptor cookie that is used for client authorization
- * to hidden services. */
-#define REND_DESC_COOKIE_LEN 16
-
-/** Length of the base64-encoded descriptor cookie that is used for
- * exchanging client authorization between hidden service and client. */
-#define REND_DESC_COOKIE_LEN_BASE64 22
-
-/** Length of client identifier in encrypted introduction points for hidden
- * service authorization type 'basic'. */
-#define REND_BASIC_AUTH_CLIENT_ID_LEN 4
-
-/** Multiple of the number of clients to which the real number of clients
- * is padded with fake clients for hidden service authorization type
- * 'basic'. */
-#define REND_BASIC_AUTH_CLIENT_MULTIPLE 16
-
-/** Length of client entry consisting of client identifier and encrypted
- * session key for hidden service authorization type 'basic'. */
-#define REND_BASIC_AUTH_CLIENT_ENTRY_LEN (REND_BASIC_AUTH_CLIENT_ID_LEN \
- + CIPHER_KEY_LEN)
-
-/** Maximum size of v2 hidden service descriptors. */
-#define REND_DESC_MAX_SIZE (20 * 1024)
-
-/** Legal characters for use in authorized client names for a hidden
- * service. */
-#define REND_LEGAL_CLIENTNAME_CHARACTERS \
- "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+-_"
-
/** Maximum length of authorized client names for a hidden service. */
#define REND_CLIENTNAME_MAX_LEN 16
@@ -402,71 +346,10 @@ struct curve25519_public_key_t;
/** Client authorization type that a hidden service performs. */
typedef enum rend_auth_type_t {
REND_NO_AUTH = 0,
- REND_BASIC_AUTH = 1,
- REND_STEALTH_AUTH = 2,
+ REND_V3_AUTH = 1, /* Dummy flag to allow adding v3 services on the
+ * control port */
} rend_auth_type_t;
-/** Client-side configuration of authorization for a hidden service. */
-typedef struct rend_service_authorization_t {
- uint8_t descriptor_cookie[REND_DESC_COOKIE_LEN];
- char onion_address[REND_SERVICE_ADDRESS_LEN+1];
- rend_auth_type_t auth_type;
-} rend_service_authorization_t;
-
-/** Client- and server-side data that is used for hidden service connection
- * establishment. Not all fields contain data depending on where this struct
- * is used. */
-typedef struct rend_data_t {
- /* Hidden service protocol version of this base object. */
- uint32_t version;
-
- /** List of HSDir fingerprints on which this request has been sent to. This
- * contains binary identity digest of the directory of size DIGEST_LEN. */
- smartlist_t *hsdirs_fp;
-
- /** Rendezvous cookie used by both, client and service. */
- char rend_cookie[REND_COOKIE_LEN];
-
- /** Number of streams associated with this rendezvous circuit. */
- int nr_streams;
-} rend_data_t;
-
-typedef struct rend_data_v2_t {
- /* Rendezvous base data. */
- rend_data_t base_;
-
- /** Onion address (without the .onion part) that a client requests. */
- char onion_address[REND_SERVICE_ID_LEN_BASE32+1];
-
- /** Descriptor ID for each replicas computed from the onion address. If
- * the onion address is empty, this array MUST be empty. We keep them so
- * we know when to purge our entry in the last hsdir request table. */
- char descriptor_id[REND_NUMBER_OF_NON_CONSECUTIVE_REPLICAS][DIGEST_LEN];
-
- /** (Optional) descriptor cookie that is used by a client. */
- char descriptor_cookie[REND_DESC_COOKIE_LEN];
-
- /** Authorization type for accessing a service used by a client. */
- rend_auth_type_t auth_type;
-
- /** Descriptor ID for a client request. The control port command HSFETCH
- * uses this. It's set if the descriptor query should only use this
- * descriptor ID. */
- char desc_id_fetch[DIGEST_LEN];
-
- /** Hash of the hidden service's PK used by a service. */
- char rend_pk_digest[DIGEST_LEN];
-} rend_data_v2_t;
-
-/* From a base rend_data_t object <b>d</d>, return the v2 object. */
-static inline
-rend_data_v2_t *TO_REND_DATA_V2(const rend_data_t *d)
-{
- tor_assert(d);
- tor_assert(d->version == 2);
- return DOWNCAST(rend_data_v2_t, d);
-}
-
/* Stub because we can't include hs_ident.h. */
struct hs_ident_edge_conn_t;
struct hs_ident_dir_conn_t;
@@ -711,18 +594,6 @@ typedef struct or_handshake_state_t or_handshake_state_t;
/** Length of Extended ORPort connection identifier. */
#define EXT_OR_CONN_ID_LEN DIGEST_LEN /* 20 */
-/*
- * OR_CONN_HIGHWATER and OR_CONN_LOWWATER moved from connection_or.c so
- * channeltls.c can see them too.
- */
-
-/** When adding cells to an OR connection's outbuf, keep adding until the
- * outbuf is at least this long, or we run out of cells. */
-#define OR_CONN_HIGHWATER (32*1024)
-
-/** Add cells to an OR connection's outbuf whenever the outbuf's data length
- * drops below this size. */
-#define OR_CONN_LOWWATER (16*1024)
typedef struct connection_t connection_t;
typedef struct control_connection_t control_connection_t;
@@ -861,6 +732,9 @@ typedef struct protover_summary_flags_t {
* negotiate hs circuit setup padding. Requires Padding=2. */
unsigned int supports_hs_setup_padding : 1;
+ /** True iff this router supports congestion control.
+ * Requires both FlowCtrl=2 *and* Relay=4 */
+ unsigned int supports_congestion_control : 1;
} protover_summary_flags_t;
typedef struct routerinfo_t routerinfo_t;
@@ -919,7 +793,8 @@ typedef enum {
#define ONION_HANDSHAKE_TYPE_TAP 0x0000
#define ONION_HANDSHAKE_TYPE_FAST 0x0001
#define ONION_HANDSHAKE_TYPE_NTOR 0x0002
-#define MAX_ONION_HANDSHAKE_TYPE 0x0002
+#define ONION_HANDSHAKE_TYPE_NTOR_V3 0x0003
+#define MAX_ONION_HANDSHAKE_TYPE 0x0003
typedef struct onion_handshake_state_t onion_handshake_state_t;
typedef struct relay_crypto_t relay_crypto_t;
@@ -1065,15 +940,9 @@ typedef struct vote_timing_t vote_timing_t;
typedef struct microdesc_cache_t microdesc_cache_t;
-/********************************* rendcommon.c ***************************/
-
-typedef struct rend_authorized_client_t rend_authorized_client_t;
-typedef struct rend_encoded_v2_service_descriptor_t
- rend_encoded_v2_service_descriptor_t;
-
/** The maximum number of non-circuit-build-timeout failures a hidden
* service client will tolerate while trying to build a circuit to an
- * introduction point. See also rend_intro_point_t.unreachable_count. */
+ * introduction point. */
#define MAX_INTRO_POINT_REACHABILITY_FAILURES 5
/** The minimum and maximum number of distinct INTRODUCE2 cells which a
@@ -1102,9 +971,6 @@ typedef struct rend_encoded_v2_service_descriptor_t
* lifetime so this is a hard limit on the amount of time we do that. */
#define MAX_INTRO_POINT_CIRCUIT_RETRIES 3
-typedef struct rend_intro_point_t rend_intro_point_t;
-typedef struct rend_service_descriptor_t rend_service_descriptor_t;
-
/********************************* routerlist.c ***************************/
typedef struct dir_server_t dir_server_t;
diff --git a/src/core/or/or_circuit_st.h b/src/core/or/or_circuit_st.h
index 4e17b1c143..11695ec301 100644
--- a/src/core/or/or_circuit_st.h
+++ b/src/core/or/or_circuit_st.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#ifndef OR_CIRCUIT_ST_H
@@ -52,6 +52,10 @@ struct or_circuit_t {
/** Stores KH for the handshake. */
char rend_circ_nonce[DIGEST_LEN];/* KH in tor-spec.txt */
+ /** Number of cells which we have discarded because of having no next hop,
+ * despite not recognizing the cell. */
+ uint32_t n_cells_discarded_at_end;
+
/** How many more relay_early cells can we send on this circuit, according
* to the specification? */
unsigned int remaining_relay_early_cells : 4;
@@ -63,6 +67,12 @@ struct or_circuit_t {
* statistics. */
unsigned int circuit_carries_hs_traffic_stats : 1;
+ /** True iff this circuit was made with a CREATE_FAST cell, or a CREATE[2]
+ * cell with a TAP handshake. If this is the case and this is a rend circuit,
+ * this is a v2 circuit, otherwise if this is a rend circuit it's a v3
+ * circuit. */
+ bool used_legacy_circuit_handshake;
+
/** Number of cells that were removed from circuit queue; reset every
* time when writing buffer stats to disk. */
uint32_t processed_cells;
@@ -87,4 +97,3 @@ struct or_circuit_t {
};
#endif /* !defined(OR_CIRCUIT_ST_H) */
-
diff --git a/src/core/or/or_connection_st.h b/src/core/or/or_connection_st.h
index d99aaaefad..aceed4d2c4 100644
--- a/src/core/or/or_connection_st.h
+++ b/src/core/or/or_connection_st.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -26,8 +26,6 @@ struct or_connection_t {
* if the other side hasn't shown us a valid identity key. */
char identity_digest[DIGEST_LEN];
- /** Extended ORPort connection identifier. */
- char *ext_or_conn_id;
/** 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
diff --git a/src/core/or/or_handshake_certs_st.h b/src/core/or/or_handshake_certs_st.h
index 31755f04a1..59e187b8c4 100644
--- a/src/core/or/or_handshake_certs_st.h
+++ b/src/core/or/or_handshake_certs_st.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/core/or/or_handshake_state_st.h b/src/core/or/or_handshake_state_st.h
index 050404046d..fffd2f0a12 100644
--- a/src/core/or/or_handshake_state_st.h
+++ b/src/core/or/or_handshake_state_st.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/core/or/or_periodic.c b/src/core/or/or_periodic.c
index 4dfdce14ca..b01790feac 100644
--- a/src/core/or/or_periodic.c
+++ b/src/core/or/or_periodic.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/core/or/or_periodic.h b/src/core/or/or_periodic.h
index 080573a838..bc1488506c 100644
--- a/src/core/or/or_periodic.h
+++ b/src/core/or/or_periodic.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/core/or/or_sys.c b/src/core/or/or_sys.c
index 73c6087dce..d724066276 100644
--- a/src/core/or/or_sys.c
+++ b/src/core/or/or_sys.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/core/or/or_sys.h b/src/core/or/or_sys.h
index 7ee56c8682..f6a66352fc 100644
--- a/src/core/or/or_sys.h
+++ b/src/core/or/or_sys.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/core/or/orconn_event.c b/src/core/or/orconn_event.c
index c30e2dd22f..ad2dac02ae 100644
--- a/src/core/or/orconn_event.c
+++ b/src/core/or/orconn_event.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2007-2020, The Tor Project, Inc. */
+/* Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/core/or/orconn_event.h b/src/core/or/orconn_event.h
index 2653b20d6e..7e1c679e32 100644
--- a/src/core/or/orconn_event.h
+++ b/src/core/or/orconn_event.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/core/or/origin_circuit_st.h b/src/core/or/origin_circuit_st.h
index ca7c4b1bef..73b971f72d 100644
--- a/src/core/or/origin_circuit_st.h
+++ b/src/core/or/origin_circuit_st.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -128,9 +128,6 @@ struct origin_circuit_t {
*/
crypt_path_t *cpath;
- /** Holds all rendezvous data on either client or service side. */
- rend_data_t *rend_data;
-
/** Holds hidden service identifier on either client or service side. This
* is for both introduction and rendezvous circuit. */
struct hs_ident_circuit_t *hs_ident;
@@ -208,34 +205,10 @@ struct origin_circuit_t {
* (in host byte order) for response comparison. */
uint32_t pathbias_probe_nonce;
- /** Set iff this is a hidden-service circuit which has timed out
- * according to our current circuit-build timeout, but which has
- * been kept around because it might still succeed in connecting to
- * its destination, and which is not a fully-connected rendezvous
- * circuit.
- *
- * (We clear this flag for client-side rendezvous circuits when they
- * are 'joined' to the other side's rendezvous circuit, so that
- * connection_ap_handshake_attach_circuit can put client streams on
- * the circuit. We also clear this flag for service-side rendezvous
- * circuits when they are 'joined' to a client's rend circ, but only
- * for symmetry with the client case. Client-side introduction
- * circuits are closed when we get a joined rend circ, and
- * service-side introduction circuits never have this flag set.) */
- unsigned int hs_circ_has_timed_out : 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;
- /** Set iff this is a service-side rendezvous circuit for which a
- * new connection attempt has been launched. We consider launching
- * a new service-side rend circ to a client when the previous one
- * fails; now that we don't necessarily close a service-side rend
- * circ when we launch a new one to the same client, this flag keeps
- * us from launching two retries for the same failed rend circ. */
- unsigned int hs_service_side_rend_circ_has_been_relaunched : 1;
-
/** What commands were sent over this circuit that decremented the
* RELAY_EARLY counter? This is for debugging task 878. */
uint8_t relay_early_commands[MAX_RELAY_EARLY_CELLS_PER_CIRCUIT];
diff --git a/src/core/or/policies.c b/src/core/or/policies.c
index 5f578d9b1a..a53849b4d0 100644
--- a/src/core/or/policies.c
+++ b/src/core/or/policies.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -59,6 +59,9 @@ static smartlist_t *authdir_invalid_policy = NULL;
/** Policy that addresses for incoming router descriptors must <b>not</b>
* match in order to not be marked as BadExit. */
static smartlist_t *authdir_badexit_policy = NULL;
+/** Policy that addresses for incoming router descriptors must <b>not</b>
+ * match in order to not be marked as MiddleOnly. */
+static smartlist_t *authdir_middleonly_policy = NULL;
/** Parsed addr_policy_t describing which addresses we believe we can start
* circuits at. */
@@ -1119,6 +1122,17 @@ authdir_policy_badexit_address(const tor_addr_t *addr, uint16_t port)
return addr_is_in_cc_list(addr, get_options()->AuthDirBadExitCCs);
}
+/** Return 1 if <b>addr</b>:<b>port</b> should be marked as MiddleOnly,
+ * based on <b>authdir_middleonly_policy</b>. Else return 0.
+ */
+int
+authdir_policy_middleonly_address(const tor_addr_t *addr, uint16_t port)
+{
+ if (!addr_policy_permits_tor_addr(addr, port, authdir_middleonly_policy))
+ return 1;
+ return addr_is_in_cc_list(addr, get_options()->AuthDirMiddleOnlyCCs);
+}
+
#define REJECT(arg) \
STMT_BEGIN *msg = tor_strdup(arg); goto err; STMT_END
@@ -1173,6 +1187,9 @@ validate_addr_policies(const or_options_t *options, char **msg)
if (parse_addr_policy(options->AuthDirBadExit, &addr_policy,
ADDR_POLICY_REJECT))
REJECT("Error in AuthDirBadExit entry.");
+ if (parse_addr_policy(options->AuthDirMiddleOnly, &addr_policy,
+ ADDR_POLICY_REJECT))
+ REJECT("Error in AuthDirMiddleOnly entry.");
if (parse_addr_policy(options->ReachableAddresses, &addr_policy,
ADDR_POLICY_ACCEPT))
@@ -1266,6 +1283,9 @@ policies_parse_from_options(const or_options_t *options)
if (load_policy_from_option(options->AuthDirBadExit, "AuthDirBadExit",
&authdir_badexit_policy, ADDR_POLICY_REJECT) < 0)
ret = -1;
+ if (load_policy_from_option(options->AuthDirMiddleOnly, "AuthDirMiddleOnly",
+ &authdir_middleonly_policy, ADDR_POLICY_REJECT) < 0)
+ ret = -1;
if (parse_metrics_port_policy(options) < 0) {
ret = -1;
}
@@ -3112,6 +3132,8 @@ policies_free_all(void)
authdir_invalid_policy = NULL;
addr_policy_list_free(authdir_badexit_policy);
authdir_badexit_policy = NULL;
+ addr_policy_list_free(authdir_middleonly_policy);
+ authdir_middleonly_policy = NULL;
if (!HT_EMPTY(&policy_root)) {
policy_map_ent_t **ent;
diff --git a/src/core/or/policies.h b/src/core/or/policies.h
index 17bd7c869f..e11e1d0ff5 100644
--- a/src/core/or/policies.h
+++ b/src/core/or/policies.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -106,6 +106,7 @@ int metrics_policy_permits_address(const tor_addr_t *addr);
int authdir_policy_permits_address(const tor_addr_t *addr, uint16_t port);
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 validate_addr_policies(const or_options_t *options, char **msg);
void policy_expand_private(smartlist_t **policy);
diff --git a/src/core/or/port_cfg_st.h b/src/core/or/port_cfg_st.h
index f8ff6f8cc8..839309ebc6 100644
--- a/src/core/or/port_cfg_st.h
+++ b/src/core/or/port_cfg_st.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/core/or/protover.c b/src/core/or/protover.c
index d45246cb83..4cd6510da7 100644
--- a/src/core/or/protover.c
+++ b/src/core/or/protover.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2020, The Tor Project, Inc. */
+/* Copyright (c) 2016-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -28,8 +28,6 @@
#include "core/or/versions.h"
#include "lib/tls/tortls.h"
-#ifndef HAVE_RUST
-
static const smartlist_t *get_supported_protocol_list(void);
static int protocol_list_contains(const smartlist_t *protos,
protocol_type_t pr, uint32_t ver);
@@ -387,6 +385,46 @@ 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_CONS_V "1-2"
+#define PR_DESC_V "1-2"
+#define PR_DIRCACHE_V "2"
+#define PR_FLOWCTRL_V "1-2"
+#define PR_HSDIR_V "2"
+#define PR_HSINTRO_V "4-5"
+#define PR_HSREND_V "1-2"
+#define PR_LINK_V "1-5"
+#ifdef HAVE_WORKING_TOR_TLS_GET_TLSSECRETS
+#define PR_LINKAUTH_V "1,3"
+#else
+#define PR_LINKAUTH_V "3"
+#endif
+#define PR_MICRODESC_V "1-2"
+#define PR_PADDING_V "2"
+#define PR_RELAY_V "1-4"
+
+/** Return the string containing the supported version for the given protocol
+ * type. */
+const char *
+protover_get_supported(const protocol_type_t type)
+{
+ switch (type) {
+ case PRT_CONS: return PR_CONS_V;
+ case PRT_DESC: return PR_DESC_V;
+ case PRT_DIRCACHE: return PR_DIRCACHE_V;
+ case PRT_FLOWCTRL: return PR_FLOWCTRL_V;
+ case PRT_HSDIR: return PR_HSDIR_V;
+ case PRT_HSINTRO: return PR_HSINTRO_V;
+ case PRT_HSREND: return PR_HSREND_V;
+ case PRT_LINK: return PR_LINK_V;
+ case PRT_LINKAUTH: return PR_LINKAUTH_V;
+ case PRT_MICRODESC: return PR_MICRODESC_V;
+ case PRT_PADDING: return PR_PADDING_V;
+ case PRT_RELAY: return PR_RELAY_V;
+ default:
+ tor_assert_unreached();
+ }
+}
/** Return the canonical string containing the list of protocols
* that we support.
@@ -433,22 +471,18 @@ protover_get_supported_protocols(void)
*/
return
- "Cons=1-2 "
- "Desc=1-2 "
- "DirCache=2 "
- "FlowCtrl=1 "
- "HSDir=2 "
- "HSIntro=4-5 "
- "HSRend=1-2 "
- "Link=1-5 "
-#ifdef HAVE_WORKING_TOR_TLS_GET_TLSSECRETS
- "LinkAuth=1,3 "
-#else
- "LinkAuth=3 "
-#endif
- "Microdesc=1-2 "
- "Padding=2 "
- "Relay=1-3";
+ "Cons=" PR_CONS_V " "
+ "Desc=" PR_DESC_V " "
+ "DirCache=" PR_DIRCACHE_V " "
+ "FlowCtrl=" PR_FLOWCTRL_V " "
+ "HSDir=" PR_HSDIR_V " "
+ "HSIntro=" PR_HSINTRO_V " "
+ "HSRend=" PR_HSREND_V " "
+ "Link=" PR_LINK_V " "
+ "LinkAuth=" PR_LINKAUTH_V " "
+ "Microdesc=" PR_MICRODESC_V " "
+ "Padding=" PR_PADDING_V " "
+ "Relay=" PR_RELAY_V;
}
/*
@@ -548,7 +582,7 @@ trailing_zeros(uint64_t x)
x>>=1;
}
return i;
-#endif
+#endif /* defined(__GNUC__) */
}
/**
@@ -855,5 +889,3 @@ protover_free_all(void)
supported_protocol_list = NULL;
}
}
-
-#endif /* !defined(HAVE_RUST) */
diff --git a/src/core/or/protover.h b/src/core/or/protover.h
index e557278d63..8f15c02fb2 100644
--- a/src/core/or/protover.h
+++ b/src/core/or/protover.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2020, The Tor Project, Inc. */
+/* Copyright (c) 2016-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -35,6 +35,8 @@ struct smartlist_t;
/** The protover version number where relays can consider IPv6 connections
* canonical */
#define PROTOVER_RELAY_CANONICAL_IPV6 3
+/** The protover version number where relays can accept ntorv3 */
+#define PROTOVER_RELAY_NTOR_V3 4
/** The protover version number that signifies HSv3 intro point support */
#define PROTOVER_HS_INTRO_V3 4
@@ -51,6 +53,9 @@ struct smartlist_t;
/** The protover that signals support for HS circuit setup padding machines */
#define PROTOVER_HS_SETUP_PADDING 2
+/** The protover that signals support for congestion control */
+#define PROTOVER_FLOWCTRL_CC 2
+
/** List of recognized subprotocols. */
/// C_RUST_COUPLED: src/rust/protover/ffi.rs `translate_to_rust`
/// C_RUST_COUPLED: src/rust/protover/protover.rs `Proto`
@@ -70,6 +75,7 @@ typedef enum protocol_type_t {
} protocol_type_t;
bool protover_list_is_invalid(const char *s);
+const char *protover_get_supported(const protocol_type_t type);
int protover_all_supported(const char *s, char **missing);
int protover_is_supported_here(protocol_type_t pr, uint32_t ver);
const char *protover_get_supported_protocols(void);
@@ -103,13 +109,13 @@ typedef struct proto_entry_t {
uint64_t bitmask;
} proto_entry_t;
-#if !defined(HAVE_RUST) && defined(TOR_UNIT_TESTS)
+#if defined(TOR_UNIT_TESTS)
STATIC struct smartlist_t *parse_protocol_list(const char *s);
STATIC char *encode_protocol_list(const struct smartlist_t *sl);
STATIC const char *protocol_type_to_str(protocol_type_t pr);
STATIC int str_to_protocol_type(const char *s, protocol_type_t *pr_out);
STATIC void proto_entry_free_(proto_entry_t *entry);
-#endif /* !defined(HAVE_RUST) && defined(TOR_UNIT_TESTS) */
+#endif /* defined(TOR_UNIT_TESTS) */
#define proto_entry_free(entry) \
FREE_AND_NULL(proto_entry_t, proto_entry_free_, (entry))
diff --git a/src/core/or/protover_rust.c b/src/core/or/protover_rust.c
deleted file mode 100644
index 99f3aa7f69..0000000000
--- a/src/core/or/protover_rust.c
+++ /dev/null
@@ -1,34 +0,0 @@
-/* Copyright (c) 2016-2020, The Tor Project, Inc. */
-/* See LICENSE for licensing information */
-
-/*
- * \file protover_rust.c
- * \brief Provide a C wrapper for functions exposed in /src/rust/protover,
- * and safe translation/handling between the Rust/C boundary.
- */
-
-#include "core/or/or.h"
-#include "core/or/protover.h"
-
-#ifdef HAVE_RUST
-
-/* Define for compatibility, used in main.c */
-void
-protover_free_all(void)
-{
-}
-
-int protover_contains_long_protocol_names_(const char *s);
-
-/**
- * Return true if the unparsed protover in <b>s</b> would contain a protocol
- * name longer than MAX_PROTOCOL_NAME_LENGTH, and false otherwise.
- */
-bool
-protover_list_is_invalid(const char *s)
-{
- return protover_contains_long_protocol_names_(s) != 0;
-}
-
-#endif /* defined(HAVE_RUST) */
-
diff --git a/src/core/or/reasons.c b/src/core/or/reasons.c
index 708f43a689..379f274b27 100644
--- a/src/core/or/reasons.c
+++ b/src/core/or/reasons.c
@@ -1,5 +1,5 @@
/* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/core/or/reasons.h b/src/core/or/reasons.h
index 2e534aab73..41327a3491 100644
--- a/src/core/or/reasons.h
+++ b/src/core/or/reasons.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/core/or/relay.c b/src/core/or/relay.c
index 66b906bfd5..39a7b783ab 100644
--- a/src/core/or/relay.c
+++ b/src/core/or/relay.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -78,12 +78,12 @@
#include "core/or/reasons.h"
#include "core/or/relay.h"
#include "core/crypto/relay_crypto.h"
-#include "feature/rend/rendcache.h"
#include "feature/rend/rendcommon.h"
#include "feature/nodelist/describe.h"
#include "feature/nodelist/routerlist.h"
#include "core/or/scheduler.h"
#include "feature/hs/hs_metrics.h"
+#include "feature/stats/rephist.h"
#include "core/or/cell_st.h"
#include "core/or/cell_queue_st.h"
@@ -97,6 +97,8 @@
#include "feature/nodelist/routerinfo_st.h"
#include "core/or/socks_request_st.h"
#include "core/or/sendme.h"
+#include "core/or/congestion_control_common.h"
+#include "core/or/congestion_control_flow.h"
static edge_connection_t *relay_lookup_conn(circuit_t *circ, cell_t *cell,
cell_direction_t cell_direction,
@@ -115,13 +117,6 @@ static void adjust_exit_policy_from_exitpolicy_failure(origin_circuit_t *circ,
node_t *node,
const tor_addr_t *addr);
-/** Stop reading on edge connections when we have this many cells
- * waiting on the appropriate queue. */
-#define CELL_QUEUE_HIGHWATER_SIZE 256
-/** Start reading from edge connections again when we get down to this many
- * cells. */
-#define CELL_QUEUE_LOWWATER_SIZE 64
-
/** Stats: how many relay cells have originated at this hop, or have
* been relayed onward (not recognized at this hop)?
*/
@@ -133,6 +128,7 @@ uint64_t stats_n_relay_cells_delivered = 0;
/** Stats: how many circuits have we closed due to the cell queue limit being
* reached (see append_cell_to_circuit_queue()) */
uint64_t stats_n_circ_max_cell_reached = 0;
+uint64_t stats_n_circ_max_cell_outq_reached = 0;
/**
* Update channel usage state based on the type of relay cell and
@@ -338,8 +334,17 @@ circuit_receive_relay_cell(cell_t *cell, circuit_t *circ,
}
return 0;
}
- log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
- "Didn't recognize cell, but circ stops here! Closing circ.");
+ if (BUG(CIRCUIT_IS_ORIGIN(circ))) {
+ /* Should be impossible at this point. */
+ return -END_CIRC_REASON_TORPROTOCOL;
+ }
+ or_circuit_t *or_circ = TO_OR_CIRCUIT(circ);
+ if (++or_circ->n_cells_discarded_at_end == 1) {
+ time_t seconds_open = approx_time() - circ->timestamp_created.tv_sec;
+ log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
+ "Didn't recognize a cell, but circ stops here! Closing circuit. "
+ "It was created %ld seconds ago.", (long)seconds_open);
+ }
return -END_CIRC_REASON_TORPROTOCOL;
}
@@ -498,7 +503,7 @@ relay_header_unpack(relay_header_t *dest, const uint8_t *src)
}
/** Convert the relay <b>command</b> into a human-readable string. */
-static const char *
+const char *
relay_command_to_string(uint8_t command)
{
static char buf[64];
@@ -1574,6 +1579,7 @@ process_sendme_cell(const relay_header_t *rh, const cell_t *cell,
}
/* Stream level SENDME cell. */
+ // TODO: Turn this off for cc_alg=1,2,3; use XON/XOFF instead
ret = sendme_process_stream_level(conn, circ, rh->length);
if (ret < 0) {
/* Means we need to close the circuit with reason ret. */
@@ -1738,6 +1744,44 @@ handle_relay_cell_command(cell_t *cell, circuit_t *circ,
}
return 0;
+ case RELAY_COMMAND_XOFF:
+ if (!conn) {
+ if (CIRCUIT_IS_ORIGIN(circ)) {
+ origin_circuit_t *ocirc = TO_ORIGIN_CIRCUIT(circ);
+ if (relay_crypt_from_last_hop(ocirc, layer_hint) &&
+ connection_half_edge_is_valid_data(ocirc->half_streams,
+ rh->stream_id)) {
+ circuit_read_valid_data(ocirc, rh->length);
+ }
+ }
+ return 0;
+ }
+
+ if (circuit_process_stream_xoff(conn, layer_hint, cell)) {
+ if (CIRCUIT_IS_ORIGIN(circ)) {
+ circuit_read_valid_data(TO_ORIGIN_CIRCUIT(circ), rh->length);
+ }
+ }
+ return 0;
+ case RELAY_COMMAND_XON:
+ if (!conn) {
+ if (CIRCUIT_IS_ORIGIN(circ)) {
+ origin_circuit_t *ocirc = TO_ORIGIN_CIRCUIT(circ);
+ if (relay_crypt_from_last_hop(ocirc, layer_hint) &&
+ connection_half_edge_is_valid_data(ocirc->half_streams,
+ rh->stream_id)) {
+ circuit_read_valid_data(ocirc, rh->length);
+ }
+ }
+ return 0;
+ }
+
+ if (circuit_process_stream_xon(conn, layer_hint, cell)) {
+ if (CIRCUIT_IS_ORIGIN(circ)) {
+ circuit_read_valid_data(TO_ORIGIN_CIRCUIT(circ), rh->length);
+ }
+ }
+ return 0;
case RELAY_COMMAND_END:
reason = rh->length > 0 ?
get_uint8(cell->payload+RELAY_HEADER_SIZE) : END_STREAM_REASON_MISC;
@@ -2091,6 +2135,7 @@ void
circuit_reset_sendme_randomness(circuit_t *circ)
{
circ->have_sent_sufficiently_random_cell = 0;
+ // XXX: do we need to change this check for congestion control?
circ->send_randomness_after_n_cells = CIRCWINDOW_INCREMENT / 2 +
crypto_fast_rng_get_uint(get_thread_fast_rng(), CIRCWINDOW_INCREMENT / 2);
}
@@ -2284,7 +2329,7 @@ connection_edge_package_raw_inbuf(edge_connection_t *conn, int package_partial,
}
/* Handle the stream-level SENDME package window. */
- if (sendme_note_stream_data_packaged(conn) < 0) {
+ if (sendme_note_stream_data_packaged(conn, length) < 0) {
connection_stop_reading(TO_CONN(conn));
log_debug(domain,"conn->package_window reached 0.");
circuit_consider_stop_edge_reading(circ, cpath_layer);
@@ -2350,15 +2395,16 @@ circuit_resume_edge_reading_helper(edge_connection_t *first_conn,
/* 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 = circ->package_window;
+
+ 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_HIGHWATER_SIZE - cells_on_queue < max_to_package)
- max_to_package = CELL_QUEUE_HIGHWATER_SIZE - cells_on_queue;
+ 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
@@ -2398,7 +2444,8 @@ 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)
+ if (conn->base_.marked_for_close || conn->package_window <= 0 ||
+ conn->xoff_received)
continue;
if (!layer_hint || conn->cpath_layer == layer_hint) {
connection_start_reading(TO_CONN(conn));
@@ -2409,7 +2456,8 @@ 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)
+ if (conn->base_.marked_for_close || conn->package_window <= 0 ||
+ conn->xoff_received)
continue;
if (!layer_hint || conn->cpath_layer == layer_hint) {
connection_start_reading(TO_CONN(conn));
@@ -2495,7 +2543,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 (circ->package_window <= 0) {
+ if (congestion_control_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));
@@ -2506,7 +2554,7 @@ 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 (layer_hint->package_window <= 0) {
+ if (congestion_control_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) {
@@ -2722,18 +2770,25 @@ cell_queues_get_total_allocation(void)
/** The time at which we were last low on memory. */
static time_t last_time_under_memory_pressure = 0;
+/** Statistics on how many bytes were removed by the OOM per type. */
+uint64_t oom_stats_n_bytes_removed_dns = 0;
+uint64_t oom_stats_n_bytes_removed_cell = 0;
+uint64_t oom_stats_n_bytes_removed_geoip = 0;
+uint64_t oom_stats_n_bytes_removed_hsdir = 0;
+
/** Check whether we've got too much space used for cells. If so,
* call the OOM handler and return 1. Otherwise, return 0. */
STATIC int
cell_queues_check_size(void)
{
+ size_t removed = 0;
time_t now = time(NULL);
size_t alloc = cell_queues_get_total_allocation();
alloc += half_streams_get_total_allocation();
alloc += buf_get_total_allocation();
alloc += tor_compress_get_total_allocation();
- const size_t rend_cache_total = rend_cache_get_total_allocation();
- alloc += rend_cache_total;
+ const size_t hs_cache_total = hs_cache_get_total_allocation();
+ alloc += hs_cache_total;
const size_t geoip_client_cache_total =
geoip_client_cache_total_allocation();
alloc += geoip_client_cache_total;
@@ -2742,26 +2797,36 @@ cell_queues_check_size(void)
if (alloc >= get_options()->MaxMemInQueues_low_threshold) {
last_time_under_memory_pressure = approx_time();
if (alloc >= get_options()->MaxMemInQueues) {
+ /* Note this overload down */
+ rep_hist_note_overload(OVERLOAD_GENERAL);
+
/* If we're spending over 20% of the memory limit on hidden service
* descriptors, free them until we're down to 10%. Do the same for geoip
* client cache. */
- if (rend_cache_total > get_options()->MaxMemInQueues / 5) {
+ if (hs_cache_total > get_options()->MaxMemInQueues / 5) {
const size_t bytes_to_remove =
- rend_cache_total - (size_t)(get_options()->MaxMemInQueues / 10);
- alloc -= hs_cache_handle_oom(now, bytes_to_remove);
+ hs_cache_total - (size_t)(get_options()->MaxMemInQueues / 10);
+ removed = hs_cache_handle_oom(now, bytes_to_remove);
+ oom_stats_n_bytes_removed_hsdir += removed;
+ alloc -= removed;
}
if (geoip_client_cache_total > get_options()->MaxMemInQueues / 5) {
const size_t bytes_to_remove =
geoip_client_cache_total -
(size_t)(get_options()->MaxMemInQueues / 10);
- alloc -= geoip_client_cache_handle_oom(now, bytes_to_remove);
+ removed = geoip_client_cache_handle_oom(now, bytes_to_remove);
+ oom_stats_n_bytes_removed_geoip += removed;
+ alloc -= removed;
}
if (dns_cache_total > get_options()->MaxMemInQueues / 5) {
const size_t bytes_to_remove =
dns_cache_total - (size_t)(get_options()->MaxMemInQueues / 10);
- alloc -= dns_cache_handle_oom(now, bytes_to_remove);
+ removed = dns_cache_handle_oom(now, bytes_to_remove);
+ oom_stats_n_bytes_removed_dns += removed;
+ alloc -= removed;
}
- circuits_handle_oom(alloc);
+ removed = circuits_handle_oom(alloc);
+ oom_stats_n_bytes_removed_cell += removed;
return 1;
}
}
@@ -3059,7 +3124,7 @@ 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_LOWWATER_SIZE)
+ if (streams_blocked && queue->n <= cell_queue_lowwatermark())
set_streams_blocked_on_circ(circ, chan, 0, 0); /* unblock streams */
/* If n_flushed < max still, loop around and pick another circuit */
@@ -3071,6 +3136,9 @@ 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.
+ *
* 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
* queue, we have a maximum of cells possible.
@@ -3093,12 +3161,12 @@ channel_flush_from_first_active_circuit, (channel_t *chan, int max))
* DoS memory pressure so the default size is a middle ground between not
* having any limit and having a very restricted one. This is why we can also
* control it through a consensus parameter. */
-#define RELAY_CIRC_CELL_QUEUE_SIZE_MIN CIRCWINDOW_START_MAX
+#define RELAY_CIRC_CELL_QUEUE_SIZE_MIN 50
/* We can't have a consensus parameter above this value. */
#define RELAY_CIRC_CELL_QUEUE_SIZE_MAX INT32_MAX
/* Default value is set to a large value so we can handle padding cells
- * properly which aren't accounted for in the SENDME window. Default is 50000
- * allowed cells in the queue resulting in ~25MB. */
+ * properly which aren't accounted for in the SENDME window. Default is 2500
+ * allowed cells in the queue resulting in ~1MB. */
#define RELAY_CIRC_CELL_QUEUE_SIZE_DEFAULT \
(50 * RELAY_CIRC_CELL_QUEUE_SIZE_MIN)
@@ -3106,6 +3174,33 @@ channel_flush_from_first_active_circuit, (channel_t *chan, int max))
* every new consensus and controlled by a parameter. */
static int32_t max_circuit_cell_queue_size =
RELAY_CIRC_CELL_QUEUE_SIZE_DEFAULT;
+/** Maximum number of cell on an outbound circuit queue. This is updated at
+ * every new consensus and controlled by a parameter. This default is incorrect
+ * and won't be used at all except in unit tests. */
+static int32_t max_circuit_cell_queue_size_out =
+ RELAY_CIRC_CELL_QUEUE_SIZE_DEFAULT;
+
+/** Return consensus parameter "circ_max_cell_queue_size". The given ns can be
+ * NULL. */
+static uint32_t
+get_param_max_circuit_cell_queue_size(const networkstatus_t *ns)
+{
+ return networkstatus_get_param(ns, "circ_max_cell_queue_size",
+ RELAY_CIRC_CELL_QUEUE_SIZE_DEFAULT,
+ RELAY_CIRC_CELL_QUEUE_SIZE_MIN,
+ RELAY_CIRC_CELL_QUEUE_SIZE_MAX);
+}
+
+/** Return consensus parameter "circ_max_cell_queue_size_out". The given ns can
+ * be NULL. */
+static uint32_t
+get_param_max_circuit_cell_queue_size_out(const networkstatus_t *ns)
+{
+ return networkstatus_get_param(ns, "circ_max_cell_queue_size_out",
+ get_param_max_circuit_cell_queue_size(ns),
+ RELAY_CIRC_CELL_QUEUE_SIZE_MIN,
+ RELAY_CIRC_CELL_QUEUE_SIZE_MAX);
+}
/* Called when the consensus has changed. At this stage, the global consensus
* object has NOT been updated. It is called from
@@ -3117,10 +3212,9 @@ relay_consensus_has_changed(const networkstatus_t *ns)
/* Update the circuit max cell queue size from the consensus. */
max_circuit_cell_queue_size =
- networkstatus_get_param(ns, "circ_max_cell_queue_size",
- RELAY_CIRC_CELL_QUEUE_SIZE_DEFAULT,
- RELAY_CIRC_CELL_QUEUE_SIZE_MIN,
- RELAY_CIRC_CELL_QUEUE_SIZE_MAX);
+ get_param_max_circuit_cell_queue_size(ns);
+ max_circuit_cell_queue_size_out =
+ get_param_max_circuit_cell_queue_size_out(ns);
}
/** Add <b>cell</b> to the queue of <b>circ</b> writing to <b>chan</b>
@@ -3137,6 +3231,7 @@ append_cell_to_circuit_queue(circuit_t *circ, channel_t *chan,
{
or_circuit_t *orcirc = NULL;
cell_queue_t *queue;
+ int32_t max_queue_size;
int streams_blocked;
int exitward;
if (circ->marked_for_close)
@@ -3146,13 +3241,22 @@ append_cell_to_circuit_queue(circuit_t *circ, channel_t *chan,
if (exitward) {
queue = &circ->n_chan_cells;
streams_blocked = circ->streams_blocked_on_n_chan;
+ max_queue_size = max_circuit_cell_queue_size_out;
} else {
orcirc = TO_OR_CIRCUIT(circ);
queue = &orcirc->p_chan_cells;
streams_blocked = circ->streams_blocked_on_p_chan;
+ max_queue_size = max_circuit_cell_queue_size;
}
- if (PREDICT_UNLIKELY(queue->n >= max_circuit_cell_queue_size)) {
+ if (PREDICT_UNLIKELY(queue->n >= max_queue_size)) {
+ /* This DoS defense only applies at the Guard as in the p_chan is likely
+ * a client IP attacking the network. */
+ if (exitward && CIRCUIT_IS_ORCIRC(circ)) {
+ stats_n_circ_max_cell_outq_reached++;
+ dos_note_circ_max_outq(CONST_TO_OR_CIRCUIT(circ)->p_chan);
+ }
+
log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
"%s circuit has %d cells in its queue, maximum allowed is %d. "
"Closing circuit for safety reasons.",
@@ -3177,7 +3281,7 @@ append_cell_to_circuit_queue(circuit_t *circ, channel_t *chan,
/* 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_HIGHWATER_SIZE)
+ if (!streams_blocked && queue->n >= cell_queue_highwatermark())
set_streams_blocked_on_circ(circ, chan, 1, 0); /* block streams */
if (streams_blocked && fromstream) {
diff --git a/src/core/or/relay.h b/src/core/or/relay.h
index 31bed0e01b..3a1f3b0ae5 100644
--- a/src/core/or/relay.h
+++ b/src/core/or/relay.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -15,8 +15,13 @@
extern uint64_t stats_n_relay_cells_relayed;
extern uint64_t stats_n_relay_cells_delivered;
extern uint64_t stats_n_circ_max_cell_reached;
+extern uint64_t stats_n_circ_max_cell_outq_reached;
+
+const char *relay_command_to_string(uint8_t command);
void relay_consensus_has_changed(const networkstatus_t *ns);
+uint32_t relay_get_param_max_circuit_cell_queue_size(
+ const networkstatus_t *ns);
int circuit_receive_relay_cell(cell_t *cell, circuit_t *circ,
cell_direction_t cell_direction);
size_t cell_queues_get_total_allocation(void);
@@ -49,6 +54,11 @@ extern uint64_t stats_n_data_bytes_packaged;
extern uint64_t stats_n_data_cells_received;
extern uint64_t stats_n_data_bytes_received;
+extern uint64_t oom_stats_n_bytes_removed_dns;
+extern uint64_t oom_stats_n_bytes_removed_cell;
+extern uint64_t oom_stats_n_bytes_removed_geoip;
+extern uint64_t oom_stats_n_bytes_removed_hsdir;
+
void dump_cell_pool_usage(int severity);
size_t packed_cell_mem_cost(void);
diff --git a/src/core/or/relay_crypto_st.h b/src/core/or/relay_crypto_st.h
index d92f486a90..32ff86235a 100644
--- a/src/core/or/relay_crypto_st.h
+++ b/src/core/or/relay_crypto_st.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/core/or/scheduler.c b/src/core/or/scheduler.c
index 18f11487d9..e1096eee14 100644
--- a/src/core/or/scheduler.c
+++ b/src/core/or/scheduler.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2020, The Tor Project, Inc. */
+/* Copyright (c) 2013-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "core/or/or.h"
diff --git a/src/core/or/scheduler.h b/src/core/or/scheduler.h
index 82df2b0b0f..7d3c6f7390 100644
--- a/src/core/or/scheduler.h
+++ b/src/core/or/scheduler.h
@@ -1,4 +1,4 @@
-/* * Copyright (c) 2017-2020, The Tor Project, Inc. */
+/* * Copyright (c) 2017-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/core/or/scheduler_kist.c b/src/core/or/scheduler_kist.c
index 8c6a7bd1d1..52bc62f1b4 100644
--- a/src/core/or/scheduler_kist.c
+++ b/src/core/or/scheduler_kist.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017-2020, The Tor Project, Inc. */
+/* Copyright (c) 2017-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -465,9 +465,17 @@ MOCK_IMPL(int, channel_should_write_to_kernel,
MOCK_IMPL(void, channel_write_to_kernel, (channel_t *chan))
{
tor_assert(chan);
+
+ /* This is possible because a channel might have an outbuf table entry even
+ * though it has no more cells in its outbuf. Just move on. */
+ size_t outbuf_len = channel_outbuf_length(chan);
+ if (outbuf_len == 0) {
+ return;
+ }
+
log_debug(LD_SCHED, "Writing %lu bytes to kernel for chan %" PRIu64,
- (unsigned long)channel_outbuf_length(chan),
- chan->global_identifier);
+ (unsigned long) outbuf_len, chan->global_identifier);
+
/* Note that 'connection_handle_write()' may change the scheduler state of
* the channel during the scheduling loop with
* 'connection_or_flushed_some()' -> 'scheduler_channel_wants_writes()'.
diff --git a/src/core/or/scheduler_vanilla.c b/src/core/or/scheduler_vanilla.c
index d862ff8710..345cae4c38 100644
--- a/src/core/or/scheduler_vanilla.c
+++ b/src/core/or/scheduler_vanilla.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017-2020, The Tor Project, Inc. */
+/* Copyright (c) 2017-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/core/or/sendme.c b/src/core/or/sendme.c
index 9cad245b29..90f4dfcf05 100644
--- a/src/core/or/sendme.c
+++ b/src/core/or/sendme.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2019-2020, The Tor Project, Inc. */
+/* Copyright (c) 2019-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -21,6 +21,8 @@
#include "core/or/or_circuit_st.h"
#include "core/or/relay.h"
#include "core/or/sendme.h"
+#include "core/or/congestion_control_common.h"
+#include "core/or/congestion_control_flow.h"
#include "feature/nodelist/networkstatus.h"
#include "lib/ctime/di_ops.h"
#include "trunnel/sendme_cell.h"
@@ -64,13 +66,6 @@ pop_first_cell_digest(const circuit_t *circ)
return NULL;
}
- /* More cell digest than the SENDME window is never suppose to happen. The
- * cell should have been rejected before reaching this point due to its
- * package_window down to 0 leading to a circuit close. Scream loudly but
- * still pop the element so we don't memory leak. */
- tor_assert_nonfatal(smartlist_len(circ->sendme_last_digests) <=
- CIRCWINDOW_START_MAX / CIRCWINDOW_INCREMENT);
-
circ_digest = smartlist_get(circ->sendme_last_digests, 0);
smartlist_del_keeporder(circ->sendme_last_digests, 0);
return circ_digest;
@@ -334,17 +329,18 @@ record_cell_digest_on_circ(circuit_t *circ, const uint8_t *sendme_digest)
/** Return true iff the next cell for the given cell window is expected to be
* a SENDME.
*
- * We are able to know that because the package or deliver window value minus
- * one cell (the possible SENDME cell) should be a multiple of the increment
- * window value. */
-static bool
-circuit_sendme_cell_is_next(int window)
+ * We are able to know that because the package or inflight window value minus
+ * one cell (the possible SENDME cell) should be a multiple of the
+ * cells-per-sendme increment value (set via consensus parameter, negotiated
+ * for the circuit, and passed in as sendme_inc).
+ *
+ * This function is used when recording a cell digest and this is done quite
+ * low in the stack when decrypting or encrypting a cell. The window is only
+ * updated once the cell is actually put in the outbuf.
+ */
+STATIC bool
+circuit_sendme_cell_is_next(int deliver_window, int sendme_inc)
{
- /* At the start of the window, no SENDME will be expected. */
- if (window == CIRCWINDOW_START) {
- return false;
- }
-
/* Are we at the limit of the increment and if not, we don't expect next
* cell is a SENDME.
*
@@ -353,10 +349,12 @@ circuit_sendme_cell_is_next(int window)
* decremented just yet so when this is called, we are currently processing
* the "window - 1" cell.
*
- * This function is used when recording a cell digest and this is done quite
- * low in the stack when decrypting or encrypting a cell. The window is only
- * updated once the cell is actually put in the outbuf. */
- if (((window - 1) % CIRCWINDOW_INCREMENT) != 0) {
+ * Because deliver_window starts at CIRCWINDOW_START and counts down,
+ * to get the actual number of received cells for this check, we must
+ * first convert to receieved cells, or the modulus operator will fail.
+ */
+ tor_assert(deliver_window <= CIRCWINDOW_START);
+ if (((CIRCWINDOW_START - (deliver_window - 1)) % sendme_inc) != 0) {
return false;
}
@@ -378,6 +376,10 @@ sendme_connection_edge_consider_sending(edge_connection_t *conn)
int log_domain = TO_CONN(conn)->type == CONN_TYPE_AP ? LD_APP : LD_EXIT;
+ /* If we use flow control, we do not send stream sendmes */
+ if (edge_uses_flow_control(conn))
+ goto end;
+
/* Don't send it if we still have data to deliver. */
if (connection_outbuf_too_full(TO_CONN(conn))) {
goto end;
@@ -419,15 +421,16 @@ sendme_circuit_consider_sending(circuit_t *circ, crypt_path_t *layer_hint)
{
bool sent_one_sendme = false;
const uint8_t *digest;
+ int sendme_inc = sendme_get_inc_count(circ, layer_hint);
while ((layer_hint ? layer_hint->deliver_window : circ->deliver_window) <=
- CIRCWINDOW_START - CIRCWINDOW_INCREMENT) {
+ CIRCWINDOW_START - sendme_inc) {
log_debug(LD_CIRC,"Queuing circuit sendme.");
if (layer_hint) {
- layer_hint->deliver_window += CIRCWINDOW_INCREMENT;
+ layer_hint->deliver_window += sendme_inc;
digest = cpath_get_sendme_digest(layer_hint);
} else {
- circ->deliver_window += CIRCWINDOW_INCREMENT;
+ circ->deliver_window += sendme_inc;
digest = relay_crypto_get_sendme_digest(&TO_OR_CIRCUIT(circ)->crypto);
}
if (send_circuit_level_sendme(circ, layer_hint, digest) < 0) {
@@ -448,6 +451,9 @@ sendme_circuit_consider_sending(circuit_t *circ, crypt_path_t *layer_hint)
* the length of the SENDME cell payload (excluding the header). The
* cell_payload is the payload.
*
+ * This function validates the SENDME's digest, and then dispatches to
+ * the appropriate congestion control algorithm in use on the circuit.
+ *
* Return 0 on success (the SENDME is valid and the package window has
* been updated properly).
*
@@ -460,6 +466,7 @@ sendme_process_circuit_level(crypt_path_t *layer_hint,
{
tor_assert(circ);
tor_assert(cell_payload);
+ congestion_control_t *cc;
/* Validate the SENDME cell. Depending on the version, different validation
* can be done. An invalid SENDME requires us to close the circuit. */
@@ -467,6 +474,36 @@ sendme_process_circuit_level(crypt_path_t *layer_hint,
return -END_CIRC_REASON_TORPROTOCOL;
}
+ /* origin circuits need to count valid sendmes as valid protocol data */
+ if (CIRCUIT_IS_ORIGIN(circ)) {
+ circuit_read_valid_data(TO_ORIGIN_CIRCUIT(circ), cell_payload_len);
+ }
+
+ // Get CC
+ if (layer_hint) {
+ cc = layer_hint->ccontrol;
+ } else {
+ cc = circ->ccontrol;
+ }
+
+ /* If there is no CC object, assume fixed alg */
+ if (!cc) {
+ return sendme_process_circuit_level_impl(layer_hint, circ);
+ }
+
+ return congestion_control_dispatch_cc_alg(cc, circ, layer_hint);
+}
+
+/**
+ * Process a SENDME for Tor's original fixed window circuit-level flow control.
+ * Updates the package_window and ensures that it does not exceed the max.
+ *
+ * Returns -END_CIRC_REASON_TORPROTOCOL if the max is exceeded, otherwise
+ * returns 0.
+ */
+int
+sendme_process_circuit_level_impl(crypt_path_t *layer_hint, circuit_t *circ)
+{
/* If we are the origin of the circuit, we are the Client so we use the
* layer hint (the Exit hop) for the package window tracking. */
if (CIRCUIT_IS_ORIGIN(circ)) {
@@ -486,10 +523,6 @@ sendme_process_circuit_level(crypt_path_t *layer_hint,
layer_hint->package_window += CIRCWINDOW_INCREMENT;
log_debug(LD_APP, "circ-level sendme at origin, packagewindow %d.",
layer_hint->package_window);
-
- /* We count circuit-level sendme's as valid delivered data because they
- * are rate limited. */
- circuit_read_valid_data(TO_ORIGIN_CIRCUIT(circ), cell_payload_len);
} else {
/* We aren't the origin of this circuit so we are the Exit and thus we
* track the package window with the circuit object. */
@@ -525,6 +558,12 @@ sendme_process_stream_level(edge_connection_t *conn, circuit_t *circ,
tor_assert(conn);
tor_assert(circ);
+ if (edge_uses_flow_control(conn)) {
+ log_fn(LOG_PROTOCOL_WARN, LD_EDGE,
+ "Congestion control got stream sendme");
+ return -END_CIRC_REASON_TORPROTOCOL;
+ }
+
/* Don't allow the other endpoint to request more than our maximum (i.e.
* initial) stream SENDME window worth of data. Well-behaved stock clients
* will not request more than this max (as per the check in the while loop
@@ -582,7 +621,12 @@ int
sendme_stream_data_received(edge_connection_t *conn)
{
tor_assert(conn);
- return --conn->deliver_window;
+
+ if (edge_uses_flow_control(conn)) {
+ return flow_control_decide_xoff(conn);
+ } else {
+ return --conn->deliver_window;
+ }
}
/* Called when a relay DATA cell is packaged on the given circuit. If
@@ -592,34 +636,56 @@ int
sendme_note_circuit_data_packaged(circuit_t *circ, crypt_path_t *layer_hint)
{
int package_window, domain;
+ congestion_control_t *cc;
tor_assert(circ);
- if (CIRCUIT_IS_ORIGIN(circ)) {
- /* Client side. */
- tor_assert(layer_hint);
- --layer_hint->package_window;
- package_window = layer_hint->package_window;
+ if (layer_hint) {
+ cc = layer_hint->ccontrol;
domain = LD_APP;
} else {
- /* Exit side. */
- tor_assert(!layer_hint);
- --circ->package_window;
- package_window = circ->package_window;
+ cc = circ->ccontrol;
domain = LD_EXIT;
}
- log_debug(domain, "Circuit package_window now %d.", package_window);
- return package_window;
+ if (cc) {
+ congestion_control_note_cell_sent(cc, circ, layer_hint);
+ } else {
+ /* Fixed alg uses package_window and must update it */
+
+ if (CIRCUIT_IS_ORIGIN(circ)) {
+ /* Client side. */
+ tor_assert(layer_hint);
+ --layer_hint->package_window;
+ package_window = layer_hint->package_window;
+ } else {
+ /* Exit side. */
+ tor_assert(!layer_hint);
+ --circ->package_window;
+ package_window = circ->package_window;
+ }
+ log_debug(domain, "Circuit package_window now %d.", package_window);
+ }
+
+ /* Return appropriate number designating how many cells can still be sent */
+ return congestion_control_get_package_window(circ, layer_hint);
}
/* Called when a relay DATA cell is packaged for the given edge connection
* conn. Update the package window and return its new value. */
int
-sendme_note_stream_data_packaged(edge_connection_t *conn)
+sendme_note_stream_data_packaged(edge_connection_t *conn, size_t len)
{
tor_assert(conn);
+ if (edge_uses_flow_control(conn)) {
+ flow_control_note_sent_data(conn, len);
+ if (conn->xoff_received)
+ return -1;
+ else
+ return 1;
+ }
+
--conn->package_window;
log_debug(LD_APP, "Stream package_window now %d.", conn->package_window);
return conn->package_window;
@@ -631,20 +697,14 @@ sendme_note_stream_data_packaged(edge_connection_t *conn)
void
sendme_record_cell_digest_on_circ(circuit_t *circ, crypt_path_t *cpath)
{
- int package_window;
uint8_t *sendme_digest;
tor_assert(circ);
- package_window = circ->package_window;
- if (cpath) {
- package_window = cpath->package_window;
- }
-
/* Is this the last cell before a SENDME? The idea is that if the
* package_window reaches a multiple of the increment, after this cell, we
* should expect a SENDME. */
- if (!circuit_sendme_cell_is_next(package_window)) {
+ if (!circuit_sent_cell_for_sendme(circ, cpath)) {
return;
}
@@ -670,7 +730,8 @@ sendme_record_received_cell_digest(circuit_t *circ, crypt_path_t *cpath)
/* Only record if the next cell is expected to be a SENDME. */
if (!circuit_sendme_cell_is_next(cpath ? cpath->deliver_window :
- circ->deliver_window)) {
+ circ->deliver_window,
+ sendme_get_inc_count(circ, cpath))) {
return;
}
@@ -692,8 +753,7 @@ sendme_record_sending_cell_digest(circuit_t *circ, crypt_path_t *cpath)
tor_assert(circ);
/* Only record if the next cell is expected to be a SENDME. */
- if (!circuit_sendme_cell_is_next(cpath ? cpath->package_window :
- circ->package_window)) {
+ if (!circuit_sent_cell_for_sendme(circ, cpath)) {
goto end;
}
diff --git a/src/core/or/sendme.h b/src/core/or/sendme.h
index 05d37ec3bb..bc1daef23d 100644
--- a/src/core/or/sendme.h
+++ b/src/core/or/sendme.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2019-2020, The Tor Project, Inc. */
+/* Copyright (c) 2019-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -22,6 +22,7 @@ void sendme_circuit_consider_sending(circuit_t *circ,
int sendme_process_circuit_level(crypt_path_t *layer_hint,
circuit_t *circ, const uint8_t *cell_payload,
uint16_t cell_payload_len);
+int sendme_process_circuit_level_impl(crypt_path_t *, circuit_t *);
int sendme_process_stream_level(edge_connection_t *conn, circuit_t *circ,
uint16_t cell_body_len);
@@ -32,7 +33,7 @@ int sendme_circuit_data_received(circuit_t *circ, crypt_path_t *layer_hint);
/* Update package window functions. */
int sendme_note_circuit_data_packaged(circuit_t *circ,
crypt_path_t *layer_hint);
-int sendme_note_stream_data_packaged(edge_connection_t *conn);
+int sendme_note_stream_data_packaged(edge_connection_t *conn, size_t len);
/* Record cell digest on circuit. */
void sendme_record_cell_digest_on_circ(circuit_t *circ, crypt_path_t *cpath);
@@ -72,6 +73,8 @@ STATIC ssize_t build_cell_payload_v1(const uint8_t *cell_digest,
STATIC bool sendme_is_valid(const circuit_t *circ,
const uint8_t *cell_payload,
size_t cell_payload_len);
+STATIC bool circuit_sendme_cell_is_next(int deliver_window,
+ int sendme_inc);
#endif /* defined(TOR_UNIT_TESTS) */
diff --git a/src/core/or/server_port_cfg_st.h b/src/core/or/server_port_cfg_st.h
index 69cdb29cbc..64c96679e8 100644
--- a/src/core/or/server_port_cfg_st.h
+++ b/src/core/or/server_port_cfg_st.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/core/or/socks_request_st.h b/src/core/or/socks_request_st.h
index 4bcdb48b92..98e5283474 100644
--- a/src/core/or/socks_request_st.h
+++ b/src/core/or/socks_request_st.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/core/or/status.c b/src/core/or/status.c
index 00a88a3178..11912ffc25 100644
--- a/src/core/or/status.c
+++ b/src/core/or/status.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2020, The Tor Project, Inc. */
+/* Copyright (c) 2010-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -30,6 +30,7 @@
#include "app/config/statefile.h"
#include "feature/hs/hs_stats.h"
#include "feature/hs/hs_service.h"
+#include "core/or/connection_st.h"
#include "core/or/dos.h"
#include "feature/stats/geoip_stats.h"
@@ -105,10 +106,9 @@ log_onion_service_stats(void)
}
log_notice(LD_HEARTBEAT,
- "Our onion service%s received %u v2 and %u v3 INTRODUCE2 cells "
+ "Heartbeat: Our onion service%s received %u v3 INTRODUCE2 cells "
"and attempted to launch %d rendezvous circuits.",
num_services == 1 ? "" : "s",
- hs_stats_get_n_introduce2_v2_cells(),
hs_stats_get_n_introduce2_v3_cells(),
hs_stats_get_n_rendezvous_launches());
}
@@ -131,21 +131,49 @@ static unsigned n_outgoing_ipv6;
* heartbeat message.
**/
void
-note_connection(bool inbound, int family)
+note_connection(bool inbound, const connection_t *conn)
{
- if (family == AF_INET) {
+ if (conn->socket_family == AF_INET) {
if (inbound) {
++n_incoming_ipv4;
} else {
++n_outgoing_ipv4;
}
- } else if (family == AF_INET6) {
+ } else if (conn->socket_family == AF_INET6) {
if (inbound) {
++n_incoming_ipv6;
} else {
++n_outgoing_ipv6;
}
}
+
+ rep_hist_note_conn_opened(inbound, conn->type, conn->socket_family);
+}
+
+/**
+ * @name Counters for unrecognized cells
+ *
+ * Track cells that we drop because they are unrecognized and we have
+ * nobody to send them to.
+ **/
+/**@{*/
+static unsigned n_circs_closed_for_unrecognized_cells;
+static uint64_t n_unrecognized_cells_discarded;
+static uint64_t n_secs_on_circs_with_unrecognized_cells;
+/**@}*/
+
+/**
+ * Note that a circuit has closed @a n_seconds after having been created,
+ * because of one or more unrecognized cells. Also note the number of
+ * unrecognized cells @a n_cells.
+ */
+void
+note_circ_closed_for_unrecognized_cells(time_t n_seconds, uint32_t n_cells)
+{
+ ++n_circs_closed_for_unrecognized_cells;
+ n_unrecognized_cells_discarded += n_cells;
+ if (n_seconds >= 0)
+ n_secs_on_circs_with_unrecognized_cells += (uint64_t) n_seconds;
}
/** Log a "heartbeat" message describing Tor's status and history so that the
@@ -241,6 +269,23 @@ log_heartbeat(time_t now)
(main_loop_idle_count));
}
+ if (n_circs_closed_for_unrecognized_cells) {
+ double avg_time_alive = ((double) n_secs_on_circs_with_unrecognized_cells)
+ / n_circs_closed_for_unrecognized_cells;
+ double avg_cells = ((double) n_unrecognized_cells_discarded)
+ / n_circs_closed_for_unrecognized_cells;
+ log_fn(LOG_NOTICE, LD_HEARTBEAT,
+ "Since our last heartbeat, %u circuits were closed because of "
+ "unrecognized cells while we were the last hop. On average, each "
+ "one was alive for %lf seconds, and had %lf unrecognized cells.",
+ n_circs_closed_for_unrecognized_cells,
+ avg_time_alive,
+ avg_cells);
+ n_circs_closed_for_unrecognized_cells = 0;
+ n_unrecognized_cells_discarded = 0;
+ n_secs_on_circs_with_unrecognized_cells = 0;
+ }
+
/** Now, if we are an HS service, log some stats about our usage */
log_onion_service_stats();
diff --git a/src/core/or/status.h b/src/core/or/status.h
index 271e0dbc9a..55492d24da 100644
--- a/src/core/or/status.h
+++ b/src/core/or/status.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2020, The Tor Project, Inc. */
+/* Copyright (c) 2010-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -11,7 +11,10 @@
#include "lib/testsupport/testsupport.h"
-void note_connection(bool inbound, int family);
+void note_connection(bool inbound, const connection_t *conn);
+void note_circ_closed_for_unrecognized_cells(time_t n_seconds,
+ uint32_t n_cells);
+
int log_heartbeat(time_t now);
#ifdef STATUS_PRIVATE
diff --git a/src/core/or/tor_version_st.h b/src/core/or/tor_version_st.h
index 46644c5eb8..0c8dc11b14 100644
--- a/src/core/or/tor_version_st.h
+++ b/src/core/or/tor_version_st.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/core/or/trace_probes_cc.c b/src/core/or/trace_probes_cc.c
new file mode 100644
index 0000000000..b0ca23e208
--- /dev/null
+++ b/src/core/or/trace_probes_cc.c
@@ -0,0 +1,34 @@
+/* Copyright (c) 2021, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file trace_probes_cc.c
+ * \brief Tracepoint provider source file for the cc subsystem. Probes
+ * are generated within this C file for LTTng-UST
+ **/
+
+#include "orconfig.h"
+
+/*
+ * Following section is specific to LTTng-UST.
+ */
+#ifdef USE_TRACING_INSTRUMENTATION_LTTNG
+
+/* Header files that the probes need. */
+#include "core/or/or.h"
+#include "core/or/channel.h"
+#include "core/or/circuit_st.h"
+#include "core/or/circuitlist.h"
+#include "core/or/congestion_control_common.h"
+#include "core/or/congestion_control_st.h"
+#include "core/or/connection_st.h"
+#include "core/or/edge_connection_st.h"
+#include "core/or/or_circuit_st.h"
+#include "core/or/origin_circuit_st.h"
+
+#define TRACEPOINT_DEFINE
+#define TRACEPOINT_CREATE_PROBES
+
+#include "core/or/trace_probes_cc.h"
+
+#endif /* defined(USE_TRACING_INSTRUMENTATION_LTTNG) */
diff --git a/src/core/or/trace_probes_cc.h b/src/core/or/trace_probes_cc.h
new file mode 100644
index 0000000000..1f87528723
--- /dev/null
+++ b/src/core/or/trace_probes_cc.h
@@ -0,0 +1,22 @@
+/* Copyright (c) 2021, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file trace_probes_cc.c
+ * \brief The tracing probes for the congestion control subsystem.
+ * Currently, only LTTng-UST probes are available.
+ **/
+
+#ifndef TOR_TRACE_PROBES_CC_H
+#define TOR_TRACE_PROBES_CC_H
+
+#include "lib/trace/events.h"
+
+/* We only build the following if LTTng instrumentation has been enabled. */
+#ifdef USE_TRACING_INSTRUMENTATION_LTTNG
+
+#include "core/or/lttng_cc.inc"
+
+#endif /* USE_TRACING_INSTRUMENTATION_LTTNG */
+
+#endif /* !defined(TOR_TRACE_PROBES_CC_H) */
diff --git a/src/core/or/trace_probes_circuit.c b/src/core/or/trace_probes_circuit.c
index b186ffda7f..4ee5a97dff 100644
--- a/src/core/or/trace_probes_circuit.c
+++ b/src/core/or/trace_probes_circuit.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2020, The Tor Project, Inc. */
+/* Copyright (c) 2020-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -25,6 +25,6 @@
#define TRACEPOINT_DEFINE
#define TRACEPOINT_CREATE_PROBES
-#include "trace_probes_circuit.h"
+#include "core/or/trace_probes_circuit.h"
-#endif /* USE_TRACING_INSTRUMENTATION_LTTNG */
+#endif /* defined(USE_TRACING_INSTRUMENTATION_LTTNG) */
diff --git a/src/core/or/trace_probes_circuit.h b/src/core/or/trace_probes_circuit.h
index 59f53c324a..4ddc46365f 100644
--- a/src/core/or/trace_probes_circuit.h
+++ b/src/core/or/trace_probes_circuit.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2020, The Tor Project, Inc. */
+/* Copyright (c) 2020-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -19,4 +19,4 @@
#endif /* USE_TRACING_INSTRUMENTATION_LTTNG */
-#endif /* TOR_TRACE_PROBES_CIRCUIT_H */
+#endif /* !defined(TOR_TRACE_PROBES_CIRCUIT_H) */
diff --git a/src/core/or/var_cell_st.h b/src/core/or/var_cell_st.h
index caf64c63a5..7a5bc9581b 100644
--- a/src/core/or/var_cell_st.h
+++ b/src/core/or/var_cell_st.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/core/or/versions.c b/src/core/or/versions.c
index 5dfe0c2cc9..9913b3ee31 100644
--- a/src/core/or/versions.c
+++ b/src/core/or/versions.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -482,6 +482,12 @@ memoize_protover_summary(protover_summary_flags_t *out,
protocol_list_supports_protocol(protocols, PRT_PADDING,
PROTOVER_HS_SETUP_PADDING);
+ out->supports_congestion_control =
+ protocol_list_supports_protocol(protocols, PRT_FLOWCTRL,
+ PROTOVER_FLOWCTRL_CC) &&
+ protocol_list_supports_protocol(protocols, PRT_RELAY,
+ PROTOVER_RELAY_NTOR_V3);
+
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/core/or/versions.h b/src/core/or/versions.h
index 75dc17f9c7..4c4c22cb41 100644
--- a/src/core/or/versions.h
+++ b/src/core/or/versions.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/core/proto/proto_cell.c b/src/core/proto/proto_cell.c
index 5c1a2c24d7..2bee0a820f 100644
--- a/src/core/proto/proto_cell.c
+++ b/src/core/proto/proto_cell.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/core/proto/proto_cell.h b/src/core/proto/proto_cell.h
index 0e9cfbfed3..bf2b8ec3c6 100644
--- a/src/core/proto/proto_cell.h
+++ b/src/core/proto/proto_cell.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/core/proto/proto_control0.c b/src/core/proto/proto_control0.c
index 323b37c539..ee26df01a4 100644
--- a/src/core/proto/proto_control0.c
+++ b/src/core/proto/proto_control0.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/core/proto/proto_control0.h b/src/core/proto/proto_control0.h
index 561bf00d19..c2a42c34c7 100644
--- a/src/core/proto/proto_control0.h
+++ b/src/core/proto/proto_control0.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/core/proto/proto_ext_or.c b/src/core/proto/proto_ext_or.c
index 23fc2393b7..d2789f809f 100644
--- a/src/core/proto/proto_ext_or.c
+++ b/src/core/proto/proto_ext_or.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/core/proto/proto_ext_or.h b/src/core/proto/proto_ext_or.h
index 3408599fb7..68f2d46993 100644
--- a/src/core/proto/proto_ext_or.h
+++ b/src/core/proto/proto_ext_or.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/core/proto/proto_haproxy.c b/src/core/proto/proto_haproxy.c
index 9129fc55bf..b082ef99e0 100644
--- a/src/core/proto/proto_haproxy.c
+++ b/src/core/proto/proto_haproxy.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2019-2020, The Tor Project, Inc. */
+/* Copyright (c) 2019-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define PROTO_HAPROXY_PRIVATE
diff --git a/src/core/proto/proto_haproxy.h b/src/core/proto/proto_haproxy.h
index 63c164e1a1..b1b7b06566 100644
--- a/src/core/proto/proto_haproxy.h
+++ b/src/core/proto/proto_haproxy.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2019-2020, The Tor Project, Inc. */
+/* Copyright (c) 2019-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#ifndef TOR_PROTO_HAPROXY_H
diff --git a/src/core/proto/proto_http.c b/src/core/proto/proto_http.c
index ef4b897fcc..8997eb6942 100644
--- a/src/core/proto/proto_http.c
+++ b/src/core/proto/proto_http.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/core/proto/proto_http.h b/src/core/proto/proto_http.h
index e0c5135346..e77347999b 100644
--- a/src/core/proto/proto_http.h
+++ b/src/core/proto/proto_http.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/core/proto/proto_socks.c b/src/core/proto/proto_socks.c
index 97863d389e..07177c418a 100644
--- a/src/core/proto/proto_socks.c
+++ b/src/core/proto/proto_socks.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/core/proto/proto_socks.h b/src/core/proto/proto_socks.h
index f3af0d988e..814af0c67b 100644
--- a/src/core/proto/proto_socks.h
+++ b/src/core/proto/proto_socks.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/ext/ed25519/donna/test-ticks.h b/src/ext/ed25519/donna/test-ticks.h
index 0103e03dde..16cec9ba92 100644
--- a/src/ext/ed25519/donna/test-ticks.h
+++ b/src/ext/ed25519/donna/test-ticks.h
@@ -13,7 +13,7 @@ get_ticks(void) {
__asm__ __volatile__("rdtsc" : "=a" (lo), "=d" (hi));
return ((uint64_t)lo | ((uint64_t)hi << 32));
#else
- need rdtsc for this compiler
+ #error need rdtsc for this compiler
#endif
#elif defined(OS_SOLARIS)
return (uint64_t)gethrtime();
@@ -35,7 +35,7 @@ get_ticks(void) {
t = ((uint64_t)t2.tv_usec << 32) | (uint64_t)t2.tv_sec;
return t;
#else
- need ticks for this platform
+ #error need ticks for this platform
#endif
}
diff --git a/src/ext/rust b/src/ext/rust
deleted file mode 160000
-Subproject aa37fb84fb829902e83ca11a7244bbc6b86b809
diff --git a/src/feature/api/tor_api.c b/src/feature/api/tor_api.c
index 531793301e..88e91ebfd5 100644
--- a/src/feature/api/tor_api.c
+++ b/src/feature/api/tor_api.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -18,9 +18,9 @@
// Include this after the above headers, to insure that they don't
// depend on anything else.
#include "orconfig.h"
+#include "lib/cc/compat_compiler.h"
#include "lib/cc/torint.h"
#include "feature/api/tor_api_internal.h"
-#include "lib/cc/compat_compiler.h"
#include <stdio.h>
#include <stdlib.h>
@@ -39,7 +39,9 @@
#include "lib/net/socketpair.h"
#define raw_socketpair tor_ersatz_socketpair
#define raw_closesocket closesocket
+#if !defined(HAVE_SNPRINTF)
#define snprintf _snprintf
+#endif
#else /* !defined(_WIN32) */
#define raw_socketpair socketpair
#define raw_closesocket close
diff --git a/src/feature/api/tor_api.h b/src/feature/api/tor_api.h
index e9993bb0d5..4391c77c5a 100644
--- a/src/feature/api/tor_api.h
+++ b/src/feature/api/tor_api.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/api/tor_api_internal.h b/src/feature/api/tor_api_internal.h
index d52b2caf44..5075922676 100644
--- a/src/feature/api/tor_api_internal.h
+++ b/src/feature/api/tor_api_internal.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/client/addressmap.c b/src/feature/client/addressmap.c
index e5bf2cc49c..8c3fb9a418 100644
--- a/src/feature/client/addressmap.c
+++ b/src/feature/client/addressmap.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -576,7 +576,7 @@ void
addressmap_register(const char *address, char *new_address, time_t expires,
addressmap_entry_source_t source,
const int wildcard_addr,
- const int wildcard_new_addr)
+ const int wildcard_new_addr, uint64_t stream_id)
{
addressmap_entry_t *ent;
@@ -626,7 +626,8 @@ addressmap_register(const char *address, char *new_address, time_t expires,
log_info(LD_CONFIG, "Addressmap: (re)mapped '%s' to '%s'",
safe_str_client(address),
safe_str_client(ent->new_address));
- control_event_address_mapped(address, ent->new_address, expires, NULL, 1);
+ control_event_address_mapped(address, ent->new_address,
+ expires, NULL, 1, stream_id);
}
/** An attempt to resolve <b>address</b> failed at some OR.
@@ -680,11 +681,15 @@ client_dns_set_addressmap_impl(entry_connection_t *for_conn,
int ttl)
{
char *extendedaddress=NULL, *extendedval=NULL;
- (void)for_conn;
+ uint64_t stream_id = 0;
tor_assert(address);
tor_assert(name);
+ if (for_conn) {
+ stream_id = ENTRY_TO_CONN(for_conn)->global_identifier;
+ }
+
if (ttl<0)
ttl = DEFAULT_DNS_TTL;
else
@@ -705,7 +710,7 @@ client_dns_set_addressmap_impl(entry_connection_t *for_conn,
"%s", name);
}
addressmap_register(extendedaddress, extendedval,
- time(NULL) + ttl, ADDRMAPSRC_DNS, 0, 0);
+ time(NULL) + ttl, ADDRMAPSRC_DNS, 0, 0, stream_id);
tor_free(extendedaddress);
}
@@ -1043,7 +1048,7 @@ addressmap_register_virtual_address(int type, char *new_address)
log_info(LD_APP, "Registering map from %s to %s", *addrp, new_address);
if (vent_needs_to_be_added)
strmap_set(virtaddress_reversemap, new_address, vent);
- addressmap_register(*addrp, new_address, 2, ADDRMAPSRC_AUTOMAP, 0, 0);
+ addressmap_register(*addrp, new_address, 2, ADDRMAPSRC_AUTOMAP, 0, 0, 0);
/* FFFF register corresponding reverse mapping. */
diff --git a/src/feature/client/addressmap.h b/src/feature/client/addressmap.h
index 7f1024e09a..54d3628a53 100644
--- a/src/feature/client/addressmap.h
+++ b/src/feature/client/addressmap.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -36,7 +36,7 @@ int addressmap_have_mapping(const char *address, int update_timeout);
void addressmap_register(const char *address, char *new_address,
time_t expires, addressmap_entry_source_t source,
const int address_wildcard,
- const int new_address_wildcard);
+ const int new_address_wildcard, uint64_t stream_id);
int parse_virtual_addr_network(const char *val,
sa_family_t family, int validate_only,
char **msg);
diff --git a/src/feature/client/bridges.c b/src/feature/client/bridges.c
index 96c3497c6f..9e36d26929 100644
--- a/src/feature/client/bridges.c
+++ b/src/feature/client/bridges.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -943,9 +943,17 @@ rewrite_node_address_for_bridge(const bridge_info_t *bridge, node_t *node)
}
/** We just learned a descriptor for a bridge. See if that
- * digest is in our entry guard list, and add it if not. */
+ * digest is in our entry guard list, and add it if not. Schedule the
+ * next fetch for a long time from now, and initiate any follow-up
+ * activities like continuing to bootstrap.
+ *
+ * <b>from_cache</b> * tells us whether we fetched it from disk (else
+ * the network)
+ *
+ * <b>desc_is_new</b> tells us if we preferred it to the old version we
+ * had, if any. */
void
-learned_bridge_descriptor(routerinfo_t *ri, int from_cache)
+learned_bridge_descriptor(routerinfo_t *ri, int from_cache, int desc_is_new)
{
tor_assert(ri);
tor_assert(ri->purpose == ROUTER_PURPOSE_BRIDGE);
@@ -961,12 +969,14 @@ learned_bridge_descriptor(routerinfo_t *ri, int from_cache)
if (bridge) { /* if we actually want to use this one */
node_t *node;
- /* it's here; schedule its re-fetch for a long time from now. */
if (!from_cache) {
/* This schedules the re-fetch at a constant interval, which produces
* a pattern of bridge traffic. But it's better than trying all
* configured bridges several times in the first few minutes. */
download_status_reset(&bridge->fetch_status);
+ /* it's here; schedule its re-fetch for a long time from now. */
+ bridge->fetch_status.next_attempt_at +=
+ get_options()->TestingBridgeDownloadInitialDelay;
}
node = node_get_mutable_by_id(ri->cache_info.identity_digest);
@@ -982,8 +992,10 @@ learned_bridge_descriptor(routerinfo_t *ri, int from_cache)
entry_guard_learned_bridge_identity(&bridge->addrport_configured,
(const uint8_t*)ri->cache_info.identity_digest);
- log_notice(LD_DIR, "new bridge descriptor '%s' (%s): %s", ri->nickname,
- from_cache ? "cached" : "fresh", router_describe(ri));
+ if (desc_is_new)
+ log_notice(LD_DIR, "new bridge descriptor '%s' (%s): %s",
+ ri->nickname,
+ from_cache ? "cached" : "fresh", router_describe(ri));
/* If we didn't have a reachable bridge before this one, try directory
* documents again. */
if (first) {
diff --git a/src/feature/client/bridges.h b/src/feature/client/bridges.h
index f5ecc1b76d..dd3e498a0a 100644
--- a/src/feature/client/bridges.h
+++ b/src/feature/client/bridges.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -46,7 +46,8 @@ void learned_router_identity(const tor_addr_t *addr, uint16_t port,
void bridge_add_from_config(struct bridge_line_t *bridge_line);
void retry_bridge_descriptor_fetch_directly(const char *digest);
void fetch_bridge_descriptors(const or_options_t *options, time_t now);
-void learned_bridge_descriptor(routerinfo_t *ri, int from_cache);
+void learned_bridge_descriptor(routerinfo_t *ri,
+ int from_cache, int desc_is_new);
const smartlist_t *get_socks_args_by_bridge_addrport(const tor_addr_t *addr,
uint16_t port);
diff --git a/src/feature/client/circpathbias.c b/src/feature/client/circpathbias.c
index 29264135f9..ff9e05a645 100644
--- a/src/feature/client/circpathbias.c
+++ b/src/feature/client/circpathbias.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/client/circpathbias.h b/src/feature/client/circpathbias.h
index 88cc982dd4..e92756ae78 100644
--- a/src/feature/client/circpathbias.h
+++ b/src/feature/client/circpathbias.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/client/dnsserv.c b/src/feature/client/dnsserv.c
index c1981ecde0..f0bb0af100 100644
--- a/src/feature/client/dnsserv.c
+++ b/src/feature/client/dnsserv.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2007-2020, The Tor Project, Inc. */
+/* Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -65,6 +65,9 @@ evdns_server_callback(struct evdns_server_request *req, void *data_)
log_info(LD_APP, "Got a new DNS request!");
+ /* Receiving a request on the DNSPort counts as user activity. */
+ note_user_activity(approx_time());
+
req->flags |= 0x80; /* set RA */
/* First, check whether the requesting address matches our SOCKSPolicy. */
diff --git a/src/feature/client/dnsserv.h b/src/feature/client/dnsserv.h
index 4011cb4e02..ef2c8420c4 100644
--- a/src/feature/client/dnsserv.h
+++ b/src/feature/client/dnsserv.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/client/entrynodes.c b/src/feature/client/entrynodes.c
index 82866ea668..e7324487da 100644
--- a/src/feature/client/entrynodes.c
+++ b/src/feature/client/entrynodes.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -132,6 +132,7 @@
#include "feature/client/entrynodes.h"
#include "feature/client/transports.h"
#include "feature/control/control_events.h"
+#include "feature/dirclient/dlstatus.h"
#include "feature/dircommon/directory.h"
#include "feature/nodelist/describe.h"
#include "feature/nodelist/microdesc.h"
@@ -559,7 +560,7 @@ get_extreme_restriction_threshold(void)
int32_t pct = networkstatus_get_param(NULL,
"guard-extreme-restriction-percent",
DFLT_EXTREME_RESTRICTION_PERCENT,
- 1, INT32_MAX);
+ 1, 100);
return pct / 100.0;
}
@@ -576,6 +577,18 @@ mark_guard_maybe_reachable(entry_guard_t *guard)
guard->is_reachable = GUARD_REACHABLE_MAYBE;
if (guard->is_filtered_guard)
guard->is_usable_filtered_guard = 1;
+
+ /* Check if it is a bridge and we don't have its descriptor yet */
+ if (guard->bridge_addr && !guard_has_descriptor(guard)) {
+ /* Reset the descriptor fetch retry schedule, so it gives it another
+ * go soon. It's important to keep any "REACHABLE_MAYBE" bridges in
+ * sync with the descriptor fetch schedule, since we will refuse to
+ * use the network until our first primary bridges are either
+ * known-usable or known-unusable. See bug 40396. */
+ download_status_t *dl = get_bridge_dl_status_by_id(guard->identity);
+ if (dl)
+ download_status_reset(dl);
+ }
}
/**
@@ -2046,6 +2059,14 @@ entry_guard_consider_retry(entry_guard_t *guard)
get_retry_schedule(guard->failing_since, now, guard->is_primary);
const time_t last_attempt = guard->last_tried_to_connect;
+ /* Check if it is a bridge and we don't have its descriptor yet */
+ if (guard->bridge_addr && !guard_has_descriptor(guard)) {
+ /* We want to leave the retry schedule to fetch_bridge_descriptors(),
+ * so we don't have two retry schedules clobbering each other. See
+ * bugs 40396 and 40497 for details of why we need this exception. */
+ return;
+ }
+
if (BUG(last_attempt == 0) ||
now >= last_attempt + delay) {
/* We should mark this retriable. */
@@ -2271,6 +2292,13 @@ entry_guards_note_guard_failure(guard_selection_t *gs,
guard->is_primary?"primary ":"",
guard->confirmed_idx>=0?"confirmed ":"",
entry_guard_describe(guard));
+
+ /* Schedule a re-assessment of whether we have enough dir info to
+ * use the network. Counterintuitively, *losing* a bridge might actually
+ * be just what we need to *resume* using the network, if we had it in
+ * state GUARD_REACHABLE_MAYBE and we were stalling to learn this
+ * outcome. See bug 40396 for more details. */
+ router_dir_info_changed();
}
/**
@@ -2295,6 +2323,12 @@ entry_guards_note_guard_success(guard_selection_t *gs,
/* If guard was not already marked as reachable, send a GUARD UP signal */
if (guard->is_reachable != GUARD_REACHABLE_YES) {
control_event_guard(guard->nickname, guard->identity, "UP");
+
+ /* Schedule a re-assessment of whether we have enough dir info to
+ * use the network. One of our guards has just moved to
+ * GUARD_REACHABLE_YES, so maybe we can resume using the network
+ * now. */
+ router_dir_info_changed();
}
guard->is_reachable = GUARD_REACHABLE_YES;
@@ -2709,7 +2743,7 @@ entry_guards_upgrade_waiting_circuits(guard_selection_t *gs,
{NONPRIMARY_GUARD_CONNECT_TIMEOUT} seconds."
*/
circuit_guard_state_t *state = origin_circuit_get_guard_state(circ);
- if BUG((state == NULL))
+ if (BUG(state == NULL))
continue;
if (state->state != GUARD_CIRC_STATE_COMPLETE)
continue;
@@ -3538,6 +3572,11 @@ entry_guards_changed_for_guard_selection(guard_selection_t *gs)
entry_guards_update_guards_in_state()
*/
or_state_mark_dirty(get_or_state(), when);
+
+ /* Schedule a re-assessment of whether we have enough dir info to
+ * use the network. When we add or remove or disable or enable a
+ * guard, the decision could shift. */
+ router_dir_info_changed();
}
/** Our list of entry guards has changed for the default guard selection
@@ -3850,7 +3889,7 @@ guards_retry_optimistic(const or_options_t *options)
* Check if we are missing any crucial dirinfo for the guard subsystem to
* work. Return NULL if everything went well, otherwise return a newly
* allocated string with an informative error message. In the latter case, use
- * the genreal descriptor information <b>using_mds</b>, <b>num_present</b> and
+ * the general descriptor information <b>using_mds</b>, <b>num_present</b> and
* <b>num_usable</b> to improve the error message. */
char *
guard_selection_get_err_str_if_dir_info_missing(guard_selection_t *gs,
@@ -3930,6 +3969,263 @@ guard_selection_free_(guard_selection_t *gs)
tor_free(gs);
}
+/**********************************************************************/
+
+/** Layer2 guard subsystem (vanguards-lite) used for onion service circuits */
+
+/** A simple representation of a layer2 guard. We just need its identity so
+ * that we feed it into a routerset, and a sampled timestamp to do expiration
+ * checks. */
+typedef struct layer2_guard_t {
+ /** Identity of the guard */
+ char identity[DIGEST_LEN];
+ /** When does this guard expire? (randomized timestamp) */
+ time_t expire_on_date;
+} layer2_guard_t;
+
+#define layer2_guard_free(val) \
+ FREE_AND_NULL(layer2_guard_t, layer2_guard_free_, (val))
+
+/** Return true if the vanguards-lite subsystem is enabled */
+bool
+vanguards_lite_is_enabled(void)
+{
+ /* First check torrc option and then maybe also the consensus parameter. */
+ const or_options_t *options = get_options();
+
+ /* If the option is explicitly disabled, that's the final word here */
+ if (options->VanguardsLiteEnabled == 0) {
+ return false;
+ }
+
+ /* If the option is set to auto, then check the consensus parameter */
+ if (options->VanguardsLiteEnabled == -1) {
+ return networkstatus_get_param(NULL, "vanguards-lite-enabled",
+ 1, /* default to "on" */
+ 0, 1);
+ }
+
+ /* else it's enabled */
+ tor_assert_nonfatal(options->VanguardsLiteEnabled == 1);
+ return options->VanguardsLiteEnabled;
+}
+
+static void
+layer2_guard_free_(layer2_guard_t *l2)
+{
+ if (!l2) {
+ return;
+ }
+
+ tor_free(l2);
+}
+
+/** Global list and routerset of L2 guards. They are both synced and they get
+ * updated periodically. We need both the list and the routerset: we use the
+ * smartlist to keep track of expiration times and the routerset is what we
+ * return to the users of this subsystem. */
+static smartlist_t *layer2_guards = NULL;
+static routerset_t *layer2_routerset = NULL;
+
+/** Number of L2 guards */
+#define NUMBER_SECOND_GUARDS 4
+/** Make sure that the number of L2 guards is less than the number of
+ * MAX_SANE_RESTRICTED_NODES */
+CTASSERT(NUMBER_SECOND_GUARDS < 20);
+
+/** Lifetime of L2 guards:
+ * 1 to 12 days, for an average of a week using the max(x,x) distribution */
+#define MIN_SECOND_GUARD_LIFETIME (3600*24)
+#define MAX_SECOND_GUARD_LIFETIME (3600*24*12)
+
+/** Return the number of guards our L2 guardset should have */
+static int
+get_number_of_layer2_hs_guards(void)
+{
+ return (int) networkstatus_get_param(NULL,
+ "guard-hs-l2-number",
+ NUMBER_SECOND_GUARDS,
+ 1, 19);
+}
+
+/** Return the minimum lifetime of L2 guards */
+static int
+get_min_lifetime_of_layer2_hs_guards(void)
+{
+ return (int) networkstatus_get_param(NULL,
+ "guard-hs-l2-lifetime-min",
+ MIN_SECOND_GUARD_LIFETIME,
+ 1, INT32_MAX);
+}
+
+/** Return the maximum lifetime of L2 guards */
+static int
+get_max_lifetime_of_layer2_hs_guards(void)
+{
+ return (int) networkstatus_get_param(NULL,
+ "guard-hs-l2-lifetime-max",
+ MAX_SECOND_GUARD_LIFETIME,
+ 1, INT32_MAX);
+}
+
+/**
+ * Sample and return a lifetime for an L2 guard.
+ *
+ * Lifetime randomized uniformly between min and max consensus params.
+ */
+static int
+get_layer2_hs_guard_lifetime(void)
+{
+ int min = get_min_lifetime_of_layer2_hs_guards();
+ int max = get_max_lifetime_of_layer2_hs_guards();
+
+ if (BUG(min >= max)) {
+ return min;
+ }
+
+ return crypto_rand_int_range(min, max);
+}
+
+/** Maintain the L2 guard list. Make sure the list contains enough guards, do
+ * expirations as necessary, and keep all the data structures of this
+ * subsystem synchronized */
+void
+maintain_layer2_guards(void)
+{
+ if (!router_have_minimum_dir_info()) {
+ return;
+ }
+
+ /* Create the list if it doesn't exist */
+ if (!layer2_guards) {
+ layer2_guards = smartlist_new();
+ }
+
+ /* Go through the list and perform any needed expirations */
+ SMARTLIST_FOREACH_BEGIN(layer2_guards, layer2_guard_t *, g) {
+ /* Expire based on expiration date */
+ if (g->expire_on_date <= approx_time()) {
+ log_info(LD_GENERAL, "Removing expired Layer2 guard %s",
+ safe_str_client(hex_str(g->identity, DIGEST_LEN)));
+ // Nickname may be gone from consensus and doesn't matter anyway
+ control_event_guard("None", g->identity, "BAD_L2");
+ layer2_guard_free(g);
+ SMARTLIST_DEL_CURRENT_KEEPORDER(layer2_guards, g);
+ continue;
+ }
+
+ /* Expire if relay has left consensus */
+ if (router_get_consensus_status_by_id(g->identity) == NULL) {
+ log_info(LD_GENERAL, "Removing missing Layer2 guard %s",
+ safe_str_client(hex_str(g->identity, DIGEST_LEN)));
+ // Nickname may be gone from consensus and doesn't matter anyway
+ control_event_guard("None", g->identity, "BAD_L2");
+ layer2_guard_free(g);
+ SMARTLIST_DEL_CURRENT_KEEPORDER(layer2_guards, g);
+ continue;
+ }
+ } SMARTLIST_FOREACH_END(g);
+
+ /* Find out how many guards we need to add */
+ int new_guards_needed_n =
+ get_number_of_layer2_hs_guards() - smartlist_len(layer2_guards);
+ if (new_guards_needed_n <= 0) {
+ return;
+ }
+
+ log_info(LD_GENERAL, "Adding %d guards to Layer2 routerset",
+ new_guards_needed_n);
+
+ /* First gather the exclusions based on our current L2 guards */
+ smartlist_t *excluded = smartlist_new();
+ SMARTLIST_FOREACH_BEGIN(layer2_guards, layer2_guard_t *, g) {
+ /* Exclude existing L2 guard so that we don't double-pick it.
+ * But, it's ok if they come from the same family. */
+ const node_t *existing = node_get_by_id(g->identity);
+ if (existing)
+ smartlist_add(excluded, (node_t *)existing);
+ } SMARTLIST_FOREACH_END(g);
+
+ /* Add required guards to the list */
+ for (int i = 0; i < new_guards_needed_n; i++) {
+ const node_t *choice = NULL;
+ const or_options_t *options = get_options();
+ /* Pick Stable nodes */
+ router_crn_flags_t flags = CRN_NEED_DESC|CRN_NEED_UPTIME;
+ choice = router_choose_random_node(excluded, options->ExcludeNodes, flags);
+ if (!choice) {
+ break;
+ }
+
+ /* We found our node: create an L2 guard out of it */
+ layer2_guard_t *layer2_guard = tor_malloc_zero(sizeof(layer2_guard_t));
+ memcpy(layer2_guard->identity, choice->identity, DIGEST_LEN);
+ layer2_guard->expire_on_date = approx_time() +
+ get_layer2_hs_guard_lifetime();
+ smartlist_add(layer2_guards, layer2_guard);
+ log_info(LD_GENERAL, "Adding Layer2 guard %s",
+ safe_str_client(hex_str(layer2_guard->identity, DIGEST_LEN)));
+ // Nickname can also be None here because it is looked up later
+ control_event_guard("None", layer2_guard->identity,
+ "GOOD_L2");
+ /* Exclude this node so that we don't double-pick it. (Again, coming
+ * from the same family is ok here.) */
+ smartlist_add(excluded, (node_t *)choice);
+ }
+
+ /* Some cleanup */
+ smartlist_free(excluded);
+
+ /* Now that the list is up to date, synchronize the routerset */
+ routerset_free(layer2_routerset);
+ layer2_routerset = routerset_new();
+
+ SMARTLIST_FOREACH_BEGIN (layer2_guards, layer2_guard_t *, g) {
+ routerset_parse(layer2_routerset,
+ hex_str(g->identity, DIGEST_LEN),
+ "l2 guards");
+ } SMARTLIST_FOREACH_END(g);
+}
+
+/**
+ * Reset vanguards-lite list(s).
+ *
+ * Used for SIGNAL NEWNYM.
+ */
+void
+purge_vanguards_lite(void)
+{
+ if (!layer2_guards)
+ return;
+
+ /* Go through the list and perform any needed expirations */
+ SMARTLIST_FOREACH_BEGIN(layer2_guards, layer2_guard_t *, g) {
+ layer2_guard_free(g);
+ } SMARTLIST_FOREACH_END(g);
+
+ smartlist_clear(layer2_guards);
+
+ /* Pick new l2 guards */
+ maintain_layer2_guards();
+}
+
+/** Return a routerset containing the L2 guards or NULL if it's not yet
+ * initialized. Callers must not free the routerset. Designed for use in
+ * pick_vanguard_middle_node() and should not be used anywhere else. Do not
+ * store this pointer -- any future calls to maintain_layer2_guards() and
+ * purge_vanguards_lite() can invalidate it. */
+const routerset_t *
+get_layer2_guards(void)
+{
+ if (!layer2_guards) {
+ maintain_layer2_guards();
+ }
+
+ return layer2_routerset;
+}
+
+/*****************************************************************************/
+
/** Release all storage held by the list of entry guards and related
* memory structs. */
void
@@ -3946,4 +4242,15 @@ entry_guards_free_all(void)
guard_contexts = NULL;
}
circuit_build_times_free_timeouts(get_circuit_build_times_mutable());
+
+ if (!layer2_guards) {
+ return;
+ }
+
+ SMARTLIST_FOREACH_BEGIN(layer2_guards, layer2_guard_t *, g) {
+ layer2_guard_free(g);
+ } SMARTLIST_FOREACH_END(g);
+
+ smartlist_free(layer2_guards);
+ routerset_free(layer2_routerset);
}
diff --git a/src/feature/client/entrynodes.h b/src/feature/client/entrynodes.h
index 4b236dc80c..08fd7cf745 100644
--- a/src/feature/client/entrynodes.h
+++ b/src/feature/client/entrynodes.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -651,4 +651,9 @@ guard_get_guardfraction_bandwidth(guardfraction_bandwidth_t *guardfraction_bw,
int orig_bandwidth,
uint32_t guardfraction_percentage);
+bool vanguards_lite_is_enabled(void);
+const routerset_t *get_layer2_guards(void);
+void maintain_layer2_guards(void);
+void purge_vanguards_lite(void);
+
#endif /* !defined(TOR_ENTRYNODES_H) */
diff --git a/src/feature/client/proxymode.c b/src/feature/client/proxymode.c
index aa269ec7fb..40b4a0b929 100644
--- a/src/feature/client/proxymode.c
+++ b/src/feature/client/proxymode.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/client/proxymode.h b/src/feature/client/proxymode.h
index 30be08ff78..4b2d554949 100644
--- a/src/feature/client/proxymode.h
+++ b/src/feature/client/proxymode.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/client/transports.c b/src/feature/client/transports.c
index 4b05d55494..80903ac9e5 100644
--- a/src/feature/client/transports.c
+++ b/src/feature/client/transports.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2020, The Tor Project, Inc. */
+/* Copyright (c) 2011-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -843,7 +843,7 @@ handle_methods_done(const managed_proxy_t *mp)
tor_assert(mp->transports);
if (smartlist_len(mp->transports) == 0)
- log_notice(LD_GENERAL, "Managed proxy '%s' was spawned successfully, "
+ log_warn(LD_GENERAL, "Managed proxy '%s' was spawned successfully, "
"but it didn't launch any pluggable transport listeners!",
mp->argv[0]);
@@ -903,14 +903,22 @@ handle_proxy_line(const char *line, managed_proxy_t *mp)
if (mp->conf_state != PT_PROTO_ACCEPTING_METHODS)
goto err;
+ /* Log the error but do not kill the managed proxy.
+ * A proxy may contain several transports and if one
+ * of them is misconfigured, we still want to use
+ * the other transports. A managed proxy with no usable
+ * transports will log a warning.
+ * See https://gitlab.torproject.org/tpo/core/tor/-/issues/7362
+ * */
parse_client_method_error(line);
- goto err;
+ return;
} else if (!strcmpstart(line, PROTO_SMETHOD_ERROR)) {
if (mp->conf_state != PT_PROTO_ACCEPTING_METHODS)
goto err;
+ /* Log the error but do not kill the managed proxy */
parse_server_method_error(line);
- goto err;
+ return;
} else if (!strcmpstart(line, PROTO_CMETHOD)) {
if (mp->conf_state != PT_PROTO_ACCEPTING_METHODS)
goto err;
diff --git a/src/feature/client/transports.h b/src/feature/client/transports.h
index 47b118e77b..3f08beadba 100644
--- a/src/feature/client/transports.h
+++ b/src/feature/client/transports.h
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/control/btrack.c b/src/feature/control/btrack.c
index 405630ecd4..73a3eb6904 100644
--- a/src/feature/control/btrack.c
+++ b/src/feature/control/btrack.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2007-2020, The Tor Project, Inc. */
+/* Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/control/btrack_circuit.c b/src/feature/control/btrack_circuit.c
index be51b51046..2ae8558986 100644
--- a/src/feature/control/btrack_circuit.c
+++ b/src/feature/control/btrack_circuit.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2007-2020, The Tor Project, Inc. */
+/* Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/control/btrack_circuit.h b/src/feature/control/btrack_circuit.h
index 75699450c3..12fcc89a8a 100644
--- a/src/feature/control/btrack_circuit.h
+++ b/src/feature/control/btrack_circuit.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2007-2020, The Tor Project, Inc. */
+/* Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/control/btrack_orconn.c b/src/feature/control/btrack_orconn.c
index 104c8af230..8b1b5788d0 100644
--- a/src/feature/control/btrack_orconn.c
+++ b/src/feature/control/btrack_orconn.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2007-2020, The Tor Project, Inc. */
+/* Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/control/btrack_orconn.h b/src/feature/control/btrack_orconn.h
index 8b3d8be37d..6f9c391e6f 100644
--- a/src/feature/control/btrack_orconn.h
+++ b/src/feature/control/btrack_orconn.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2007-2020, The Tor Project, Inc. */
+/* Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/control/btrack_orconn_cevent.c b/src/feature/control/btrack_orconn_cevent.c
index d11be59280..525f4f5d0d 100644
--- a/src/feature/control/btrack_orconn_cevent.c
+++ b/src/feature/control/btrack_orconn_cevent.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2007-2020, The Tor Project, Inc. */
+/* Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/control/btrack_orconn_cevent.h b/src/feature/control/btrack_orconn_cevent.h
index 8b2207721e..a95eeeb03f 100644
--- a/src/feature/control/btrack_orconn_cevent.h
+++ b/src/feature/control/btrack_orconn_cevent.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2007-2020, The Tor Project, Inc. */
+/* Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/control/btrack_orconn_maps.c b/src/feature/control/btrack_orconn_maps.c
index a60dffb8c4..2b458d5826 100644
--- a/src/feature/control/btrack_orconn_maps.c
+++ b/src/feature/control/btrack_orconn_maps.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2007-2020, The Tor Project, Inc. */
+/* Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/control/btrack_orconn_maps.h b/src/feature/control/btrack_orconn_maps.h
index c83b22b1e8..7183b9bc3c 100644
--- a/src/feature/control/btrack_orconn_maps.h
+++ b/src/feature/control/btrack_orconn_maps.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2007-2020, The Tor Project, Inc. */
+/* Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/control/btrack_sys.h b/src/feature/control/btrack_sys.h
index 5a157b7b54..ab660f7efb 100644
--- a/src/feature/control/btrack_sys.h
+++ b/src/feature/control/btrack_sys.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2007-2020, The Tor Project, Inc. */
+/* Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/control/control.c b/src/feature/control/control.c
index 2aebe1aac6..ac37357818 100644
--- a/src/feature/control/control.c
+++ b/src/feature/control/control.c
@@ -1,5 +1,5 @@
/* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -48,8 +48,8 @@
#include "feature/control/control_cmd.h"
#include "feature/control/control_events.h"
#include "feature/control/control_proto.h"
-#include "feature/rend/rendcommon.h"
-#include "feature/rend/rendservice.h"
+#include "feature/hs/hs_common.h"
+#include "feature/hs/hs_service.h"
#include "lib/evloop/procmon.h"
#include "feature/control/control_connection_st.h"
@@ -240,9 +240,7 @@ connection_control_closed(control_connection_t *conn)
*/
if (conn->ephemeral_onion_services) {
SMARTLIST_FOREACH_BEGIN(conn->ephemeral_onion_services, char *, cp) {
- if (rend_valid_v2_service_id(cp)) {
- rend_service_del_ephemeral(cp);
- } else if (hs_address_is_valid(cp)) {
+ if (hs_address_is_valid(cp)) {
hs_service_del_ephemeral(cp);
} else {
/* An invalid .onion in our list should NEVER happen */
diff --git a/src/feature/control/control.h b/src/feature/control/control.h
index f884286ec7..fc6196133b 100644
--- a/src/feature/control/control.h
+++ b/src/feature/control/control.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/control/control_auth.c b/src/feature/control/control_auth.c
index b60623ab5c..2af6517493 100644
--- a/src/feature/control/control_auth.c
+++ b/src/feature/control/control_auth.c
@@ -1,5 +1,5 @@
/* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/control/control_auth.h b/src/feature/control/control_auth.h
index d4c1dd78a7..3d2d300b5a 100644
--- a/src/feature/control/control_auth.h
+++ b/src/feature/control/control_auth.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/control/control_bootstrap.c b/src/feature/control/control_bootstrap.c
index d6dfdad94e..26d7b99b07 100644
--- a/src/feature/control/control_bootstrap.c
+++ b/src/feature/control/control_bootstrap.c
@@ -1,5 +1,5 @@
/* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/control/control_cmd.c b/src/feature/control/control_cmd.c
index a1c5e55fe1..dd0cde4f7d 100644
--- a/src/feature/control/control_cmd.c
+++ b/src/feature/control/control_cmd.c
@@ -1,5 +1,5 @@
/* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -33,13 +33,11 @@
#include "feature/control/control_getinfo.h"
#include "feature/control/control_proto.h"
#include "feature/hs/hs_control.h"
+#include "feature/hs/hs_service.h"
#include "feature/nodelist/nodelist.h"
#include "feature/nodelist/routerinfo.h"
#include "feature/nodelist/routerlist.h"
-#include "feature/rend/rendclient.h"
#include "feature/rend/rendcommon.h"
-#include "feature/rend/rendparse.h"
-#include "feature/rend/rendservice.h"
#include "lib/crypt_ops/crypto_rand.h"
#include "lib/crypt_ops/crypto_util.h"
#include "lib/encoding/confline.h"
@@ -53,11 +51,8 @@
#include "feature/control/control_connection_st.h"
#include "feature/nodelist/node_st.h"
#include "feature/nodelist/routerinfo_st.h"
-#include "feature/rend/rend_authorized_client_st.h"
-#include "feature/rend/rend_encoded_v2_service_descriptor_st.h"
-#include "feature/rend/rend_service_descriptor_st.h"
-#include "src/app/config/statefile.h"
+#include "app/config/statefile.h"
static int control_setconf_helper(control_connection_t *conn,
const control_cmd_args_t *args,
@@ -828,7 +823,10 @@ handle_control_extendcircuit(control_connection_t *conn,
first_node = zero_circ;
SMARTLIST_FOREACH(nodes, const node_t *, node,
{
- extend_info_t *info = extend_info_from_node(node, first_node);
+ /* We treat every hop as an exit to try to negotiate congestion
+ * control, because we have no idea which hop the controller wil
+ * try to use for streams and when */
+ extend_info_t *info = extend_info_from_node(node, first_node, true);
if (!info) {
tor_assert_nonfatal(first_node);
log_warn(LD_CONTROL,
@@ -1082,7 +1080,7 @@ static const control_cmd_syntax_t redirectstream_syntax = {
.max_args = UINT_MAX, // XXX should be 3.
};
-/** Called when we receive a REDIRECTSTERAM command. Try to change the target
+/** Called when we receive a REDIRECTSTREAM command. Try to change the target
* address of the named AP stream, and report success or failure. */
static int
handle_control_redirectstream(control_connection_t *conn,
@@ -1235,7 +1233,7 @@ handle_control_resolve(control_connection_t *conn,
send_control_done(conn);
SMARTLIST_FOREACH(failed, const char *, arg, {
control_event_address_mapped(arg, arg, time(NULL),
- "internal", 0);
+ "internal", 0, 0);
});
smartlist_free(failed);
@@ -1445,9 +1443,7 @@ handle_control_hsfetch(control_connection_t *conn,
const control_cmd_args_t *args)
{
- char *desc_id = NULL;
smartlist_t *hsdirs = NULL;
- rend_data_t *rend_query = NULL;
ed25519_public_key_t v3_pk;
uint32_t version;
const char *hsaddress = NULL;
@@ -1483,22 +1479,6 @@ handle_control_hsfetch(control_connection_t *conn,
}
}
- if (version == HS_VERSION_TWO) {
- rend_query = rend_data_client_create(hsaddress, desc_id, NULL,
- REND_NO_AUTH);
- if (rend_query == NULL) {
- control_write_endreply(conn, 551, "Error creating the HS query");
- goto done;
- }
- }
-
- /* Using a descriptor ID, we force the user to provide at least one
- * hsdir server using the SERVER= option. */
- if (desc_id && (!hsdirs || !smartlist_len(hsdirs))) {
- control_write_endreply(conn, 512, "SERVER option is required");
- goto done;
- }
-
/* We are about to trigger HSDir fetch so send the OK now because after
* that 650 event(s) are possible so better to have the 250 OK before them
* to avoid out of order replies. */
@@ -1507,16 +1487,13 @@ handle_control_hsfetch(control_connection_t *conn,
/* Trigger the fetch using the built rend query and possibly a list of HS
* directory to use. This function ignores the client cache thus this will
* always send a fetch command. */
- if (version == HS_VERSION_TWO) {
- rend_client_fetch_v2_desc(rend_query, hsdirs);
- } else if (version == HS_VERSION_THREE) {
+ if (version == HS_VERSION_THREE) {
hs_control_hsfetch_command(&v3_pk, hsdirs);
}
done:
/* Contains data pointer that we don't own thus no cleanup. */
smartlist_free(hsdirs);
- rend_data_free(rend_query);
return 0;
}
@@ -1537,7 +1514,6 @@ handle_control_hspost(control_connection_t *conn,
{
smartlist_t *hs_dirs = NULL;
const char *encoded_desc = args->cmddata;
- size_t encoded_desc_len = args->cmddata_len;
const char *onion_address = NULL;
const config_line_t *line;
@@ -1577,49 +1553,6 @@ handle_control_hspost(control_connection_t *conn,
goto done;
}
- /* As for HSFETCH, we no longer support v2 on the network and so we stop
- * right now. Code is not removed in order to minimize the merge forward
- * conflicts. */
- goto done;
-
- /* From this point on, it is only v2. */
-
- /* parse it. */
- rend_encoded_v2_service_descriptor_t *desc =
- tor_malloc_zero(sizeof(rend_encoded_v2_service_descriptor_t));
- desc->desc_str = tor_memdup_nulterm(encoded_desc, encoded_desc_len);
-
- rend_service_descriptor_t *parsed = NULL;
- char *intro_content = NULL;
- size_t intro_size;
- size_t encoded_size;
- const char *next_desc;
- if (!rend_parse_v2_service_descriptor(&parsed, desc->desc_id, &intro_content,
- &intro_size, &encoded_size,
- &next_desc, desc->desc_str, 1)) {
- /* Post the descriptor. */
- char serviceid[REND_SERVICE_ID_LEN_BASE32+1];
- if (!rend_get_service_id(parsed->pk, serviceid)) {
- smartlist_t *descs = smartlist_new();
- smartlist_add(descs, desc);
-
- /* We are about to trigger HS descriptor upload so send the OK now
- * because after that 650 event(s) are possible so better to have the
- * 250 OK before them to avoid out of order replies. */
- send_control_done(conn);
-
- /* Trigger the descriptor upload */
- directory_post_to_hs_dir(parsed, descs, hs_dirs, serviceid, 0);
- smartlist_free(descs);
- }
-
- rend_service_descriptor_free(parsed);
- } else {
- control_write_endreply(conn, 554, "Invalid descriptor");
- }
-
- tor_free(intro_content);
- rend_encoded_v2_service_descriptor_free(desc);
done:
smartlist_free(hs_dirs); /* Contents belong to the rend service code. */
return 0;
@@ -1635,18 +1568,17 @@ handle_control_hspost(control_connection_t *conn,
* The port_cfgs is a list of service port. Ownership transferred to service.
* The max_streams refers to the MaxStreams= key.
* The max_streams_close_circuit refers to the MaxStreamsCloseCircuit key.
- * The auth_type is the authentication type of the clients in auth_clients.
* The ownership of that list is transferred to the service.
*
* On success (RSAE_OKAY), the address_out points to a newly allocated string
* containing the onion address without the .onion part. On error, address_out
* is untouched. */
-static hs_service_add_ephemeral_status_t
+STATIC hs_service_add_ephemeral_status_t
add_onion_helper_add_service(int hs_version,
add_onion_secret_key_t *pk,
smartlist_t *port_cfgs, int max_streams,
- int max_streams_close_circuit, int auth_type,
- smartlist_t *auth_clients, char **address_out)
+ int max_streams_close_circuit,
+ smartlist_t *auth_clients_v3, char **address_out)
{
hs_service_add_ephemeral_status_t ret;
@@ -1654,17 +1586,11 @@ add_onion_helper_add_service(int hs_version,
tor_assert(port_cfgs);
tor_assert(address_out);
- /* Version 2 is disabled. */
- (void) auth_type;
- (void) auth_clients;
-
switch (hs_version) {
- case HS_VERSION_TWO:
- ret = RSAE_INTERNAL;
- break;
case HS_VERSION_THREE:
ret = hs_service_add_ephemeral(pk->v3, port_cfgs, max_streams,
- max_streams_close_circuit, address_out);
+ max_streams_close_circuit,
+ auth_clients_v3, address_out);
break;
default:
tor_assert_unreached();
@@ -1688,7 +1614,7 @@ get_detached_onion_services(void)
}
static const char *add_onion_keywords[] = {
- "Port", "Flags", "MaxStreams", "ClientAuth", NULL
+ "Port", "Flags", "MaxStreams", "ClientAuth", "ClientAuthV3", NULL
};
static const control_cmd_syntax_t add_onion_syntax = {
.min_args = 1, .max_args = 1,
@@ -1706,22 +1632,21 @@ handle_control_add_onion(control_connection_t *conn,
* material first, since there's no reason to touch that at all if any of
* the other arguments are malformed.
*/
+ rend_auth_type_t auth_type = REND_NO_AUTH;
smartlist_t *port_cfgs = smartlist_new();
- smartlist_t *auth_clients = NULL;
- smartlist_t *auth_created_clients = NULL;
+ smartlist_t *auth_clients_v3 = NULL;
+ smartlist_t *auth_clients_v3_str = NULL;
int discard_pk = 0;
int detach = 0;
int max_streams = 0;
int max_streams_close_circuit = 0;
- rend_auth_type_t auth_type = REND_NO_AUTH;
int non_anonymous = 0;
const config_line_t *arg;
for (arg = args->kwargs; arg; arg = arg->next) {
if (!strcasecmp(arg->key, "Port")) {
/* "Port=VIRTPORT[,TARGET]". */
- rend_service_port_config_t *cfg =
- rend_service_parse_port_config(arg->value, ",", NULL);
+ hs_port_config_t *cfg = hs_parse_port_config(arg->value, ",", NULL);
if (!cfg) {
control_write_endreply(conn, 512, "Invalid VIRTPORT/TARGET");
goto out;
@@ -1752,7 +1677,7 @@ handle_control_add_onion(control_connection_t *conn,
static const char *discard_flag = "DiscardPK";
static const char *detach_flag = "Detach";
static const char *max_s_close_flag = "MaxStreamsCloseCircuit";
- static const char *basicauth_flag = "BasicAuth";
+ static const char *v3auth_flag = "V3Auth";
static const char *non_anonymous_flag = "NonAnonymous";
smartlist_t *flags = smartlist_new();
@@ -1771,8 +1696,8 @@ handle_control_add_onion(control_connection_t *conn,
detach = 1;
} else if (!strcasecmp(flag, max_s_close_flag)) {
max_streams_close_circuit = 1;
- } else if (!strcasecmp(flag, basicauth_flag)) {
- auth_type = REND_BASIC_AUTH;
+ } else if (!strcasecmp(flag, v3auth_flag)) {
+ auth_type = REND_V3_AUTH;
} else if (!strcasecmp(flag, non_anonymous_flag)) {
non_anonymous = 1;
} else {
@@ -1786,36 +1711,21 @@ handle_control_add_onion(control_connection_t *conn,
smartlist_free(flags);
if (bad)
goto out;
-
- } else if (!strcasecmp(arg->key, "ClientAuth")) {
- int created = 0;
- rend_authorized_client_t *client =
- add_onion_helper_clientauth(arg->value, &created, conn);
- if (!client) {
+ } else if (!strcasecmp(arg->key, "ClientAuthV3")) {
+ hs_service_authorized_client_t *client_v3 =
+ parse_authorized_client_key(arg->value, LOG_INFO);
+ if (!client_v3) {
+ control_write_endreply(conn, 512, "Cannot decode v3 client auth key");
goto out;
}
- if (auth_clients != NULL) {
- int bad = 0;
- SMARTLIST_FOREACH_BEGIN(auth_clients, rend_authorized_client_t *, ac) {
- if (strcmp(ac->client_name, client->client_name) == 0) {
- bad = 1;
- break;
- }
- } SMARTLIST_FOREACH_END(ac);
- if (bad) {
- control_write_endreply(conn, 512, "Duplicate name in ClientAuth");
- rend_authorized_client_free(client);
- goto out;
- }
- } else {
- auth_clients = smartlist_new();
- auth_created_clients = smartlist_new();
- }
- smartlist_add(auth_clients, client);
- if (created) {
- smartlist_add(auth_created_clients, client);
+ if (auth_clients_v3 == NULL) {
+ auth_clients_v3 = smartlist_new();
+ auth_clients_v3_str = smartlist_new();
}
+
+ smartlist_add(auth_clients_v3, client_v3);
+ smartlist_add(auth_clients_v3_str, tor_strdup(arg->value));
} else {
tor_assert_nonfatal_unreached();
goto out;
@@ -1824,20 +1734,14 @@ handle_control_add_onion(control_connection_t *conn,
if (smartlist_len(port_cfgs) == 0) {
control_write_endreply(conn, 512, "Missing 'Port' argument");
goto out;
- } else if (auth_type == REND_NO_AUTH && auth_clients != NULL) {
+ } else if (auth_type == REND_NO_AUTH && auth_clients_v3 != NULL) {
control_write_endreply(conn, 512, "No auth type specified");
goto out;
- } else if (auth_type != REND_NO_AUTH && auth_clients == NULL) {
+ } else if (auth_type != REND_NO_AUTH && auth_clients_v3 == NULL) {
control_write_endreply(conn, 512, "No auth clients specified");
goto out;
- } else if ((auth_type == REND_BASIC_AUTH &&
- smartlist_len(auth_clients) > 512) ||
- (auth_type == REND_STEALTH_AUTH &&
- smartlist_len(auth_clients) > 16)) {
- control_write_endreply(conn, 512, "Too many auth clients");
- goto out;
- } else if (non_anonymous != rend_service_non_anonymous_mode_enabled(
- get_options())) {
+ } else if (non_anonymous != hs_service_non_anonymous_mode_enabled(
+ get_options())) {
/* If we failed, and the non-anonymous flag is set, Tor must be in
* anonymous hidden service mode.
* The error message changes based on the current Tor config:
@@ -1864,25 +1768,16 @@ handle_control_add_onion(control_connection_t *conn,
goto out;
}
- /* Hidden service version 3 don't have client authentication support so if
- * ClientAuth was given, send back an error. */
- if (hs_version == HS_VERSION_THREE && auth_clients) {
- control_write_endreply(conn, 513, "ClientAuth not supported");
- goto out;
- }
-
- /* Create the HS, using private key pk, client authentication auth_type,
- * the list of auth_clients, and port config port_cfg.
- * rend_service_add_ephemeral() will take ownership of pk and port_cfg,
- * regardless of success/failure.
- */
+ /* Create the HS, using private key pk and port config port_cfg.
+ * hs_service_add_ephemeral() will take ownership of pk and port_cfg,
+ * regardless of success/failure. */
char *service_id = NULL;
int ret = add_onion_helper_add_service(hs_version, &pk, port_cfgs,
max_streams,
- max_streams_close_circuit, auth_type,
- auth_clients, &service_id);
- port_cfgs = NULL; /* port_cfgs is now owned by the rendservice code. */
- auth_clients = NULL; /* so is auth_clients */
+ max_streams_close_circuit,
+ auth_clients_v3, &service_id);
+ port_cfgs = NULL; /* port_cfgs is now owned by the hs_service code. */
+ auth_clients_v3 = NULL; /* so is auth_clients_v3 */
switch (ret) {
case RSAE_OKAY:
{
@@ -1903,15 +1798,9 @@ handle_control_add_onion(control_connection_t *conn,
control_printf_midreply(conn, 250, "PrivateKey=%s:%s",
key_new_alg, key_new_blob);
}
- if (auth_created_clients) {
- SMARTLIST_FOREACH(auth_created_clients, rend_authorized_client_t *, ac, {
- char *encoded = rend_auth_encode_cookie(ac->descriptor_cookie,
- auth_type);
- tor_assert(encoded);
- control_printf_midreply(conn, 250, "ClientAuth=%s:%s",
- ac->client_name, encoded);
- memwipe(encoded, 0, strlen(encoded));
- tor_free(encoded);
+ if (auth_clients_v3_str) {
+ SMARTLIST_FOREACH(auth_clients_v3_str, char *, client_str, {
+ control_printf_midreply(conn, 250, "ClientAuthV3=%s", client_str);
});
}
@@ -1941,20 +1830,21 @@ handle_control_add_onion(control_connection_t *conn,
out:
if (port_cfgs) {
- SMARTLIST_FOREACH(port_cfgs, rend_service_port_config_t*, p,
- rend_service_port_config_free(p));
+ SMARTLIST_FOREACH(port_cfgs, hs_port_config_t*, p,
+ hs_port_config_free(p));
smartlist_free(port_cfgs);
}
-
- if (auth_clients) {
- SMARTLIST_FOREACH(auth_clients, rend_authorized_client_t *, ac,
- rend_authorized_client_free(ac));
- smartlist_free(auth_clients);
+ if (auth_clients_v3) {
+ SMARTLIST_FOREACH(auth_clients_v3, hs_service_authorized_client_t *, ac,
+ service_authorized_client_free(ac));
+ smartlist_free(auth_clients_v3);
}
- if (auth_created_clients) {
- // Do not free entries; they are the same as auth_clients
- smartlist_free(auth_created_clients);
+ if (auth_clients_v3_str) {
+ SMARTLIST_FOREACH(auth_clients_v3_str, char *, client_str,
+ tor_free(client_str));
+ smartlist_free(auth_clients_v3_str);
}
+
return 0;
}
@@ -1978,7 +1868,6 @@ add_onion_helper_keyarg(const char *arg, int discard_pk,
control_connection_t *conn)
{
smartlist_t *key_args = smartlist_new();
- crypto_pk_t *pk = NULL;
const char *key_new_alg = NULL;
char *key_new_blob = NULL;
int ret = -1;
@@ -1992,27 +1881,12 @@ add_onion_helper_keyarg(const char *arg, int discard_pk,
/* The format is "KeyType:KeyBlob". */
static const char *key_type_new = "NEW";
static const char *key_type_best = "BEST";
- static const char *key_type_rsa1024 = "RSA1024";
static const char *key_type_ed25519_v3 = "ED25519-V3";
const char *key_type = smartlist_get(key_args, 0);
const char *key_blob = smartlist_get(key_args, 1);
- if (!strcasecmp(key_type_rsa1024, key_type)) {
- /* "RSA:<Base64 Blob>" - Loading a pre-existing RSA1024 key. */
- pk = crypto_pk_base64_decode_private(key_blob, strlen(key_blob));
- if (!pk) {
- control_write_endreply(conn, 512, "Failed to decode RSA key");
- goto err;
- }
- if (crypto_pk_num_bits(pk) != PK_BYTES*8) {
- crypto_pk_free(pk);
- control_write_endreply(conn, 512, "Invalid RSA key size");
- goto err;
- }
- decoded_key->v2 = pk;
- *hs_version = HS_VERSION_TWO;
- } else if (!strcasecmp(key_type_ed25519_v3, key_type)) {
+ if (!strcasecmp(key_type_ed25519_v3, key_type)) {
/* parsing of private ed25519 key */
/* "ED25519-V3:<Base64 Blob>" - Loading a pre-existing ed25519 key. */
ed25519_secret_key_t *sk = tor_malloc_zero(sizeof(*sk));
@@ -2026,27 +1900,8 @@ add_onion_helper_keyarg(const char *arg, int discard_pk,
*hs_version = HS_VERSION_THREE;
} else if (!strcasecmp(key_type_new, key_type)) {
/* "NEW:<Algorithm>" - Generating a new key, blob as algorithm. */
- if (!strcasecmp(key_type_rsa1024, key_blob)) {
- /* "RSA1024", RSA 1024 bit, also currently "BEST" by default. */
- pk = crypto_pk_new();
- if (crypto_pk_generate_key(pk)) {
- control_printf_endreply(conn, 551, "Failed to generate %s key",
- key_type_rsa1024);
- goto err;
- }
- if (!discard_pk) {
- if (crypto_pk_base64_encode_private(pk, &key_new_blob)) {
- crypto_pk_free(pk);
- control_printf_endreply(conn, 551, "Failed to encode %s key",
- key_type_rsa1024);
- goto err;
- }
- key_new_alg = key_type_rsa1024;
- }
- decoded_key->v2 = pk;
- *hs_version = HS_VERSION_TWO;
- } else if (!strcasecmp(key_type_ed25519_v3, key_blob) ||
- !strcasecmp(key_type_best, key_blob)) {
+ if (!strcasecmp(key_type_ed25519_v3, key_blob) ||
+ !strcasecmp(key_type_best, key_blob)) {
/* "ED25519-V3", ed25519 key, also currently "BEST" by default. */
ed25519_secret_key_t *sk = tor_malloc_zero(sizeof(*sk));
if (ed25519_secret_key_generate(sk, 1) < 0) {
@@ -2095,68 +1950,6 @@ add_onion_helper_keyarg(const char *arg, int discard_pk,
return ret;
}
-/** Helper function to handle parsing a ClientAuth argument to the
- * ADD_ONION command. Return a new rend_authorized_client_t, or NULL
- * and an optional control protocol error message on failure. The
- * caller is responsible for freeing the returned auth_client.
- *
- * If 'created' is specified, it will be set to 1 when a new cookie has
- * been generated.
- *
- * Note: conn is only used for writing control replies. For testing
- * purposes, it can be NULL if control_write_reply() is appropriately
- * mocked.
- */
-STATIC rend_authorized_client_t *
-add_onion_helper_clientauth(const char *arg, int *created,
- control_connection_t *conn)
-{
- int ok = 0;
-
- tor_assert(arg);
- tor_assert(created);
-
- smartlist_t *auth_args = smartlist_new();
- rend_authorized_client_t *client =
- tor_malloc_zero(sizeof(rend_authorized_client_t));
- smartlist_split_string(auth_args, arg, ":", 0, 0);
- if (smartlist_len(auth_args) < 1 || smartlist_len(auth_args) > 2) {
- control_write_endreply(conn, 512, "Invalid ClientAuth syntax");
- goto err;
- }
- client->client_name = tor_strdup(smartlist_get(auth_args, 0));
- if (smartlist_len(auth_args) == 2) {
- char *decode_err_msg = NULL;
- if (rend_auth_decode_cookie(smartlist_get(auth_args, 1),
- client->descriptor_cookie,
- NULL, &decode_err_msg) < 0) {
- tor_assert(decode_err_msg);
- control_write_endreply(conn, 512, decode_err_msg);
- tor_free(decode_err_msg);
- goto err;
- }
- *created = 0;
- } else {
- crypto_rand((char *) client->descriptor_cookie, REND_DESC_COOKIE_LEN);
- *created = 1;
- }
-
- if (!rend_valid_client_name(client->client_name)) {
- control_write_endreply(conn, 512, "Invalid name in ClientAuth");
- goto err;
- }
-
- ok = 1;
- err:
- SMARTLIST_FOREACH(auth_args, char *, item, tor_free(item));
- smartlist_free(auth_args);
- if (!ok) {
- rend_authorized_client_free(client);
- client = NULL;
- }
- return client;
-}
-
static const control_cmd_syntax_t del_onion_syntax = {
.min_args = 1, .max_args = 1,
};
@@ -2172,9 +1965,7 @@ handle_control_del_onion(control_connection_t *conn,
tor_assert(smartlist_len(args) == 1);
const char *service_id = smartlist_get(args, 0);
- if (rend_valid_v2_service_id(service_id)) {
- hs_version = HS_VERSION_TWO;
- } else if (hs_address_is_valid(service_id)) {
+ if (hs_address_is_valid(service_id)) {
hs_version = HS_VERSION_THREE;
} else {
control_write_endreply(conn, 512, "Malformed Onion Service id");
@@ -2205,9 +1996,6 @@ handle_control_del_onion(control_connection_t *conn,
} else {
int ret = -1;
switch (hs_version) {
- case HS_VERSION_TWO:
- ret = rend_service_del_ephemeral(service_id);
- break;
case HS_VERSION_THREE:
ret = hs_service_del_ephemeral(service_id);
break;
diff --git a/src/feature/control/control_cmd.h b/src/feature/control/control_cmd.h
index 0ff0f0755f..8cbe70a2ed 100644
--- a/src/feature/control/control_cmd.h
+++ b/src/feature/control/control_cmd.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -75,14 +75,13 @@ typedef struct control_cmd_syntax_t {
} control_cmd_syntax_t;
#ifdef CONTROL_CMD_PRIVATE
+#include "feature/hs/hs_service.h"
#include "lib/crypt_ops/crypto_ed25519.h"
/* ADD_ONION secret key to create an ephemeral service. The command supports
* multiple versions so this union stores the key and passes it to the HS
* subsystem depending on the requested version. */
typedef union add_onion_secret_key_t {
- /* Hidden service v2 secret key. */
- crypto_pk_t *v2;
/* Hidden service v3 secret key. */
ed25519_secret_key_t *v3;
} add_onion_secret_key_t;
@@ -94,8 +93,12 @@ STATIC int add_onion_helper_keyarg(const char *arg, int discard_pk,
int *hs_version,
control_connection_t *conn);
-STATIC rend_authorized_client_t *add_onion_helper_clientauth(const char *arg,
- int *created, control_connection_t *conn);
+STATIC hs_service_add_ephemeral_status_t add_onion_helper_add_service(
+ int hs_version,
+ add_onion_secret_key_t *pk,
+ smartlist_t *port_cfgs, int max_streams,
+ int max_streams_close_circuit,
+ smartlist_t *auth_clients_v3, char **address_out);
STATIC control_cmd_args_t *control_cmd_parse_args(
const char *command,
diff --git a/src/feature/control/control_cmd_args_st.h b/src/feature/control/control_cmd_args_st.h
index e7d064c6fe..f97be52605 100644
--- a/src/feature/control/control_cmd_args_st.h
+++ b/src/feature/control/control_cmd_args_st.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/control/control_connection_st.h b/src/feature/control/control_connection_st.h
index 9e410324e0..a4ce0da7c5 100644
--- a/src/feature/control/control_connection_st.h
+++ b/src/feature/control/control_connection_st.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/control/control_events.c b/src/feature/control/control_events.c
index 0dd52659ec..4c8cf9a425 100644
--- a/src/feature/control/control_events.c
+++ b/src/feature/control/control_events.c
@@ -1,5 +1,5 @@
/* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -21,6 +21,7 @@
#include "core/or/command.h"
#include "core/or/connection_edge.h"
#include "core/or/connection_or.h"
+#include "core/or/congestion_control_common.h"
#include "core/or/reasons.h"
#include "feature/control/control.h"
#include "feature/control/control_events.h"
@@ -819,6 +820,10 @@ control_event_stream_status(entry_connection_t *conn, stream_status_event_t tp,
case STREAM_EVENT_FAILED_RETRIABLE: status = "DETACHED"; break;
case STREAM_EVENT_REMAP: status = "REMAP"; break;
case STREAM_EVENT_CONTROLLER_WAIT: status = "CONTROLLER_WAIT"; break;
+ case STREAM_EVENT_XOFF_SENT: status = "XOFF_SENT"; break;
+ case STREAM_EVENT_XOFF_RECV: status = "XOFF_RECV"; break;
+ case STREAM_EVENT_XON_SENT: status = "XON_SENT"; break;
+ case STREAM_EVENT_XON_RECV: status = "XON_RECV"; break;
default:
log_warn(LD_BUG, "Unrecognized status code %d", (int)tp);
return 0;
@@ -1075,10 +1080,12 @@ control_event_circ_bandwidth_used_for_circ(origin_circuit_t *ocirc)
tor_gettimeofday(&now);
format_iso_time_nospace_usec(tbuf, &now);
+
+ char *ccontrol_buf = congestion_control_get_control_port_fields(ocirc);
send_control_event(EVENT_CIRC_BANDWIDTH_USED,
"650 CIRC_BW ID=%d READ=%lu WRITTEN=%lu TIME=%s "
"DELIVERED_READ=%lu OVERHEAD_READ=%lu "
- "DELIVERED_WRITTEN=%lu OVERHEAD_WRITTEN=%lu\r\n",
+ "DELIVERED_WRITTEN=%lu OVERHEAD_WRITTEN=%lu%s\r\n",
ocirc->global_identifier,
(unsigned long)ocirc->n_read_circ_bw,
(unsigned long)ocirc->n_written_circ_bw,
@@ -1086,11 +1093,16 @@ control_event_circ_bandwidth_used_for_circ(origin_circuit_t *ocirc)
(unsigned long)ocirc->n_delivered_read_circ_bw,
(unsigned long)ocirc->n_overhead_read_circ_bw,
(unsigned long)ocirc->n_delivered_written_circ_bw,
- (unsigned long)ocirc->n_overhead_written_circ_bw);
+ (unsigned long)ocirc->n_overhead_written_circ_bw,
+ ccontrol_buf ? ccontrol_buf : "");
+
ocirc->n_written_circ_bw = ocirc->n_read_circ_bw = 0;
ocirc->n_overhead_written_circ_bw = ocirc->n_overhead_read_circ_bw = 0;
ocirc->n_delivered_written_circ_bw = ocirc->n_delivered_read_circ_bw = 0;
+ if (ccontrol_buf)
+ tor_free(ccontrol_buf);
+
return 0;
}
@@ -1477,31 +1489,40 @@ control_event_descriptors_changed(smartlist_t *routers)
* mode of the mapping.
*/
int
-control_event_address_mapped(const char *from, const char *to, time_t expires,
- const char *error, const int cached)
+control_event_address_mapped(const char *from, const char *to,
+ time_t expires, const char *error,
+ const int cached, uint64_t stream_id)
{
+ char *stream_id_str = NULL;
if (!EVENT_IS_INTERESTING(EVENT_ADDRMAP))
return 0;
+ if (stream_id) {
+ tor_asprintf(&stream_id_str, " STREAMID=%"PRIu64"", stream_id);
+ }
+
if (expires < 3 || expires == TIME_MAX)
send_control_event(EVENT_ADDRMAP,
"650 ADDRMAP %s %s NEVER %s%s"
- "CACHED=\"%s\"\r\n",
- from, to, error?error:"", error?" ":"",
- cached?"YES":"NO");
+ "CACHED=\"%s\"%s\r\n",
+ from, to, error ? error : "", error ? " " : "",
+ cached ? "YES" : "NO",
+ stream_id ? stream_id_str : "");
else {
char buf[ISO_TIME_LEN+1];
char buf2[ISO_TIME_LEN+1];
format_local_iso_time(buf,expires);
format_iso_time(buf2,expires);
send_control_event(EVENT_ADDRMAP,
- "650 ADDRMAP %s %s \"%s\""
- " %s%sEXPIRES=\"%s\" CACHED=\"%s\"\r\n",
- from, to, buf,
- error?error:"", error?" ":"",
- buf2, cached?"YES":"NO");
+ "650 ADDRMAP %s %s \"%s\" %s%sEXPIRES=\"%s\" "
+ "CACHED=\"%s\"%s\r\n",
+ from, to, buf, error ? error : "",
+ error ? " " : "", buf2, cached ? "YES" : "NO",
+ stream_id ? stream_id_str: "");
}
+ tor_free(stream_id_str);
+
return 0;
}
/** The network liveness has changed; this is called from circuitstats.c
@@ -1921,11 +1942,8 @@ rend_auth_type_to_string(rend_auth_type_t auth_type)
case REND_NO_AUTH:
str = "NO_AUTH";
break;
- case REND_BASIC_AUTH:
- str = "BASIC_AUTH";
- break;
- case REND_STEALTH_AUTH:
- str = "STEALTH_AUTH";
+ case REND_V3_AUTH:
+ str = "REND_V3_AUTH";
break;
default:
str = "UNKNOWN";
@@ -2054,8 +2072,6 @@ control_event_hs_descriptor_upload(const char *onion_address,
/** send HS_DESC event after got response from hs directory.
*
* NOTE: this is an internal function used by following functions:
- * control_event_hsv2_descriptor_received
- * control_event_hsv2_descriptor_failed
* control_event_hsv3_descriptor_failed
*
* So do not call this function directly.
@@ -2126,82 +2142,6 @@ control_event_hs_descriptor_upload_end(const char *action,
tor_free(reason_field);
}
-/** For an HS descriptor query <b>rend_data</b>, using the
- * <b>onion_address</b> and HSDir fingerprint <b>hsdir_fp</b>, find out
- * which descriptor ID in the query is the right one.
- *
- * Return a pointer of the binary descriptor ID found in the query's object
- * or NULL if not found. */
-static const char *
-get_desc_id_from_query(const rend_data_t *rend_data, const char *hsdir_fp)
-{
- int replica;
- const char *desc_id = NULL;
- const rend_data_v2_t *rend_data_v2 = TO_REND_DATA_V2(rend_data);
-
- /* Possible if the fetch was done using a descriptor ID. This means that
- * the HSFETCH command was used. */
- if (!tor_digest_is_zero(rend_data_v2->desc_id_fetch)) {
- desc_id = rend_data_v2->desc_id_fetch;
- goto end;
- }
-
- /* Without a directory fingerprint at this stage, we can't do much. */
- if (hsdir_fp == NULL) {
- goto end;
- }
-
- /* OK, we have an onion address so now let's find which descriptor ID
- * is the one associated with the HSDir fingerprint. */
- for (replica = 0; replica < REND_NUMBER_OF_NON_CONSECUTIVE_REPLICAS;
- replica++) {
- const char *digest = rend_data_get_desc_id(rend_data, replica, NULL);
-
- SMARTLIST_FOREACH_BEGIN(rend_data->hsdirs_fp, char *, fingerprint) {
- if (tor_memcmp(fingerprint, hsdir_fp, DIGEST_LEN) == 0) {
- /* Found it! This descriptor ID is the right one. */
- desc_id = digest;
- goto end;
- }
- } SMARTLIST_FOREACH_END(fingerprint);
- }
-
- end:
- return desc_id;
-}
-
-/** send HS_DESC RECEIVED event
- *
- * called when we successfully received a hidden service descriptor.
- */
-void
-control_event_hsv2_descriptor_received(const char *onion_address,
- const rend_data_t *rend_data,
- const char *hsdir_id_digest)
-{
- char *desc_id_field = NULL;
- const char *desc_id;
-
- if (BUG(!rend_data || !hsdir_id_digest || !onion_address)) {
- return;
- }
-
- desc_id = get_desc_id_from_query(rend_data, hsdir_id_digest);
- if (desc_id != NULL) {
- char desc_id_base32[REND_DESC_ID_V2_LEN_BASE32 + 1];
- /* Set the descriptor ID digest to base32 so we can send it. */
- base32_encode(desc_id_base32, sizeof(desc_id_base32), desc_id,
- DIGEST_LEN);
- /* Extra whitespace is needed before the value. */
- tor_asprintf(&desc_id_field, " %s", desc_id_base32);
- }
-
- event_hs_descriptor_receive_end("RECEIVED", onion_address, desc_id_field,
- TO_REND_DATA_V2(rend_data)->auth_type,
- hsdir_id_digest, NULL);
- tor_free(desc_id_field);
-}
-
/* Send HS_DESC RECEIVED event
*
* Called when we successfully received a hidden service descriptor. */
@@ -2241,40 +2181,6 @@ control_event_hs_descriptor_uploaded(const char *id_digest,
id_digest, NULL);
}
-/** Send HS_DESC event to inform controller that query <b>rend_data</b>
- * failed to retrieve hidden service descriptor from directory identified by
- * <b>id_digest</b>. If NULL, "UNKNOWN" is used. If <b>reason</b> is not NULL,
- * add it to REASON= field.
- */
-void
-control_event_hsv2_descriptor_failed(const rend_data_t *rend_data,
- const char *hsdir_id_digest,
- const char *reason)
-{
- char *desc_id_field = NULL;
- const char *desc_id;
-
- if (BUG(!rend_data)) {
- return;
- }
-
- desc_id = get_desc_id_from_query(rend_data, hsdir_id_digest);
- if (desc_id != NULL) {
- char desc_id_base32[REND_DESC_ID_V2_LEN_BASE32 + 1];
- /* Set the descriptor ID digest to base32 so we can send it. */
- base32_encode(desc_id_base32, sizeof(desc_id_base32), desc_id,
- DIGEST_LEN);
- /* Extra whitespace is needed before the value. */
- tor_asprintf(&desc_id_field, " %s", desc_id_base32);
- }
-
- event_hs_descriptor_receive_end("FAILED", rend_data_get_address(rend_data),
- desc_id_field,
- TO_REND_DATA_V2(rend_data)->auth_type,
- hsdir_id_digest, reason);
- tor_free(desc_id_field);
-}
-
/** Send HS_DESC event to inform controller that the query to
* <b>onion_address</b> failed to retrieve hidden service descriptor
* <b>desc_id</b> from directory identified by <b>hsdir_id_digest</b>. If
diff --git a/src/feature/control/control_events.h b/src/feature/control/control_events.h
index 0ac233cc6e..901d2701cf 100644
--- a/src/feature/control/control_events.h
+++ b/src/feature/control/control_events.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -37,7 +37,11 @@ typedef enum stream_status_event_t {
STREAM_EVENT_NEW_RESOLVE = 6,
STREAM_EVENT_FAILED_RETRIABLE = 7,
STREAM_EVENT_REMAP = 8,
- STREAM_EVENT_CONTROLLER_WAIT = 9
+ STREAM_EVENT_CONTROLLER_WAIT = 9,
+ STREAM_EVENT_XOFF_SENT = 10,
+ STREAM_EVENT_XOFF_RECV = 11,
+ STREAM_EVENT_XON_SENT = 12,
+ STREAM_EVENT_XON_RECV = 13
} stream_status_event_t;
/** Used to indicate the type of a buildtime event */
@@ -137,7 +141,7 @@ void control_event_logmsg_pending(void);
int control_event_descriptors_changed(smartlist_t *routers);
int control_event_address_mapped(const char *from, const char *to,
time_t expires, const char *error,
- const int cached);
+ const int cached, uint64_t stream_id);
int control_event_my_descriptor_changed(void);
int control_event_network_liveness_update(int liveness);
int control_event_networkstatus_changed(smartlist_t *statuses);
@@ -202,13 +206,6 @@ void control_event_hs_descriptor_upload_end(const char *action,
const char *reason);
void control_event_hs_descriptor_uploaded(const char *hs_dir,
const char *onion_address);
-/* Hidden service v2 HS_DESC specific. */
-void control_event_hsv2_descriptor_failed(const rend_data_t *rend_data,
- const char *id_digest,
- const char *reason);
-void control_event_hsv2_descriptor_received(const char *onion_address,
- const rend_data_t *rend_data,
- const char *id_digest);
/* Hidden service v3 HS_DESC specific. */
void control_event_hsv3_descriptor_failed(const char *onion_address,
const char *desc_id,
diff --git a/src/feature/control/control_fmt.c b/src/feature/control/control_fmt.c
index 014427c5b5..cc8686818a 100644
--- a/src/feature/control/control_fmt.c
+++ b/src/feature/control/control_fmt.c
@@ -1,5 +1,5 @@
/* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -122,15 +122,11 @@ circuit_describe_status_for_controller(origin_circuit_t *circ)
}
}
- if (circ->rend_data != NULL || circ->hs_ident != NULL) {
+ if (circ->hs_ident != NULL) {
char addr[HS_SERVICE_ADDR_LEN_BASE32 + 1];
const char *onion_address;
- if (circ->rend_data) {
- onion_address = rend_data_get_address(circ->rend_data);
- } else {
- hs_build_address(&circ->hs_ident->identity_pk, HS_VERSION_THREE, addr);
- onion_address = addr;
- }
+ hs_build_address(&circ->hs_ident->identity_pk, HS_VERSION_THREE, addr);
+ onion_address = addr;
smartlist_add_asprintf(descparts, "REND_QUERY=%s", onion_address);
}
diff --git a/src/feature/control/control_fmt.h b/src/feature/control/control_fmt.h
index f3357cfc4e..acd4be752d 100644
--- a/src/feature/control/control_fmt.h
+++ b/src/feature/control/control_fmt.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/control/control_getinfo.c b/src/feature/control/control_getinfo.c
index 899f188546..e6874b0cf5 100644
--- a/src/feature/control/control_getinfo.c
+++ b/src/feature/control/control_getinfo.c
@@ -1,5 +1,5 @@
/* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -47,7 +47,6 @@
#include "feature/relay/router.h"
#include "feature/relay/routermode.h"
#include "feature/relay/selftest.h"
-#include "feature/rend/rendcache.h"
#include "feature/stats/geoip_stats.h"
#include "feature/stats/predict_ports.h"
#include "feature/stats/rephist.h"
@@ -540,25 +539,14 @@ getinfo_helper_dir(control_connection_t *control_conn,
hostname_type_t addr_type;
question += strlen("hs/client/desc/id/");
- if (rend_valid_v2_service_id(question)) {
- addr_type = ONION_V2_HOSTNAME;
- } else if (hs_address_is_valid(question)) {
+ if (hs_address_is_valid(question)) {
addr_type = ONION_V3_HOSTNAME;
} else {
*errmsg = "Invalid address";
return -1;
}
- if (addr_type == ONION_V2_HOSTNAME) {
- rend_cache_entry_t *e = NULL;
- if (!rend_cache_lookup_entry(question, -1, &e)) {
- /* Descriptor found in cache */
- *answer = tor_strdup(e->desc);
- } else {
- *errmsg = "Not found in cache";
- return -1;
- }
- } else {
+ if (addr_type == ONION_V3_HOSTNAME) {
ed25519_public_key_t service_pk;
const char *desc;
@@ -582,25 +570,14 @@ getinfo_helper_dir(control_connection_t *control_conn,
hostname_type_t addr_type;
question += strlen("hs/service/desc/id/");
- if (rend_valid_v2_service_id(question)) {
- addr_type = ONION_V2_HOSTNAME;
- } else if (hs_address_is_valid(question)) {
+ if (hs_address_is_valid(question)) {
addr_type = ONION_V3_HOSTNAME;
} else {
*errmsg = "Invalid address";
return -1;
}
- rend_cache_entry_t *e = NULL;
- if (addr_type == ONION_V2_HOSTNAME) {
- if (!rend_cache_lookup_v2_desc_as_service(question, &e)) {
- /* Descriptor found in cache */
- *answer = tor_strdup(e->desc);
- } else {
- *errmsg = "Not found in cache";
- return -1;
- }
- } else {
+ if (addr_type == ONION_V3_HOSTNAME) {
ed25519_public_key_t service_pk;
char *desc;
diff --git a/src/feature/control/control_getinfo.h b/src/feature/control/control_getinfo.h
index f61d632446..17f6352865 100644
--- a/src/feature/control/control_getinfo.h
+++ b/src/feature/control/control_getinfo.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/control/control_hs.c b/src/feature/control/control_hs.c
index 54b767cd0d..d1a5c0a3a9 100644
--- a/src/feature/control/control_hs.c
+++ b/src/feature/control/control_hs.c
@@ -1,5 +1,5 @@
/* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2019-2020, The Tor Project, Inc. */
+ * Copyright (c) 2019-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/control/control_hs.h b/src/feature/control/control_hs.h
index 8a0cd6818d..5b1bbd2008 100644
--- a/src/feature/control/control_hs.h
+++ b/src/feature/control/control_hs.h
@@ -1,5 +1,5 @@
/* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2019-2020, The Tor Project, Inc. */
+ * Copyright (c) 2019-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/control/control_proto.c b/src/feature/control/control_proto.c
index 98715ad9d5..319bb438b8 100644
--- a/src/feature/control/control_proto.c
+++ b/src/feature/control/control_proto.c
@@ -1,5 +1,5 @@
/* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/control/control_proto.h b/src/feature/control/control_proto.h
index 4c32b820d1..c95e1824a1 100644
--- a/src/feature/control/control_proto.h
+++ b/src/feature/control/control_proto.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/control/getinfo_geoip.c b/src/feature/control/getinfo_geoip.c
index 542f3e97f7..be89c2c641 100644
--- a/src/feature/control/getinfo_geoip.c
+++ b/src/feature/control/getinfo_geoip.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/control/getinfo_geoip.h b/src/feature/control/getinfo_geoip.h
index 5bc4b08414..5bd6d37191 100644
--- a/src/feature/control/getinfo_geoip.h
+++ b/src/feature/control/getinfo_geoip.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/dirauth/authmode.c b/src/feature/dirauth/authmode.c
index 0fde7bc679..de3261096e 100644
--- a/src/feature/dirauth/authmode.c
+++ b/src/feature/dirauth/authmode.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/dirauth/authmode.h b/src/feature/dirauth/authmode.h
index 6e6ba7f8ae..abc2aee20e 100644
--- a/src/feature/dirauth/authmode.h
+++ b/src/feature/dirauth/authmode.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2018-2020, The Tor Project, Inc. */
+/* Copyright (c) 2018-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/dirauth/bridgeauth.c b/src/feature/dirauth/bridgeauth.c
index b7bf3e4e04..ade30ed6b1 100644
--- a/src/feature/dirauth/bridgeauth.c
+++ b/src/feature/dirauth/bridgeauth.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/dirauth/bridgeauth.h b/src/feature/dirauth/bridgeauth.h
index 382d1cfcb8..dd02818987 100644
--- a/src/feature/dirauth/bridgeauth.h
+++ b/src/feature/dirauth/bridgeauth.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/dirauth/bwauth.c b/src/feature/dirauth/bwauth.c
index ff0c78f018..90b425842a 100644
--- a/src/feature/dirauth/bwauth.c
+++ b/src/feature/dirauth/bwauth.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/dirauth/bwauth.h b/src/feature/dirauth/bwauth.h
index 849c58e2fc..e981daf9a2 100644
--- a/src/feature/dirauth/bwauth.h
+++ b/src/feature/dirauth/bwauth.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/dirauth/dirauth_config.c b/src/feature/dirauth/dirauth_config.c
index 1ffd33e5f1..f98513ef75 100644
--- a/src/feature/dirauth/dirauth_config.c
+++ b/src/feature/dirauth/dirauth_config.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -434,6 +434,11 @@ dirauth_options_validate(const void *arg, char **msg)
"Recommended*Versions.");
}
+ if (options->AuthDirVoteGuardBwThresholdFraction > 1.0 ||
+ options->AuthDirVoteGuardBwThresholdFraction < 0.0) {
+ REJECT("Guard bandwdith threshold fraction is invalid.");
+ }
+
char *t;
/* Call these functions to produce warnings only. */
t = format_recommended_version_list(options->RecommendedClientVersions, 1);
diff --git a/src/feature/dirauth/dirauth_config.h b/src/feature/dirauth/dirauth_config.h
index 9042ff8779..00e37740c4 100644
--- a/src/feature/dirauth/dirauth_config.h
+++ b/src/feature/dirauth/dirauth_config.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/dirauth/dirauth_options.inc b/src/feature/dirauth/dirauth_options.inc
index 05726b8c2f..a43ed285ce 100644
--- a/src/feature/dirauth/dirauth_options.inc
+++ b/src/feature/dirauth/dirauth_options.inc
@@ -27,6 +27,10 @@ CONF_VAR(AuthDirHasIPv6Connectivity, BOOL, 0, "0")
* good. */
CONF_VAR(AuthDirListBadExits, BOOL, 0, "0")
+/** True iff we should list middle-only relays, and vote for all other
+ * relays as possibly suitable for other positions. */
+CONF_VAR(AuthDirListMiddleOnly, BOOL, 0, "0")
+
/** Do not permit more than this number of servers per IP address. */
CONF_VAR(AuthDirMaxServersPerAddr, POSINT, 0, "2")
@@ -72,6 +76,31 @@ CONF_VAR(RecommendedClientVersions, LINELIST, 0, NULL)
/** Which versions of tor should we tell users to run on relays? */
CONF_VAR(RecommendedServerVersions, LINELIST, 0, NULL)
+/** Relays which should be voted Guard regardless of uptime and bandwidth. */
+CONF_VAR(AuthDirVoteGuard, ROUTERSET, 0, NULL)
+
+/** If a relay's uptime is at least this value, then it is always considered
+ * stable, regardless of the rest of the network. This way we resist attacks
+ * where an attacker doubles the size of the network using allegedly
+ * high-uptime nodes, displacing all the current guards. */
+CONF_VAR(AuthDirVoteStableGuaranteeMinUptime, INTERVAL, 0, "30 days")
+
+/** If a relay's MTBF is at least this value, then it is always stable. See
+ * above. */
+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. */
+CONF_VAR(AuthDirVoteGuardGuaranteeTimeKnown, INTERVAL, 0, "8 days")
+
+/** A relay with sufficient WFU is around enough to be a guard. */
+CONF_VAR(AuthDirVoteGuardGuaranteeWFU, DOUBLE, 0, "0.98")
+
+/** The Guard flag bandwidth performance threshold fraction that is the
+ * fraction representing who gets the Guard flag out of all measured
+ * bandwidth. */
+CONF_VAR(AuthDirVoteGuardBwThresholdFraction, DOUBLE, 0, "0.75")
+
/** If an authority has been around for less than this amount of time, it
* does not believe its reachability information is accurate. Only
* altered on testing networks. */
diff --git a/src/feature/dirauth/dirauth_options_st.h b/src/feature/dirauth/dirauth_options_st.h
index 02a498c054..7d5515a6e1 100644
--- a/src/feature/dirauth/dirauth_options_st.h
+++ b/src/feature/dirauth/dirauth_options_st.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/dirauth/dirauth_periodic.c b/src/feature/dirauth/dirauth_periodic.c
index 19e51c5a05..57d93c8ffc 100644
--- a/src/feature/dirauth/dirauth_periodic.c
+++ b/src/feature/dirauth/dirauth_periodic.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/dirauth/dirauth_periodic.h b/src/feature/dirauth/dirauth_periodic.h
index ccdda92a77..ba2455381a 100644
--- a/src/feature/dirauth/dirauth_periodic.h
+++ b/src/feature/dirauth/dirauth_periodic.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/dirauth/dirauth_stub.c b/src/feature/dirauth/dirauth_stub.c
index 9f48ce14fd..42967aa0bc 100644
--- a/src/feature/dirauth/dirauth_stub.c
+++ b/src/feature/dirauth/dirauth_stub.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/dirauth/dirauth_sys.c b/src/feature/dirauth/dirauth_sys.c
index 07c5743877..8ea5c1de8f 100644
--- a/src/feature/dirauth/dirauth_sys.c
+++ b/src/feature/dirauth/dirauth_sys.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/dirauth/dirauth_sys.h b/src/feature/dirauth/dirauth_sys.h
index c512b91b33..0d54b9d3ee 100644
--- a/src/feature/dirauth/dirauth_sys.h
+++ b/src/feature/dirauth/dirauth_sys.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/dirauth/dircollate.c b/src/feature/dirauth/dircollate.c
index 2657f53853..cd299da3ab 100644
--- a/src/feature/dirauth/dircollate.c
+++ b/src/feature/dirauth/dircollate.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/dirauth/dircollate.h b/src/feature/dirauth/dircollate.h
index 90c6bddad5..00d34fbd6e 100644
--- a/src/feature/dirauth/dircollate.h
+++ b/src/feature/dirauth/dircollate.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/dirauth/dirvote.c b/src/feature/dirauth/dirvote.c
index f2032d71f6..1bb4fd7de1 100644
--- a/src/feature/dirauth/dirvote.c
+++ b/src/feature/dirauth/dirvote.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define DIRVOTE_PRIVATE
@@ -1479,6 +1479,21 @@ compute_nth_protocol_set(int n, int n_voters, const smartlist_t *votes)
return result;
}
+/** Helper: Takes a smartlist of `const char *` flags, and a flag to remove.
+ *
+ * Removes that flag if it is present in the list. Doesn't free it.
+ */
+static void
+remove_flag(smartlist_t *sl, const char *flag)
+{
+ /* We can't use smartlist_string_remove() here, since that doesn't preserve
+ * order, and since it frees elements from the string. */
+
+ int idx = smartlist_string_pos(sl, flag);
+ if (idx >= 0)
+ smartlist_del_keeporder(sl, idx);
+}
+
/** Given a list of vote networkstatus_t in <b>votes</b>, our public
* authority <b>identity_key</b>, our private authority <b>signing_key</b>,
* and the number of <b>total_authorities</b> that we believe exist in our
@@ -1633,6 +1648,9 @@ networkstatus_compute_consensus(smartlist_t *votes,
tor_free(votesec_list);
tor_free(distsec_list);
}
+ // True if anybody is voting on the BadExit flag.
+ const bool badexit_flag_is_listed =
+ smartlist_contains_string(flags, "BadExit");
chunks = smartlist_new();
@@ -1757,26 +1775,14 @@ networkstatus_compute_consensus(smartlist_t *votes,
}
{
- char *max_unmeasured_param = NULL;
- /* XXXX Extract this code into a common function. Or don't! see #19011 */
- if (params) {
- if (strcmpstart(params, "maxunmeasuredbw=") == 0)
- max_unmeasured_param = params;
- else
- max_unmeasured_param = strstr(params, " maxunmeasuredbw=");
- }
- if (max_unmeasured_param) {
- int ok = 0;
- char *eq = strchr(max_unmeasured_param, '=');
- if (eq) {
- max_unmeasured_bw_kb = (uint32_t)
- tor_parse_ulong(eq+1, 10, 1, UINT32_MAX, &ok, NULL);
- if (!ok) {
- log_warn(LD_DIR, "Bad element '%s' in max unmeasured bw param",
- escaped(max_unmeasured_param));
- max_unmeasured_bw_kb = DEFAULT_MAX_UNMEASURED_BW_KB;
- }
- }
+ if (consensus_method < MIN_METHOD_FOR_CORRECT_BWWEIGHTSCALE) {
+ max_unmeasured_bw_kb = (int32_t) extract_param_buggy(
+ params, "maxunmeasuredbw", DEFAULT_MAX_UNMEASURED_BW_KB);
+ } else {
+ max_unmeasured_bw_kb = dirvote_get_intermediate_param_value(
+ param_list, "maxunmeasurdbw", DEFAULT_MAX_UNMEASURED_BW_KB);
+ if (max_unmeasured_bw_kb < 1)
+ max_unmeasured_bw_kb = 1;
}
}
@@ -1936,7 +1942,7 @@ networkstatus_compute_consensus(smartlist_t *votes,
const char *chosen_name = NULL;
int exitsummary_disagreement = 0;
int is_named = 0, is_unnamed = 0, is_running = 0, is_valid = 0;
- int is_guard = 0, is_exit = 0, is_bad_exit = 0;
+ int is_guard = 0, is_exit = 0, is_bad_exit = 0, is_middle_only = 0;
int naming_conflict = 0;
int n_listing = 0;
char microdesc_digest[DIGEST256_LEN];
@@ -2067,7 +2073,6 @@ networkstatus_compute_consensus(smartlist_t *votes,
}
/* Set the flags. */
- smartlist_add(chosen_flags, (char*)"s"); /* for the start of the line. */
SMARTLIST_FOREACH_BEGIN(flags, const char *, fl) {
if (!strcmp(fl, "Named")) {
if (is_named)
@@ -2089,6 +2094,8 @@ networkstatus_compute_consensus(smartlist_t *votes,
is_running = 1;
else if (!strcmp(fl, "BadExit"))
is_bad_exit = 1;
+ else if (!strcmp(fl, "MiddleOnly"))
+ is_middle_only = 1;
else if (!strcmp(fl, "Valid"))
is_valid = 1;
}
@@ -2105,6 +2112,22 @@ networkstatus_compute_consensus(smartlist_t *votes,
if (!is_valid)
continue;
+ /* Starting with consensus method 32, we handle the middle-only
+ * flag specially: when it is present, we clear some flags, and
+ * set others. */
+ if (is_middle_only && consensus_method >= MIN_METHOD_FOR_MIDDLEONLY) {
+ remove_flag(chosen_flags, "Exit");
+ remove_flag(chosen_flags, "V2Dir");
+ remove_flag(chosen_flags, "Guard");
+ remove_flag(chosen_flags, "HSDir");
+ is_exit = is_guard = 0;
+ if (! is_bad_exit && badexit_flag_is_listed) {
+ is_bad_exit = 1;
+ smartlist_add(chosen_flags, (char *)"BadExit");
+ smartlist_sort_strings(chosen_flags); // restore order.
+ }
+ }
+
/* Pick the version. */
if (smartlist_len(versions)) {
sort_version_list(versions, 0);
@@ -2265,6 +2288,8 @@ networkstatus_compute_consensus(smartlist_t *votes,
smartlist_add_asprintf(chunks, "m %s\n", m);
}
/* Next line is all flags. The "\n" is missing. */
+ smartlist_add_asprintf(chunks, "s%s",
+ smartlist_len(chosen_flags)?" ":"");
smartlist_add(chunks,
smartlist_join_strings(chosen_flags, " ", 0, NULL));
/* Now the version line. */
@@ -2326,38 +2351,16 @@ networkstatus_compute_consensus(smartlist_t *votes,
smartlist_add_strdup(chunks, "directory-footer\n");
{
- int64_t weight_scale = BW_WEIGHT_SCALE;
- char *bw_weight_param = NULL;
-
- // Parse params, extract BW_WEIGHT_SCALE if present
- // DO NOT use consensus_param_bw_weight_scale() in this code!
- // The consensus is not formed yet!
- /* XXXX Extract this code into a common function. Or not: #19011. */
- if (params) {
- if (strcmpstart(params, "bwweightscale=") == 0)
- bw_weight_param = params;
- else
- bw_weight_param = strstr(params, " bwweightscale=");
- }
-
- if (bw_weight_param) {
- int ok=0;
- char *eq = strchr(bw_weight_param, '=');
- if (eq) {
- weight_scale = tor_parse_long(eq+1, 10, 1, INT32_MAX, &ok,
- NULL);
- if (!ok) {
- log_warn(LD_DIR, "Bad element '%s' in bw weight param",
- escaped(bw_weight_param));
- weight_scale = BW_WEIGHT_SCALE;
- }
- } else {
- log_warn(LD_DIR, "Bad element '%s' in bw weight param",
- escaped(bw_weight_param));
- weight_scale = BW_WEIGHT_SCALE;
- }
+ int64_t weight_scale;
+ if (consensus_method < MIN_METHOD_FOR_CORRECT_BWWEIGHTSCALE) {
+ weight_scale = extract_param_buggy(params, "bwweightscale",
+ BW_WEIGHT_SCALE);
+ } else {
+ weight_scale = dirvote_get_intermediate_param_value(
+ param_list, "bwweightscale", BW_WEIGHT_SCALE);
+ if (weight_scale < 1)
+ weight_scale = 1;
}
-
added_weights = networkstatus_compute_bw_weights_v10(chunks, G, M, E, D,
T, weight_scale);
}
@@ -2459,6 +2462,53 @@ networkstatus_compute_consensus(smartlist_t *votes,
return result;
}
+/** Extract the value of a parameter from a string encoding a list of
+ * parameters, badly.
+ *
+ * This is a deliberately buggy implementation, for backward compatibility
+ * with versions of Tor affected by #19011. Once all authorities have
+ * upgraded to consensus method 31 or later, then we can throw away this
+ * function. */
+STATIC int64_t
+extract_param_buggy(const char *params,
+ const char *param_name,
+ int64_t default_value)
+{
+ int64_t value = default_value;
+ const char *param_str = NULL;
+
+ if (params) {
+ char *prefix1 = NULL, *prefix2=NULL;
+ tor_asprintf(&prefix1, "%s=", param_name);
+ tor_asprintf(&prefix2, " %s=", param_name);
+ if (strcmpstart(params, prefix1) == 0)
+ param_str = params;
+ else
+ param_str = strstr(params, prefix2);
+ tor_free(prefix1);
+ tor_free(prefix2);
+ }
+
+ if (param_str) {
+ int ok=0;
+ char *eq = strchr(param_str, '=');
+ if (eq) {
+ value = tor_parse_long(eq+1, 10, 1, INT32_MAX, &ok, NULL);
+ if (!ok) {
+ log_warn(LD_DIR, "Bad element '%s' in %s",
+ escaped(param_str), param_name);
+ value = default_value;
+ }
+ } else {
+ log_warn(LD_DIR, "Bad element '%s' in %s",
+ escaped(param_str), param_name);
+ value = default_value;
+ }
+ }
+
+ return value;
+}
+
/** Given a list of networkstatus_t for each vote, return a newly allocated
* string containing the "package" lines for the vote. */
STATIC char *
@@ -4411,6 +4461,7 @@ get_all_possible_sybil(const smartlist_t *routers)
// Return the digestmap: it now contains all the possible sybils
return omit_as_sybil;
}
+
/** Given a platform string as in a routerinfo_t (possibly null), return a
* newly allocated version string for a networkstatus document, or NULL if the
* platform doesn't give a Tor version. */
@@ -4528,13 +4579,16 @@ routers_make_ed_keys_unique(smartlist_t *routers)
} SMARTLIST_FOREACH_END(ri);
}
-/** Routerstatus <b>rs</b> is part of a group of routers that are on
- * too narrow an IP-space. Clear out its flags since we don't want it be used
+/** Routerstatus <b>rs</b> is part of a group of routers that are on too
+ * narrow an IP-space. Clear out its flags since we don't want it be used
* because of its Sybil-like appearance.
*
* Leave its BadExit flag alone though, since if we think it's a bad exit,
* we want to vote that way in case all the other authorities are voting
* Running and Exit.
+ *
+ * Also set the Sybil flag in order to let a relay operator know that's
+ * why their relay hasn't been voted on.
*/
static void
clear_status_flags_on_sybil(routerstatus_t *rs)
@@ -4542,6 +4596,7 @@ clear_status_flags_on_sybil(routerstatus_t *rs)
rs->is_authority = rs->is_exit = rs->is_stable = rs->is_fast =
rs->is_flagged_running = rs->is_named = rs->is_valid =
rs->is_hs_dir = rs->is_v2_dir = rs->is_possible_guard = 0;
+ rs->is_sybil = 1;
/* FFFF we might want some mechanism to check later on if we
* missed zeroing any flags: it's easy to add a new flag but
* forget to add it to this clause. */
@@ -4556,12 +4611,14 @@ const char DIRVOTE_UNIVERSAL_FLAGS[] =
"HSDir "
"Stable "
"StaleDesc "
+ "Sybil "
"V2Dir "
"Valid";
/** Space-separated list of all flags that we may or may not vote on,
* depending on our configuration. */
const char DIRVOTE_OPTIONAL_FLAGS[] =
"BadExit "
+ "MiddleOnly "
"Running";
/** Return a new networkstatus_t* containing our current opinion. (For v3
@@ -4579,7 +4636,8 @@ dirserv_generate_networkstatus_vote_obj(crypto_pk_t *private_key,
smartlist_t *routers, *routerstatuses;
char identity_digest[DIGEST_LEN];
char signing_key_digest[DIGEST_LEN];
- const int listbadexits = d_options->AuthDirListBadExits;
+ const int list_bad_exits = d_options->AuthDirListBadExits;
+ const int list_middle_only = d_options->AuthDirListMiddleOnly;
routerlist_t *rl = router_get_routerlist();
time_t now = time(NULL);
time_t cutoff = now - ROUTER_MAX_AGE_TO_PUBLISH;
@@ -4684,7 +4742,8 @@ dirserv_generate_networkstatus_vote_obj(crypto_pk_t *private_key,
vrs = tor_malloc_zero(sizeof(vote_routerstatus_t));
rs = &vrs->status;
dirauth_set_routerstatus_from_routerinfo(rs, node, ri, now,
- listbadexits);
+ list_bad_exits,
+ list_middle_only);
if (ri->cache_info.signing_key_cert) {
memcpy(vrs->ed25519_id,
@@ -4735,7 +4794,6 @@ dirserv_generate_networkstatus_vote_obj(crypto_pk_t *private_key,
dirserv_read_measured_bandwidths(options->V3BandwidthsFile,
routerstatuses, bw_file_headers,
bw_file_digest256);
-
} else {
/*
* No bandwidths file; clear the measured bandwidth cache in case we had
@@ -4807,8 +4865,10 @@ dirserv_generate_networkstatus_vote_obj(crypto_pk_t *private_key,
0, SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
if (vote_on_reachability)
smartlist_add_strdup(v3_out->known_flags, "Running");
- if (listbadexits)
+ if (list_bad_exits)
smartlist_add_strdup(v3_out->known_flags, "BadExit");
+ if (list_middle_only)
+ smartlist_add_strdup(v3_out->known_flags, "MiddleOnly");
smartlist_sort_strings(v3_out->known_flags);
if (d_options->ConsensusParams) {
diff --git a/src/feature/dirauth/dirvote.h b/src/feature/dirauth/dirvote.h
index 81a7733e8c..64aaec116e 100644
--- a/src/feature/dirauth/dirvote.h
+++ b/src/feature/dirauth/dirvote.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -53,7 +53,7 @@
#define MIN_SUPPORTED_CONSENSUS_METHOD 28
/** The highest consensus method that we currently support. */
-#define MAX_SUPPORTED_CONSENSUS_METHOD 30
+#define MAX_SUPPORTED_CONSENSUS_METHOD 32
/**
* Lowest consensus method where microdescriptor lines are put in canonical
@@ -65,6 +65,15 @@
* See #7869 */
#define MIN_METHOD_FOR_UNPADDED_NTOR_KEY 30
+/** Lowest consensus method for which we use the correct algorithm for
+ * extracting the bwweightscale= and maxunmeasuredbw= parameters. See #19011.
+ */
+#define MIN_METHOD_FOR_CORRECT_BWWEIGHTSCALE 31
+
+/** Lowest consensus method for which we handle the MiddleOnly flag specially.
+ */
+#define MIN_METHOD_FOR_MIDDLEONLY 32
+
/** 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.) */
@@ -259,6 +268,9 @@ STATIC
char *networkstatus_get_detached_signatures(smartlist_t *consensuses);
STATIC microdesc_t *dirvote_create_microdescriptor(const routerinfo_t *ri,
int consensus_method);
+STATIC int64_t extract_param_buggy(const char *params,
+ const char *param_name,
+ int64_t default_value);
#endif /* defined(DIRVOTE_PRIVATE) */
diff --git a/src/feature/dirauth/dsigs_parse.c b/src/feature/dirauth/dsigs_parse.c
index d0bb931814..5ac2ff6e49 100644
--- a/src/feature/dirauth/dsigs_parse.c
+++ b/src/feature/dirauth/dsigs_parse.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/dirauth/dsigs_parse.h b/src/feature/dirauth/dsigs_parse.h
index b25e3e0b28..656c569b3f 100644
--- a/src/feature/dirauth/dsigs_parse.h
+++ b/src/feature/dirauth/dsigs_parse.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/dirauth/guardfraction.c b/src/feature/dirauth/guardfraction.c
index b84f804f5f..98ea04f643 100644
--- a/src/feature/dirauth/guardfraction.c
+++ b/src/feature/dirauth/guardfraction.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/dirauth/guardfraction.h b/src/feature/dirauth/guardfraction.h
index c10fd9b7bb..1d0218eb8e 100644
--- a/src/feature/dirauth/guardfraction.h
+++ b/src/feature/dirauth/guardfraction.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/dirauth/keypin.c b/src/feature/dirauth/keypin.c
index 21afff550a..29aefd1069 100644
--- a/src/feature/dirauth/keypin.c
+++ b/src/feature/dirauth/keypin.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2020, The Tor Project, Inc. */
+/* Copyright (c) 2014-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -58,18 +58,16 @@
* with which Ed25519 keys, and force such associations to be permanent.
*
* This module implements a key-pinning mechanism to ensure that it's safe
- * to use RSA keys as identitifers even as we migrate to Ed25519 keys. It
- * remembers, for every Ed25519 key we've seen, what the associated Ed25519
+ * to use RSA keys as identifiers even as we migrate to Ed25519 keys. It
+ * remembers, for every Ed25519 key we've seen, what the associated RSA
* key is. This way, if we see a different Ed25519 key with that RSA key,
* we'll know that there's a mismatch.
*
- * (As of this writing, these key associations are advisory only, mostly
- * because some relay operators kept mishandling their Ed25519 keys during
- * the initial Ed25519 rollout. We should fix this problem, and then toggle
- * the AuthDirPinKeys option.)
+ * As of Tor 0.3.0.2-alpha the AuthDirPinKeys option has been on, meaning
+ * we drop descriptors with mismatches.
*
* We persist these entries to disk using a simple format, where each line
- * has a base64-encoded RSA SHA1 hash, then a base64-endoded Ed25519 key.
+ * has a base64-encoded RSA SHA1 hash, then a base64-encoded Ed25519 key.
* Empty lines, malformed lines, and lines beginning with # are
* ignored. Lines beginning with @ are reserved for future extensions.
*
diff --git a/src/feature/dirauth/keypin.h b/src/feature/dirauth/keypin.h
index 881f010f0e..b94cf59d9c 100644
--- a/src/feature/dirauth/keypin.h
+++ b/src/feature/dirauth/keypin.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2020, The Tor Project, Inc. */
+/* Copyright (c) 2014-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/dirauth/ns_detached_signatures_st.h b/src/feature/dirauth/ns_detached_signatures_st.h
index f409431ec1..1bb5378e1d 100644
--- a/src/feature/dirauth/ns_detached_signatures_st.h
+++ b/src/feature/dirauth/ns_detached_signatures_st.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/dirauth/process_descs.c b/src/feature/dirauth/process_descs.c
index a382f237c4..f1d4f49c46 100644
--- a/src/feature/dirauth/process_descs.c
+++ b/src/feature/dirauth/process_descs.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -226,6 +226,8 @@ dirserv_load_fingerprint_file(void)
add_status = RTR_BADEXIT;
} else if (!strcasecmp(nickname, "!invalid")) {
add_status = RTR_INVALID;
+ } else if (!strcasecmp(nickname, "!middleonly")) {
+ add_status = RTR_MIDDLEONLY;
}
/* Check if fingerprint is RSA or ed25519 by verifying it. */
@@ -402,21 +404,17 @@ dirserv_rejects_tor_version(const char *platform,
static const char please_upgrade_string[] =
"Tor version is insecure or unsupported. Please upgrade!";
- /* Versions before Tor 0.3.5 are unsupported.
- *
- * Also, reject unstable versions of 0.3.5, since (as of this writing)
- * they are almost none of the network. */
- if (!tor_version_as_new_as(platform,"0.3.5.7")) {
- if (msg)
+ /* 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;
}
- /* Series between Tor 0.3.6 and 0.4.1 inclusive are unsupported. Reject
- * them. 0.3.6.0-alpha-dev only existed for a short time, before it was
- * renamed to 0.4.0.0-alpha-dev. */
- if (tor_version_as_new_as(platform,"0.3.6.0-alpha-dev") &&
- !tor_version_as_new_as(platform,"0.4.2.1-alpha")) {
+ /* Reject 0.4.6.x series. */
+ if (tor_version_as_new_as(platform, "0.4.6.0") &&
+ !tor_version_as_new_as(platform, "0.4.7.0-alpha-dev")) {
if (msg) {
*msg = please_upgrade_string;
}
@@ -496,6 +494,13 @@ dirserv_get_status_impl(const char *id_digest,
result |= RTR_BADEXIT;
}
+ if (authdir_policy_middleonly_address(ipv4_addr, ipv4_orport)) {
+ log_fn(severity, LD_DIRSERV,
+ "Marking '%s' as middle-only because of address '%s'",
+ nickname, fmt_addr(ipv4_addr));
+ result |= RTR_MIDDLEONLY;
+ }
+
if (!authdir_policy_permits_address(ipv4_addr, ipv4_orport)) {
log_fn(severity, LD_DIRSERV, "Rejecting '%s' because of address '%s'",
nickname, fmt_addr(ipv4_addr));
@@ -630,6 +635,7 @@ dirserv_set_node_flags_from_authoritative_status(node_t *node,
{
node->is_valid = (authstatus & RTR_INVALID) ? 0 : 1;
node->is_bad_exit = (authstatus & RTR_BADEXIT) ? 1 : 0;
+ node->is_middle_only = (authstatus & RTR_MIDDLEONLY) ? 1 : 0;
}
/** True iff <b>a</b> is more severe than <b>b</b>. */
@@ -963,6 +969,11 @@ directory_remove_invalid(void)
(r & RTR_BADEXIT) ? "bad" : "good");
node->is_bad_exit = (r&RTR_BADEXIT) ? 1: 0;
}
+ if (bool_neq((r & RTR_MIDDLEONLY), node->is_middle_only)) {
+ log_info(LD_DIRSERV, "Router '%s' is now %smiddle-only", description,
+ (r & RTR_MIDDLEONLY) ? "" : "not");
+ node->is_middle_only = (r&RTR_MIDDLEONLY) ? 1: 0;
+ }
} SMARTLIST_FOREACH_END(node);
routerlist_assert_ok(rl);
diff --git a/src/feature/dirauth/process_descs.h b/src/feature/dirauth/process_descs.h
index 1461ab697d..a509eb1fbe 100644
--- a/src/feature/dirauth/process_descs.h
+++ b/src/feature/dirauth/process_descs.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -45,7 +45,8 @@ typedef struct authdir_config_t {
#define RTR_REJECT 4 /**< We will not publish this router. */
/* 8 Historically used to avoid using this as a dir. */
#define RTR_BADEXIT 16 /**< We'll tell clients not to use this as an exit. */
-/* 32 Historically used to indicade Unnamed */
+/** We'll vote to only use this router as a midpoint. */
+#define RTR_MIDDLEONLY 32
#endif /* defined(PROCESS_DESCS_PRIVATE) || defined(TOR_UNIT_TESTS) */
diff --git a/src/feature/dirauth/reachability.c b/src/feature/dirauth/reachability.c
index 8717646314..9754ded133 100644
--- a/src/feature/dirauth/reachability.c
+++ b/src/feature/dirauth/reachability.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/dirauth/reachability.h b/src/feature/dirauth/reachability.h
index 19448a67f3..74be47df66 100644
--- a/src/feature/dirauth/reachability.h
+++ b/src/feature/dirauth/reachability.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/dirauth/recommend_pkg.c b/src/feature/dirauth/recommend_pkg.c
index 84254566c6..5d7e53c6d9 100644
--- a/src/feature/dirauth/recommend_pkg.c
+++ b/src/feature/dirauth/recommend_pkg.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/dirauth/recommend_pkg.h b/src/feature/dirauth/recommend_pkg.h
index dcd9f8be8a..5ec031c944 100644
--- a/src/feature/dirauth/recommend_pkg.h
+++ b/src/feature/dirauth/recommend_pkg.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/dirauth/shared_random.c b/src/feature/dirauth/shared_random.c
index e7c13787c4..72c5a79e97 100644
--- a/src/feature/dirauth/shared_random.c
+++ b/src/feature/dirauth/shared_random.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2020, The Tor Project, Inc. */
+/* Copyright (c) 2016-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/dirauth/shared_random.h b/src/feature/dirauth/shared_random.h
index c4e259dcdb..384e59a43d 100644
--- a/src/feature/dirauth/shared_random.h
+++ b/src/feature/dirauth/shared_random.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2020, The Tor Project, Inc. */
+/* Copyright (c) 2016-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#ifndef TOR_SHARED_RANDOM_H
diff --git a/src/feature/dirauth/shared_random_state.c b/src/feature/dirauth/shared_random_state.c
index c555202942..80848daee4 100644
--- a/src/feature/dirauth/shared_random_state.c
+++ b/src/feature/dirauth/shared_random_state.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2020, The Tor Project, Inc. */
+/* Copyright (c) 2016-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/dirauth/shared_random_state.h b/src/feature/dirauth/shared_random_state.h
index 3a34bcc3e7..0b672b18c8 100644
--- a/src/feature/dirauth/shared_random_state.h
+++ b/src/feature/dirauth/shared_random_state.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2020, The Tor Project, Inc. */
+/* Copyright (c) 2016-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/dirauth/vote_microdesc_hash_st.h b/src/feature/dirauth/vote_microdesc_hash_st.h
index 6870bbab2c..f8b9288507 100644
--- a/src/feature/dirauth/vote_microdesc_hash_st.h
+++ b/src/feature/dirauth/vote_microdesc_hash_st.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/dirauth/voteflags.c b/src/feature/dirauth/voteflags.c
index 3938b61adb..71ee03e265 100644
--- a/src/feature/dirauth/voteflags.c
+++ b/src/feature/dirauth/voteflags.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -36,24 +36,6 @@
#include "lib/container/order.h"
-/** If a router's uptime is at least this value, then it is always
- * considered stable, regardless of the rest of the network. This
- * way we resist attacks where an attacker doubles the size of the
- * network using allegedly high-uptime nodes, displacing all the
- * current guards. */
-#define UPTIME_TO_GUARANTEE_STABLE (3600*24*30)
-/** If a router's MTBF is at least this value, then it is always stable.
- * See above. (Corresponds to about 7 days for current decay rates.) */
-#define MTBF_TO_GUARANTEE_STABLE (60*60*24*5)
-/** Similarly, every node with at least this much weighted time known can be
- * considered familiar enough to be a guard. Corresponds to about 20 days for
- * current decay rates.
- */
-#define TIME_KNOWN_TO_GUARANTEE_FAMILIAR (8*24*60*60)
-/** Similarly, every node with sufficient WFU is around enough to be a guard.
- */
-#define WFU_TO_GUARANTEE_GUARD (0.98)
-
/* Thresholds for server performance: set by
* dirserv_compute_performance_thresholds, and used by
* generate_v2_networkstatus */
@@ -111,13 +93,13 @@ dirserv_thinks_router_is_unreliable(time_t now,
*/
long uptime = real_uptime(router, now);
if ((unsigned)uptime < stable_uptime &&
- (unsigned)uptime < UPTIME_TO_GUARANTEE_STABLE)
+ uptime < dirauth_get_options()->AuthDirVoteStableGuaranteeMinUptime)
return 1;
} else {
double mtbf =
rep_hist_get_stability(router->cache_info.identity_digest, now);
if (mtbf < stable_mtbf &&
- mtbf < MTBF_TO_GUARANTEE_STABLE)
+ mtbf < dirauth_get_options()->AuthDirVoteStableGuaranteeMTBF)
return 1;
}
}
@@ -325,13 +307,15 @@ dirserv_compute_performance_thresholds(digestmap_t *omit_as_sybil)
/* (Now bandwidths is sorted.) */
if (fast_bandwidth_kb < RELAY_REQUIRED_MIN_BANDWIDTH/(2 * 1000))
fast_bandwidth_kb = bandwidths_kb[n_active/4];
+ int nth = (int)(n_active *
+ dirauth_options->AuthDirVoteGuardBwThresholdFraction);
guard_bandwidth_including_exits_kb =
- third_quartile_uint32(bandwidths_kb, n_active);
+ find_nth_uint32(bandwidths_kb, n_active, nth);
guard_tk = find_nth_long(tks, n_active, n_active/8);
}
- if (guard_tk > TIME_KNOWN_TO_GUARANTEE_FAMILIAR)
- guard_tk = TIME_KNOWN_TO_GUARANTEE_FAMILIAR;
+ if (guard_tk > dirauth_options->AuthDirVoteGuardGuaranteeTimeKnown)
+ guard_tk = dirauth_options->AuthDirVoteGuardGuaranteeTimeKnown;
{
/* We can vote on a parameter for the minimum and maximum. */
@@ -379,15 +363,16 @@ dirserv_compute_performance_thresholds(digestmap_t *omit_as_sybil)
} SMARTLIST_FOREACH_END(node);
if (n_familiar)
guard_wfu = median_double(wfus, n_familiar);
- if (guard_wfu > WFU_TO_GUARANTEE_GUARD)
- guard_wfu = WFU_TO_GUARANTEE_GUARD;
+ if (guard_wfu > dirauth_options->AuthDirVoteGuardGuaranteeWFU)
+ guard_wfu = dirauth_options->AuthDirVoteGuardGuaranteeWFU;
enough_mtbf_info = rep_hist_have_measured_enough_stability();
if (n_active_nonexit) {
+ int nth = (int)(n_active_nonexit *
+ dirauth_options->AuthDirVoteGuardBwThresholdFraction);
guard_bandwidth_excluding_exits_kb =
- find_nth_uint32(bandwidths_excluding_exits_kb,
- n_active_nonexit, n_active_nonexit*3/4);
+ find_nth_uint32(bandwidths_excluding_exits_kb, n_active_nonexit, nth);
}
log_info(LD_DIRSERV,
@@ -457,7 +442,26 @@ dirserv_get_flag_thresholds_line(void)
return result;
}
-/* DOCDOC running_long_enough_to_decide_unreachable */
+/** Directory authorities should avoid expressing an opinion on the
+ * Running flag if their own uptime is too low for the opinion to be
+ * accurate. They implement this step by not listing Running on the
+ * "known-flags" line in their vote.
+ *
+ * The default threshold is 30 minutes, because authorities do a full
+ * reachability sweep of the ID space every 10*128=1280 seconds
+ * (see REACHABILITY_TEST_CYCLE_PERIOD).
+ *
+ * For v3 dir auths, as long as some authorities express an opinion about
+ * Running, it's fine if a few authorities don't. There's an explicit
+ * check, when making the consensus, to abort if *no* authorities list
+ * Running as a known-flag.
+ *
+ * For the bridge authority, if it doesn't vote about Running, the
+ * resulting networkstatus file simply won't list any bridges as Running.
+ * That means the supporting tools, like bridgedb/rdsys and onionoo, need
+ * to be able to handle getting a bridge networkstatus document with no
+ * Running flags. For more details, see
+ * https://bugs.torproject.org/tpo/anti-censorship/rdsys/102 */
int
running_long_enough_to_decide_unreachable(void)
{
@@ -554,6 +558,21 @@ should_publish_node_ipv6(const node_t *node, const routerinfo_t *ri,
router_is_me(ri));
}
+/** Set routerstatus flags based on the authority options. Same as the testing
+ * function but for the main network. */
+static void
+dirserv_set_routerstatus_flags(routerstatus_t *rs)
+{
+ const dirauth_options_t *options = dirauth_get_options();
+
+ tor_assert(rs);
+
+ /* Assign Guard flag to relays that can get it unconditionnaly. */
+ if (routerset_contains_routerstatus(options->AuthDirVoteGuard, rs, 0)) {
+ rs->is_possible_guard = 1;
+ }
+}
+
/**
* Extract status information from <b>ri</b> and from other authority
* functions and store it in <b>rs</b>, as per
@@ -565,7 +584,8 @@ dirauth_set_routerstatus_from_routerinfo(routerstatus_t *rs,
node_t *node,
const routerinfo_t *ri,
time_t now,
- int listbadexits)
+ int listbadexits,
+ int listmiddleonly)
{
const or_options_t *options = get_options();
uint32_t routerbw_kb = dirserv_get_credible_bandwidth_kb(ri);
@@ -597,6 +617,14 @@ dirauth_set_routerstatus_from_routerinfo(routerstatus_t *rs,
/* Override rs->is_bad_exit */
rs->is_bad_exit = listbadexits && node->is_bad_exit;
+ /* Override rs->is_middle_only and related flags. */
+ rs->is_middle_only = listmiddleonly && node->is_middle_only;
+ if (rs->is_middle_only) {
+ if (listbadexits)
+ rs->is_bad_exit = 1;
+ rs->is_exit = rs->is_possible_guard = rs->is_hs_dir = rs->is_v2_dir = 0;
+ }
+
/* Set rs->is_staledesc. */
rs->is_staledesc =
(ri->cache_info.published_on + DESC_IS_STALE_INTERVAL) < now;
@@ -610,6 +638,8 @@ dirauth_set_routerstatus_from_routerinfo(routerstatus_t *rs,
if (options->TestingTorNetwork) {
dirserv_set_routerstatus_testing(rs);
+ } else {
+ dirserv_set_routerstatus_flags(rs);
}
}
diff --git a/src/feature/dirauth/voteflags.h b/src/feature/dirauth/voteflags.h
index 91f3854573..8371f1c315 100644
--- a/src/feature/dirauth/voteflags.h
+++ b/src/feature/dirauth/voteflags.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -22,7 +22,8 @@ void dirauth_set_routerstatus_from_routerinfo(routerstatus_t *rs,
node_t *node,
const routerinfo_t *ri,
time_t now,
- int listbadexits);
+ int listbadexits,
+ int listmiddleonly);
void dirserv_compute_performance_thresholds(digestmap_t *omit_as_sybil);
#endif /* defined(HAVE_MODULE_DIRAUTH) */
diff --git a/src/feature/dirauth/voting_schedule.c b/src/feature/dirauth/voting_schedule.c
index efc4a0b316..3a4abca4cb 100644
--- a/src/feature/dirauth/voting_schedule.c
+++ b/src/feature/dirauth/voting_schedule.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2018-2020, The Tor Project, Inc. */
+/* Copyright (c) 2018-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/dirauth/voting_schedule.h b/src/feature/dirauth/voting_schedule.h
index 271bdcda33..8d13e208b7 100644
--- a/src/feature/dirauth/voting_schedule.h
+++ b/src/feature/dirauth/voting_schedule.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2018-2020, The Tor Project, Inc. */
+/* Copyright (c) 2018-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/dircache/cached_dir_st.h b/src/feature/dircache/cached_dir_st.h
index ede1d028da..92af3752e0 100644
--- a/src/feature/dircache/cached_dir_st.h
+++ b/src/feature/dircache/cached_dir_st.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/dircache/conscache.c b/src/feature/dircache/conscache.c
index 2a831aa447..66ab9712a0 100644
--- a/src/feature/dircache/conscache.c
+++ b/src/feature/dircache/conscache.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017-2020, The Tor Project, Inc. */
+/* Copyright (c) 2017-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/dircache/conscache.h b/src/feature/dircache/conscache.h
index ace5908e40..b3912f3f54 100644
--- a/src/feature/dircache/conscache.h
+++ b/src/feature/dircache/conscache.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017-2020, The Tor Project, Inc. */
+/* Copyright (c) 2017-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/dircache/consdiffmgr.c b/src/feature/dircache/consdiffmgr.c
index 21f536432c..9a3d4db560 100644
--- a/src/feature/dircache/consdiffmgr.c
+++ b/src/feature/dircache/consdiffmgr.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017-2020, The Tor Project, Inc. */
+/* Copyright (c) 2017-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -183,9 +183,9 @@ static HT_HEAD(cdm_diff_ht, cdm_diff_t) cdm_diff_ht = HT_INITIALIZER();
// diff manager becomes larger than 64. To see if the issue goes away, we
// hardcode this value to 64 now while we investigate a better solution.
# define CACHE_MAX_NUM 64
-#else
+#else /* !defined(_WIN32) */
# define CACHE_MAX_NUM 128
-#endif
+#endif /* defined(_WIN32) */
/**
* Configuration for this module
diff --git a/src/feature/dircache/consdiffmgr.h b/src/feature/dircache/consdiffmgr.h
index 27b8165e94..6f8bfed3ee 100644
--- a/src/feature/dircache/consdiffmgr.h
+++ b/src/feature/dircache/consdiffmgr.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017-2020, The Tor Project, Inc. */
+/* Copyright (c) 2017-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/dircache/dircache.c b/src/feature/dircache/dircache.c
index 2af550a760..7319b96caf 100644
--- a/src/feature/dircache/dircache.c
+++ b/src/feature/dircache/dircache.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -31,7 +31,6 @@
#include "feature/nodelist/routerlist.h"
#include "feature/relay/relay_config.h"
#include "feature/relay/routermode.h"
-#include "feature/rend/rendcache.h"
#include "feature/stats/geoip_stats.h"
#include "feature/stats/rephist.h"
#include "lib/compress/compress.h"
@@ -1347,7 +1346,7 @@ handle_get_keys(dir_connection_t *conn, const get_handler_args_t *args)
return 0;
}
-/** Helper function for GET /tor/hs/3/... Only for version 3.
+/** Helper function for GET `/tor/hs/3/...`. Only for version 3.
*/
STATIC int
handle_get_hs_descriptor_v3(dir_connection_t *conn,
diff --git a/src/feature/dircache/dircache.h b/src/feature/dircache/dircache.h
index 8e0945125d..2c90a77ae2 100644
--- a/src/feature/dircache/dircache.h
+++ b/src/feature/dircache/dircache.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/dircache/dircache_stub.c b/src/feature/dircache/dircache_stub.c
index 725c44bd4d..16da0ae4ce 100644
--- a/src/feature/dircache/dircache_stub.c
+++ b/src/feature/dircache/dircache_stub.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/dircache/dirserv.c b/src/feature/dircache/dirserv.c
index fb8db879a4..2b5349923d 100644
--- a/src/feature/dircache/dirserv.c
+++ b/src/feature/dircache/dirserv.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "core/or/or.h"
diff --git a/src/feature/dircache/dirserv.h b/src/feature/dircache/dirserv.h
index 73a64b1b7e..cde38ff1b2 100644
--- a/src/feature/dircache/dirserv.h
+++ b/src/feature/dircache/dirserv.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/dirclient/dir_server_st.h b/src/feature/dirclient/dir_server_st.h
index 57530a571b..ac45f3787b 100644
--- a/src/feature/dirclient/dir_server_st.h
+++ b/src/feature/dirclient/dir_server_st.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -16,6 +16,8 @@
#include "core/or/or.h"
#include "feature/nodelist/routerstatus_st.h"
+struct smartlist_t;
+
/** Represents information about a single trusted or fallback directory
* server. */
struct dir_server_t {
@@ -48,6 +50,10 @@ struct dir_server_t {
time_t addr_current_at; /**< When was the document that we derived the
* address information from published? */
+ /** Authority only. Can be null. If present, a list of auth_dirport_t
+ * representing HTTP dirports for this authority. */
+ struct smartlist_t *auth_dirports;
+
routerstatus_t fake_status; /**< Used when we need to pass this trusted
* dir_server_t to
* directory_request_set_routerstatus.
diff --git a/src/feature/dirclient/dirclient.c b/src/feature/dirclient/dirclient.c
index cc6c5e04f4..4e9c8e2f45 100644
--- a/src/feature/dirclient/dirclient.c
+++ b/src/feature/dirclient/dirclient.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -47,10 +47,7 @@
#include "feature/relay/relay_find_addr.h"
#include "feature/relay/routermode.h"
#include "feature/relay/selftest.h"
-#include "feature/rend/rendcache.h"
-#include "feature/rend/rendclient.h"
#include "feature/rend/rendcommon.h"
-#include "feature/rend/rendservice.h"
#include "feature/stats/predict_ports.h"
#include "lib/cc/ctassert.h"
@@ -67,7 +64,6 @@
#include "feature/nodelist/networkstatus_st.h"
#include "feature/nodelist/node_st.h"
#include "feature/nodelist/routerinfo_st.h"
-#include "feature/rend/rend_service_descriptor_st.h"
/** Maximum size, in bytes, for any directory object that we've downloaded. */
#define MAX_DIR_DL_SIZE ((1<<24)-1) /* 16 MB - 1 */
@@ -120,10 +116,6 @@ dir_conn_purpose_to_string(int purpose)
return "status vote fetch";
case DIR_PURPOSE_FETCH_DETACHED_SIGNATURES:
return "consensus signature fetch";
- case DIR_PURPOSE_FETCH_RENDDESC_V2:
- return "hidden-service v2 descriptor fetch";
- case DIR_PURPOSE_UPLOAD_RENDDESC_V2:
- return "hidden-service v2 descriptor upload";
case DIR_PURPOSE_FETCH_HSDESC:
return "hidden-service descriptor fetch";
case DIR_PURPOSE_UPLOAD_HSDESC:
@@ -704,24 +696,6 @@ directory_choose_address_routerstatus(const routerstatus_t *status,
return 0;
}
-/** Return true iff <b>conn</b> is the client side of a directory connection
- * we launched to ourself in order to determine the reachability of our
- * dir_port. */
-static int
-directory_conn_is_self_reachability_test(dir_connection_t *conn)
-{
- if (conn->requested_resource &&
- !strcmpstart(conn->requested_resource,"authority")) {
- const routerinfo_t *me = router_get_my_routerinfo();
- if (me &&
- router_digest_is_me(conn->identity_digest) &&
- tor_addr_eq(&TO_CONN(conn)->addr, &me->ipv4_addr) &&
- me->ipv4_dirport == conn->base_.port)
- return 1;
- }
- return 0;
-}
-
/** Called when we are unable to complete the client's request to a directory
* server due to a network error: Mark the router as down and try again if
* possible.
@@ -734,9 +708,6 @@ connection_dir_client_request_failed(dir_connection_t *conn)
* failed. */
entry_guard_failed(&conn->guard_state);
}
- if (directory_conn_is_self_reachability_test(conn)) {
- return; /* this was a test fetch. don't retry. */
- }
if (!entry_list_is_constrained(get_options()))
/* We must not set a directory to non-running for HS purposes else we end
* up flagging nodes from the hashring has unusable. It doesn't have direct
@@ -965,7 +936,6 @@ directory_request_new(uint8_t dir_purpose)
tor_assert(dir_purpose >= DIR_PURPOSE_MIN_);
tor_assert(dir_purpose <= DIR_PURPOSE_MAX_);
tor_assert(dir_purpose != DIR_PURPOSE_SERVER);
- tor_assert(dir_purpose != DIR_PURPOSE_HAS_FETCHED_RENDDESC_V2);
tor_assert(dir_purpose != DIR_PURPOSE_HAS_FETCHED_HSDESC);
directory_request_t *result = tor_malloc_zero(sizeof(*result));
@@ -1103,21 +1073,6 @@ directory_request_add_header(directory_request_t *req,
config_line_prepend(&req->additional_headers, key, val);
}
/**
- * Set an object containing HS data to be associated with this request. Note
- * that only an alias to <b>query</b> is stored, so the <b>query</b> object
- * must outlive the request.
- */
-void
-directory_request_set_rend_query(directory_request_t *req,
- const rend_data_t *query)
-{
- if (query) {
- tor_assert(req->dir_purpose == DIR_PURPOSE_FETCH_RENDDESC_V2 ||
- req->dir_purpose == DIR_PURPOSE_UPLOAD_RENDDESC_V2);
- }
- req->rend_query = query;
-}
-/**
* Set an object containing HS connection identifier to be associated with
* this request. Note that only an alias to <b>ident</b> is stored, so the
* <b>ident</b> object must outlive the request.
@@ -1179,6 +1134,7 @@ directory_request_set_routerstatus(directory_request_t *req,
{
req->routerstatus = status;
}
+
/**
* Helper: update the addresses, ports, and identities in <b>req</b>
* from the routerstatus object in <b>req</b>. Return 0 on success.
@@ -1221,7 +1177,7 @@ directory_request_set_dir_from_routerstatus(directory_request_t *req)
return -1;
}
- /* At this point, if we are a client making a direct connection to a
+ /* At this point, if we are a client making a direct connection to a
* directory server, we have selected a server that has at least one address
* allowed by ClientUseIPv4/6 and Reachable{"",OR,Dir}Addresses. This
* selection uses the preference in ClientPreferIPv6{OR,Dir}Port, if
@@ -1236,6 +1192,37 @@ directory_request_set_dir_from_routerstatus(directory_request_t *req)
return -1;
}
+ /* One last thing: If we're talking to an authority, we might want to use
+ * a special HTTP port for it based on our purpose.
+ */
+ if (req->indirection == DIRIND_DIRECT_CONN && status->is_authority) {
+ const dir_server_t *ds = router_get_trusteddirserver_by_digest(
+ status->identity_digest);
+ if (ds) {
+ const tor_addr_port_t *v4 = NULL;
+ if (authdir_mode_v3(get_options())) {
+ // An authority connecting to another authority should always
+ // prefer the VOTING usage, if one is specifically configured.
+ v4 = trusted_dir_server_get_dirport_exact(
+ ds, AUTH_USAGE_VOTING, AF_INET);
+ }
+ if (! v4) {
+ // Everybody else should prefer a usage dependent on their
+ // the dir_purpose.
+ auth_dirport_usage_t usage =
+ auth_dirport_usage_for_purpose(req->dir_purpose);
+ v4 = trusted_dir_server_get_dirport(ds, usage, AF_INET);
+ }
+ tor_assert_nonfatal(v4);
+ if (v4) {
+ // XXXX We could, if we wanted, also select a v6 address. But a v4
+ // address must exist here, and we as a relay are required to support
+ // ipv4. So we just that.
+ tor_addr_port_copy(&use_dir_ap, v4);
+ }
+ }
+ }
+
directory_request_set_or_addr_port(req, &use_or_ap);
directory_request_set_dir_addr_port(req, &use_dir_ap);
directory_request_set_directory_id_digest(req, status->identity_digest);
@@ -1254,7 +1241,7 @@ directory_initiate_request,(directory_request_t *request))
tor_assert_nonfatal(
! directory_request_dir_contact_info_specified(request));
if (directory_request_set_dir_from_routerstatus(request) < 0) {
- return;
+ return; // or here XXXX
}
}
@@ -1265,7 +1252,6 @@ directory_initiate_request,(directory_request_t *request))
const uint8_t router_purpose = request->router_purpose;
const dir_indirection_t indirection = request->indirection;
const char *resource = request->resource;
- const rend_data_t *rend_query = request->rend_query;
const hs_ident_dir_conn_t *hs_ident = request->hs_ident;
circuit_guard_state_t *guard_state = request->guard_state;
@@ -1301,7 +1287,7 @@ directory_initiate_request,(directory_request_t *request))
if (purpose_needs_anonymity(dir_purpose, router_purpose, resource)) {
tor_assert(anonymized_connection ||
- rend_non_anonymous_mode_enabled(options));
+ hs_service_non_anonymous_mode_enabled(options));
}
/* use encrypted begindir connections for everything except relays
@@ -1353,15 +1339,7 @@ directory_initiate_request,(directory_request_t *request))
/* XXXX This is a bad name for this field now. */
conn->dirconn_direct = !anonymized_connection;
- /* copy rendezvous data, if any */
- if (rend_query) {
- /* We can't have both v2 and v3+ identifier. */
- tor_assert_nonfatal(!hs_ident);
- conn->rend_data = rend_data_dup(rend_query);
- }
if (hs_ident) {
- /* We can't have both v2 and v3+ identifier. */
- tor_assert_nonfatal(!rend_query);
conn->hs_ident = hs_ident_dir_conn_dup(hs_ident);
}
@@ -1378,6 +1356,8 @@ directory_initiate_request,(directory_request_t *request))
entry_guard_cancel(&guard_state);
}
+ // XXXX This is the case where we replace.
+
switch (connection_connect(TO_CONN(conn), conn->base_.address, &addr,
port, &socket_error)) {
case -1:
@@ -1696,13 +1676,6 @@ directory_send_command(dir_connection_t *conn,
httpcommand = "POST";
url = tor_strdup("/tor/post/consensus-signature");
break;
- case DIR_PURPOSE_FETCH_RENDDESC_V2:
- tor_assert(resource);
- tor_assert(strlen(resource) <= REND_DESC_ID_V2_LEN_BASE32);
- tor_assert(!payload);
- httpcommand = "GET";
- tor_asprintf(&url, "/tor/rendezvous2/%s", resource);
- break;
case DIR_PURPOSE_FETCH_HSDESC:
tor_assert(resource);
tor_assert(strlen(resource) <= ED25519_BASE64_LEN);
@@ -1710,12 +1683,6 @@ directory_send_command(dir_connection_t *conn,
httpcommand = "GET";
tor_asprintf(&url, "/tor/hs/3/%s", resource);
break;
- case DIR_PURPOSE_UPLOAD_RENDDESC_V2:
- tor_assert(!resource);
- tor_assert(payload);
- httpcommand = "POST";
- url = tor_strdup("/tor/rendezvous2/publish");
- break;
case DIR_PURPOSE_UPLOAD_HSDESC:
tor_assert(resource);
tor_assert(payload);
@@ -1859,10 +1826,6 @@ static int handle_response_upload_vote(dir_connection_t *,
const response_handler_args_t *);
static int handle_response_upload_signatures(dir_connection_t *,
const response_handler_args_t *);
-static int handle_response_fetch_renddesc_v2(dir_connection_t *,
- const response_handler_args_t *);
-static int handle_response_upload_renddesc_v2(dir_connection_t *,
- const response_handler_args_t *);
static int handle_response_upload_hsdesc(dir_connection_t *,
const response_handler_args_t *);
@@ -2210,9 +2173,6 @@ connection_dir_client_reached_eof(dir_connection_t *conn)
case DIR_PURPOSE_FETCH_MICRODESC:
rv = handle_response_fetch_microdesc(conn, &args);
break;
- case DIR_PURPOSE_FETCH_RENDDESC_V2:
- rv = handle_response_fetch_renddesc_v2(conn, &args);
- break;
case DIR_PURPOSE_UPLOAD_DIR:
rv = handle_response_upload_dir(conn, &args);
break;
@@ -2222,9 +2182,6 @@ connection_dir_client_reached_eof(dir_connection_t *conn)
case DIR_PURPOSE_UPLOAD_VOTE:
rv = handle_response_upload_vote(conn, &args);
break;
- case DIR_PURPOSE_UPLOAD_RENDDESC_V2:
- rv = handle_response_upload_renddesc_v2(conn, &args);
- break;
case DIR_PURPOSE_UPLOAD_HSDESC:
rv = handle_response_upload_hsdesc(conn, &args);
break;
@@ -2593,8 +2550,6 @@ handle_response_fetch_desc(dir_connection_t *conn,
SMARTLIST_FOREACH(which, char *, cp, tor_free(cp));
smartlist_free(which);
}
- if (directory_conn_is_self_reachability_test(conn))
- router_dirport_found_reachable();
return 0;
}
@@ -2823,153 +2778,6 @@ handle_response_fetch_hsdesc_v3(dir_connection_t *conn,
}
/**
- * Handler function: processes a response to a request for a v2 hidden service
- * descriptor.
- **/
-static int
-handle_response_fetch_renddesc_v2(dir_connection_t *conn,
- const response_handler_args_t *args)
-{
- tor_assert(conn->base_.purpose == DIR_PURPOSE_FETCH_RENDDESC_V2);
- const int status_code = args->status_code;
- const char *reason = args->reason;
- const char *body = args->body;
- const size_t body_len = args->body_len;
-
-#define SEND_HS_DESC_FAILED_EVENT(reason) \
- (control_event_hsv2_descriptor_failed(conn->rend_data, \
- conn->identity_digest, \
- reason))
-#define SEND_HS_DESC_FAILED_CONTENT() \
- (control_event_hs_descriptor_content( \
- rend_data_get_address(conn->rend_data), \
- conn->requested_resource, \
- conn->identity_digest, \
- NULL))
-
- tor_assert(conn->rend_data);
- log_info(LD_REND,"Received rendezvous descriptor (body size %d, status %d "
- "(%s))",
- (int)body_len, status_code, escaped(reason));
- switch (status_code) {
- case 200:
- {
- rend_cache_entry_t *entry = NULL;
-
- if (rend_cache_store_v2_desc_as_client(body,
- conn->requested_resource,
- conn->rend_data, &entry) < 0) {
- log_warn(LD_REND,"Fetching v2 rendezvous descriptor failed. "
- "Retrying at another directory.");
- /* We'll retry when connection_about_to_close_connection()
- * cleans this dir conn up. */
- SEND_HS_DESC_FAILED_EVENT("BAD_DESC");
- SEND_HS_DESC_FAILED_CONTENT();
- } else {
- char service_id[REND_SERVICE_ID_LEN_BASE32 + 1];
- /* Should never be NULL here if we found the descriptor. */
- tor_assert(entry);
- rend_get_service_id(entry->parsed->pk, service_id);
-
- /* success. notify pending connections about this. */
- log_info(LD_REND, "Successfully fetched v2 rendezvous "
- "descriptor.");
- control_event_hsv2_descriptor_received(service_id,
- conn->rend_data,
- conn->identity_digest);
- control_event_hs_descriptor_content(service_id,
- conn->requested_resource,
- conn->identity_digest,
- body);
- conn->base_.purpose = DIR_PURPOSE_HAS_FETCHED_RENDDESC_V2;
- rend_client_desc_trynow(service_id);
- memwipe(service_id, 0, sizeof(service_id));
- }
- break;
- }
- case 404:
- /* Not there. We'll retry when
- * connection_about_to_close_connection() cleans this conn up. */
- log_info(LD_REND,"Fetching v2 rendezvous descriptor failed: "
- "Retrying at another directory.");
- SEND_HS_DESC_FAILED_EVENT("NOT_FOUND");
- SEND_HS_DESC_FAILED_CONTENT();
- break;
- case 400:
- log_warn(LD_REND, "Fetching v2 rendezvous descriptor failed: "
- "http status 400 (%s). Dirserver didn't like our "
- "v2 rendezvous query? Retrying at another directory.",
- escaped(reason));
- SEND_HS_DESC_FAILED_EVENT("QUERY_REJECTED");
- SEND_HS_DESC_FAILED_CONTENT();
- break;
- default:
- log_warn(LD_REND, "Fetching v2 rendezvous descriptor failed: "
- "http status %d (%s) response unexpected while "
- "fetching v2 hidden service descriptor (server %s). "
- "Retrying at another directory.",
- status_code, escaped(reason),
- connection_describe_peer(TO_CONN(conn)));
- SEND_HS_DESC_FAILED_EVENT("UNEXPECTED");
- SEND_HS_DESC_FAILED_CONTENT();
- break;
- }
-
- return 0;
-}
-
-/**
- * Handler function: processes a response to a POST request to upload a v2
- * hidden service descriptor.
- **/
-static int
-handle_response_upload_renddesc_v2(dir_connection_t *conn,
- const response_handler_args_t *args)
-{
- tor_assert(conn->base_.purpose == DIR_PURPOSE_UPLOAD_RENDDESC_V2);
- const int status_code = args->status_code;
- const char *reason = args->reason;
-
-#define SEND_HS_DESC_UPLOAD_FAILED_EVENT(reason) \
- (control_event_hs_descriptor_upload_failed( \
- conn->identity_digest, \
- rend_data_get_address(conn->rend_data), \
- reason))
-
- log_info(LD_REND,"Uploaded rendezvous descriptor (status %d "
- "(%s))",
- status_code, escaped(reason));
- /* Without the rend data, we'll have a problem identifying what has been
- * uploaded for which service. */
- tor_assert(conn->rend_data);
- switch (status_code) {
- case 200:
- log_info(LD_REND,
- "Uploading rendezvous descriptor: finished with status "
- "200 (%s)", escaped(reason));
- control_event_hs_descriptor_uploaded(conn->identity_digest,
- rend_data_get_address(conn->rend_data));
- rend_service_desc_has_uploaded(conn->rend_data);
- break;
- case 400:
- log_warn(LD_REND,"http status 400 (%s) response from dirserver "
- "%s. Malformed rendezvous descriptor?",
- escaped(reason), connection_describe_peer(TO_CONN(conn)));
- SEND_HS_DESC_UPLOAD_FAILED_EVENT("UPLOAD_REJECTED");
- break;
- default:
- log_warn(LD_REND,"http status %d (%s) response unexpected (server "
- "%s).",
- status_code, escaped(reason),
- connection_describe_peer(TO_CONN(conn)));
- SEND_HS_DESC_UPLOAD_FAILED_EVENT("UNEXPECTED");
- break;
- }
-
- return 0;
-}
-
-/**
* Handler function: processes a response to a POST request to upload an
* hidden service descriptor.
**/
@@ -3045,17 +2853,6 @@ connection_dir_client_refetch_hsdesc_if_needed(dir_connection_t *dir_conn)
{
connection_t *conn = TO_CONN(dir_conn);
- /* If we were trying to fetch a v2 rend desc and did not succeed, retry as
- * needed. (If a fetch is successful, the connection state is changed to
- * DIR_PURPOSE_HAS_FETCHED_RENDDESC_V2 or DIR_PURPOSE_HAS_FETCHED_HSDESC to
- * mark that refetching is unnecessary.) */
- if (conn->purpose == DIR_PURPOSE_FETCH_RENDDESC_V2 &&
- dir_conn->rend_data &&
- rend_valid_v2_service_id(
- rend_data_get_address(dir_conn->rend_data))) {
- rend_client_refetch_v2_renddesc(dir_conn->rend_data);
- }
-
/* Check for v3 rend desc fetch */
if (conn->purpose == DIR_PURPOSE_FETCH_HSDESC &&
dir_conn->hs_ident &&
diff --git a/src/feature/dirclient/dirclient.h b/src/feature/dirclient/dirclient.h
index 096b197526..f233fa70d2 100644
--- a/src/feature/dirclient/dirclient.h
+++ b/src/feature/dirclient/dirclient.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -74,8 +74,6 @@ void directory_request_set_payload(directory_request_t *req,
size_t payload_len);
void directory_request_set_if_modified_since(directory_request_t *req,
time_t if_modified_since);
-void directory_request_set_rend_query(directory_request_t *req,
- const rend_data_t *query);
void directory_request_upload_set_hs_ident(directory_request_t *req,
const hs_ident_dir_conn_t *ident);
void directory_request_fetch_set_hs_ident(directory_request_t *req,
@@ -125,8 +123,6 @@ struct directory_request_t {
size_t payload_len;
/** Value to send in an if-modified-since header, or 0 for none. */
time_t if_modified_since;
- /** Hidden-service-specific information v2. */
- const rend_data_t *rend_query;
/** Extra headers to append to the request */
struct config_line_t *additional_headers;
/** Hidden-service-specific information for v3+. */
diff --git a/src/feature/dirclient/dirclient_modes.c b/src/feature/dirclient/dirclient_modes.c
index db25196213..06ed15222e 100644
--- a/src/feature/dirclient/dirclient_modes.c
+++ b/src/feature/dirclient/dirclient_modes.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/dirclient/dirclient_modes.h b/src/feature/dirclient/dirclient_modes.h
index c402207724..e525413e28 100644
--- a/src/feature/dirclient/dirclient_modes.h
+++ b/src/feature/dirclient/dirclient_modes.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/dirclient/dlstatus.c b/src/feature/dirclient/dlstatus.c
index ab3fbb8577..c21dd113b4 100644
--- a/src/feature/dirclient/dlstatus.c
+++ b/src/feature/dirclient/dlstatus.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -73,15 +73,14 @@ find_dl_min_delay(const download_status_t *dls, const or_options_t *options)
}
}
case DL_SCHED_BRIDGE:
- if (options->UseBridges && num_bridges_usable(0) > 0) {
- /* A bridge client that is sure that one or more of its bridges are
- * running can afford to wait longer to update bridge descriptors. */
- return options->TestingBridgeDownloadInitialDelay;
- } else {
- /* A bridge client which might have no running bridges, must try to
- * get bridge descriptors straight away. */
- return options->TestingBridgeBootstrapDownloadInitialDelay;
- }
+ /* Be conservative here: always return the 'during bootstrap' delay
+ * value, so we never delay while trying to fetch descriptors
+ * for new bridges. Once we do succeed at fetching a descriptor
+ * for our bridge, we will adjust its next_attempt_at based on
+ * the longer "TestingBridgeDownloadInitialDelay" value. See
+ * learned_bridge_descriptor() for details.
+ */
+ return options->TestingBridgeBootstrapDownloadInitialDelay;
default:
tor_assert(0);
}
diff --git a/src/feature/dirclient/dlstatus.h b/src/feature/dirclient/dlstatus.h
index e5c8b756c4..e1a40ef669 100644
--- a/src/feature/dirclient/dlstatus.h
+++ b/src/feature/dirclient/dlstatus.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/dirclient/download_status_st.h b/src/feature/dirclient/download_status_st.h
index 92efcb44d0..ae73bf0230 100644
--- a/src/feature/dirclient/download_status_st.h
+++ b/src/feature/dirclient/download_status_st.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/dircommon/consdiff.c b/src/feature/dircommon/consdiff.c
index 9511177e2b..323f2bd576 100644
--- a/src/feature/dircommon/consdiff.c
+++ b/src/feature/dircommon/consdiff.c
@@ -1,5 +1,5 @@
/* Copyright (c) 2014, Daniel Martí
- * Copyright (c) 2014-2020, The Tor Project, Inc. */
+ * Copyright (c) 2014-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/dircommon/consdiff.h b/src/feature/dircommon/consdiff.h
index c2dcb6da24..b5e90c6210 100644
--- a/src/feature/dircommon/consdiff.h
+++ b/src/feature/dircommon/consdiff.h
@@ -1,5 +1,5 @@
/* Copyright (c) 2014, Daniel Martí
- * Copyright (c) 2014-2020, The Tor Project, Inc. */
+ * Copyright (c) 2014-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/dircommon/dir_connection_st.h b/src/feature/dircommon/dir_connection_st.h
index 12230e6741..e1a88a45b0 100644
--- a/src/feature/dircommon/dir_connection_st.h
+++ b/src/feature/dircommon/dir_connection_st.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -42,9 +42,6 @@ struct dir_connection_t {
/** The compression object doing on-the-fly compression for spooled data. */
struct tor_compress_state_t *compress_state;
- /** What rendezvous service are we querying for? */
- rend_data_t *rend_data;
-
/* Hidden service connection identifier for dir connections: Used by HS
client-side code to fetch HS descriptors, and by the service-side code to
upload descriptors. */
diff --git a/src/feature/dircommon/directory.c b/src/feature/dircommon/directory.c
index b276ac3441..6614bb065e 100644
--- a/src/feature/dircommon/directory.c
+++ b/src/feature/dircommon/directory.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "core/or/or.h"
@@ -68,7 +68,6 @@
* router_upload_dir_desc_to_dirservers() in router.c
* upload_service_descriptor() in rendservice.c
* - directory_get_from_dirserver(), called from
- * rend_client_refetch_renddesc() in rendclient.c
* run_scheduled_events() in main.c
* do_hup() in main.c
* - connection_dir_process_inbuf(), called from
@@ -143,9 +142,6 @@ purpose_needs_anonymity(uint8_t dir_purpose, uint8_t router_purpose,
case DIR_PURPOSE_FETCH_MICRODESC:
return 0;
case DIR_PURPOSE_HAS_FETCHED_HSDESC:
- case DIR_PURPOSE_HAS_FETCHED_RENDDESC_V2:
- case DIR_PURPOSE_UPLOAD_RENDDESC_V2:
- case DIR_PURPOSE_FETCH_RENDDESC_V2:
case DIR_PURPOSE_FETCH_HSDESC:
case DIR_PURPOSE_UPLOAD_HSDESC:
return 1;
diff --git a/src/feature/dircommon/directory.h b/src/feature/dircommon/directory.h
index 2cd9c176c8..7d861682bb 100644
--- a/src/feature/dircommon/directory.h
+++ b/src/feature/dircommon/directory.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -30,10 +30,7 @@ const dir_connection_t *CONST_TO_DIR_CONN(const connection_t *c);
#define DIR_CONN_STATE_SERVER_WRITING 6
#define DIR_CONN_STATE_MAX_ 6
-#define DIR_PURPOSE_MIN_ 4
-/** A connection to a directory server: set after a v2 rendezvous
- * descriptor is downloaded. */
-#define DIR_PURPOSE_HAS_FETCHED_RENDDESC_V2 4
+#define DIR_PURPOSE_MIN_ 6
/** A connection to a directory server: download one or more server
* descriptors. */
#define DIR_PURPOSE_FETCH_SERVERDESC 6
@@ -61,12 +58,9 @@ const dir_connection_t *CONST_TO_DIR_CONN(const connection_t *c);
/** Purpose for connection at a directory server. */
#define DIR_PURPOSE_SERVER 16
-/** A connection to a hidden service directory server: upload a v2 rendezvous
- * descriptor. */
-#define DIR_PURPOSE_UPLOAD_RENDDESC_V2 17
-/** A connection to a hidden service directory server: download a v2 rendezvous
- * descriptor. */
-#define DIR_PURPOSE_FETCH_RENDDESC_V2 18
+
+/** Value 17 and 18 were onion service v2 purposes. */
+
/** A connection to a directory server: download a microdescriptor. */
#define DIR_PURPOSE_FETCH_MICRODESC 19
/** A connection to a hidden service directory: upload a v3 descriptor. */
@@ -84,7 +78,6 @@ const dir_connection_t *CONST_TO_DIR_CONN(const connection_t *c);
((p)==DIR_PURPOSE_UPLOAD_DIR || \
(p)==DIR_PURPOSE_UPLOAD_VOTE || \
(p)==DIR_PURPOSE_UPLOAD_SIGNATURES || \
- (p)==DIR_PURPOSE_UPLOAD_RENDDESC_V2 || \
(p)==DIR_PURPOSE_UPLOAD_HSDESC)
/** True iff p is a purpose corresponding to onion service that is either
diff --git a/src/feature/dircommon/fp_pair.c b/src/feature/dircommon/fp_pair.c
index 87e1c253bd..ef6642925e 100644
--- a/src/feature/dircommon/fp_pair.c
+++ b/src/feature/dircommon/fp_pair.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2020, The Tor Project, Inc. */
+/* Copyright (c) 2013-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/dircommon/fp_pair.h b/src/feature/dircommon/fp_pair.h
index ae71ea7b71..23e3b84ed3 100644
--- a/src/feature/dircommon/fp_pair.h
+++ b/src/feature/dircommon/fp_pair.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2020, The Tor Project, Inc. */
+/* Copyright (c) 2013-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/dircommon/vote_timing_st.h b/src/feature/dircommon/vote_timing_st.h
index 103d950f86..ace2ace43b 100644
--- a/src/feature/dircommon/vote_timing_st.h
+++ b/src/feature/dircommon/vote_timing_st.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/dirparse/authcert_members.h b/src/feature/dirparse/authcert_members.h
index 53eab175d6..635779901b 100644
--- a/src/feature/dirparse/authcert_members.h
+++ b/src/feature/dirparse/authcert_members.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/dirparse/authcert_parse.c b/src/feature/dirparse/authcert_parse.c
index b2460f6ace..7c74630235 100644
--- a/src/feature/dirparse/authcert_parse.c
+++ b/src/feature/dirparse/authcert_parse.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/dirparse/authcert_parse.h b/src/feature/dirparse/authcert_parse.h
index 7f6dd1c02f..509d6ca938 100644
--- a/src/feature/dirparse/authcert_parse.h
+++ b/src/feature/dirparse/authcert_parse.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/dirparse/microdesc_parse.c b/src/feature/dirparse/microdesc_parse.c
index 31415f3fb7..beb38bda30 100644
--- a/src/feature/dirparse/microdesc_parse.c
+++ b/src/feature/dirparse/microdesc_parse.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/dirparse/microdesc_parse.h b/src/feature/dirparse/microdesc_parse.h
index e81126b8cd..47f52a6654 100644
--- a/src/feature/dirparse/microdesc_parse.h
+++ b/src/feature/dirparse/microdesc_parse.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/dirparse/ns_parse.c b/src/feature/dirparse/ns_parse.c
index 138d248b08..cd3e2731be 100644
--- a/src/feature/dirparse/ns_parse.c
+++ b/src/feature/dirparse/ns_parse.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -434,6 +434,8 @@ routerstatus_parse_entry_from_string(memarea_t *area,
rs->is_possible_guard = 1;
else if (!strcmp(tok->args[i], "BadExit"))
rs->is_bad_exit = 1;
+ else if (!strcmp(tok->args[i], "MiddleOnly"))
+ rs->is_middle_only = 1;
else if (!strcmp(tok->args[i], "Authority"))
rs->is_authority = 1;
else if (!strcmp(tok->args[i], "Unnamed") &&
@@ -446,6 +448,8 @@ routerstatus_parse_entry_from_string(memarea_t *area,
rs->is_v2_dir = 1;
} else if (!strcmp(tok->args[i], "StaleDesc")) {
rs->is_staledesc = 1;
+ } else if (!strcmp(tok->args[i], "Sybil")) {
+ rs->is_sybil = 1;
}
}
/* These are implied true by having been included in a consensus made
diff --git a/src/feature/dirparse/ns_parse.h b/src/feature/dirparse/ns_parse.h
index 6a1ea85c92..2b1518bb4d 100644
--- a/src/feature/dirparse/ns_parse.h
+++ b/src/feature/dirparse/ns_parse.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/dirparse/parsecommon.c b/src/feature/dirparse/parsecommon.c
index ab465c4d7f..d7a6d65346 100644
--- a/src/feature/dirparse/parsecommon.c
+++ b/src/feature/dirparse/parsecommon.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2020, The Tor Project, Inc. */
+/* Copyright (c) 2016-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -216,7 +216,6 @@ token_check_object(memarea_t *area, const char *kwd,
}
break;
case NEED_KEY_1024: /* There must be a 1024-bit public key. */
- case NEED_SKEY_1024: /* There must be a 1024-bit private key. */
if (tok->key && crypto_pk_num_bits(tok->key) != PK_BYTES*8) {
tor_snprintf(ebuf, sizeof(ebuf), "Wrong size on key for %s: %d bits",
kwd, crypto_pk_num_bits(tok->key));
@@ -228,18 +227,11 @@ token_check_object(memarea_t *area, const char *kwd,
tor_snprintf(ebuf, sizeof(ebuf), "Missing public key for %s", kwd);
RET_ERR(ebuf);
}
- if (o_syn != NEED_SKEY_1024) {
- if (crypto_pk_key_is_private(tok->key)) {
- tor_snprintf(ebuf, sizeof(ebuf),
- "Private key given for %s, which wants a public key", kwd);
- RET_ERR(ebuf);
- }
- } else { /* o_syn == NEED_SKEY_1024 */
- if (!crypto_pk_key_is_private(tok->key)) {
- tor_snprintf(ebuf, sizeof(ebuf),
- "Public key given for %s, which wants a private key", kwd);
- RET_ERR(ebuf);
- }
+
+ if (crypto_pk_key_is_private(tok->key)) {
+ tor_snprintf(ebuf, sizeof(ebuf),
+ "Private key given for %s, which wants a public key", kwd);
+ RET_ERR(ebuf);
}
break;
case OBJ_OK:
@@ -409,15 +401,6 @@ get_next_token(memarea_t *area,
tok->key = crypto_pk_asn1_decode(tok->object_body, tok->object_size);
if (! tok->key)
RET_ERR("Couldn't parse public key.");
- } else if (!strcmp(tok->object_type, "RSA PRIVATE KEY")) { /* private key */
- if (o_syn != NEED_SKEY_1024 && o_syn != OBJ_OK) {
- RET_ERR("Unexpected private key.");
- }
- tok->key = crypto_pk_asn1_decode_private(tok->object_body,
- tok->object_size,
- 1024);
- if (! tok->key)
- RET_ERR("Couldn't parse private key.");
}
*s = eol;
diff --git a/src/feature/dirparse/parsecommon.h b/src/feature/dirparse/parsecommon.h
index 4db9a89f13..675c5f68d5 100644
--- a/src/feature/dirparse/parsecommon.h
+++ b/src/feature/dirparse/parsecommon.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2020, The Tor Project, Inc. */
+/* Copyright (c) 2016-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -172,6 +172,7 @@ typedef enum {
R3_DESC_AUTH_KEY,
R3_DESC_AUTH_CLIENT,
R3_ENCRYPTED,
+ R3_FLOW_CONTROL,
R_IPO_IDENTIFIER,
R_IPO_IP_ADDRESS,
@@ -218,7 +219,6 @@ typedef struct directory_token_t {
typedef enum {
NO_OBJ, /**< No object, ever. */
NEED_OBJ, /**< Object is required. */
- NEED_SKEY_1024,/**< Object is required, and must be a 1024 bit private key */
NEED_KEY_1024, /**< Object is required, and must be a 1024 bit public key */
NEED_KEY, /**< Object is required, and must be a public key. */
OBJ_OK, /**< Object is optional. */
diff --git a/src/feature/dirparse/policy_parse.c b/src/feature/dirparse/policy_parse.c
index 28cd174686..8d30410f58 100644
--- a/src/feature/dirparse/policy_parse.c
+++ b/src/feature/dirparse/policy_parse.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -192,6 +192,10 @@ router_parse_addr_policy_private(directory_token_t *tok)
uint16_t port_min, port_max;
addr_policy_t result;
+ /* Safeguard: always flag non canonical because it is a stack allocated
+ * object and thus should not be considered a copy stored in a map. */
+ result.is_canonical = 0;
+
arg = tok->args[0];
if (strcmpstart(arg, "private"))
return NULL;
diff --git a/src/feature/dirparse/policy_parse.h b/src/feature/dirparse/policy_parse.h
index 7764069e66..dffeb8f5ad 100644
--- a/src/feature/dirparse/policy_parse.h
+++ b/src/feature/dirparse/policy_parse.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/dirparse/routerparse.c b/src/feature/dirparse/routerparse.c
index 3d90c1bc91..844057c47e 100644
--- a/src/feature/dirparse/routerparse.c
+++ b/src/feature/dirparse/routerparse.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/dirparse/routerparse.h b/src/feature/dirparse/routerparse.h
index 519044e9b0..aeb9b72e52 100644
--- a/src/feature/dirparse/routerparse.h
+++ b/src/feature/dirparse/routerparse.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/dirparse/sigcommon.c b/src/feature/dirparse/sigcommon.c
index fb81b2da6e..96f79d5f87 100644
--- a/src/feature/dirparse/sigcommon.c
+++ b/src/feature/dirparse/sigcommon.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/dirparse/sigcommon.h b/src/feature/dirparse/sigcommon.h
index c7f370f8e8..2e3b262f80 100644
--- a/src/feature/dirparse/sigcommon.h
+++ b/src/feature/dirparse/sigcommon.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/dirparse/signing.c b/src/feature/dirparse/signing.c
index e420e5b6b9..44b1c79163 100644
--- a/src/feature/dirparse/signing.c
+++ b/src/feature/dirparse/signing.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/dirparse/signing.h b/src/feature/dirparse/signing.h
index 7ca34bb14a..a55e855e9b 100644
--- a/src/feature/dirparse/signing.h
+++ b/src/feature/dirparse/signing.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/dirparse/unparseable.c b/src/feature/dirparse/unparseable.c
index a91148a661..e966db734a 100644
--- a/src/feature/dirparse/unparseable.c
+++ b/src/feature/dirparse/unparseable.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -403,7 +403,7 @@ dump_desc_compare_fifo_entries(const void **a_v, const void **b_v)
}
} else {
/*
- * We shouldn't see this, but what the hell, NULLs precede everythin
+ * We shouldn't see this, but what the hell, NULLs precede everything
* else
*/
return 1;
diff --git a/src/feature/dirparse/unparseable.h b/src/feature/dirparse/unparseable.h
index cff91c82cc..f8bebfc544 100644
--- a/src/feature/dirparse/unparseable.h
+++ b/src/feature/dirparse/unparseable.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/hibernate/hibernate.c b/src/feature/hibernate/hibernate.c
index 82c33659aa..1c616ec6fe 100644
--- a/src/feature/hibernate/hibernate.c
+++ b/src/feature/hibernate/hibernate.c
@@ -1,5 +1,5 @@
/* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/hibernate/hibernate.h b/src/feature/hibernate/hibernate.h
index 48a03e8239..6f239fc41c 100644
--- a/src/feature/hibernate/hibernate.h
+++ b/src/feature/hibernate/hibernate.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/hs/hs_cache.c b/src/feature/hs/hs_cache.c
index 9c35936748..cf8e377313 100644
--- a/src/feature/hs/hs_cache.c
+++ b/src/feature/hs/hs_cache.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2020, The Tor Project, Inc. */
+/* Copyright (c) 2016-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -19,12 +19,15 @@
#include "feature/hs/hs_descriptor.h"
#include "feature/nodelist/microdesc.h"
#include "feature/nodelist/networkstatus.h"
-#include "feature/rend/rendcache.h"
+#include "feature/stats/rephist.h"
#include "feature/hs/hs_cache.h"
#include "feature/nodelist/networkstatus_st.h"
+/* Total counter of the cache size. */
+static size_t hs_cache_total_allocation = 0;
+
static int cached_client_descriptor_has_expired(time_t now,
const hs_cache_client_descriptor_t *cached_desc);
@@ -163,7 +166,7 @@ cache_store_v3_as_dir(hs_cache_dir_descriptor_t *desc)
* remove the entry we currently have from our cache so we can then
* store the new one. */
remove_v3_desc_as_dir(cache_entry);
- rend_cache_decrement_allocation(cache_get_dir_entry_size(cache_entry));
+ hs_cache_decrement_allocation(cache_get_dir_entry_size(cache_entry));
cache_dir_desc_free(cache_entry);
}
/* Store the descriptor we just got. We are sure here that either we
@@ -173,9 +176,12 @@ cache_store_v3_as_dir(hs_cache_dir_descriptor_t *desc)
/* Update our total cache size with this entry for the OOM. This uses the
* old HS protocol cache subsystem for which we are tied with. */
- rend_cache_increment_allocation(cache_get_dir_entry_size(desc));
+ hs_cache_increment_allocation(cache_get_dir_entry_size(desc));
- /* XXX: Update HS statistics. We should have specific stats for v3. */
+ /* Update HSv3 statistics */
+ if (get_options()->HiddenServiceStatistics) {
+ rep_hist_hsdir_stored_maybe_new_v3_onion(desc->key);
+ }
return 0;
@@ -255,7 +261,7 @@ cache_clean_v3_as_dir(time_t now, time_t global_cutoff)
/* Entry is not in the cache anymore, destroy it. */
cache_dir_desc_free(entry);
/* Update our cache entry allocation size for the OOM. */
- rend_cache_decrement_allocation(entry_size);
+ hs_cache_decrement_allocation(entry_size);
/* Logging. */
{
char key_b64[BASE64_DIGEST256_LEN + 1];
@@ -332,12 +338,6 @@ hs_cache_lookup_as_dir(uint32_t version, const char *query,
void
hs_cache_clean_as_dir(time_t now)
{
- time_t cutoff;
-
- /* Start with v2 cache cleaning. */
- cutoff = now - rend_cache_max_entry_lifetime();
- rend_cache_clean_v2_descs_as_dir(cutoff);
-
/* Now, clean the v3 cache. Set the cutoff to 0 telling the cleanup function
* to compute the cutoff by itself using the lifetime value. */
cache_clean_v3_as_dir(now, 0);
@@ -408,7 +408,7 @@ remove_v3_desc_as_client(const hs_cache_client_descriptor_t *desc)
tor_assert(desc);
digest256map_remove(hs_cache_v3_client, desc->key.pubkey);
/* Update cache size with this entry for the OOM handler. */
- rend_cache_decrement_allocation(cache_get_client_entry_size(desc));
+ hs_cache_decrement_allocation(cache_get_client_entry_size(desc));
}
/** Store a given descriptor in our cache. */
@@ -429,7 +429,7 @@ store_v3_desc_as_client(hs_cache_client_descriptor_t *desc)
}
digest256map_set(hs_cache_v3_client, desc->key.pubkey, desc);
/* Update cache size with this entry for the OOM handler. */
- rend_cache_increment_allocation(cache_get_client_entry_size(desc));
+ hs_cache_increment_allocation(cache_get_client_entry_size(desc));
}
/** Query our cache and return the entry or NULL if not found or if expired. */
@@ -803,7 +803,7 @@ cache_clean_v3_as_client(time_t now)
cache_client_desc_free(entry);
/* Update our OOM. We didn't use the remove() function because we are in
* a loop so we have to explicitly decrement. */
- rend_cache_decrement_allocation(entry_size);
+ hs_cache_decrement_allocation(entry_size);
/* Logging. */
{
char key_b64[BASE64_DIGEST256_LEN + 1];
@@ -941,8 +941,6 @@ hs_cache_remove_as_client(const ed25519_public_key_t *key)
void
hs_cache_clean_as_client(time_t now)
{
- /* Start with v2 cache cleaning. */
- rend_cache_clean(now, REND_CACHE_TYPE_CLIENT);
/* Now, clean the v3 cache. Set the cutoff to 0 telling the cleanup function
* to compute the cutoff by itself using the lifetime value. */
cache_clean_v3_as_client(now);
@@ -959,7 +957,7 @@ hs_cache_purge_as_client(void)
cache_client_desc_free(entry);
/* Update our OOM. We didn't use the remove() function because we are in
* a loop so we have to explicitly decrement. */
- rend_cache_decrement_allocation(entry_size);
+ hs_cache_decrement_allocation(entry_size);
} DIGEST256MAP_FOREACH_END;
log_info(LD_REND, "Hidden service client descriptor cache purged.");
@@ -1081,19 +1079,16 @@ hs_cache_handle_oom(time_t now, size_t min_remove_bytes)
/* The algorithm is as follow. K is the oldest expected descriptor age.
*
- * 1) Deallocate all entries from v2 cache that are older than K hours.
- * 1.1) If the amount of remove bytes has been reached, stop.
- * 2) Deallocate all entries from v3 cache that are older than K hours
+ * 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.
- * 3) Set K = K - RendPostPeriod and repeat process until K is < 0.
+ * 2) Set K = K - RendPostPeriod and repeat process until K is < 0.
*
* This ends up being O(Kn).
*/
/* Set K to the oldest expected age in seconds which is the maximum
- * lifetime of a cache entry. We'll use the v2 lifetime because it's much
- * bigger than the v3 thus leading to cleaning older descriptors. */
- k = rend_cache_max_entry_lifetime();
+ * lifetime of a cache entry. */
+ k = hs_cache_max_entry_lifetime();
do {
time_t cutoff;
@@ -1106,9 +1101,6 @@ hs_cache_handle_oom(time_t now, size_t min_remove_bytes)
/* Compute a cutoff value with K and the current time. */
cutoff = now - k;
- /* Start by cleaning the v2 cache with that cutoff. */
- bytes_removed += rend_cache_clean_v2_descs_as_dir(cutoff);
-
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);
@@ -1157,4 +1149,45 @@ hs_cache_free_all(void)
digest256map_free(hs_cache_client_intro_state,
cache_client_intro_state_free_void);
hs_cache_client_intro_state = NULL;
+ hs_cache_total_allocation = 0;
+}
+
+/* Return total size of the cache. */
+size_t
+hs_cache_get_total_allocation(void)
+{
+ return hs_cache_total_allocation;
+}
+
+/** Decrement the total bytes attributed to the rendezvous cache by n. */
+void
+hs_cache_decrement_allocation(size_t n)
+{
+ static int have_underflowed = 0;
+
+ if (hs_cache_total_allocation >= n) {
+ hs_cache_total_allocation -= n;
+ } else {
+ hs_cache_total_allocation = 0;
+ if (! have_underflowed) {
+ have_underflowed = 1;
+ log_warn(LD_BUG, "Underflow in hs_cache_decrement_allocation");
+ }
+ }
+}
+
+/** Increase the total bytes attributed to the rendezvous cache by n. */
+void
+hs_cache_increment_allocation(size_t n)
+{
+ static int have_overflowed = 0;
+ if (hs_cache_total_allocation <= SIZE_MAX - n) {
+ hs_cache_total_allocation += n;
+ } else {
+ hs_cache_total_allocation = SIZE_MAX;
+ if (! have_overflowed) {
+ have_overflowed = 1;
+ log_warn(LD_BUG, "Overflow in hs_cache_increment_allocation");
+ }
+ }
}
diff --git a/src/feature/hs/hs_cache.h b/src/feature/hs/hs_cache.h
index bb3c77f224..dd55f54ba4 100644
--- a/src/feature/hs/hs_cache.h
+++ b/src/feature/hs/hs_cache.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2020, The Tor Project, Inc. */
+/* Copyright (c) 2016-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -21,6 +21,14 @@ struct ed25519_public_key_t;
/** This is the maximum time an introduction point state object can stay in the
* client cache in seconds (2 mins or 120 seconds). */
#define HS_CACHE_CLIENT_INTRO_STATE_MAX_AGE (2 * 60)
+/** How old do we let hidden service descriptors get before discarding
+ * them as too old? */
+#define HS_CACHE_MAX_AGE (2*24*60*60)
+/** How wrong do we assume our clock may be when checking whether hidden
+ * services are too old or too new? */
+#define HS_CACHE_MAX_SKEW (24*60*60)
+/** How old do we keep an intro point failure entry in the failure cache? */
+#define HS_CACHE_FAILURE_MAX_AGE (5*60)
/** Introduction point state. */
typedef struct hs_cache_intro_state_t {
@@ -57,7 +65,6 @@ typedef struct hs_cache_dir_descriptor_t {
/** Descriptor plaintext information. Obviously, we can't decrypt the
* encrypted part of the descriptor. */
hs_desc_plaintext_data_t *plaintext_data;
-
/** Encoded descriptor which is basically in text form. It's a NUL terminated
* string thus safe to strlen(). */
char *encoded_desc;
@@ -65,6 +72,13 @@ typedef struct hs_cache_dir_descriptor_t {
/* Public API */
+/* Return maximum lifetime in seconds of a cache entry. */
+static inline time_t
+hs_cache_max_entry_lifetime(void)
+{
+ return HS_CACHE_MAX_AGE + HS_CACHE_MAX_SKEW;
+}
+
void hs_cache_init(void);
void hs_cache_free_all(void);
void hs_cache_clean_as_dir(time_t now);
@@ -102,6 +116,10 @@ void hs_cache_client_intro_state_purge(void);
bool hs_cache_client_new_auth_parse(const ed25519_public_key_t *service_pk);
+size_t hs_cache_get_total_allocation(void);
+void hs_cache_decrement_allocation(size_t n);
+void hs_cache_increment_allocation(size_t n);
+
#ifdef HS_CACHE_PRIVATE
#include "lib/crypt_ops/crypto_ed25519.h"
diff --git a/src/feature/hs/hs_cell.c b/src/feature/hs/hs_cell.c
index 8bdaa4922a..490f05e54f 100644
--- a/src/feature/hs/hs_cell.c
+++ b/src/feature/hs/hs_cell.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017-2020, The Tor Project, Inc. */
+/* Copyright (c) 2017-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -9,18 +9,19 @@
#include "core/or/or.h"
#include "app/config/config.h"
#include "lib/crypt_ops/crypto_util.h"
-#include "feature/rend/rendservice.h"
#include "feature/hs_common/replaycache.h"
#include "feature/hs/hs_cell.h"
#include "feature/hs/hs_ob.h"
#include "core/crypto/hs_ntor.h"
+#include "core/or/congestion_control_common.h"
#include "core/or/origin_circuit_st.h"
/* Trunnel. */
+#include "trunnel/congestion_control.h"
#include "trunnel/ed25519_cert.h"
-#include "trunnel/hs/cell_common.h"
+#include "trunnel/extension.h"
#include "trunnel/hs/cell_establish_intro.h"
#include "trunnel/hs/cell_introduce1.h"
#include "trunnel/hs/cell_rendezvous.h"
@@ -194,37 +195,10 @@ parse_introduce2_encrypted(const uint8_t *decrypted_data,
return NULL;
}
-/** Build a legacy ESTABLISH_INTRO cell with the given circuit nonce and RSA
- * encryption key. The encoded cell is put in cell_out that MUST at least be
- * of the size of RELAY_PAYLOAD_SIZE. Return the encoded cell length on
- * success else a negative value and cell_out is untouched. */
-static ssize_t
-build_legacy_establish_intro(const char *circ_nonce, crypto_pk_t *enc_key,
- uint8_t *cell_out)
-{
- ssize_t cell_len;
-
- tor_assert(circ_nonce);
- tor_assert(enc_key);
- tor_assert(cell_out);
-
- memwipe(cell_out, 0, RELAY_PAYLOAD_SIZE);
-
- cell_len = rend_service_encode_establish_intro_cell((char*)cell_out,
- RELAY_PAYLOAD_SIZE,
- enc_key, circ_nonce);
- return cell_len;
-}
-
/** Parse an INTRODUCE2 cell from payload of size payload_len for the given
* service and circuit which are used only for logging purposes. The resulting
* parsed cell is put in cell_ptr_out.
*
- * This function only parses prop224 INTRODUCE2 cells even when the intro point
- * is a legacy intro point. That's because intro points don't actually care
- * about the contents of the introduce cell. Legacy INTRODUCE cells are only
- * used by the legacy system now.
- *
* Return 0 on success else a negative value and cell_ptr_out is untouched. */
static int
parse_introduce2_cell(const hs_service_t *service,
@@ -400,6 +374,26 @@ introduce1_encrypt_and_encode(trn_cell_introduce1_t *cell,
tor_free(encrypted);
}
+/** Build and set the INTRODUCE congestion control extension in the given
+ * extensions. */
+static void
+build_introduce_cc_extension(trn_extension_t *extensions)
+{
+ trn_extension_field_t *field = NULL;
+
+ /* Build CC request extension. */
+ field = trn_extension_field_new();
+ trn_extension_field_set_field_type(field,
+ TRUNNEL_EXT_TYPE_CC_FIELD_REQUEST);
+
+ /* No payload indicating a request to use congestion control. */
+ trn_extension_field_set_field_len(field, 0);
+
+ /* Build final extension. */
+ trn_extension_add_fields(extensions, field);
+ trn_extension_set_num(extensions, trn_extension_get_num(extensions) + 1);
+}
+
/** Using the INTRODUCE1 data, setup the ENCRYPTED section in cell. This means
* set it, encrypt it and encode it. */
static void
@@ -407,7 +401,7 @@ introduce1_set_encrypted(trn_cell_introduce1_t *cell,
const hs_cell_introduce1_data_t *data)
{
trn_cell_introduce_encrypted_t *enc_cell;
- trn_cell_extension_t *ext;
+ trn_extension_t *ext;
tor_assert(cell);
tor_assert(data);
@@ -415,10 +409,13 @@ introduce1_set_encrypted(trn_cell_introduce1_t *cell,
enc_cell = trn_cell_introduce_encrypted_new();
tor_assert(enc_cell);
- /* Set extension data. None are used. */
- ext = trn_cell_extension_new();
+ /* Setup extension(s) if any. */
+ ext = trn_extension_new();
tor_assert(ext);
- trn_cell_extension_set_num(ext, 0);
+ /* Build congestion control extension is enabled. */
+ if (data->cc_enabled) {
+ build_introduce_cc_extension(ext);
+ }
trn_cell_introduce_encrypted_set_extensions(enc_cell, ext);
/* Set the rendezvous cookie. */
@@ -457,28 +454,6 @@ introduce1_set_auth_key(trn_cell_introduce1_t *cell,
data->auth_pk->pubkey, trn_cell_introduce1_getlen_auth_key(cell));
}
-/** Set the legacy ID field in the INTRODUCE1 cell from the given data. */
-static void
-introduce1_set_legacy_id(trn_cell_introduce1_t *cell,
- const hs_cell_introduce1_data_t *data)
-{
- tor_assert(cell);
- tor_assert(data);
-
- if (data->is_legacy) {
- uint8_t digest[DIGEST_LEN];
- if (BUG(crypto_pk_get_digest(data->legacy_key, (char *) digest) < 0)) {
- return;
- }
- memcpy(trn_cell_introduce1_getarray_legacy_key_id(cell),
- digest, trn_cell_introduce1_getlen_legacy_key_id(cell));
- } else {
- /* We have to zeroed the LEGACY_KEY_ID field. */
- memset(trn_cell_introduce1_getarray_legacy_key_id(cell), 0,
- trn_cell_introduce1_getlen_legacy_key_id(cell));
- }
-}
-
/** Build and add to the given DoS cell extension the given parameter type and
* value. */
static void
@@ -504,20 +479,20 @@ build_establish_intro_dos_param(trn_cell_extension_dos_t *dos_ext,
* possible if there is a bug.) */
static int
build_establish_intro_dos_extension(const hs_service_config_t *service_config,
- trn_cell_extension_t *extensions)
+ trn_extension_t *extensions)
{
ssize_t ret;
size_t dos_ext_encoded_len;
uint8_t *field_array;
- trn_cell_extension_field_t *field = NULL;
+ trn_extension_field_t *field = NULL;
trn_cell_extension_dos_t *dos_ext = NULL;
tor_assert(service_config);
tor_assert(extensions);
/* We are creating a cell extension field of the type DoS. */
- field = trn_cell_extension_field_new();
- trn_cell_extension_field_set_field_type(field,
+ field = trn_extension_field_new();
+ trn_extension_field_set_field_type(field,
TRUNNEL_CELL_EXTENSION_TYPE_DOS);
/* Build DoS extension field. We will put in two parameters. */
@@ -540,24 +515,23 @@ build_establish_intro_dos_extension(const hs_service_config_t *service_config,
}
dos_ext_encoded_len = ret;
/* Set length field and the field array size length. */
- trn_cell_extension_field_set_field_len(field, dos_ext_encoded_len);
- trn_cell_extension_field_setlen_field(field, dos_ext_encoded_len);
+ trn_extension_field_set_field_len(field, dos_ext_encoded_len);
+ trn_extension_field_setlen_field(field, dos_ext_encoded_len);
/* Encode the DoS extension into the cell extension field. */
- field_array = trn_cell_extension_field_getarray_field(field);
+ field_array = trn_extension_field_getarray_field(field);
ret = trn_cell_extension_dos_encode(field_array,
- trn_cell_extension_field_getlen_field(field), dos_ext);
+ trn_extension_field_getlen_field(field), dos_ext);
if (BUG(ret <= 0)) {
goto err;
}
tor_assert(ret == (ssize_t) dos_ext_encoded_len);
/* Finally, encode field into the cell extension. */
- trn_cell_extension_add_fields(extensions, field);
+ trn_extension_add_fields(extensions, field);
/* We've just add an extension field to the cell extensions so increment the
* total number. */
- trn_cell_extension_set_num(extensions,
- trn_cell_extension_get_num(extensions) + 1);
+ trn_extension_set_num(extensions, trn_extension_get_num(extensions) + 1);
/* Cleanup. DoS extension has been encoded at this point. */
trn_cell_extension_dos_free(dos_ext);
@@ -565,7 +539,7 @@ build_establish_intro_dos_extension(const hs_service_config_t *service_config,
return 0;
err:
- trn_cell_extension_field_free(field);
+ trn_extension_field_free(field);
trn_cell_extension_dos_free(dos_ext);
return -1;
}
@@ -576,18 +550,18 @@ build_establish_intro_dos_extension(const hs_service_config_t *service_config,
/** Allocate and build all the ESTABLISH_INTRO cell extension. The given
* extensions pointer is always set to a valid cell extension object. */
-STATIC trn_cell_extension_t *
+STATIC trn_extension_t *
build_establish_intro_extensions(const hs_service_config_t *service_config,
const hs_service_intro_point_t *ip)
{
int ret;
- trn_cell_extension_t *extensions;
+ trn_extension_t *extensions;
tor_assert(service_config);
tor_assert(ip);
- extensions = trn_cell_extension_new();
- trn_cell_extension_set_num(extensions, 0);
+ extensions = trn_extension_new();
+ trn_extension_set_num(extensions, 0);
/* If the defense has been enabled service side (by the operator with a
* torrc option) and the intro point does support it. */
@@ -608,8 +582,7 @@ build_establish_intro_extensions(const hs_service_config_t *service_config,
/** Build an ESTABLISH_INTRO cell with the given circuit nonce and intro point
* object. The encoded cell is put in cell_out that MUST at least be of the
* size of RELAY_PAYLOAD_SIZE. Return the encoded cell length on success else
- * a negative value and cell_out is untouched. This function also supports
- * legacy cell creation. */
+ * a negative value and cell_out is untouched. */
ssize_t
hs_cell_build_establish_intro(const char *circ_nonce,
const hs_service_config_t *service_config,
@@ -619,22 +592,12 @@ hs_cell_build_establish_intro(const char *circ_nonce,
ssize_t cell_len = -1;
uint16_t sig_len = ED25519_SIG_LEN;
trn_cell_establish_intro_t *cell = NULL;
- trn_cell_extension_t *extensions;
+ trn_extension_t *extensions;
tor_assert(circ_nonce);
tor_assert(service_config);
tor_assert(ip);
- /* Quickly handle the legacy IP. */
- if (ip->base.is_only_legacy) {
- tor_assert(ip->legacy_key);
- cell_len = build_legacy_establish_intro(circ_nonce, ip->legacy_key,
- cell_out);
- tor_assert(cell_len <= RELAY_PAYLOAD_SIZE);
- /* Success or not we are done here. */
- goto done;
- }
-
/* Build the extensions, if any. */
extensions = build_establish_intro_extensions(service_config, ip);
@@ -821,6 +784,31 @@ get_introduce2_keys_and_verify_mac(hs_cell_introduce2_data_t *data,
return intro_keys_result;
}
+/** 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,
+ const trn_extension_field_t *field)
+{
+ 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:
+ /* CC requests, enable it. */
+ data->cc_enabled = 1;
+ data->pv.protocols_known = 1;
+ data->pv.supports_congestion_control = data->cc_enabled;
+ break;
+ default:
+ break;
+ }
+
+ trn_extension_field_cc_free(cc_field);
+}
+
/** Parse the INTRODUCE2 cell using data which contains everything we need to
* do so and contains the destination buffers of information we extract and
* compute from the cell. Return 0 on success else a negative value. The
@@ -949,6 +937,27 @@ hs_cell_parse_introduce2(hs_cell_introduce2_data_t *data,
smartlist_add(data->link_specifiers, lspec_dup);
}
+ /* Extract any extensions. */
+ const trn_extension_t *extensions =
+ trn_cell_introduce_encrypted_get_extensions(enc_cell);
+ if (extensions != NULL) {
+ for (size_t idx = 0; idx < trn_extension_get_num(extensions); idx++) {
+ const trn_extension_field_t *field =
+ trn_extension_getconst_fields(extensions, idx);
+ if (BUG(field == NULL)) {
+ /* The number of extensions should match the number of fields. */
+ break;
+ }
+ parse_introduce_cell_extension(data, field);
+ }
+ }
+
+ /* 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()) {
+ goto done;
+ }
+
/* Success. */
ret = 0;
log_info(LD_REND, "Valid INTRODUCE2 cell. Launching rendezvous circuit.");
@@ -1008,7 +1017,7 @@ hs_cell_build_introduce1(const hs_cell_introduce1_data_t *data,
{
ssize_t cell_len;
trn_cell_introduce1_t *cell;
- trn_cell_extension_t *ext;
+ trn_extension_t *ext;
tor_assert(data);
tor_assert(cell_out);
@@ -1017,14 +1026,11 @@ hs_cell_build_introduce1(const hs_cell_introduce1_data_t *data,
tor_assert(cell);
/* Set extension data. None are used. */
- ext = trn_cell_extension_new();
+ ext = trn_extension_new();
tor_assert(ext);
- trn_cell_extension_set_num(ext, 0);
+ trn_extension_set_num(ext, 0);
trn_cell_introduce1_set_extensions(cell, ext);
- /* Set the legacy ID field. */
- introduce1_set_legacy_id(cell, data);
-
/* Set the authentication key. */
introduce1_set_auth_key(cell, data);
@@ -1067,18 +1073,6 @@ hs_cell_parse_introduce_ack(const uint8_t *payload, size_t payload_len)
tor_assert(payload);
- /* If it is a legacy IP, rend-spec.txt specifies that a ACK is 0 byte and a
- * NACK is 1 byte. We can't use the legacy function for this so we have to
- * do a special case. */
- if (payload_len <= 1) {
- if (payload_len == 0) {
- ret = TRUNNEL_HS_INTRO_ACK_STATUS_SUCCESS;
- } else {
- ret = TRUNNEL_HS_INTRO_ACK_STATUS_UNKNOWN_ID;
- }
- goto end;
- }
-
if (trn_cell_introduce_ack_parse(&cell, payload, payload_len) < 0) {
log_info(LD_REND, "Invalid INTRODUCE_ACK cell. Unable to parse it.");
goto end;
diff --git a/src/feature/hs/hs_cell.h b/src/feature/hs/hs_cell.h
index 5889e7c6dd..c76a0690a8 100644
--- a/src/feature/hs/hs_cell.h
+++ b/src/feature/hs/hs_cell.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017-2020, The Tor Project, Inc. */
+/* Copyright (c) 2017-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -40,6 +40,8 @@ typedef struct hs_cell_introduce1_data_t {
const curve25519_keypair_t *client_kp;
/** Rendezvous point link specifiers. */
smartlist_t *link_specifiers;
+ /** Congestion control parameters. */
+ unsigned int cc_enabled : 1;
} hs_cell_introduce1_data_t;
/** This data structure contains data that we need to parse an INTRODUCE2 cell
@@ -82,6 +84,10 @@ typedef struct hs_cell_introduce2_data_t {
smartlist_t *link_specifiers;
/** 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. */
@@ -115,9 +121,9 @@ void hs_cell_introduce1_data_clear(hs_cell_introduce1_data_t *data);
#ifdef TOR_UNIT_TESTS
-#include "trunnel/hs/cell_common.h"
+#include "trunnel/extension.h"
-STATIC trn_cell_extension_t *
+STATIC trn_extension_t *
build_establish_intro_extensions(const hs_service_config_t *service_config,
const hs_service_intro_point_t *ip);
diff --git a/src/feature/hs/hs_circuit.c b/src/feature/hs/hs_circuit.c
index eaf99cf8b2..53855d40a9 100644
--- a/src/feature/hs/hs_circuit.c
+++ b/src/feature/hs/hs_circuit.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017-2020, The Tor Project, Inc. */
+/* Copyright (c) 2017-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -17,6 +17,8 @@
#include "core/or/relay.h"
#include "core/or/crypt_path.h"
#include "core/or/extendinfo.h"
+#include "core/or/congestion_control_common.h"
+#include "core/crypto/onion_crypto.h"
#include "feature/client/circpathbias.h"
#include "feature/hs/hs_cell.h"
#include "feature/hs/hs_circuit.h"
@@ -28,8 +30,6 @@
#include "feature/hs/hs_service.h"
#include "feature/nodelist/describe.h"
#include "feature/nodelist/nodelist.h"
-#include "feature/rend/rendservice.h"
-#include "feature/rend/rendclient.h"
#include "feature/stats/rephist.h"
#include "lib/crypt_ops/crypto_dh.h"
#include "lib/crypt_ops/crypto_rand.h"
@@ -37,9 +37,9 @@
/* Trunnel. */
#include "trunnel/ed25519_cert.h"
-#include "trunnel/hs/cell_common.h"
#include "trunnel/hs/cell_establish_intro.h"
+#include "core/or/congestion_control_st.h"
#include "core/or/cpath_build_state_st.h"
#include "core/or/crypt_path_st.h"
#include "feature/nodelist/node_st.h"
@@ -106,57 +106,6 @@ create_rend_cpath(const uint8_t *ntor_key_seed, size_t seed_len,
return cpath;
}
-/** We are a v2 legacy HS client: Create and return a crypt path for the hidden
- * service on the other side of the rendezvous circuit <b>circ</b>. Initialize
- * the crypt path crypto using the body of the RENDEZVOUS1 cell at
- * <b>rend_cell_body</b> (which must be at least DH1024_KEY_LEN+DIGEST_LEN
- * bytes).
- */
-static crypt_path_t *
-create_rend_cpath_legacy(origin_circuit_t *circ, const uint8_t *rend_cell_body)
-{
- crypt_path_t *hop = NULL;
- char keys[DIGEST_LEN+CPATH_KEY_MATERIAL_LEN];
-
- /* first DH1024_KEY_LEN bytes are g^y from the service. Finish the dh
- * handshake...*/
- tor_assert(circ->build_state);
- tor_assert(circ->build_state->pending_final_cpath);
- hop = circ->build_state->pending_final_cpath;
-
- tor_assert(hop->rend_dh_handshake_state);
- if (crypto_dh_compute_secret(LOG_PROTOCOL_WARN, hop->rend_dh_handshake_state,
- (char*)rend_cell_body, DH1024_KEY_LEN,
- keys, DIGEST_LEN+CPATH_KEY_MATERIAL_LEN)<0) {
- log_warn(LD_GENERAL, "Couldn't complete DH handshake.");
- goto err;
- }
- /* ... and set up cpath. */
- if (cpath_init_circuit_crypto(hop,
- keys+DIGEST_LEN, sizeof(keys)-DIGEST_LEN,
- 0, 0) < 0)
- goto err;
-
- /* Check whether the digest is right... */
- if (tor_memneq(keys, rend_cell_body+DH1024_KEY_LEN, DIGEST_LEN)) {
- log_warn(LD_PROTOCOL, "Incorrect digest of key material.");
- goto err;
- }
-
- /* clean up the crypto stuff we just made */
- crypto_dh_free(hop->rend_dh_handshake_state);
- hop->rend_dh_handshake_state = NULL;
-
- goto done;
-
- err:
- hop = NULL;
-
- done:
- memwipe(keys, 0, sizeof(keys));
- return hop;
-}
-
/** Append the final <b>hop</b> to the cpath of the rend <b>circ</b>, and mark
* <b>circ</b> ready for use to transfer HS relay cells. */
static void
@@ -177,21 +126,15 @@ finalize_rend_circuit(origin_circuit_t *circ, crypt_path_t *hop,
hop->package_window = circuit_initial_package_window();
hop->deliver_window = CIRCWINDOW_START;
- /* Now that this circuit has finished connecting to its destination,
- * make sure circuit_get_open_circ_or_launch is willing to return it
- * so we can actually use it. */
- circ->hs_circ_has_timed_out = 0;
+ /* If congestion control, transfer ccontrol onto the cpath. */
+ if (TO_CIRCUIT(circ)->ccontrol) {
+ hop->ccontrol = TO_CIRCUIT(circ)->ccontrol;
+ TO_CIRCUIT(circ)->ccontrol = NULL;
+ }
/* Append the hop to the cpath of this circuit */
cpath_extend_linked_list(&circ->cpath, hop);
- /* In legacy code, 'pending_final_cpath' points to the final hop we just
- * appended to the cpath. We set the original pointer to NULL so that we
- * don't double free it. */
- if (circ->build_state) {
- circ->build_state->pending_final_cpath = NULL;
- }
-
/* Finally, mark circuit as ready to be used for client streams */
if (!is_service_side) {
circuit_try_attaching_streams(circ);
@@ -199,7 +142,7 @@ finalize_rend_circuit(origin_circuit_t *circ, crypt_path_t *hop,
}
/** For a given circuit and a service introduction point object, register the
- * intro circuit to the circuitmap. This supports legacy intro point. */
+ * intro circuit to the circuitmap. */
static void
register_intro_circ(const hs_service_intro_point_t *ip,
origin_circuit_t *circ)
@@ -207,13 +150,8 @@ register_intro_circ(const hs_service_intro_point_t *ip,
tor_assert(ip);
tor_assert(circ);
- if (ip->base.is_only_legacy) {
- hs_circuitmap_register_intro_circ_v2_service_side(circ,
- ip->legacy_key_digest);
- } else {
- hs_circuitmap_register_intro_circ_v3_service_side(circ,
- &ip->auth_key_kp.pubkey);
- }
+ hs_circuitmap_register_intro_circ_v3_service_side(circ,
+ &ip->auth_key_kp.pubkey);
}
/** Return the number of opened introduction circuit for the given circuit that
@@ -473,6 +411,12 @@ launch_rendezvous_point_circuit,(const hs_service_t *service,
tor_assert(circ->hs_ident);
}
+ /* Setup congestion control if asked by the client from the INTRO cell. */
+ if (data->cc_enabled) {
+ hs_circ_setup_congestion_control(circ, congestion_control_sendme_inc(),
+ service->config.is_single_onion);
+ }
+
end:
extend_info_free(info);
}
@@ -489,16 +433,6 @@ can_relaunch_service_rendezvous_point(const origin_circuit_t *circ)
/* XXX: Retrying under certain condition. This is related to #22455. */
- /* Avoid to relaunch twice a circuit to the same rendezvous point at the
- * same time. */
- if (circ->hs_service_side_rend_circ_has_been_relaunched) {
- log_info(LD_REND, "Rendezvous circuit to %s has already been retried. "
- "Skipping retry.",
- safe_str_client(
- extend_info_describe(circ->build_state->chosen_exit)));
- goto disallow;
- }
-
/* We check failure_count >= hs_get_service_max_rend_failures()-1 below, and
* the -1 is because we increment the failure count for our current failure
* *after* this clause. */
@@ -569,6 +503,15 @@ retry_service_rendezvous_point(const origin_circuit_t *circ)
new_circ->build_state->expiry_time = bstate->expiry_time;
new_circ->hs_ident = hs_ident_circuit_dup(circ->hs_ident);
+ /* Setup congestion control if asked by the client from the INTRO cell. */
+ if (TO_CIRCUIT(circ)->ccontrol) {
+ /* As per above, in this case, we are a full 3 hop rend, even if we're a
+ * single-onion service. */
+ hs_circ_setup_congestion_control(new_circ,
+ TO_CIRCUIT(circ)->ccontrol->sendme_inc,
+ false);
+ }
+
done:
return;
}
@@ -606,10 +549,6 @@ setup_introduce1_data(const hs_desc_intro_point_t *ip,
/* Populate the introduce1 data object. */
memset(intro1_data, 0, sizeof(hs_cell_introduce1_data_t));
- if (ip->legacy.key != NULL) {
- intro1_data->is_legacy = 1;
- intro1_data->legacy_key = ip->legacy.key;
- }
intro1_data->auth_pk = &ip->auth_key_cert->signed_key;
intro1_data->enc_pk = &ip->enc_key;
intro1_data->subcredential = subcredential;
@@ -619,6 +558,7 @@ setup_introduce1_data(const hs_desc_intro_point_t *ip,
/* We can't rendezvous without the curve25519 onion key. */
goto end;
}
+
/* Success, we have valid introduce data. */
ret = 0;
@@ -636,8 +576,8 @@ cleanup_on_close_client_circ(circuit_t *circ)
if (circuit_is_hs_v3(circ)) {
hs_client_circuit_cleanup_on_close(circ);
}
- /* It is possible the circuit has an HS purpose but no identifier (rend_data
- * or hs_ident). Thus possible that this passes through. */
+ /* It is possible the circuit has an HS purpose but no identifier (hs_ident).
+ * Thus possible that this passes through. */
}
/** Helper: cleanup function for client circuit. This is for every HS version.
@@ -647,19 +587,52 @@ cleanup_on_free_client_circ(circuit_t *circ)
{
tor_assert(circ);
- if (circuit_is_hs_v2(circ)) {
- rend_client_circuit_cleanup_on_free(circ);
- } else if (circuit_is_hs_v3(circ)) {
+ if (circuit_is_hs_v3(circ)) {
hs_client_circuit_cleanup_on_free(circ);
}
- /* It is possible the circuit has an HS purpose but no identifier (rend_data
- * or hs_ident). Thus possible that this passes through. */
+ /* It is possible the circuit has an HS purpose but no identifier (hs_ident).
+ * Thus possible that this passes through. */
}
/* ========== */
/* Public API */
/* ========== */
+/** Setup on the given circuit congestion control with the given parameters.
+ *
+ * This function assumes that congestion control is enabled on the network and
+ * so it is the caller responsability to make sure of it. */
+void
+hs_circ_setup_congestion_control(origin_circuit_t *origin_circ,
+ uint8_t sendme_inc, bool is_single_onion)
+{
+ circuit_t *circ = NULL;
+ circuit_params_t circ_params = {0};
+
+ tor_assert(origin_circ);
+
+ /* Ease our lives */
+ circ = TO_CIRCUIT(origin_circ);
+
+ circ_params.cc_enabled = true;
+ circ_params.sendme_inc_cells = sendme_inc;
+
+ /* It is setup on the circuit in order to indicate that congestion control is
+ * enabled. It will be transferred to the RP crypt_path_t once the handshake
+ * is finalized in finalize_rend_circuit() for both client and service
+ * because the final hop is not available until then. */
+
+ if (is_single_onion) {
+ circ->ccontrol = congestion_control_new(&circ_params, CC_PATH_ONION_SOS);
+ } else {
+ if (get_options()->HSLayer3Nodes) {
+ circ->ccontrol = congestion_control_new(&circ_params, CC_PATH_ONION_VG);
+ } else {
+ circ->ccontrol = congestion_control_new(&circ_params, CC_PATH_ONION);
+ }
+ }
+}
+
/** Return an introduction point circuit matching the given intro point object.
* NULL is returned is no such circuit can be found. */
origin_circuit_t *
@@ -667,12 +640,7 @@ hs_circ_service_get_intro_circ(const hs_service_intro_point_t *ip)
{
tor_assert(ip);
- if (ip->base.is_only_legacy) {
- return hs_circuitmap_get_intro_circ_v2_service_side(ip->legacy_key_digest);
- } else {
- return hs_circuitmap_get_intro_circ_v3_service_side(
- &ip->auth_key_kp.pubkey);
- }
+ return hs_circuitmap_get_intro_circ_v3_service_side(&ip->auth_key_kp.pubkey);
}
/** Return an introduction point established circuit matching the given intro
@@ -685,12 +653,7 @@ hs_circ_service_get_established_intro_circ(const hs_service_intro_point_t *ip)
tor_assert(ip);
- if (ip->base.is_only_legacy) {
- circ = hs_circuitmap_get_intro_circ_v2_service_side(ip->legacy_key_digest);
- } else {
- circ = hs_circuitmap_get_intro_circ_v3_service_side(
- &ip->auth_key_kp.pubkey);
- }
+ circ = hs_circuitmap_get_intro_circ_v3_service_side(&ip->auth_key_kp.pubkey);
/* Only return circuit if it is established. */
return (circ && TO_CIRCUIT(circ)->purpose == CIRCUIT_PURPOSE_S_INTRO) ?
@@ -698,8 +661,7 @@ hs_circ_service_get_established_intro_circ(const hs_service_intro_point_t *ip)
}
/** Called when we fail building a rendezvous circuit at some point other than
- * the last hop: launches a new circuit to the same rendezvous point. This
- * supports legacy service.
+ * the last hop: launches a new circuit to the same rendezvous point.
*
* We currently relaunch connections to rendezvous points if:
* - A rendezvous circuit timed out before connecting to RP.
@@ -712,7 +674,7 @@ hs_circ_service_get_established_intro_circ(const hs_service_intro_point_t *ip)
* - We've already retried this specific rendezvous circuit.
*/
void
-hs_circ_retry_service_rendezvous_point(origin_circuit_t *circ)
+hs_circ_retry_service_rendezvous_point(const origin_circuit_t *circ)
{
tor_assert(circ);
tor_assert(TO_CIRCUIT(circ)->purpose == CIRCUIT_PURPOSE_S_CONNECT_REND);
@@ -722,15 +684,9 @@ hs_circ_retry_service_rendezvous_point(origin_circuit_t *circ)
goto done;
}
- /* Flag the circuit that we are relaunching, to avoid to relaunch twice a
- * circuit to the same rendezvous point at the same time. */
- circ->hs_service_side_rend_circ_has_been_relaunched = 1;
-
/* Legacy services don't have a hidden service ident. */
if (circ->hs_ident) {
retry_service_rendezvous_point(circ);
- } else {
- rend_service_relaunch_rendezvous(circ);
}
done:
@@ -765,9 +721,7 @@ hs_circ_launch_intro_point(hs_service_t *service,
goto end;
}
/* We only use a one-hop path on the first attempt. If the first attempt
- * fails, we use a 3-hop path for reachability / reliability.
- * (Unlike v2, retries is incremented by the caller before it calls this
- * function.) */
+ * fails, we use a 3-hop path for reachability / reliability. */
if (direct_conn && ip->circuit_retries == 1) {
circ_flags |= CIRCLAUNCH_ONEHOP_TUNNEL;
}
@@ -955,10 +909,8 @@ hs_circ_handle_intro_established(const hs_service_t *service,
}
/* Try to parse the payload into a cell making sure we do actually have a
- * valid cell. For a legacy node, it's an empty payload so as long as we
- * have the cell, we are good. */
- if (!ip->base.is_only_legacy &&
- hs_cell_parse_intro_established(payload, payload_len) < 0) {
+ * valid cell. */
+ if (hs_cell_parse_intro_established(payload, payload_len) < 0) {
log_warn(LD_REND, "Unable to parse the INTRO_ESTABLISHED cell on "
"circuit %u for service %s",
TO_CIRCUIT(circ)->n_circ_id,
@@ -1043,6 +995,7 @@ hs_circ_handle_introduce2(const hs_service_t *service,
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)) {
@@ -1115,31 +1068,6 @@ hs_circuit_setup_e2e_rend_circ(origin_circuit_t *circ,
return 0;
}
-/** We are a v2 legacy HS client and we just received a RENDEZVOUS1 cell
- * <b>rend_cell_body</b> on <b>circ</b>. Finish up the DH key exchange and then
- * extend the crypt path of <b>circ</b> so that the hidden service is on the
- * other side. */
-int
-hs_circuit_setup_e2e_rend_circ_legacy_client(origin_circuit_t *circ,
- const uint8_t *rend_cell_body)
-{
-
- if (BUG(!circuit_purpose_is_correct_for_rend(
- TO_CIRCUIT(circ)->purpose, 0))) {
- return -1;
- }
-
- crypt_path_t *hop = create_rend_cpath_legacy(circ, rend_cell_body);
- if (!hop) {
- log_warn(LD_GENERAL, "Couldn't get v2 cpath.");
- return -1;
- }
-
- finalize_rend_circuit(circ, hop, 0);
-
- return 0;
-}
-
/** Given the introduction circuit intro_circ, the rendezvous circuit
* rend_circ, a descriptor intro point object ip and the service's
* subcredential, send an INTRODUCE1 cell on intro_circ.
@@ -1181,11 +1109,17 @@ hs_circ_send_introduce1(origin_circuit_t *intro_circ,
/* We should never select an invalid rendezvous point in theory but if we
* do, this function will fail to populate the introduce data. */
if (setup_introduce1_data(ip, exit_node, subcredential, &intro1_data) < 0) {
- log_warn(LD_REND, "Unable to setup INTRODUCE1 data. The chosen rendezvous "
+ log_info(LD_REND, "Unable to setup INTRODUCE1 data. The chosen rendezvous "
"point is unusable. Closing circuit.");
goto close;
}
+ /* 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) {
+ intro1_data.cc_enabled = 1;
+ }
+
/* Final step before we encode a cell, we setup the circuit identifier which
* will generate both the rendezvous cookie and client keypair for this
* connection. Those are put in the ident. */
@@ -1366,6 +1300,17 @@ hs_circ_cleanup_on_repurpose(circuit_t *circ)
if (circ->hs_token) {
hs_circuitmap_remove_circuit(circ);
}
+
+ switch (circ->purpose) {
+ case CIRCUIT_PURPOSE_S_CONNECT_REND:
+ /* This circuit was connecting to a rendezvous point but it is being
+ * repurposed so we need to relaunch an attempt else the client will be
+ * left hanging waiting for the rendezvous. */
+ hs_circ_retry_service_rendezvous_point(TO_ORIGIN_CIRCUIT(circ));
+ break;
+ default:
+ break;
+ }
}
/** Return true iff the given established client rendezvous circuit was sent
@@ -1384,31 +1329,20 @@ hs_circ_is_rend_sent_in_intro1(const origin_circuit_t *circ)
* confirmed rendezsvous circuit but without an introduction ACK. */
tor_assert(TO_CIRCUIT(circ)->purpose == CIRCUIT_PURPOSE_C_REND_READY);
- /* The v2 and v3 circuit are handled differently:
- *
- * v2: A circ's pending_final_cpath field is non-NULL iff it is a rend circ
- * and we have tried to send an INTRODUCE1 cell specifying it. Thus, if the
- * pending_final_cpath field *is* NULL, then we want to not spare it.
- *
- * v3: When the INTRODUCE1 cell is sent, the introduction encryption public
+ /* When the INTRODUCE1 cell is sent, the introduction encryption public
* key is copied in the rendezvous circuit hs identifier. If it is a valid
* key, we know that this circuit is waiting the ACK on the introduction
* circuit. We want to _not_ spare the circuit if the key was never set. */
- if (circ->rend_data) {
- /* v2. */
- if (circ->build_state && circ->build_state->pending_final_cpath != NULL) {
- return true;
- }
- } else if (circ->hs_ident) {
+ if (circ->hs_ident) {
/* v3. */
if (curve25519_public_key_is_ok(&circ->hs_ident->intro_enc_pk)) {
return true;
}
} else {
- /* A circuit with an HS purpose without an hs_ident or rend_data in theory
- * can not happen. In case, scream loudly and return false to the caller
- * that the rendezvous was not sent in the INTRO1 cell. */
+ /* A circuit with an HS purpose without an hs_ident in theory can not
+ * happen. In case, scream loudly and return false to the caller that the
+ * rendezvous was not sent in the INTRO1 cell. */
tor_assert_nonfatal_unreached();
}
diff --git a/src/feature/hs/hs_circuit.h b/src/feature/hs/hs_circuit.h
index 4dd9bf94c5..afbff7b894 100644
--- a/src/feature/hs/hs_circuit.h
+++ b/src/feature/hs/hs_circuit.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017-2020, The Tor Project, Inc. */
+/* Copyright (c) 2017-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -33,7 +33,7 @@ int hs_circ_launch_intro_point(hs_service_t *service,
int hs_circ_launch_rendezvous_point(const hs_service_t *service,
const curve25519_public_key_t *onion_key,
const uint8_t *rendezvous_cookie);
-void hs_circ_retry_service_rendezvous_point(origin_circuit_t *circ);
+void hs_circ_retry_service_rendezvous_point(const origin_circuit_t *circ);
origin_circuit_t *hs_circ_service_get_intro_circ(
const hs_service_intro_point_t *ip);
@@ -69,6 +69,10 @@ int hs_circuit_setup_e2e_rend_circ_legacy_client(origin_circuit_t *circ,
bool hs_circ_is_rend_sent_in_intro1(const origin_circuit_t *circ);
+void hs_circ_setup_congestion_control(origin_circuit_t *origin_circ,
+ uint8_t sendme_inc,
+ bool is_single_onion);
+
#ifdef HS_CIRCUIT_PRIVATE
struct hs_ntor_rend_cell_keys_t;
diff --git a/src/feature/hs/hs_circuitmap.c b/src/feature/hs/hs_circuitmap.c
index e46b008a5c..4499a00298 100644
--- a/src/feature/hs/hs_circuitmap.c
+++ b/src/feature/hs/hs_circuitmap.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2020, The Tor Project, Inc. */
+/* Copyright (c) 2016-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -273,7 +273,7 @@ hs_circuitmap_get_or_circuit(hs_token_type_t type,
/**** Public relay-side getters: */
-/** Public function: Return v2 and v3 introduction circuit to this relay.
+/** Public function: Return v3 introduction circuit to this relay.
* Always return a newly allocated list for which it is the caller's
* responsibility to free it. */
smartlist_t *
@@ -286,12 +286,11 @@ hs_circuitmap_get_all_intro_circ_relay_side(void)
circuit_t *circ = *iter;
/* An origin circuit or purpose is wrong or the hs token is not set to be
- * a v2 or v3 intro relay side type, we ignore the circuit. Else, we have
+ * a v3 intro relay side type, we ignore the circuit. Else, we have
* a match so add it to our list. */
if (CIRCUIT_IS_ORIGIN(circ) ||
circ->purpose != CIRCUIT_PURPOSE_INTRO_POINT ||
- (circ->hs_token->type != HS_TOKEN_INTRO_V3_RELAY_SIDE &&
- circ->hs_token->type != HS_TOKEN_INTRO_V2_RELAY_SIDE)) {
+ circ->hs_token->type != HS_TOKEN_INTRO_V3_RELAY_SIDE) {
continue;
}
smartlist_add(circuit_list, circ);
@@ -312,16 +311,6 @@ hs_circuitmap_get_intro_circ_v3_relay_side(
CIRCUIT_PURPOSE_INTRO_POINT);
}
-/** Public function: Return v2 introduction circuit to this relay with
- * <b>digest</b>. Return NULL if no such circuit is found in the circuitmap. */
-or_circuit_t *
-hs_circuitmap_get_intro_circ_v2_relay_side(const uint8_t *digest)
-{
- return hs_circuitmap_get_or_circuit(HS_TOKEN_INTRO_V2_RELAY_SIDE,
- REND_TOKEN_LEN, digest,
- CIRCUIT_PURPOSE_INTRO_POINT);
-}
-
/** Public function: Return rendezvous circuit to this relay with rendezvous
* <b>cookie</b>. Return NULL if no such circuit is found in the circuitmap. */
or_circuit_t *
@@ -344,16 +333,6 @@ hs_circuitmap_register_rend_circ_relay_side(or_circuit_t *circ,
HS_TOKEN_REND_RELAY_SIDE,
REND_TOKEN_LEN, cookie);
}
-/** Public function: Register v2 intro circuit with key <b>digest</b> to the
- * circuitmap. */
-void
-hs_circuitmap_register_intro_circ_v2_relay_side(or_circuit_t *circ,
- const uint8_t *digest)
-{
- hs_circuitmap_register_circuit(TO_CIRCUIT(circ),
- HS_TOKEN_INTRO_V2_RELAY_SIDE,
- REND_TOKEN_LEN, digest);
-}
/** Public function: Register v3 intro circuit with key <b>auth_key</b> to the
* circuitmap. */
@@ -393,30 +372,6 @@ hs_circuitmap_get_intro_circ_v3_service_side(const
return circ;
}
-/** Public function: Return v2 introduction circuit originating from this
- * hidden service with <b>digest</b>. Return NULL if no such circuit is found
- * in the circuitmap. */
-origin_circuit_t *
-hs_circuitmap_get_intro_circ_v2_service_side(const uint8_t *digest)
-{
- origin_circuit_t *circ = NULL;
-
- /* Check first for established intro circuits */
- circ = hs_circuitmap_get_origin_circuit(HS_TOKEN_INTRO_V2_SERVICE_SIDE,
- REND_TOKEN_LEN, digest,
- CIRCUIT_PURPOSE_S_INTRO);
- if (circ) {
- return circ;
- }
-
- /* ...if nothing found, check for pending intro circs */
- circ = hs_circuitmap_get_origin_circuit(HS_TOKEN_INTRO_V2_SERVICE_SIDE,
- REND_TOKEN_LEN, digest,
- CIRCUIT_PURPOSE_S_ESTABLISH_INTRO);
-
- return circ;
-}
-
/** Public function: Return rendezvous circuit originating from this hidden
* service with rendezvous <b>cookie</b>. Return NULL if no such circuit is
* found in the circuitmap. */
@@ -515,17 +470,6 @@ hs_circuitmap_get_established_rend_circ_client_side(const uint8_t *cookie)
/**** Public servide-side setters: */
-/** Public function: Register v2 intro circuit with key <b>digest</b> to the
- * circuitmap. */
-void
-hs_circuitmap_register_intro_circ_v2_service_side(origin_circuit_t *circ,
- const uint8_t *digest)
-{
- hs_circuitmap_register_circuit(TO_CIRCUIT(circ),
- HS_TOKEN_INTRO_V2_SERVICE_SIDE,
- REND_TOKEN_LEN, digest);
-}
-
/** Public function: Register v3 intro circuit with key <b>auth_key</b> to the
* circuitmap. */
void
diff --git a/src/feature/hs/hs_circuitmap.h b/src/feature/hs/hs_circuitmap.h
index df3e7a6e7e..ba857e0172 100644
--- a/src/feature/hs/hs_circuitmap.h
+++ b/src/feature/hs/hs_circuitmap.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2020, The Tor Project, Inc. */
+/* Copyright (c) 2016-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -24,14 +24,10 @@ struct or_circuit_t *
hs_circuitmap_get_intro_circ_v3_relay_side(const
struct ed25519_public_key_t *auth_key);
struct or_circuit_t *
-hs_circuitmap_get_intro_circ_v2_relay_side(const uint8_t *digest);
-struct or_circuit_t *
hs_circuitmap_get_rend_circ_relay_side(const uint8_t *cookie);
void hs_circuitmap_register_rend_circ_relay_side(struct or_circuit_t *circ,
const uint8_t *cookie);
-void hs_circuitmap_register_intro_circ_v2_relay_side(struct or_circuit_t *circ,
- const uint8_t *digest);
void hs_circuitmap_register_intro_circ_v3_relay_side(struct or_circuit_t *circ,
const struct ed25519_public_key_t *auth_key);
@@ -43,17 +39,12 @@ struct origin_circuit_t *
hs_circuitmap_get_intro_circ_v3_service_side(const
struct ed25519_public_key_t *auth_key);
struct origin_circuit_t *
-hs_circuitmap_get_intro_circ_v2_service_side(const uint8_t *digest);
-struct origin_circuit_t *
hs_circuitmap_get_rend_circ_service_side(const uint8_t *cookie);
struct origin_circuit_t *
hs_circuitmap_get_rend_circ_client_side(const uint8_t *cookie);
struct origin_circuit_t *
hs_circuitmap_get_established_rend_circ_client_side(const uint8_t *cookie);
-void hs_circuitmap_register_intro_circ_v2_service_side(
- struct origin_circuit_t *circ,
- const uint8_t *digest);
void hs_circuitmap_register_intro_circ_v3_service_side(
struct origin_circuit_t *circ,
const struct ed25519_public_key_t *auth_key);
@@ -75,15 +66,11 @@ void hs_circuitmap_free_all(void);
typedef enum {
/** A rendezvous cookie on a relay (128bit)*/
HS_TOKEN_REND_RELAY_SIDE,
- /** A v2 introduction point pubkey on a relay (160bit) */
- HS_TOKEN_INTRO_V2_RELAY_SIDE,
/** A v3 introduction point pubkey on a relay (256bit) */
HS_TOKEN_INTRO_V3_RELAY_SIDE,
/** A rendezvous cookie on a hidden service (128bit)*/
HS_TOKEN_REND_SERVICE_SIDE,
- /** A v2 introduction point pubkey on a hidden service (160bit) */
- HS_TOKEN_INTRO_V2_SERVICE_SIDE,
/** A v3 introduction point pubkey on a hidden service (256bit) */
HS_TOKEN_INTRO_V3_SERVICE_SIDE,
diff --git a/src/feature/hs/hs_client.c b/src/feature/hs/hs_client.c
index 6c9645f0b8..a50598d9f3 100644
--- a/src/feature/hs/hs_client.c
+++ b/src/feature/hs/hs_client.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2020, The Tor Project, Inc. */
+/* Copyright (c) 2016-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -11,12 +11,15 @@
#include "core/or/or.h"
#include "app/config/config.h"
#include "core/crypto/hs_ntor.h"
+#include "core/crypto/onion_crypto.h"
#include "core/mainloop/connection.h"
#include "core/or/circuitbuild.h"
#include "core/or/circuitlist.h"
#include "core/or/circuituse.h"
#include "core/or/connection_edge.h"
+#include "core/or/congestion_control_common.h"
#include "core/or/extendinfo.h"
+#include "core/or/protover.h"
#include "core/or/reasons.h"
#include "feature/client/circpathbias.h"
#include "feature/dirclient/dirclient.h"
@@ -34,7 +37,6 @@
#include "feature/nodelist/networkstatus.h"
#include "feature/nodelist/nodelist.h"
#include "feature/nodelist/routerset.h"
-#include "feature/rend/rendclient.h"
#include "lib/crypt_ops/crypto_format.h"
#include "lib/crypt_ops/crypto_rand.h"
#include "lib/crypt_ops/crypto_util.h"
@@ -380,16 +382,6 @@ note_connection_attempt_succeeded(const hs_ident_edge_conn_t *hs_conn_ident)
/* Remove from the hid serv cache all requests for that service so we can
* query the HSDir again later on for various reasons. */
purge_hid_serv_request(&hs_conn_ident->identity_pk);
-
- /* The v2 subsystem cleans up the intro point time out flag at this stage.
- * We don't try to do it here because we still need to keep intact the intro
- * point state for future connections. Even though we are able to connect to
- * the service, doesn't mean we should reset the timed out intro points.
- *
- * It is not possible to have successfully connected to an intro point
- * present in our cache that was on error or timed out. Every entry in that
- * cache have a 2 minutes lifetime so ultimately the intro point(s) state
- * will be reset and thus possible to be retried. */
}
/** Given the pubkey of a hidden service in <b>onion_identity_pk</b>, fetch its
@@ -652,6 +644,16 @@ 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
+ * 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()
+ && hs_desc_supports_congestion_control(desc)) {
+ circuit_mark_for_close(TO_CIRCUIT(rend_circ), END_CIRC_REASON_INTERNAL);
+ goto tran_err;
+ }
+
/* We need to find which intro point in the descriptor we are connected to
* on intro_circ. */
ip = find_desc_intro_point_by_ident(intro_circ->hs_ident, desc);
@@ -787,6 +789,45 @@ client_intro_circ_has_opened(origin_circuit_t *circ)
connection_ap_attach_pending(1);
}
+/** Setup the congestion control parameters on the given rendezvous circuit.
+ * This looks at the service descriptor flow control line (if any).
+ *
+ * It is possible that we are unable to set congestion control on the circuit
+ * if the descriptor can't be found. In that case, the introduction circuit
+ * can't be opened without it so a fetch will be triggered.
+ *
+ * However, if the descriptor asks for congestion control but the RP circuit
+ * doesn't have it, it will be closed and a new circuit will be opened. */
+static void
+setup_rendezvous_circ_congestion_control(origin_circuit_t *circ)
+{
+ tor_assert(circ);
+
+ /* Setup congestion control parameters on the circuit. */
+ const hs_descriptor_t *desc =
+ hs_cache_lookup_as_client(&circ->hs_ident->identity_pk);
+ if (desc == NULL) {
+ /* This is possible because between launching the circuit and the circuit
+ * ending in opened state, the descriptor could have been removed from the
+ * cache. In this case, we just can't setup congestion control. */
+ return;
+ }
+
+ /* Check if the service lists support for congestion control in its
+ * descriptor. If not, we don't setup congestion control. */
+ if (!hs_desc_supports_congestion_control(desc)) {
+ return;
+ }
+
+ /* If network doesn't enable it, do not setup. */
+ if (!congestion_control_enabled()) {
+ return;
+ }
+
+ hs_circ_setup_congestion_control(circ, desc->encrypted_data.sendme_inc,
+ desc->encrypted_data.single_onion_service);
+}
+
/** Called when a rendezvous circuit has opened. */
static void
client_rendezvous_circ_has_opened(origin_circuit_t *circ)
@@ -816,6 +857,9 @@ client_rendezvous_circ_has_opened(origin_circuit_t *circ)
log_info(LD_REND, "Rendezvous circuit has opened to %s.",
safe_str_client(extend_info_describe(rp_ei)));
+ /* Setup congestion control parameters on the circuit. */
+ setup_rendezvous_circ_congestion_control(circ);
+
/* Ignore returned value, nothing we can really do. On failure, the circuit
* will be marked for close. */
hs_circ_send_establish_rendezvous(circ);
@@ -1151,7 +1195,7 @@ handle_introduce_ack_success(origin_circuit_t *intro_circ)
rend_circ =
hs_circuitmap_get_established_rend_circ_client_side(rendezvous_cookie);
if (rend_circ == NULL) {
- log_warn(LD_REND, "Can't find any rendezvous circuit. Stopping");
+ log_info(LD_REND, "Can't find any rendezvous circuit. Stopping");
goto end;
}
@@ -1920,7 +1964,7 @@ void
hs_client_circuit_cleanup_on_free(const circuit_t *circ)
{
bool has_timed_out;
- rend_intro_point_failure_t failure = INTRO_POINT_FAILURE_GENERIC;
+ rend_intro_point_failure_t failure = INTRO_POINT_FAILURE_UNREACHABLE;
const origin_circuit_t *orig_circ = NULL;
tor_assert(circ);
@@ -1971,17 +2015,9 @@ hs_client_note_connection_attempt_succeeded(const edge_connection_t *conn)
{
tor_assert(connection_edge_is_rendezvous_stream(conn));
- if (BUG(conn->rend_data && conn->hs_ident)) {
- log_warn(LD_BUG, "Stream had both rend_data and hs_ident..."
- "Prioritizing hs_ident");
- }
-
if (conn->hs_ident) { /* It's v3: pass it to the prop224 handler */
note_connection_attempt_succeeded(conn->hs_ident);
return;
- } else if (conn->rend_data) { /* It's v2: pass it to the legacy handler */
- rend_client_note_connection_attempt_ended(conn->rend_data);
- return;
}
}
@@ -2107,9 +2143,7 @@ int
hs_client_send_introduce1(origin_circuit_t *intro_circ,
origin_circuit_t *rend_circ)
{
- return (intro_circ->hs_ident) ? send_introduce1(intro_circ, rend_circ) :
- rend_client_send_introduction(intro_circ,
- rend_circ);
+ return send_introduce1(intro_circ, rend_circ);
}
/** Called when the client circuit circ has been established. It can be either
@@ -2120,21 +2154,15 @@ hs_client_circuit_has_opened(origin_circuit_t *circ)
{
tor_assert(circ);
- /* Handle both version. v2 uses rend_data and v3 uses the hs circuit
- * identifier hs_ident. Can't be both. */
switch (TO_CIRCUIT(circ)->purpose) {
case CIRCUIT_PURPOSE_C_INTRODUCING:
if (circ->hs_ident) {
client_intro_circ_has_opened(circ);
- } else {
- rend_client_introcirc_has_opened(circ);
}
break;
case CIRCUIT_PURPOSE_C_ESTABLISH_REND:
if (circ->hs_ident) {
client_rendezvous_circ_has_opened(circ);
- } else {
- rend_client_rendcirc_has_opened(circ);
}
break;
default:
@@ -2448,9 +2476,7 @@ hs_client_get_random_intro_from_edge(const edge_connection_t *edge_conn)
{
tor_assert(edge_conn);
- return (edge_conn->hs_ident) ?
- client_get_random_intro(&edge_conn->hs_ident->identity_pk) :
- rend_client_get_random_intro(edge_conn->rend_data);
+ return client_get_random_intro(&edge_conn->hs_ident->identity_pk);
}
/** Called when get an INTRODUCE_ACK cell on the introduction circuit circ.
@@ -2472,9 +2498,7 @@ hs_client_receive_introduce_ack(origin_circuit_t *circ,
goto end;
}
- ret = (circ->hs_ident) ? handle_introduce_ack(circ, payload, payload_len) :
- rend_client_introduction_acked(circ, payload,
- payload_len);
+ ret = handle_introduce_ack(circ, payload, payload_len);
/* For path bias: This circuit was used successfully. NACK or ACK counts. */
pathbias_mark_use_success(circ);
@@ -2508,9 +2532,8 @@ hs_client_receive_rendezvous2(origin_circuit_t *circ,
log_info(LD_REND, "Got RENDEZVOUS2 cell from hidden service on circuit %u.",
TO_CIRCUIT(circ)->n_circ_id);
- ret = (circ->hs_ident) ? handle_rendezvous2(circ, payload, payload_len) :
- rend_client_receive_rendezvous(circ, payload,
- payload_len);
+ ret = handle_rendezvous2(circ, payload, payload_len);
+
end:
return ret;
}
@@ -2531,9 +2554,7 @@ hs_client_reextend_intro_circuit(origin_circuit_t *circ)
tor_assert(circ);
- ei = (circ->hs_ident) ?
- client_get_random_intro(&circ->hs_ident->identity_pk) :
- rend_client_get_random_intro(circ->rend_data);
+ ei = client_get_random_intro(&circ->hs_ident->identity_pk);
if (ei == NULL) {
log_warn(LD_REND, "No usable introduction points left. Closing.");
circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_INTERNAL);
@@ -2614,9 +2635,6 @@ hs_client_free_all(void)
void
hs_client_purge_state(void)
{
- /* v2 subsystem. */
- rend_client_purge_state();
-
/* Cancel all descriptor fetches. Do this first so once done we are sure
* that our descriptor cache won't modified. */
cancel_descriptor_fetches();
diff --git a/src/feature/hs/hs_client.h b/src/feature/hs/hs_client.h
index 411fa659f2..2fe955605f 100644
--- a/src/feature/hs/hs_client.h
+++ b/src/feature/hs/hs_client.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017-2020, The Tor Project, Inc. */
+/* Copyright (c) 2017-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/hs/hs_common.c b/src/feature/hs/hs_common.c
index fa27ac5223..e326581dd1 100644
--- a/src/feature/hs/hs_common.c
+++ b/src/feature/hs/hs_common.c
@@ -1,12 +1,10 @@
-/* Copyright (c) 2016-2020, The Tor Project, Inc. */
+/* Copyright (c) 2016-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
* \file hs_common.c
* \brief Contains code shared between different HS protocol version as well
* as useful data structures and accessors used by other subsystems.
- * The rendcommon.c should only contains code relating to the v2
- * protocol.
**/
#define HS_COMMON_PRIVATE
@@ -33,10 +31,10 @@
#include "feature/nodelist/nodelist.h"
#include "feature/nodelist/routerset.h"
#include "feature/rend/rendcommon.h"
-#include "feature/rend/rendservice.h"
#include "feature/relay/routermode.h"
#include "lib/crypt_ops/crypto_rand.h"
#include "lib/crypt_ops/crypto_util.h"
+#include "lib/net/resolve.h"
#include "core/or/edge_connection_st.h"
#include "feature/nodelist/networkstatus_st.h"
@@ -57,12 +55,12 @@ static const char *str_ed25519_basepoint =
#ifdef HAVE_SYS_UN_H
-/** Given <b>ports</b>, a smarlist containing rend_service_port_config_t,
+/** Given <b>ports</b>, a smartlist containing hs_port_config_t,
* add the given <b>p</b>, a AF_UNIX port to the list. Return 0 on success
* else return -ENOSYS if AF_UNIX is not supported (see function in the
* #else statement below). */
static int
-add_unix_port(smartlist_t *ports, rend_service_port_config_t *p)
+add_unix_port(smartlist_t *ports, hs_port_config_t *p)
{
tor_assert(ports);
tor_assert(p);
@@ -76,7 +74,7 @@ add_unix_port(smartlist_t *ports, rend_service_port_config_t *p)
* on success else return -ENOSYS if AF_UNIX is not supported (see function
* in the #else statement below). */
static int
-set_unix_port(edge_connection_t *conn, rend_service_port_config_t *p)
+set_unix_port(edge_connection_t *conn, hs_port_config_t *p)
{
tor_assert(conn);
tor_assert(p);
@@ -92,7 +90,7 @@ set_unix_port(edge_connection_t *conn, rend_service_port_config_t *p)
#else /* !defined(HAVE_SYS_UN_H) */
static int
-set_unix_port(edge_connection_t *conn, rend_service_port_config_t *p)
+set_unix_port(edge_connection_t *conn, hs_port_config_t *p)
{
(void) conn;
(void) p;
@@ -100,7 +98,7 @@ set_unix_port(edge_connection_t *conn, rend_service_port_config_t *p)
}
static int
-add_unix_port(smartlist_t *ports, rend_service_port_config_t *p)
+add_unix_port(smartlist_t *ports, hs_port_config_t *p)
{
(void) ports;
(void) p;
@@ -336,258 +334,6 @@ hs_get_start_time_of_next_time_period(time_t now)
return (time_t)(start_of_next_tp_in_mins * 60 + time_period_rotation_offset);
}
-/** Create a new rend_data_t for a specific given <b>version</b>.
- * Return a pointer to the newly allocated data structure. */
-static rend_data_t *
-rend_data_alloc(uint32_t version)
-{
- rend_data_t *rend_data = NULL;
-
- switch (version) {
- case HS_VERSION_TWO:
- {
- rend_data_v2_t *v2 = tor_malloc_zero(sizeof(*v2));
- v2->base_.version = HS_VERSION_TWO;
- v2->base_.hsdirs_fp = smartlist_new();
- rend_data = &v2->base_;
- break;
- }
- default:
- tor_assert(0);
- break;
- }
-
- return rend_data;
-}
-
-/** Free all storage associated with <b>data</b> */
-void
-rend_data_free_(rend_data_t *data)
-{
- if (!data) {
- return;
- }
- /* By using our allocation function, this should always be set. */
- tor_assert(data->hsdirs_fp);
- /* Cleanup the HSDir identity digest. */
- SMARTLIST_FOREACH(data->hsdirs_fp, char *, d, tor_free(d));
- smartlist_free(data->hsdirs_fp);
- /* Depending on the version, cleanup. */
- switch (data->version) {
- case HS_VERSION_TWO:
- {
- rend_data_v2_t *v2_data = TO_REND_DATA_V2(data);
- tor_free(v2_data);
- break;
- }
- default:
- tor_assert(0);
- }
-}
-
-/** Allocate and return a deep copy of <b>data</b>. */
-rend_data_t *
-rend_data_dup(const rend_data_t *data)
-{
- rend_data_t *data_dup = NULL;
- smartlist_t *hsdirs_fp = smartlist_new();
-
- tor_assert(data);
- tor_assert(data->hsdirs_fp);
-
- SMARTLIST_FOREACH(data->hsdirs_fp, char *, fp,
- smartlist_add(hsdirs_fp, tor_memdup(fp, DIGEST_LEN)));
-
- switch (data->version) {
- case HS_VERSION_TWO:
- {
- rend_data_v2_t *v2_data = tor_memdup(TO_REND_DATA_V2(data),
- sizeof(*v2_data));
- data_dup = &v2_data->base_;
- data_dup->hsdirs_fp = hsdirs_fp;
- break;
- }
- default:
- tor_assert(0);
- break;
- }
-
- return data_dup;
-}
-
-/** Compute the descriptor ID for each HS descriptor replica and save them. A
- * valid onion address must be present in the <b>rend_data</b>.
- *
- * Return 0 on success else -1. */
-static int
-compute_desc_id(rend_data_t *rend_data)
-{
- int ret = 0;
- unsigned replica;
- time_t now = time(NULL);
-
- tor_assert(rend_data);
-
- switch (rend_data->version) {
- case HS_VERSION_TWO:
- {
- rend_data_v2_t *v2_data = TO_REND_DATA_V2(rend_data);
- /* Compute descriptor ID for each replicas. */
- for (replica = 0; replica < ARRAY_LENGTH(v2_data->descriptor_id);
- replica++) {
- ret = rend_compute_v2_desc_id(v2_data->descriptor_id[replica],
- v2_data->onion_address,
- v2_data->descriptor_cookie,
- now, replica);
- if (ret < 0) {
- goto end;
- }
- }
- break;
- }
- default:
- tor_assert(0);
- }
-
- end:
- return ret;
-}
-
-/** Allocate and initialize a rend_data_t object for a service using the
- * provided arguments. All arguments are optional (can be NULL), except from
- * <b>onion_address</b> which MUST be set. The <b>pk_digest</b> is the hash of
- * the service private key. The <b>cookie</b> is the rendezvous cookie and
- * <b>auth_type</b> is which authentiation this service is configured with.
- *
- * Return a valid rend_data_t pointer. This only returns a version 2 object of
- * rend_data_t. */
-rend_data_t *
-rend_data_service_create(const char *onion_address, const char *pk_digest,
- const uint8_t *cookie, rend_auth_type_t auth_type)
-{
- /* Create a rend_data_t object for version 2. */
- rend_data_t *rend_data = rend_data_alloc(HS_VERSION_TWO);
- rend_data_v2_t *v2= TO_REND_DATA_V2(rend_data);
-
- /* We need at least one else the call is wrong. */
- tor_assert(onion_address != NULL);
-
- if (pk_digest) {
- memcpy(v2->rend_pk_digest, pk_digest, sizeof(v2->rend_pk_digest));
- }
- if (cookie) {
- memcpy(rend_data->rend_cookie, cookie, sizeof(rend_data->rend_cookie));
- }
-
- strlcpy(v2->onion_address, onion_address, sizeof(v2->onion_address));
- v2->auth_type = auth_type;
-
- return rend_data;
-}
-
-/** Allocate and initialize a rend_data_t object for a client request using the
- * given arguments. Either an onion address or a descriptor ID is needed. Both
- * can be given but in this case only the onion address will be used to make
- * the descriptor fetch. The <b>cookie</b> is the rendezvous cookie and
- * <b>auth_type</b> is which authentiation the service is configured with.
- *
- * Return a valid rend_data_t pointer or NULL on error meaning the
- * descriptor IDs couldn't be computed from the given data. */
-rend_data_t *
-rend_data_client_create(const char *onion_address, const char *desc_id,
- const char *cookie, rend_auth_type_t auth_type)
-{
- /* Create a rend_data_t object for version 2. */
- rend_data_t *rend_data = rend_data_alloc(HS_VERSION_TWO);
- rend_data_v2_t *v2= TO_REND_DATA_V2(rend_data);
-
- /* We need at least one else the call is wrong. */
- tor_assert(onion_address != NULL || desc_id != NULL);
-
- if (cookie) {
- memcpy(v2->descriptor_cookie, cookie, sizeof(v2->descriptor_cookie));
- }
- if (desc_id) {
- memcpy(v2->desc_id_fetch, desc_id, sizeof(v2->desc_id_fetch));
- }
- if (onion_address) {
- strlcpy(v2->onion_address, onion_address, sizeof(v2->onion_address));
- if (compute_desc_id(rend_data) < 0) {
- goto error;
- }
- }
-
- v2->auth_type = auth_type;
-
- return rend_data;
-
- error:
- rend_data_free(rend_data);
- return NULL;
-}
-
-/** Return the onion address from the rend data. Depending on the version,
- * the size of the address can vary but it's always NUL terminated. */
-const char *
-rend_data_get_address(const rend_data_t *rend_data)
-{
- tor_assert(rend_data);
-
- switch (rend_data->version) {
- case HS_VERSION_TWO:
- return TO_REND_DATA_V2(rend_data)->onion_address;
- default:
- /* We should always have a supported version. */
- tor_assert_unreached();
- }
-}
-
-/** Return the descriptor ID for a specific replica number from the rend
- * data. The returned data is a binary digest and depending on the version its
- * size can vary. The size of the descriptor ID is put in <b>len_out</b> if
- * non NULL. */
-const char *
-rend_data_get_desc_id(const rend_data_t *rend_data, uint8_t replica,
- size_t *len_out)
-{
- tor_assert(rend_data);
-
- switch (rend_data->version) {
- case HS_VERSION_TWO:
- tor_assert(replica < REND_NUMBER_OF_NON_CONSECUTIVE_REPLICAS);
- if (len_out) {
- *len_out = DIGEST_LEN;
- }
- return TO_REND_DATA_V2(rend_data)->descriptor_id[replica];
- default:
- /* We should always have a supported version. */
- tor_assert_unreached();
- }
-}
-
-/** Return the public key digest using the given <b>rend_data</b>. The size of
- * the digest is put in <b>len_out</b> (if set) which can differ depending on
- * the version. */
-const uint8_t *
-rend_data_get_pk_digest(const rend_data_t *rend_data, size_t *len_out)
-{
- tor_assert(rend_data);
-
- switch (rend_data->version) {
- case HS_VERSION_TWO:
- {
- const rend_data_v2_t *v2_data = TO_REND_DATA_V2(rend_data);
- if (len_out) {
- *len_out = sizeof(v2_data->rend_pk_digest);
- }
- return (const uint8_t *) v2_data->rend_pk_digest;
- }
- default:
- /* We should always have a supported version. */
- tor_assert_unreached();
- }
-}
-
/** Using the given time period number, compute the disaster shared random
* value and put it in srv_out. It MUST be at least DIGEST256_LEN bytes. */
static void
@@ -859,7 +605,7 @@ hs_get_subcredential(const ed25519_public_key_t *identity_pk,
int
hs_set_conn_addr_port(const smartlist_t *ports, edge_connection_t *conn)
{
- rend_service_port_config_t *chosen_port;
+ hs_port_config_t *chosen_port;
unsigned int warn_once = 0;
smartlist_t *matching_ports;
@@ -867,7 +613,7 @@ hs_set_conn_addr_port(const smartlist_t *ports, edge_connection_t *conn)
tor_assert(conn);
matching_ports = smartlist_new();
- SMARTLIST_FOREACH_BEGIN(ports, rend_service_port_config_t *, p) {
+ SMARTLIST_FOREACH_BEGIN(ports, hs_port_config_t *, p) {
if (TO_CONN(conn)->port != p->virtual_port) {
continue;
}
@@ -890,7 +636,6 @@ hs_set_conn_addr_port(const smartlist_t *ports, edge_connection_t *conn)
chosen_port = smartlist_choose(matching_ports);
smartlist_free(matching_ports);
if (chosen_port) {
- /* Remember, v2 doesn't use an hs_ident. */
if (conn->hs_ident) {
/* There is always a connection identifier at this point. Regardless of a
* Unix or TCP port, note the virtual port. */
@@ -912,6 +657,138 @@ hs_set_conn_addr_port(const smartlist_t *ports, edge_connection_t *conn)
return (chosen_port) ? 0 : -1;
}
+/** Return a new hs_port_config_t with its path set to
+ * <b>socket_path</b> or empty if <b>socket_path</b> is NULL */
+static hs_port_config_t *
+hs_port_config_new(const char *socket_path)
+{
+ if (!socket_path)
+ return tor_malloc_zero(sizeof(hs_port_config_t) + 1);
+
+ const size_t pathlen = strlen(socket_path) + 1;
+ hs_port_config_t *conf =
+ tor_malloc_zero(sizeof(hs_port_config_t) + pathlen);
+ memcpy(conf->unix_addr, socket_path, pathlen);
+ conf->is_unix_addr = 1;
+ return conf;
+}
+
+/** Parses a virtual-port to real-port/socket mapping separated by
+ * the provided separator and returns a new hs_port_config_t,
+ * or NULL and an optional error string on failure.
+ *
+ * The format is: VirtualPort SEP (IP|RealPort|IP:RealPort|'socket':path)?
+ *
+ * IP defaults to 127.0.0.1; RealPort defaults to VirtualPort.
+ */
+hs_port_config_t *
+hs_parse_port_config(const char *string, const char *sep,
+ char **err_msg_out)
+{
+ smartlist_t *sl;
+ int virtport;
+ int realport = 0;
+ uint16_t p;
+ tor_addr_t addr;
+ hs_port_config_t *result = NULL;
+ unsigned int is_unix_addr = 0;
+ const char *socket_path = NULL;
+ char *err_msg = NULL;
+ char *addrport = NULL;
+
+ sl = smartlist_new();
+ smartlist_split_string(sl, string, sep,
+ SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 2);
+ if (smartlist_len(sl) < 1 || BUG(smartlist_len(sl) > 2)) {
+ err_msg = tor_strdup("Bad syntax in hidden service port configuration.");
+ goto err;
+ }
+ virtport = (int)tor_parse_long(smartlist_get(sl,0), 10, 1, 65535, NULL,NULL);
+ if (!virtport) {
+ tor_asprintf(&err_msg, "Missing or invalid port %s in hidden service "
+ "port configuration", escaped(smartlist_get(sl,0)));
+
+ goto err;
+ }
+ if (smartlist_len(sl) == 1) {
+ /* No addr:port part; use default. */
+ realport = virtport;
+ tor_addr_from_ipv4h(&addr, 0x7F000001u); /* 127.0.0.1 */
+ } else {
+ int ret;
+
+ const char *addrport_element = smartlist_get(sl,1);
+ const char *rest = NULL;
+ int is_unix;
+ ret = port_cfg_line_extract_addrport(addrport_element, &addrport,
+ &is_unix, &rest);
+
+ if (ret < 0) {
+ tor_asprintf(&err_msg, "Couldn't process address <%s> from hidden "
+ "service configuration", addrport_element);
+ goto err;
+ }
+
+ if (rest && strlen(rest)) {
+ err_msg = tor_strdup("HiddenServicePort parse error: invalid port "
+ "mapping");
+ goto err;
+ }
+
+ if (is_unix) {
+ socket_path = addrport;
+ is_unix_addr = 1;
+ } else if (strchr(addrport, ':') || strchr(addrport, '.')) {
+ /* else try it as an IP:port pair if it has a : or . in it */
+ if (tor_addr_port_lookup(addrport, &addr, &p)<0) {
+ err_msg = tor_strdup("Unparseable address in hidden service port "
+ "configuration.");
+ goto err;
+ }
+ realport = p?p:virtport;
+ } else {
+ /* No addr:port, no addr -- must be port. */
+ realport = (int)tor_parse_long(addrport, 10, 1, 65535, NULL, NULL);
+ if (!realport) {
+ tor_asprintf(&err_msg, "Unparseable or out-of-range port %s in "
+ "hidden service port configuration.",
+ escaped(addrport));
+ goto err;
+ }
+ tor_addr_from_ipv4h(&addr, 0x7F000001u); /* Default to 127.0.0.1 */
+ }
+ }
+
+ /* Allow room for unix_addr */
+ result = hs_port_config_new(socket_path);
+ result->virtual_port = virtport;
+ result->is_unix_addr = is_unix_addr;
+ if (!is_unix_addr) {
+ result->real_port = realport;
+ tor_addr_copy(&result->real_addr, &addr);
+ result->unix_addr[0] = '\0';
+ }
+
+ err:
+ tor_free(addrport);
+ if (err_msg_out != NULL) {
+ *err_msg_out = err_msg;
+ } else {
+ tor_free(err_msg);
+ }
+ SMARTLIST_FOREACH(sl, char *, c, tor_free(c));
+ smartlist_free(sl);
+
+ return result;
+}
+
+/** Release all storage held in a hs_port_config_t. */
+void
+hs_port_config_free_(hs_port_config_t *p)
+{
+ tor_free(p);
+}
+
/** Using a base32 representation of a service address, parse its content into
* the key_out, checksum_out and version_out. Any out variable can be NULL in
* case the caller would want only one field. checksum_out MUST at least be 2
@@ -1140,7 +1017,7 @@ hs_service_requires_uptime_circ(const smartlist_t *ports)
{
tor_assert(ports);
- SMARTLIST_FOREACH_BEGIN(ports, rend_service_port_config_t *, p) {
+ SMARTLIST_FOREACH_BEGIN(ports, hs_port_config_t *, p) {
if (smartlist_contains_int_as_string(get_options()->LongLivedPorts,
p->virtual_port)) {
return 1;
@@ -1470,8 +1347,8 @@ hs_hsdir_requery_period(const or_options_t *options)
/** Tracks requests for fetching hidden service descriptors. It's used by
* hidden service clients, to avoid querying HSDirs that have already failed
- * giving back a descriptor. The same data structure is used to track both v2
- * and v3 HS descriptor requests.
+ * giving back a descriptor. The same data structure is used to track v3 HS
+ * descriptor requests.
*
* The string map is a key/value store that contains the last request times to
* hidden service directories for certain queries. Specifically:
@@ -1480,8 +1357,7 @@ hs_hsdir_requery_period(const or_options_t *options)
* value = time_t of last request for that hs_identity to that HSDir
*
* where 'hsdir_identity' is the identity digest of the HSDir node, and
- * 'hs_identity' is the descriptor ID of the HS in the v2 case, or the ed25519
- * blinded public key of the HS in the v3 case. */
+ * 'hs_identity' is the ed25519 blinded public key of the HS for v3. */
static strmap_t *last_hid_serv_requests_ = NULL;
/** Returns last_hid_serv_requests_, initializing it to a new strmap if
@@ -1495,10 +1371,10 @@ get_last_hid_serv_requests(void)
}
/** Look up the last request time to hidden service directory <b>hs_dir</b>
- * for descriptor request key <b>req_key_str</b> which is the descriptor ID
- * for a v2 service or the blinded key for v3. If <b>set</b> is non-zero,
- * assign the current time <b>now</b> and return that. Otherwise, return the
- * most recent request time, or 0 if no such request has been sent before. */
+ * for descriptor request key <b>req_key_str</b> which is the blinded key for
+ * v3. If <b>set</b> is non-zero, assign the current time <b>now</b> and
+ * return that. Otherwise, return the most recent request time, or 0 if no
+ * such request has been sent before. */
time_t
hs_lookup_last_hid_serv_request(routerstatus_t *hs_dir,
const char *req_key_str,
@@ -1559,9 +1435,8 @@ hs_clean_last_hid_serv_requests(time_t now)
* <b>req_key_str</b> from the history of times of requests to hidden service
* directories.
*
- * This is called from rend_client_note_connection_attempt_ended(), which
- * must be idempotent, so any future changes to this function must leave it
- * idempotent too. */
+ * This is called from purge_hid_serv_request(), which must be idempotent, so
+ * any future changes to this function must leave it idempotent too. */
void
hs_purge_hid_serv_from_last_hid_serv_requests(const char *req_key_str)
{
@@ -1581,8 +1456,7 @@ hs_purge_hid_serv_from_last_hid_serv_requests(const char *req_key_str)
* check on the strings we are about to compare. The key is variable sized
* since it's composed as follows:
* key = base32(hsdir_identity) + base32(req_key_str)
- * where 'req_key_str' is the descriptor ID of the HS in the v2 case, or
- * the ed25519 blinded public key of the HS in the v3 case. */
+ * where 'req_key_str' is the ed25519 blinded public key of the HS v3. */
if (strlen(key) < REND_DESC_ID_V2_LEN_BASE32 + strlen(req_key_str)) {
iter = strmap_iter_next(last_hid_serv_requests, iter);
continue;
@@ -1813,7 +1687,7 @@ hs_get_extend_info_from_lspecs(const smartlist_t *lspecs,
/* We do have everything for which we think we can connect successfully. */
info = extend_info_new(NULL, legacy_id,
(have_ed25519_id) ? &ed25519_pk : NULL, NULL,
- onion_key, &ap.addr, ap.port);
+ onion_key, &ap.addr, ap.port, NULL, false);
done:
return info;
}
@@ -1849,9 +1723,7 @@ hs_dec_rdv_stream_counter(origin_circuit_t *circ)
{
tor_assert(circ);
- if (circ->rend_data) {
- circ->rend_data->nr_streams--;
- } else if (circ->hs_ident) {
+ if (circ->hs_ident) {
circ->hs_ident->num_rdv_streams--;
} else {
/* Should not be called if this circuit is not for hidden service. */
@@ -1866,9 +1738,7 @@ hs_inc_rdv_stream_counter(origin_circuit_t *circ)
{
tor_assert(circ);
- if (circ->rend_data) {
- circ->rend_data->nr_streams++;
- } else if (circ->hs_ident) {
+ if (circ->hs_ident) {
circ->hs_ident->num_rdv_streams++;
} else {
/* Should not be called if this circuit is not for hidden service. */
diff --git a/src/feature/hs/hs_common.h b/src/feature/hs/hs_common.h
index 274017180a..a7a8f23a3c 100644
--- a/src/feature/hs/hs_common.h
+++ b/src/feature/hs/hs_common.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2020, The Tor Project, Inc. */
+/* Copyright (c) 2016-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -19,9 +19,6 @@ struct ed25519_keypair_t;
/* Trunnel */
#include "trunnel/ed25519_cert.h"
-/** Protocol version 2. Use this instead of hardcoding "2" in the code base,
- * this adds a clearer semantic to the value when used. */
-#define HS_VERSION_TWO 2
/** Version 3 of the protocol (prop224). */
#define HS_VERSION_THREE 3
/** Earliest version we support. */
@@ -138,7 +135,7 @@ typedef enum {
} hs_auth_key_type_t;
/** Return value when adding an ephemeral service through the ADD_ONION
- * control port command. Both v2 and v3 share these. */
+ * control port command. */
typedef enum {
RSAE_BADAUTH = -5, /**< Invalid auth_type/auth_clients */
RSAE_BADVIRTPORT = -4, /**< Invalid VIRTPORT/TARGET(s) */
@@ -150,7 +147,7 @@ typedef enum {
/** Represents the mapping from a virtual port of a rendezvous service to a
* real port on some IP. */
-typedef struct rend_service_port_config_t {
+typedef struct hs_port_config_t {
/** The incoming HS virtual port we're mapping */
uint16_t virtual_port;
/** Is this an AF_UNIX port? */
@@ -161,7 +158,7 @@ typedef struct rend_service_port_config_t {
tor_addr_t real_addr;
/** The socket path to connect to, if is_unix_addr */
char unix_addr[FLEXIBLE_ARRAY_MEMBER];
-} rend_service_port_config_t;
+} hs_port_config_t;
void hs_init(void);
void hs_free_all(void);
@@ -194,24 +191,6 @@ void hs_build_blinded_keypair(const struct ed25519_keypair_t *kp,
struct ed25519_keypair_t *kp_out);
int hs_service_requires_uptime_circ(const smartlist_t *ports);
-void rend_data_free_(rend_data_t *data);
-#define rend_data_free(data) \
- FREE_AND_NULL(rend_data_t, rend_data_free_, (data))
-rend_data_t *rend_data_dup(const rend_data_t *data);
-rend_data_t *rend_data_client_create(const char *onion_address,
- const char *desc_id,
- const char *cookie,
- rend_auth_type_t auth_type);
-rend_data_t *rend_data_service_create(const char *onion_address,
- const char *pk_digest,
- const uint8_t *cookie,
- rend_auth_type_t auth_type);
-const char *rend_data_get_address(const rend_data_t *rend_data);
-const char *rend_data_get_desc_id(const rend_data_t *rend_data,
- uint8_t replica, size_t *len_out);
-const uint8_t *rend_data_get_pk_digest(const rend_data_t *rend_data,
- size_t *len_out);
-
routerstatus_t *pick_hsdir(const char *desc_id, const char *desc_id_base32);
struct hs_subcredential_t;
@@ -260,6 +239,11 @@ void hs_purge_hid_serv_from_last_hid_serv_requests(const char *desc_id);
void hs_purge_last_hid_serv_requests(void);
int hs_set_conn_addr_port(const smartlist_t *ports, edge_connection_t *conn);
+hs_port_config_t *hs_parse_port_config(const char *string, const char *sep,
+ char **err_msg_out);
+void hs_port_config_free_(hs_port_config_t *p);
+#define hs_port_config_free(p) \
+ FREE_AND_NULL(hs_port_config_t, hs_port_config_free_, (p))
void hs_inc_rdv_stream_counter(origin_circuit_t *circ);
void hs_dec_rdv_stream_counter(origin_circuit_t *circ);
diff --git a/src/feature/hs/hs_config.c b/src/feature/hs/hs_config.c
index f8d71674de..a76893fe1a 100644
--- a/src/feature/hs/hs_config.c
+++ b/src/feature/hs/hs_config.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017-2020, The Tor Project, Inc. */
+/* Copyright (c) 2017-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -28,8 +28,6 @@
#include "feature/hs/hs_client.h"
#include "feature/hs/hs_ob.h"
#include "feature/hs/hs_service.h"
-#include "feature/rend/rendclient.h"
-#include "feature/rend/rendservice.h"
#include "lib/encoding/confline.h"
#include "lib/conf/confdecl.h"
#include "lib/confmgt/confmgt.h"
@@ -102,23 +100,6 @@ stage_services(smartlist_t *service_list)
{
tor_assert(service_list);
- /* This is v2 specific. Trigger service pruning which will make sure the
- * just configured services end up in the main global list. It should only
- * be done in non validation mode because v2 subsystem handles service
- * object differently. */
- rend_service_prune_list();
-
- /* Cleanup v2 service from the list, we don't need those object anymore
- * because we validated them all against the others and we want to stage
- * only >= v3 service. And remember, v2 has a different object type which is
- * shadow copied from an hs_service_t type. */
- SMARTLIST_FOREACH_BEGIN(service_list, hs_service_t *, s) {
- if (s->config.version == HS_VERSION_TWO) {
- SMARTLIST_DEL_CURRENT(service_list, s);
- hs_service_free(s);
- }
- } SMARTLIST_FOREACH_END(s);
-
/* This is >= v3 specific. Using the newly configured service list, stage
* them into our global state. Every object ownership is lost after. */
hs_service_stage_services(service_list);
@@ -146,8 +127,7 @@ service_is_duplicate_in_list(const smartlist_t *service_list,
/* XXX: Validate if we have any service that has the given service dir path.
* This has two problems:
*
- * a) It's O(n^2), but the same comment from the bottom of
- * rend_config_services() should apply.
+ * a) It's O(n^2)
*
* b) We only compare directory paths as strings, so we can't
* detect two distinct paths that specify the same directory
@@ -274,15 +254,6 @@ config_has_invalid_options(const config_line_t *line_,
NULL /* End marker. */
};
- const char *opts_exclude_v2[] = {
- "HiddenServiceExportCircuitID",
- "HiddenServiceEnableIntroDoSDefense",
- "HiddenServiceEnableIntroDoSRatePerSec",
- "HiddenServiceEnableIntroDoSBurstPerSec",
- "HiddenServiceOnionBalanceInstance",
- NULL /* End marker. */
- };
-
/* Defining the size explicitly allows us to take advantage of the compiler
* which warns us if we ever bump the max version but forget to grow this
* array. The plus one is because we have a version 0 :). */
@@ -291,7 +262,7 @@ config_has_invalid_options(const config_line_t *line_,
} exclude_lists[HS_VERSION_MAX + 1] = {
{ NULL }, /* v0. */
{ NULL }, /* v1. */
- { opts_exclude_v2 }, /* v2 */
+ { NULL }, /* v2. */
{ opts_exclude_v3 }, /* v3. */
};
@@ -315,16 +286,6 @@ config_has_invalid_options(const config_line_t *line_,
"version %" PRIu32 " of service in %s",
opt, service->config.version,
service->config.directory_path);
-
- if (!strcasecmp(line->key, "HiddenServiceAuthorizeClient")) {
- /* Special case this v2 option so that we can offer alternatives.
- * If more such special cases appear, it would be good to
- * generalize the exception mechanism here. */
- log_warn(LD_CONFIG, "For v3 onion service client authorization, "
- "please read the 'CLIENT AUTHORIZATION' section in the "
- "manual.");
- }
-
ret = 1;
/* Continue the loop so we can find all possible options. */
continue;
@@ -479,6 +440,12 @@ config_generic_service(const hs_opts_t *hs_opts,
/* Protocol version for the service. */
if (hs_opts->HiddenServiceVersion == -1) {
/* No value was set; stay with the default. */
+ } else if (hs_opts->HiddenServiceVersion == 2) {
+ log_warn(LD_CONFIG, "Onion services version 2 are obsolete. Please see "
+ "https://blog.torproject.org/v2-deprecation-timeline "
+ "for more details and for instructions on how to "
+ "transition to version 3.");
+ goto err;
} else if (CHECK_OOB(hs_opts, HiddenServiceVersion,
HS_VERSION_MIN, HS_VERSION_MAX)) {
goto err;
@@ -492,8 +459,8 @@ config_generic_service(const hs_opts_t *hs_opts,
portline; portline = portline->next) {
char *err_msg = NULL;
/* XXX: Can we rename this? */
- rend_service_port_config_t *portcfg =
- rend_service_parse_port_config(portline->value, " ", &err_msg);
+ hs_port_config_t *portcfg =
+ hs_parse_port_config(portline->value, " ", &err_msg);
if (!portcfg) {
if (err_msg) {
log_warn(LD_CONFIG, "%s", err_msg);
@@ -526,7 +493,7 @@ config_generic_service(const hs_opts_t *hs_opts,
/* Check if we are configured in non anonymous mode meaning every service
* becomes a single onion service. */
- if (rend_service_non_anonymous_mode_enabled(options)) {
+ if (hs_service_non_anonymous_mode_enabled(options)) {
config->is_single_onion = 1;
}
@@ -581,15 +548,19 @@ config_service(config_line_t *line, const or_options_t *options,
tor_assert(service->config.version <= HS_VERSION_MAX);
- /* Check permission on service directory that was just parsed. And this must
- * be done regardless of the service version. Do not ask for the directory
- * to be created, this is done when the keys are loaded because we could be
- * in validation mode right now. */
- if (hs_check_service_private_dir(options->User,
- service->config.directory_path,
- service->config.dir_group_readable,
- 0) < 0) {
- goto err;
+ /* If we're running with TestingTorNetwork enabled, we relax the permissions
+ * check on the hs directory. */
+ if (!options->TestingTorNetwork) {
+ /* Check permission on service directory that was just parsed. And this
+ * must be done regardless of the service version. Do not ask for the
+ * directory to be created, this is done when the keys are loaded because
+ * we could be in validation mode right now. */
+ if (hs_check_service_private_dir(options->User,
+ service->config.directory_path,
+ service->config.dir_group_readable,
+ 0) < 0) {
+ goto err;
+ }
}
/* We'll try to learn the service version here by loading the key(s) if
@@ -599,8 +570,7 @@ config_service(config_line_t *line, const or_options_t *options,
service->config.version = config_learn_service_version(service);
}
- /* We make sure that this set of options for a service are valid that is for
- * instance an option only for v2 is not used for v3. */
+ /* We make sure that this set of options for a service are valid. */
if (config_has_invalid_options(line->next, service)) {
goto err;
}
@@ -609,9 +579,6 @@ config_service(config_line_t *line, const or_options_t *options,
* start just after the service directory line so once we hit another
* directory line, the function knows that it has to stop parsing. */
switch (service->config.version) {
- case HS_VERSION_TWO:
- ret = rend_config_service(hs_opts, options, &service->config);
- break;
case HS_VERSION_THREE:
ret = config_service_v3(hs_opts, &service->config);
break;
@@ -677,6 +644,7 @@ hs_config_service_all(const or_options_t *options, int validate_only)
int rv = config_service(section, options, new_service_list);
config_free_lines(section);
if (rv < 0) {
+ config_free_lines(remaining);
goto err;
}
}
@@ -692,11 +660,6 @@ hs_config_service_all(const or_options_t *options, int validate_only)
* services. We don't need those objects anymore. */
SMARTLIST_FOREACH(new_service_list, hs_service_t *, s,
hs_service_free(s));
- /* For the v2 subsystem, the configuration function adds the service
- * object to the staging list and it is transferred in the main list
- * through the prunning process. In validation mode, we thus have to purge
- * the staging list so it's not kept in memory as valid service. */
- rend_service_free_staging_list();
}
/* Success. Note that the service list has no ownership of its content. */
@@ -721,11 +684,6 @@ hs_config_client_auth_all(const or_options_t *options, int validate_only)
{
int ret = -1;
- /* Configure v2 authorization. */
- if (rend_parse_service_authorization(options, validate_only) < 0) {
- goto done;
- }
-
/* Configure v3 authorization. */
if (hs_config_client_authorization(options, validate_only) < 0) {
goto done;
diff --git a/src/feature/hs/hs_config.h b/src/feature/hs/hs_config.h
index 48c24b1a08..b250c62c8b 100644
--- a/src/feature/hs/hs_config.h
+++ b/src/feature/hs/hs_config.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2020, The Tor Project, Inc. */
+/* Copyright (c) 2016-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/hs/hs_control.c b/src/feature/hs/hs_control.c
index 78b0735c29..8d26922a12 100644
--- a/src/feature/hs/hs_control.c
+++ b/src/feature/hs/hs_control.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017-2020, The Tor Project, Inc. */
+/* Copyright (c) 2017-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/hs/hs_control.h b/src/feature/hs/hs_control.h
index 947b0ebf1c..c7dbcf8bb5 100644
--- a/src/feature/hs/hs_control.h
+++ b/src/feature/hs/hs_control.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017-2020, The Tor Project, Inc. */
+/* Copyright (c) 2017-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/hs/hs_descriptor.c b/src/feature/hs/hs_descriptor.c
index 6e448b322e..15ad9d8efb 100644
--- a/src/feature/hs/hs_descriptor.c
+++ b/src/feature/hs/hs_descriptor.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2020, The Tor Project, Inc. */
+/* Copyright (c) 2016-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -61,15 +61,17 @@
#include "trunnel/ed25519_cert.h" /* Trunnel interface. */
#include "feature/hs/hs_descriptor.h"
#include "core/or/circuitbuild.h"
+#include "core/or/congestion_control_common.h"
+#include "core/or/protover.h"
#include "lib/crypt_ops/crypto_rand.h"
#include "lib/crypt_ops/crypto_util.h"
#include "feature/dirparse/parsecommon.h"
-#include "feature/rend/rendcache.h"
#include "feature/hs/hs_cache.h"
#include "feature/hs/hs_config.h"
#include "feature/nodelist/torcert.h" /* tor_cert_encode_ed22519() */
#include "lib/memarea/memarea.h"
#include "lib/crypt_ops/crypto_format.h"
+#include "core/or/versions.h"
#include "core/or/extend_info_st.h"
@@ -93,6 +95,7 @@
#define str_ip_legacy_key "legacy-key"
#define str_ip_legacy_key_cert "legacy-key-cert"
#define str_intro_point_start "\n" str_intro_point " "
+#define str_flow_control "flow-control"
/* Constant string value for the construction to encrypt the encrypted data
* section. */
#define str_enc_const_superencryption "hsdir-superencrypted-data"
@@ -139,6 +142,7 @@ static token_rule_t hs_desc_encrypted_v3_token_table[] = {
T1_START(str_create2_formats, R3_CREATE2_FORMATS, CONCAT_ARGS, NO_OBJ),
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),
END_OF_TABLE
};
@@ -766,6 +770,13 @@ get_inner_encrypted_layer_plaintext(const hs_descriptor_t *desc)
if (desc->encrypted_data.single_onion_service) {
smartlist_add_asprintf(lines, "%s\n", str_single_onion);
}
+
+ if (congestion_control_enabled()) {
+ /* Add flow control line into the descriptor. */
+ smartlist_add_asprintf(lines, "%s %s %u\n", str_flow_control,
+ protover_get_supported(PRT_FLOWCTRL),
+ congestion_control_sendme_inc());
+ }
}
/* Build the introduction point(s) section. */
@@ -1608,8 +1619,8 @@ decrypt_desc_layer,(const hs_descriptor_t *desc,
* put in decrypted_out which contains the superencrypted layer of the
* descriptor. Return the length of decrypted_out on success else 0 is
* returned and decrypted_out is set to NULL. */
-static size_t
-desc_decrypt_superencrypted(const hs_descriptor_t *desc, char **decrypted_out)
+MOCK_IMPL(STATIC size_t,
+desc_decrypt_superencrypted,(const hs_descriptor_t *desc,char **decrypted_out))
{
size_t superencrypted_len = 0;
char *superencrypted_plaintext = NULL;
@@ -1640,10 +1651,10 @@ desc_decrypt_superencrypted(const hs_descriptor_t *desc, char **decrypted_out)
* decrypted_out which contains the encrypted layer of the descriptor.
* Return the length of decrypted_out on success else 0 is returned and
* decrypted_out is set to NULL. */
-static size_t
-desc_decrypt_encrypted(const hs_descriptor_t *desc,
- const curve25519_secret_key_t *client_auth_sk,
- char **decrypted_out)
+MOCK_IMPL(STATIC size_t,
+desc_decrypt_encrypted,(const hs_descriptor_t *desc,
+ const curve25519_secret_key_t *client_auth_sk,
+ char **decrypted_out))
{
size_t encrypted_len = 0;
char *encrypted_plaintext = NULL;
@@ -2146,7 +2157,7 @@ desc_decode_plaintext_v3(smartlist_t *tokens,
/** Decode the version 3 superencrypted section of the given descriptor desc.
* The desc_superencrypted_out will be populated with the decoded data. */
-static hs_desc_decode_status_t
+STATIC hs_desc_decode_status_t
desc_decode_superencrypted_v3(const hs_descriptor_t *desc,
hs_desc_superencrypted_data_t *
desc_superencrypted_out)
@@ -2260,7 +2271,7 @@ desc_decode_superencrypted_v3(const hs_descriptor_t *desc,
/** Decode the version 3 encrypted section of the given descriptor desc. The
* desc_encrypted_out will be populated with the decoded data. */
-static hs_desc_decode_status_t
+STATIC hs_desc_decode_status_t
desc_decode_encrypted_v3(const hs_descriptor_t *desc,
const curve25519_secret_key_t *client_auth_sk,
hs_desc_encrypted_data_t *desc_encrypted_out)
@@ -2336,6 +2347,23 @@ desc_decode_encrypted_v3(const hs_descriptor_t *desc,
desc_encrypted_out->single_onion_service = 1;
}
+ /* Get flow control if any. */
+ tok = find_opt_by_keyword(tokens, R3_FLOW_CONTROL);
+ if (tok) {
+ int ok;
+
+ tor_asprintf(&desc_encrypted_out->flow_control_pv, "FlowCtrl=%s",
+ tok->args[0]);
+ uint8_t sendme_inc =
+ (uint8_t) tor_parse_uint64(tok->args[1], 10, 0, UINT8_MAX, &ok, NULL);
+ if (!ok || !congestion_control_validate_sendme_increment(sendme_inc)) {
+ log_warn(LD_REND, "Service descriptor flow control sendme "
+ "value is invalid");
+ goto err;
+ }
+ desc_encrypted_out->sendme_inc = sendme_inc;
+ }
+
/* 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();
@@ -2746,6 +2774,7 @@ hs_desc_encrypted_data_free_contents(hs_desc_encrypted_data_t *desc)
hs_desc_intro_point_free(ip));
smartlist_free(desc->intro_points);
}
+ tor_free(desc->flow_control_pv);
memwipe(desc, 0, sizeof(*desc));
}
@@ -2958,3 +2987,16 @@ hs_descriptor_clear_intro_points(hs_descriptor_t *desc)
smartlist_clear(ips);
}
}
+
+/** Return true iff we support the given descriptor congestion control
+ * parameters. */
+bool
+hs_desc_supports_congestion_control(const hs_descriptor_t *desc)
+{
+ tor_assert(desc);
+
+ /* Validate that we support the protocol version in the descriptor. */
+ return desc->encrypted_data.flow_control_pv &&
+ protocol_list_supports_protocol(desc->encrypted_data.flow_control_pv,
+ PRT_FLOWCTRL, PROTOVER_FLOWCTRL_CC);
+}
diff --git a/src/feature/hs/hs_descriptor.h b/src/feature/hs/hs_descriptor.h
index 08daa904b6..8f42b2138b 100644
--- a/src/feature/hs/hs_descriptor.h
+++ b/src/feature/hs/hs_descriptor.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2020, The Tor Project, Inc. */
+/* Copyright (c) 2016-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -167,6 +167,10 @@ typedef struct hs_desc_encrypted_data_t {
/** Is this descriptor a single onion service? */
unsigned int single_onion_service : 1;
+ /** Flow control protocol version line. */
+ char *flow_control_pv;
+ uint8_t sendme_inc;
+
/** A list of intro points. Contains hs_desc_intro_point_t objects. */
smartlist_t *intro_points;
} hs_desc_encrypted_data_t;
@@ -315,6 +319,8 @@ void hs_desc_superencrypted_data_free_contents(
hs_desc_superencrypted_data_t *desc);
void hs_desc_encrypted_data_free_contents(hs_desc_encrypted_data_t *desc);
+bool hs_desc_supports_congestion_control(const hs_descriptor_t *desc);
+
#ifdef HS_DESCRIPTOR_PRIVATE
/* Encoding. */
@@ -339,6 +345,25 @@ MOCK_DECL(STATIC size_t, decrypt_desc_layer,(const hs_descriptor_t *desc,
bool is_superencrypted_layer,
char **decrypted_out));
+STATIC hs_desc_decode_status_t desc_decode_encrypted_v3(
+ const hs_descriptor_t *desc,
+ const curve25519_secret_key_t *client_auth_sk,
+ hs_desc_encrypted_data_t *desc_encrypted_out);
+
+STATIC hs_desc_decode_status_t
+desc_decode_superencrypted_v3(const hs_descriptor_t *desc,
+ hs_desc_superencrypted_data_t *
+ desc_superencrypted_out);
+
+MOCK_DECL(STATIC size_t, desc_decrypt_encrypted,(
+ const hs_descriptor_t *desc,
+ const curve25519_secret_key_t *client_auth_sk,
+ char **decrypted_out));
+
+MOCK_DECL(STATIC size_t, desc_decrypt_superencrypted,(
+ const hs_descriptor_t *desc,
+ char **decrypted_out));
+
#endif /* defined(HS_DESCRIPTOR_PRIVATE) */
#endif /* !defined(TOR_HS_DESCRIPTOR_H) */
diff --git a/src/feature/hs/hs_dos.c b/src/feature/hs/hs_dos.c
index 04c2bfbb89..6323dbeeac 100644
--- a/src/feature/hs/hs_dos.c
+++ b/src/feature/hs/hs_dos.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2019-2020, The Tor Project, Inc. */
+/* Copyright (c) 2019-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/hs/hs_dos.h b/src/feature/hs/hs_dos.h
index 8e36ece204..c4feb699f9 100644
--- a/src/feature/hs/hs_dos.h
+++ b/src/feature/hs/hs_dos.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2019-2020, The Tor Project, Inc. */
+/* Copyright (c) 2019-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/hs/hs_ident.c b/src/feature/hs/hs_ident.c
index 53360f6e9d..7e99f033ea 100644
--- a/src/feature/hs/hs_ident.c
+++ b/src/feature/hs/hs_ident.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017-2020, The Tor Project, Inc. */
+/* Copyright (c) 2017-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/hs/hs_ident.h b/src/feature/hs/hs_ident.h
index 0a71602852..cb1249cbdc 100644
--- a/src/feature/hs/hs_ident.h
+++ b/src/feature/hs/hs_ident.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017-2020, The Tor Project, Inc. */
+/* Copyright (c) 2017-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/hs/hs_intropoint.c b/src/feature/hs/hs_intropoint.c
index fa6b54b18a..0a656b78dd 100644
--- a/src/feature/hs/hs_intropoint.c
+++ b/src/feature/hs/hs_intropoint.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2020, The Tor Project, Inc. */
+/* Copyright (c) 2016-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -20,7 +20,7 @@
/* Trunnel */
#include "trunnel/ed25519_cert.h"
-#include "trunnel/hs/cell_common.h"
+#include "trunnel/extension.h"
#include "trunnel/hs/cell_establish_intro.h"
#include "trunnel/hs/cell_introduce1.h"
@@ -155,14 +155,14 @@ hs_intro_send_intro_established_cell,(or_circuit_t *circ))
uint8_t *encoded_cell = NULL;
ssize_t encoded_len, result_len;
trn_cell_intro_established_t *cell;
- trn_cell_extension_t *ext;
+ trn_extension_t *ext;
tor_assert(circ);
/* Build the cell payload. */
cell = trn_cell_intro_established_new();
- ext = trn_cell_extension_new();
- trn_cell_extension_set_num(ext, 0);
+ ext = trn_extension_new();
+ trn_extension_set_num(ext, 0);
trn_cell_intro_established_set_extensions(cell, ext);
/* Encode the cell to binary format. */
encoded_len = trn_cell_intro_established_encoded_len(cell);
@@ -249,7 +249,7 @@ cell_dos_extension_parameters_are_valid(uint64_t intro2_rate_per_sec,
* values, the DoS defenses is disabled on the circuit. */
static void
handle_establish_intro_cell_dos_extension(
- const trn_cell_extension_field_t *field,
+ const trn_extension_field_t *field,
or_circuit_t *circ)
{
ssize_t ret;
@@ -260,8 +260,8 @@ handle_establish_intro_cell_dos_extension(
tor_assert(circ);
ret = trn_cell_extension_dos_parse(&dos,
- trn_cell_extension_field_getconstarray_field(field),
- trn_cell_extension_field_getlen_field(field));
+ trn_extension_field_getconstarray_field(field),
+ trn_extension_field_getlen_field(field));
if (ret < 0) {
goto end;
}
@@ -332,7 +332,7 @@ handle_establish_intro_cell_extensions(
const trn_cell_establish_intro_t *parsed_cell,
or_circuit_t *circ)
{
- const trn_cell_extension_t *extensions;
+ const trn_extension_t *extensions;
tor_assert(parsed_cell);
tor_assert(circ);
@@ -343,15 +343,15 @@ handle_establish_intro_cell_extensions(
}
/* Go over all extensions. */
- for (size_t idx = 0; idx < trn_cell_extension_get_num(extensions); idx++) {
- const trn_cell_extension_field_t *field =
- trn_cell_extension_getconst_fields(extensions, idx);
+ for (size_t idx = 0; idx < trn_extension_get_num(extensions); idx++) {
+ const trn_extension_field_t *field =
+ trn_extension_getconst_fields(extensions, idx);
if (BUG(field == NULL)) {
/* The number of extensions should match the number of fields. */
break;
}
- switch (trn_cell_extension_field_get_field_type(field)) {
+ switch (trn_extension_field_get_field_type(field)) {
case TRUNNEL_CELL_EXTENSION_TYPE_DOS:
/* After this, the circuit should be set for DoS defenses. */
handle_establish_intro_cell_dos_extension(field, circ);
@@ -494,8 +494,8 @@ hs_intro_circuit_is_suitable_for_establish_intro(const or_circuit_t *circ)
return circuit_is_suitable_intro_point(circ, "ESTABLISH_INTRO");
}
-/** We just received an ESTABLISH_INTRO cell in <b>circ</b>. Figure out of it's
- * a legacy or a next gen cell, and pass it to the appropriate handler. */
+/** We just received an ESTABLISH_INTRO cell in <b>circ</b>. Pass it to the
+ * appropriate handler. */
int
hs_intro_received_establish_intro(or_circuit_t *circ, const uint8_t *request,
size_t request_len)
@@ -514,7 +514,8 @@ hs_intro_received_establish_intro(or_circuit_t *circ, const uint8_t *request,
switch (first_byte) {
case TRUNNEL_HS_INTRO_AUTH_KEY_TYPE_LEGACY0:
case TRUNNEL_HS_INTRO_AUTH_KEY_TYPE_LEGACY1:
- /* Don't accept version 2 introduction anymore. */
+ /* Likely version 2 onion service which is now obsolete. Avoid a
+ * protocol warning considering they still exists on the network. */
goto err;
case TRUNNEL_HS_INTRO_AUTH_KEY_TYPE_ED25519:
return handle_establish_intro(circ, request, request_len);
@@ -540,7 +541,7 @@ send_introduce_ack_cell(or_circuit_t *circ, uint16_t status)
uint8_t *encoded_cell = NULL;
ssize_t encoded_len, result_len;
trn_cell_introduce_ack_t *cell;
- trn_cell_extension_t *ext;
+ trn_extension_t *ext;
tor_assert(circ);
@@ -549,8 +550,8 @@ send_introduce_ack_cell(or_circuit_t *circ, uint16_t status)
cell = trn_cell_introduce_ack_new();
ret = trn_cell_introduce_ack_set_status(cell, status);
/* We have no cell extensions in an INTRODUCE_ACK cell. */
- ext = trn_cell_extension_new();
- trn_cell_extension_set_num(ext, 0);
+ ext = trn_extension_new();
+ trn_extension_set_num(ext, 0);
trn_cell_introduce_ack_set_extensions(cell, ext);
/* A wrong status is a very bad code flow error as this value is controlled
* by the code in this file and not an external input. This means we use a
@@ -718,23 +719,6 @@ handle_introduce1(or_circuit_t *client_circ, const uint8_t *request,
return ret;
}
-/** Identify if the encoded cell we just received is a legacy one or not. The
- * <b>request</b> should be at least DIGEST_LEN bytes long. */
-STATIC int
-introduce1_cell_is_legacy(const uint8_t *request)
-{
- tor_assert(request);
-
- /* If the first 20 bytes of the cell (DIGEST_LEN) are NOT zeroes, it
- * indicates a legacy cell (v2). */
- if (!fast_mem_is_zero((const char *) request, DIGEST_LEN)) {
- /* Legacy cell. */
- return 1;
- }
- /* Not a legacy cell. */
- return 0;
-}
-
/** Return true iff the circuit <b>circ</b> is suitable for receiving an
* INTRODUCE1 cell. */
STATIC int
@@ -773,13 +757,10 @@ int
hs_intro_received_introduce1(or_circuit_t *circ, const uint8_t *request,
size_t request_len)
{
- int ret;
-
tor_assert(circ);
tor_assert(request);
- /* A cell that can't hold a DIGEST_LEN is invalid as we need to check if
- * it's a legacy cell or not using the first DIGEST_LEN bytes. */
+ /* A cell that can't hold a DIGEST_LEN is invalid. */
if (request_len < DIGEST_LEN) {
log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "Invalid INTRODUCE1 cell length.");
goto err;
@@ -795,15 +776,8 @@ hs_intro_received_introduce1(or_circuit_t *circ, const uint8_t *request,
* DoS mitigation since one circuit with one client can hammer a service. */
circ->already_received_introduce1 = 1;
- /* We are sure here to have at least DIGEST_LEN bytes. */
- if (introduce1_cell_is_legacy(request)) {
- /* Handle a legacy cell. */
- ret = rend_mid_introduce_legacy(circ, request, request_len);
- } else {
- /* Handle a non legacy cell. */
- ret = handle_introduce1(circ, request, request_len);
- }
- return ret;
+ /* Handle the cell. */
+ return handle_introduce1(circ, request, request_len);
err:
circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_TORPROTOCOL);
diff --git a/src/feature/hs/hs_intropoint.h b/src/feature/hs/hs_intropoint.h
index 8b2b9892b3..ae920ee12d 100644
--- a/src/feature/hs/hs_intropoint.h
+++ b/src/feature/hs/hs_intropoint.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2020, The Tor Project, Inc. */
+/* Copyright (c) 2016-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -52,7 +52,6 @@ STATIC void
get_auth_key_from_cell(ed25519_public_key_t *auth_key_out,
unsigned int cell_type, const void *cell);
-STATIC int introduce1_cell_is_legacy(const uint8_t *request);
STATIC int handle_introduce1(or_circuit_t *client_circ,
const uint8_t *request, size_t request_len);
STATIC int validate_introduce1_parsed_cell(const trn_cell_introduce1_t *cell);
diff --git a/src/feature/hs/hs_metrics.c b/src/feature/hs/hs_metrics.c
index 25e2e62111..e80d98c2dd 100644
--- a/src/feature/hs/hs_metrics.c
+++ b/src/feature/hs/hs_metrics.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2020, The Tor Project, Inc. */
+/* Copyright (c) 2020-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -29,22 +29,6 @@ port_to_str(const uint16_t port)
return buf;
}
-/** Return a static buffer pointer that contains a formatted label on the form
- * of key=value.
- *
- * NOTE: Important, label values MUST NOT contain double quotes else, in the
- * case of Prometheus, it will fail with a malformed line because we force the
- * label value to be enclosed in double quotes.
- *
- * Subsequent call to this function invalidates the previous buffer. */
-static const char *
-format_label(const char *key, const char *value)
-{
- static char buf[128];
- tor_snprintf(buf, sizeof(buf), "%s=\"%s\"", key, value);
- return buf;
-}
-
/** Initialize a metrics store for the given service.
*
* Essentially, this goes over the base_metrics array and adds them all to the
@@ -62,23 +46,23 @@ init_store(hs_service_t *service)
/* 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 rend_service_port_config_t *, p) {
+ 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,
- format_label("onion", service->onion_address));
+ metrics_format_label("onion", service->onion_address));
metrics_store_entry_add_label(entry,
- format_label("port", port_to_str(p->virtual_port)));
+ metrics_format_label("port", port_to_str(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,
- format_label("onion", service->onion_address));
+ metrics_format_label("onion", service->onion_address));
}
}
}
@@ -107,7 +91,7 @@ hs_metrics_update_by_service(const hs_metrics_key_t key,
SMARTLIST_FOREACH_BEGIN(entries, metrics_store_entry_t *, entry) {
if (port == 0 ||
metrics_store_entry_has_label(entry,
- format_label("port", port_to_str(port)))) {
+ metrics_format_label("port", port_to_str(port)))) {
metrics_store_entry_update(entry, n);
break;
}
diff --git a/src/feature/hs/hs_metrics.h b/src/feature/hs/hs_metrics.h
index 506831b3fd..6af3a7e7f0 100644
--- a/src/feature/hs/hs_metrics.h
+++ b/src/feature/hs/hs_metrics.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2020, The Tor Project, Inc. */
+/* Copyright (c) 2020-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/hs/hs_metrics_entry.c b/src/feature/hs/hs_metrics_entry.c
index 7eb78db5ac..46d2d88aca 100644
--- a/src/feature/hs/hs_metrics_entry.c
+++ b/src/feature/hs/hs_metrics_entry.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2020, The Tor Project, Inc. */
+/* Copyright (c) 2020-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/hs/hs_metrics_entry.h b/src/feature/hs/hs_metrics_entry.h
index f68c1ab8e9..b9786ac6f7 100644
--- a/src/feature/hs/hs_metrics_entry.h
+++ b/src/feature/hs/hs_metrics_entry.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2020, The Tor Project, Inc. */
+/* Copyright (c) 2020-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -46,6 +46,6 @@ typedef struct hs_metrics_entry_t {
extern const hs_metrics_entry_t base_metrics[];
extern const size_t base_metrics_size;
-#endif /* HS_METRICS_ENTRY_PRIVATE */
+#endif /* defined(HS_METRICS_ENTRY_PRIVATE) */
#endif /* !defined(TOR_FEATURE_HS_METRICS_ENTRY_H) */
diff --git a/src/feature/hs/hs_ob.c b/src/feature/hs/hs_ob.c
index 1b8ab121a0..f0e615d6cc 100644
--- a/src/feature/hs/hs_ob.c
+++ b/src/feature/hs/hs_ob.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017-2020, The Tor Project, Inc. */
+/* Copyright (c) 2017-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/hs/hs_ob.h b/src/feature/hs/hs_ob.h
index d6e6e73a84..6586ae8d4e 100644
--- a/src/feature/hs/hs_ob.h
+++ b/src/feature/hs/hs_ob.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2020, The Tor Project, Inc. */
+/* Copyright (c) 2020-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/hs/hs_options.inc b/src/feature/hs/hs_options.inc
index 1a1444fd05..d3ca688b46 100644
--- a/src/feature/hs/hs_options.inc
+++ b/src/feature/hs/hs_options.inc
@@ -22,7 +22,6 @@ CONF_VAR(HiddenServiceDirGroupReadable, BOOL, 0, "0")
CONF_VAR(HiddenServicePort, LINELIST, 0, NULL)
// "-1" means "auto" here.
CONF_VAR(HiddenServiceVersion, INT, 0, "-1")
-CONF_VAR(HiddenServiceAuthorizeClient, STRING, 0, NULL)
CONF_VAR(HiddenServiceAllowUnknownPorts, BOOL, 0, "0")
CONF_VAR(HiddenServiceMaxStreams, POSINT, 0, "0")
CONF_VAR(HiddenServiceMaxStreamsCloseCircuit, BOOL, 0, "0")
diff --git a/src/feature/hs/hs_opts_st.h b/src/feature/hs/hs_opts_st.h
index 279f0d6da6..47a4acc21f 100644
--- a/src/feature/hs/hs_opts_st.h
+++ b/src/feature/hs/hs_opts_st.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/hs/hs_service.c b/src/feature/hs/hs_service.c
index 908ac02044..1caa5ab64a 100644
--- a/src/feature/hs/hs_service.c
+++ b/src/feature/hs/hs_service.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2020, The Tor Project, Inc. */
+/* Copyright (c) 2016-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -16,6 +16,7 @@
#include "core/or/circuitbuild.h"
#include "core/or/circuitlist.h"
#include "core/or/circuituse.h"
+#include "core/or/congestion_control_common.h"
#include "core/or/extendinfo.h"
#include "core/or/relay.h"
#include "feature/client/circpathbias.h"
@@ -29,7 +30,6 @@
#include "feature/nodelist/nickname.h"
#include "feature/nodelist/node_select.h"
#include "feature/nodelist/nodelist.h"
-#include "feature/rend/rendservice.h"
#include "lib/crypt_ops/crypto_ope.h"
#include "lib/crypt_ops/crypto_rand.h"
#include "lib/crypt_ops/crypto_util.h"
@@ -60,7 +60,6 @@
/* Trunnel */
#include "trunnel/ed25519_cert.h"
-#include "trunnel/hs/cell_common.h"
#include "trunnel/hs/cell_establish_intro.h"
#ifdef HAVE_SYS_STAT_H
@@ -161,6 +160,15 @@ HT_GENERATE2(hs_service_ht, hs_service_t, hs_service_node,
hs_service_ht_hash, hs_service_ht_eq,
0.6, tor_reallocarray, tor_free_);
+/** Return true iff the given service has client authorization configured that
+ * is the client list is non empty. */
+static inline bool
+is_client_auth_enabled(const hs_service_t *service)
+{
+ return (service->config.clients != NULL &&
+ smartlist_len(service->config.clients) > 0);
+}
+
/** 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
@@ -266,8 +274,8 @@ service_clear_config(hs_service_config_t *config)
}
tor_free(config->directory_path);
if (config->ports) {
- SMARTLIST_FOREACH(config->ports, rend_service_port_config_t *, p,
- rend_service_port_config_free(p););
+ SMARTLIST_FOREACH(config->ports, hs_port_config_t *, p,
+ hs_port_config_free(p););
smartlist_free(config->ports);
}
if (config->clients) {
@@ -706,7 +714,7 @@ get_extend_info_from_intro_point(const hs_service_intro_point_t *ip,
/* In the case of a direct connection (single onion service), it is possible
* our firewall policy won't allow it so this can return a NULL value. */
- info = extend_info_from_node(node, direct_conn);
+ info = extend_info_from_node(node, direct_conn, false);
end:
return info;
@@ -1118,6 +1126,43 @@ client_filename_is_valid(const char *filename)
return ret;
}
+/** Parse an base32-encoded authorized client from a string.
+ *
+ * Return the key on success, return NULL, otherwise. */
+hs_service_authorized_client_t *
+parse_authorized_client_key(const char *key_str, int severity)
+{
+ hs_service_authorized_client_t *client = NULL;
+
+ /* We expect a specific length of the base64 encoded key so make sure we
+ * have that so we don't successfully decode a value with a different length
+ * and end up in trouble when copying the decoded key into a fixed length
+ * buffer. */
+ if (strlen(key_str) != BASE32_NOPAD_LEN(CURVE25519_PUBKEY_LEN)) {
+ log_fn(severity, LD_REND, "Client authorization encoded base32 public key "
+ "length is invalid: %s", key_str);
+ goto err;
+ }
+
+ client = tor_malloc_zero(sizeof(hs_service_authorized_client_t));
+ if (base32_decode((char *) client->client_pk.public_key,
+ sizeof(client->client_pk.public_key),
+ key_str, strlen(key_str)) !=
+ sizeof(client->client_pk.public_key)) {
+ log_fn(severity, LD_REND, "Client authorization public key cannot be "
+ "decoded: %s", key_str);
+ goto err;
+ }
+
+ return client;
+
+ err:
+ if (client != NULL) {
+ service_authorized_client_free(client);
+ }
+ return NULL;
+}
+
/** Parse an authorized client from a string. The format of a client string
* looks like (see rend-spec-v3.txt):
*
@@ -1164,23 +1209,7 @@ parse_authorized_client(const char *client_key_str)
goto err;
}
- /* We expect a specific length of the base32 encoded key so make sure we
- * have that so we don't successfully decode a value with a different length
- * and end up in trouble when copying the decoded key into a fixed length
- * buffer. */
- if (strlen(pubkey_b32) != BASE32_NOPAD_LEN(CURVE25519_PUBKEY_LEN)) {
- log_warn(LD_REND, "Client authorization encoded base32 public key "
- "length is invalid: %s", pubkey_b32);
- goto err;
- }
-
- client = tor_malloc_zero(sizeof(hs_service_authorized_client_t));
- if (base32_decode((char *) client->client_pk.public_key,
- sizeof(client->client_pk.public_key),
- pubkey_b32, strlen(pubkey_b32)) !=
- sizeof(client->client_pk.public_key)) {
- log_warn(LD_REND, "Client authorization public key cannot be decoded: %s",
- pubkey_b32);
+ if ((client = parse_authorized_client_key(pubkey_b32, LOG_WARN)) == NULL) {
goto err;
}
@@ -1282,11 +1311,6 @@ load_client_keys(hs_service_t *service)
} SMARTLIST_FOREACH_END(filename);
- /* If the number of clients is greater than zero, set the flag to be true. */
- if (smartlist_len(config->clients) > 0) {
- config->is_client_auth_enabled = 1;
- }
-
/* Success. */
ret = 0;
end:
@@ -1304,7 +1328,7 @@ load_client_keys(hs_service_t *service)
}
/** Release all storage held in <b>client</b>. */
-STATIC void
+void
service_authorized_client_free_(hs_service_authorized_client_t *client)
{
if (!client) {
@@ -1796,7 +1820,7 @@ build_service_desc_superencrypted(const hs_service_t *service,
/* We do not need to build the desc authorized client if the client
* authorization is disabled */
- if (config->is_client_auth_enabled) {
+ if (is_client_auth_enabled(service)) {
SMARTLIST_FOREACH_BEGIN(config->clients,
hs_service_authorized_client_t *, client) {
hs_desc_authorized_client_t *desc_client;
@@ -2647,8 +2671,6 @@ run_housekeeping_event(time_t now)
static void
run_build_descriptor_event(time_t now)
{
- /* For v2 services, this step happens in the upload event. */
-
/* Run v3+ events. */
/* We start by rotating the descriptors only if needed. */
rotate_all_descriptors(now);
@@ -2821,11 +2843,6 @@ run_build_circuit_event(time_t now)
return;
}
- /* Run v2 check. */
- if (rend_num_services() > 0) {
- rend_consider_services_intro_points(now);
- }
-
/* Run v3+ check. */
FOR_EACH_SERVICE_BEGIN(service) {
/* For introduction circuit, we need to make sure we don't stress too much
@@ -3261,13 +3278,6 @@ refresh_service_descriptor(const hs_service_t *service,
STATIC void
run_upload_descriptor_event(time_t now)
{
- /* v2 services use the same function for descriptor creation and upload so
- * we do everything here because the intro circuits were checked before. */
- if (rend_num_services() > 0) {
- rend_consider_services_upload(now);
- rend_consider_descriptor_republication();
- }
-
/* Run v3+ check. */
FOR_EACH_SERVICE_BEGIN(service) {
FOR_EACH_DESCRIPTOR_BEGIN(service, desc) {
@@ -3582,7 +3592,7 @@ service_encode_descriptor(const hs_service_t *service,
/* If the client authorization is enabled, send the descriptor cookie to
* hs_desc_encode_descriptor. Otherwise, send NULL */
- if (service->config.is_client_auth_enabled) {
+ if (is_client_auth_enabled(service)) {
descriptor_cookie = desc->descriptor_cookie;
}
@@ -3596,6 +3606,54 @@ service_encode_descriptor(const hs_service_t *service,
/* Public API */
/* ========== */
+/* Are HiddenServiceSingleHopMode and HiddenServiceNonAnonymousMode consistent?
+ */
+static int
+hs_service_non_anonymous_mode_consistent(const or_options_t *options)
+{
+ /* !! is used to make these options boolean */
+ return (!! options->HiddenServiceSingleHopMode ==
+ !! options->HiddenServiceNonAnonymousMode);
+}
+
+/* Do the options allow onion services to make direct (non-anonymous)
+ * connections to introduction or rendezvous points?
+ * Must only be called after options_validate_single_onion() has successfully
+ * checked onion service option consistency.
+ * Returns true if tor is in HiddenServiceSingleHopMode. */
+int
+hs_service_allow_non_anonymous_connection(const or_options_t *options)
+{
+ tor_assert(hs_service_non_anonymous_mode_consistent(options));
+ return options->HiddenServiceSingleHopMode ? 1 : 0;
+}
+
+/* Do the options allow us to reveal the exact startup time of the onion
+ * service?
+ * Single Onion Services prioritise availability over hiding their
+ * startup time, as their IP address is publicly discoverable anyway.
+ * Must only be called after options_validate_single_onion() has successfully
+ * checked onion service option consistency.
+ * Returns true if tor is in non-anonymous hidden service mode. */
+int
+hs_service_reveal_startup_time(const or_options_t *options)
+{
+ tor_assert(hs_service_non_anonymous_mode_consistent(options));
+ return hs_service_non_anonymous_mode_enabled(options);
+}
+
+/* Is non-anonymous mode enabled using the HiddenServiceNonAnonymousMode
+ * config option?
+ * Must only be called after options_validate_single_onion() has successfully
+ * checked onion service option consistency.
+ */
+int
+hs_service_non_anonymous_mode_enabled(const or_options_t *options)
+{
+ tor_assert(hs_service_non_anonymous_mode_consistent(options));
+ return options->HiddenServiceNonAnonymousMode ? 1 : 0;
+}
+
/** Called when a circuit was just cleaned up. This is done right before the
* circuit is marked for close. */
void
@@ -3617,12 +3675,15 @@ hs_service_circuit_cleanup_on_close(const circuit_t *circ)
hs_metrics_close_established_rdv(
&CONST_TO_ORIGIN_CIRCUIT(circ)->hs_ident->identity_pk);
break;
+ case CIRCUIT_PURPOSE_S_CONNECT_REND:
+ hs_circ_retry_service_rendezvous_point(CONST_TO_ORIGIN_CIRCUIT(circ));
+ break;
default:
break;
}
}
-/** This is called every time the service map (v2 or v3) changes that is if an
+/** This is called every time the service map changes that is if an
* element is added or removed. */
void
hs_service_map_has_changed(void)
@@ -3633,6 +3694,34 @@ hs_service_map_has_changed(void)
rescan_periodic_events(get_options());
}
+/** Called when a new consensus has arrived and has been set globally. The new
+ * consensus is pointed by ns. */
+void
+hs_service_new_consensus_params(const networkstatus_t *ns)
+{
+ tor_assert(ns);
+
+ /* This value is the new value from the consensus. */
+ uint8_t current_sendme_inc = congestion_control_sendme_inc();
+
+ if (!hs_service_map)
+ return;
+
+ /* Check each service and look if their descriptor contains a different
+ * sendme increment. If so, nuke all intro points by forcing an expiration
+ * which will lead to rebuild and reupload with the new value. */
+ FOR_EACH_SERVICE_BEGIN(service) {
+ FOR_EACH_DESCRIPTOR_BEGIN(service, desc) {
+ if (desc->desc &&
+ desc->desc->encrypted_data.sendme_inc != current_sendme_inc) {
+ /* Passing the maximum time_t will force expiration of all intro points
+ * and thus will lead to a rebuild of the descriptor. */
+ cleanup_intro_points(service, LONG_MAX);
+ }
+ } FOR_EACH_DESCRIPTOR_END;
+ } FOR_EACH_SERVICE_END;
+}
+
/** Upload an encoded descriptor in encoded_desc of the given version. This
* descriptor is for the service identity_pk and blinded_pk used to setup the
* directory connection identifier. It is uploaded to the directory hsdir_rs
@@ -3684,15 +3773,17 @@ hs_service_upload_desc_to_dir(const char *encoded_desc,
/** Add the ephemeral service using the secret key sk and ports. Both max
* streams parameter will be set in the newly created service.
*
- * Ownership of sk and ports is passed to this routine. Regardless of
- * success/failure, callers should not touch these values after calling this
- * routine, and may assume that correct cleanup has been done on failure.
+ * Ownership of sk, ports, and auth_clients_v3 is passed to this routine.
+ * Regardless of success/failure, callers should not touch these values
+ * after calling this routine, and may assume that correct cleanup has
+ * been done on failure.
*
* Return an appropriate hs_service_add_ephemeral_status_t. */
hs_service_add_ephemeral_status_t
hs_service_add_ephemeral(ed25519_secret_key_t *sk, smartlist_t *ports,
int max_streams_per_rdv_circuit,
- int max_streams_close_circuit, char **address_out)
+ int max_streams_close_circuit,
+ smartlist_t *auth_clients_v3, char **address_out)
{
hs_service_add_ephemeral_status_t ret;
hs_service_t *service = NULL;
@@ -3736,6 +3827,16 @@ hs_service_add_ephemeral(ed25519_secret_key_t *sk, smartlist_t *ports,
goto err;
}
+ if (auth_clients_v3) {
+ service->config.clients = smartlist_new();
+ SMARTLIST_FOREACH(auth_clients_v3, hs_service_authorized_client_t *, c, {
+ if (c != NULL) {
+ smartlist_add(service->config.clients, c);
+ }
+ });
+ smartlist_free(auth_clients_v3);
+ }
+
/* Build the onion address for logging purposes but also the control port
* uses it for the HS_DESC event. */
hs_build_address(&service->keys.identity_pk,
@@ -3961,9 +4062,6 @@ hs_service_lists_fnames_for_sandbox(smartlist_t *file_list,
tor_assert(file_list);
tor_assert(dir_list);
- /* Add files and dirs for legacy services. */
- rend_services_add_filenames_to_lists(file_list, dir_list);
-
/* Add files and dirs for v3+. */
FOR_EACH_SERVICE_BEGIN(service) {
/* Skip ephemeral service, they don't touch the disk. */
@@ -4014,10 +4112,7 @@ hs_service_receive_introduce2(origin_circuit_t *circ, const uint8_t *payload,
if (circ->hs_ident) {
ret = service_handle_introduce2(circ, payload, payload_len);
- hs_stats_note_introduce2_cell(1);
- } else {
- ret = rend_service_receive_introduction(circ, payload, payload_len);
- hs_stats_note_introduce2_cell(0);
+ hs_stats_note_introduce2_cell();
}
done:
@@ -4044,12 +4139,8 @@ hs_service_receive_intro_established(origin_circuit_t *circ,
goto err;
}
- /* Handle both version. v2 uses rend_data and v3 uses the hs circuit
- * identifier hs_ident. Can't be both. */
if (circ->hs_ident) {
ret = service_handle_intro_established(circ, payload, payload_len);
- } else {
- ret = rend_service_intro_established(circ, payload, payload_len);
}
if (ret < 0) {
@@ -4068,21 +4159,15 @@ hs_service_circuit_has_opened(origin_circuit_t *circ)
{
tor_assert(circ);
- /* Handle both version. v2 uses rend_data and v3 uses the hs circuit
- * identifier hs_ident. Can't be both. */
switch (TO_CIRCUIT(circ)->purpose) {
case CIRCUIT_PURPOSE_S_ESTABLISH_INTRO:
if (circ->hs_ident) {
service_intro_circ_has_opened(circ);
- } else {
- rend_service_intro_has_opened(circ);
}
break;
case CIRCUIT_PURPOSE_S_CONNECT_REND:
if (circ->hs_ident) {
service_rendezvous_circ_has_opened(circ);
- } else {
- rend_service_rendezvous_has_opened(circ);
}
break;
default:
@@ -4110,11 +4195,6 @@ hs_service_get_version_from_key(const hs_service_t *service)
version = HS_VERSION_THREE;
goto end;
}
- /* Version 2 check. */
- if (rend_service_key_on_disk(directory_path)) {
- version = HS_VERSION_TWO;
- goto end;
- }
end:
return version;
@@ -4125,13 +4205,6 @@ hs_service_get_version_from_key(const hs_service_t *service)
int
hs_service_load_all_keys(void)
{
- /* Load v2 service keys if we have v2. */
- if (rend_num_services() != 0) {
- if (rend_service_load_all_keys(NULL) < 0) {
- goto err;
- }
- }
-
/* Load or/and generate them for v3+. */
SMARTLIST_FOREACH_BEGIN(hs_service_staging_list, hs_service_t *, service) {
/* Ignore ephemeral service, they already have their keys set. */
@@ -4331,9 +4404,6 @@ hs_service_init(void)
tor_assert(!hs_service_map);
tor_assert(!hs_service_staging_list);
- /* v2 specific. */
- rend_service_init();
-
hs_service_map = tor_malloc_zero(sizeof(struct hs_service_ht));
HT_INIT(hs_service_ht, hs_service_map);
@@ -4344,7 +4414,6 @@ hs_service_init(void)
void
hs_service_free_all(void)
{
- rend_service_free_all();
service_free_all();
hs_config_free_all();
}
diff --git a/src/feature/hs/hs_service.h b/src/feature/hs/hs_service.h
index ec0e83f2c2..95461289ce 100644
--- a/src/feature/hs/hs_service.h
+++ b/src/feature/hs/hs_service.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2020, The Tor Project, Inc. */
+/* Copyright (c) 2016-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -210,7 +210,7 @@ typedef struct hs_service_config_t {
/** Have we explicitly set HiddenServiceVersion? */
unsigned int hs_version_explicitly_set : 1;
- /** List of rend_service_port_config_t */
+ /** List of hs_port_config_t */
smartlist_t *ports;
/** Path on the filesystem where the service persistent data is stored. NULL
@@ -230,9 +230,6 @@ typedef struct hs_service_config_t {
* HiddenServiceNumIntroductionPoints option. */
unsigned int num_intro_points;
- /** True iff the client auth is enabled. */
- unsigned int is_client_auth_enabled : 1;
-
/** List of hs_service_authorized_client_t's of clients that may access this
* service. Specified by HiddenServiceAuthorizeClient option. */
smartlist_t *clients;
@@ -358,6 +355,7 @@ smartlist_t *hs_service_get_metrics_stores(void);
void hs_service_map_has_changed(void);
void hs_service_dir_info_changed(void);
+void hs_service_new_consensus_params(const networkstatus_t *ns);
void hs_service_run_scheduled_events(time_t now);
void hs_service_circuit_has_opened(origin_circuit_t *circ);
int hs_service_receive_intro_established(origin_circuit_t *circ,
@@ -372,7 +370,8 @@ char *hs_service_lookup_current_desc(const ed25519_public_key_t *pk);
hs_service_add_ephemeral_status_t
hs_service_add_ephemeral(ed25519_secret_key_t *sk, smartlist_t *ports,
int max_streams_per_rdv_circuit,
- int max_streams_close_circuit, char **address_out);
+ int max_streams_close_circuit,
+ smartlist_t *auth_clients_v3, char **address_out);
int hs_service_del_ephemeral(const char *address);
/* Used outside of the HS subsystem by the control port command HSPOST. */
@@ -388,6 +387,20 @@ hs_service_exports_circuit_id(const ed25519_public_key_t *pk);
void hs_service_dump_stats(int severity);
void hs_service_circuit_cleanup_on_close(const circuit_t *circ);
+hs_service_authorized_client_t *
+parse_authorized_client_key(const char *key_str, int severity);
+
+void
+service_authorized_client_free_(hs_service_authorized_client_t *client);
+#define service_authorized_client_free(c) \
+ FREE_AND_NULL(hs_service_authorized_client_t, \
+ service_authorized_client_free_, (c))
+
+/* Config options. */
+int hs_service_allow_non_anonymous_connection(const or_options_t *options);
+int hs_service_non_anonymous_mode_enabled(const or_options_t *options);
+int hs_service_reveal_startup_time(const or_options_t *options);
+
#ifdef HS_SERVICE_PRIVATE
#ifdef TOR_UNIT_TESTS
@@ -452,12 +465,6 @@ STATIC void service_descriptor_free_(hs_service_descriptor_t *desc);
FREE_AND_NULL(hs_service_descriptor_t, \
service_descriptor_free_, (d))
-STATIC void
-service_authorized_client_free_(hs_service_authorized_client_t *client);
-#define service_authorized_client_free(c) \
- FREE_AND_NULL(hs_service_authorized_client_t, \
- service_authorized_client_free_, (c))
-
STATIC int
write_address_to_file(const hs_service_t *service, const char *fname_);
diff --git a/src/feature/hs/hs_stats.c b/src/feature/hs/hs_stats.c
index f9d458d630..cf191bd9d4 100644
--- a/src/feature/hs/hs_stats.c
+++ b/src/feature/hs/hs_stats.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2020, The Tor Project, Inc. */
+/* Copyright (c) 2016-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -12,20 +12,14 @@
/** Number of v3 INTRODUCE2 cells received */
static uint32_t n_introduce2_v3 = 0;
-/** Number of v2 INTRODUCE2 cells received */
-static uint32_t n_introduce2_v2 = 0;
/** Number of attempts to make a circuit to a rendezvous point */
static uint32_t n_rendezvous_launches = 0;
/** Note that we received another INTRODUCE2 cell. */
void
-hs_stats_note_introduce2_cell(int is_hsv3)
+hs_stats_note_introduce2_cell(void)
{
- if (is_hsv3) {
- n_introduce2_v3++;
- } else {
- n_introduce2_v2++;
- }
+ n_introduce2_v3++;
}
/** Return the number of v3 INTRODUCE2 cells we have received. */
@@ -35,13 +29,6 @@ hs_stats_get_n_introduce2_v3_cells(void)
return n_introduce2_v3;
}
-/** Return the number of v2 INTRODUCE2 cells we have received. */
-uint32_t
-hs_stats_get_n_introduce2_v2_cells(void)
-{
- return n_introduce2_v2;
-}
-
/** Note that we attempted to launch another circuit to a rendezvous point. */
void
hs_stats_note_service_rendezvous_launch(void)
diff --git a/src/feature/hs/hs_stats.h b/src/feature/hs/hs_stats.h
index aea2ccf5c2..1933017602 100644
--- a/src/feature/hs/hs_stats.h
+++ b/src/feature/hs/hs_stats.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2020, The Tor Project, Inc. */
+/* Copyright (c) 2016-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -9,9 +9,8 @@
#ifndef TOR_HS_STATS_H
#define TOR_HS_STATS_H
-void hs_stats_note_introduce2_cell(int is_hsv3);
+void hs_stats_note_introduce2_cell(void);
uint32_t hs_stats_get_n_introduce2_v3_cells(void);
-uint32_t hs_stats_get_n_introduce2_v2_cells(void);
void hs_stats_note_service_rendezvous_launch(void);
uint32_t hs_stats_get_n_rendezvous_launches(void);
diff --git a/src/feature/hs/hs_sys.c b/src/feature/hs/hs_sys.c
index 6524dc3e4e..21f1fa0707 100644
--- a/src/feature/hs/hs_sys.c
+++ b/src/feature/hs/hs_sys.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2020, The Tor Project, Inc. */
+/* Copyright (c) 2020-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/hs/hs_sys.h b/src/feature/hs/hs_sys.h
index 4427b59b9c..a42d5323c5 100644
--- a/src/feature/hs/hs_sys.h
+++ b/src/feature/hs/hs_sys.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2020, The Tor Project, Inc. */
+/* Copyright (c) 2020-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/hs/hsdir_index_st.h b/src/feature/hs/hsdir_index_st.h
index 6ce0bf5c69..f6a2c922ec 100644
--- a/src/feature/hs/hsdir_index_st.h
+++ b/src/feature/hs/hsdir_index_st.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/hs_common/replaycache.c b/src/feature/hs_common/replaycache.c
index ab058ce759..63444de464 100644
--- a/src/feature/hs_common/replaycache.c
+++ b/src/feature/hs_common/replaycache.c
@@ -1,4 +1,4 @@
- /* Copyright (c) 2012-2020, The Tor Project, Inc. */
+ /* Copyright (c) 2012-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/hs_common/replaycache.h b/src/feature/hs_common/replaycache.h
index 3a3eed29c0..3111149717 100644
--- a/src/feature/hs_common/replaycache.h
+++ b/src/feature/hs_common/replaycache.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2020, The Tor Project, Inc. */
+/* Copyright (c) 2012-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/hs_common/shared_random_client.c b/src/feature/hs_common/shared_random_client.c
index 4e8a2942fc..a09dbd5d29 100644
--- a/src/feature/hs_common/shared_random_client.c
+++ b/src/feature/hs_common/shared_random_client.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2018-2020, The Tor Project, Inc. */
+/* Copyright (c) 2018-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -34,12 +34,11 @@ srv_to_control_string(const sr_srv_t *srv)
}
/**
- * If we have no consensus and we are not an authority, assume that this is
- * the voting interval. We should never actually use this: only authorities
- * should be trying to figure out the schedule when they don't have a
- * consensus.
- **/
+ * If we have no consensus and we are not an authority, assume that this is the
+ * voting interval. This can be used while bootstrapping as a relay and we are
+ * asked to initialize HS stats (see rep_hist_hs_stats_init()) */
#define DEFAULT_NETWORK_VOTING_INTERVAL (3600)
+#define TESTING_DEFAULT_NETWORK_VOTING_INTERVAL (20)
/* This is an unpleasing workaround for tests. Our unit tests assume that we
* are scheduling all of our shared random stuff as if we were a directory
@@ -72,11 +71,13 @@ get_voting_interval(void)
* It's better than falling back to the non-consensus case. */
interval = (int)(consensus->fresh_until - consensus->valid_after);
} else {
- /* We should never be reaching this point, since a client should never
- * call this code unless they have some kind of a consensus. All we can
- * do is hope that this network is using the default voting interval. */
- tor_assert_nonfatal_unreached_once();
- interval = DEFAULT_NETWORK_VOTING_INTERVAL;
+ /* We can reach this as a relay when bootstrapping and we are asked to
+ * initialize HS stats (see rep_hist_hs_stats_init()). */
+ if (get_options()->TestingTorNetwork) {
+ interval = TESTING_DEFAULT_NETWORK_VOTING_INTERVAL;
+ } else {
+ interval = DEFAULT_NETWORK_VOTING_INTERVAL;
+ }
}
tor_assert(interval > 0);
return interval;
diff --git a/src/feature/hs_common/shared_random_client.h b/src/feature/hs_common/shared_random_client.h
index 37a086d590..679eb24c37 100644
--- a/src/feature/hs_common/shared_random_client.h
+++ b/src/feature/hs_common/shared_random_client.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2018-2020, The Tor Project, Inc. */
+/* Copyright (c) 2018-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/keymgt/loadkey.c b/src/feature/keymgt/loadkey.c
index 6ea3df492d..1000826376 100644
--- a/src/feature/keymgt/loadkey.c
+++ b/src/feature/keymgt/loadkey.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -712,7 +712,7 @@ ed_key_init_from_file(const char *fname, uint32_t flags,
}
/**
- * Create a new signing key and (optionally) certficiate; do not read or write
+ * Create a new signing key and (optionally) certificate; do not read or write
* from disk. See ed_key_init_from_file() for more information.
*/
ed25519_keypair_t *
diff --git a/src/feature/keymgt/loadkey.h b/src/feature/keymgt/loadkey.h
index 5a8ca32dea..6efbb415e7 100644
--- a/src/feature/keymgt/loadkey.h
+++ b/src/feature/keymgt/loadkey.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/metrics/metrics.c b/src/feature/metrics/metrics.c
index 9a72fe7145..5c10d553d3 100644
--- a/src/feature/metrics/metrics.c
+++ b/src/feature/metrics/metrics.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2007-2020, The Tor Project, Inc. */
+/* Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/metrics/metrics.h b/src/feature/metrics/metrics.h
index e072519d10..33e15f8bc9 100644
--- a/src/feature/metrics/metrics.h
+++ b/src/feature/metrics/metrics.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2020, The Tor Project, Inc. */
+/* Copyright (c) 2020-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/metrics/metrics_sys.c b/src/feature/metrics/metrics_sys.c
index 419318068e..d34c9fca38 100644
--- a/src/feature/metrics/metrics_sys.c
+++ b/src/feature/metrics/metrics_sys.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2020, The Tor Project, Inc. */
+/* Copyright (c) 2020-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/metrics/metrics_sys.h b/src/feature/metrics/metrics_sys.h
index 30c1b14836..617291ec73 100644
--- a/src/feature/metrics/metrics_sys.h
+++ b/src/feature/metrics/metrics_sys.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2020, The Tor Project, Inc. */
+/* Copyright (c) 2020-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/nodelist/authcert.c b/src/feature/nodelist/authcert.c
index c5b31be9e3..4ac3acc1bc 100644
--- a/src/feature/nodelist/authcert.c
+++ b/src/feature/nodelist/authcert.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/nodelist/authcert.h b/src/feature/nodelist/authcert.h
index 4c3d79ceed..7c42f6bf5f 100644
--- a/src/feature/nodelist/authcert.h
+++ b/src/feature/nodelist/authcert.h
@@ -1,6 +1,6 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/nodelist/authority_cert_st.h b/src/feature/nodelist/authority_cert_st.h
index aa9831d12e..7c9e31a27c 100644
--- a/src/feature/nodelist/authority_cert_st.h
+++ b/src/feature/nodelist/authority_cert_st.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/nodelist/desc_store_st.h b/src/feature/nodelist/desc_store_st.h
index 5f35a490a5..fd1d36fa6e 100644
--- a/src/feature/nodelist/desc_store_st.h
+++ b/src/feature/nodelist/desc_store_st.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/nodelist/describe.c b/src/feature/nodelist/describe.c
index b6a0fe74f7..758454830b 100644
--- a/src/feature/nodelist/describe.c
+++ b/src/feature/nodelist/describe.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/nodelist/describe.h b/src/feature/nodelist/describe.h
index 898b5c943b..b57bf596af 100644
--- a/src/feature/nodelist/describe.h
+++ b/src/feature/nodelist/describe.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/nodelist/dirlist.c b/src/feature/nodelist/dirlist.c
index 423c4106e2..1f1ac4d106 100644
--- a/src/feature/nodelist/dirlist.c
+++ b/src/feature/nodelist/dirlist.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -43,6 +43,14 @@
#include "feature/dirclient/dir_server_st.h"
#include "feature/nodelist/node_st.h"
+/** Information about an (HTTP) dirport for a directory authority. */
+struct auth_dirport_t {
+ /** What is the intended usage for this dirport? One of AUTH_USAGE_* */
+ auth_dirport_usage_t usage;
+ /** What is the correct address/port ? */
+ tor_addr_port_t dirport;
+};
+
/** Global list of a dir_server_t object for each directory
* authority. */
static smartlist_t *trusted_dir_servers = NULL;
@@ -66,6 +74,11 @@ add_trusted_dir_to_nodelist_addr_set(const dir_server_t *dir)
/* IPv6 DirPort is not a thing yet for authorities. */
nodelist_add_addr_to_address_set(&dir->ipv6_addr, dir->ipv6_orport, 0);
}
+ if (dir->auth_dirports) {
+ SMARTLIST_FOREACH_BEGIN(dir->auth_dirports, const auth_dirport_t *, p) {
+ nodelist_add_addr_to_address_set(&p->dirport.addr, 0, p->dirport.port);
+ } SMARTLIST_FOREACH_END(p);
+ }
}
/** Go over the trusted directory server list and add their address(es) to the
@@ -256,7 +269,10 @@ MOCK_IMPL(int, router_digest_is_trusted_dir_type,
/** Return true iff the given address matches a trusted directory that matches
* at least one bit of type.
*
- * If type is NO_DIRINFO or ALL_DIRINFO, any authority is matched. */
+ * If type is NO_DIRINFO or ALL_DIRINFO, any authority is matched.
+ *
+ * Only ORPorts' addresses are considered.
+ */
bool
router_addr_is_trusted_dir_type(const tor_addr_t *addr, dirinfo_type_t type)
{
@@ -281,6 +297,39 @@ router_addr_is_trusted_dir_type(const tor_addr_t *addr, dirinfo_type_t type)
return false;
}
+/** Return an appropriate usage value describing which authdir port to use
+ * for a given directory connection purpose.
+ */
+auth_dirport_usage_t
+auth_dirport_usage_for_purpose(int purpose)
+{
+ switch (purpose) {
+ case DIR_PURPOSE_FETCH_SERVERDESC:
+ case DIR_PURPOSE_FETCH_EXTRAINFO:
+ case DIR_PURPOSE_FETCH_CONSENSUS:
+ case DIR_PURPOSE_FETCH_CERTIFICATE:
+ case DIR_PURPOSE_FETCH_MICRODESC:
+ return AUTH_USAGE_DOWNLOAD;
+
+ case DIR_PURPOSE_UPLOAD_DIR:
+ return AUTH_USAGE_UPLOAD;
+
+ case DIR_PURPOSE_UPLOAD_VOTE:
+ case DIR_PURPOSE_UPLOAD_SIGNATURES:
+ case DIR_PURPOSE_FETCH_DETACHED_SIGNATURES:
+ case DIR_PURPOSE_FETCH_STATUS_VOTE:
+ return AUTH_USAGE_VOTING;
+
+ case DIR_PURPOSE_SERVER:
+ case DIR_PURPOSE_UPLOAD_HSDESC:
+ case DIR_PURPOSE_FETCH_HSDESC:
+ case DIR_PURPOSE_HAS_FETCHED_HSDESC:
+ default:
+ tor_assert_nonfatal_unreached();
+ return AUTH_USAGE_LEGACY;
+ }
+}
+
/** Create a directory server at <b>address</b>:<b>port</b>, with OR identity
* key <b>digest</b> which has DIGEST_LEN bytes. If <b>address</b> is NULL,
* add ourself. If <b>is_authority</b>, this is a directory authority. Return
@@ -357,6 +406,7 @@ dir_server_new(int is_authority,
ent->fake_status.ipv4_dirport = ent->ipv4_dirport;
ent->fake_status.ipv4_orport = ent->ipv4_orport;
ent->fake_status.ipv6_orport = ent->ipv6_orport;
+ ent->fake_status.is_authority = !! is_authority;
return ent;
}
@@ -404,10 +454,98 @@ trusted_dir_server_new(const char *nickname, const char *address,
ipv6_addrport,
digest,
v3_auth_digest, type, weight);
+
+ if (ipv4_dirport) {
+ tor_addr_port_t p;
+ memset(&p, 0, sizeof(p));
+ tor_addr_copy(&p.addr, &ipv4_addr);
+ p.port = ipv4_dirport;
+ trusted_dir_server_add_dirport(result, AUTH_USAGE_LEGACY, &p);
+ }
tor_free(hostname);
return result;
}
+/**
+ * Add @a dirport as an HTTP DirPort contact point for the directory authority
+ * @a ds, for use when contacting that authority for the given @a usage.
+ *
+ * Multiple ports of the same usage are allowed; if present, then only
+ * the first one of each address family is currently used.
+ */
+void
+trusted_dir_server_add_dirport(dir_server_t *ds,
+ auth_dirport_usage_t usage,
+ const tor_addr_port_t *dirport)
+{
+ tor_assert(ds);
+ tor_assert(dirport);
+
+ if (BUG(! ds->is_authority)) {
+ return;
+ }
+
+ if (ds->auth_dirports == NULL) {
+ ds->auth_dirports = smartlist_new();
+ }
+
+ auth_dirport_t *port = tor_malloc_zero(sizeof(auth_dirport_t));
+ port->usage = usage;
+ tor_addr_port_copy(&port->dirport, dirport);
+ smartlist_add(ds->auth_dirports, port);
+}
+
+/**
+ * Helper for trusted_dir_server_get_dirport: only return the exact requested
+ * usage type.
+ */
+const tor_addr_port_t *
+trusted_dir_server_get_dirport_exact(const dir_server_t *ds,
+ auth_dirport_usage_t usage,
+ int addr_family)
+{
+ tor_assert(ds);
+ tor_assert_nonfatal(addr_family == AF_INET || addr_family == AF_INET6);
+ if (ds->auth_dirports == NULL)
+ return NULL;
+
+ SMARTLIST_FOREACH_BEGIN(ds->auth_dirports, const auth_dirport_t *, port) {
+ if (port->usage == usage &&
+ tor_addr_family(&port->dirport.addr) == addr_family) {
+ return &port->dirport;
+ }
+ } SMARTLIST_FOREACH_END(port);
+
+ return NULL;
+}
+
+/**
+ * Return the DirPort of the authority @a ds for with the usage type
+ * @a usage and address family @a addr_family. If none is found, try
+ * again with an AUTH_USAGE_LEGACY dirport, if there is one. Return NULL
+ * if no port can be found.
+ */
+const tor_addr_port_t *
+trusted_dir_server_get_dirport(const dir_server_t *ds,
+ auth_dirport_usage_t usage,
+ int addr_family)
+{
+ const tor_addr_port_t *port;
+
+ while (1) {
+ port = trusted_dir_server_get_dirport_exact(ds, usage, addr_family);
+ if (port)
+ return port;
+
+ // If we tried LEGACY, there is no fallback from this point.
+ if (usage == AUTH_USAGE_LEGACY)
+ return NULL;
+
+ // Try again with LEGACY.
+ usage = AUTH_USAGE_LEGACY;
+ }
+}
+
/** Return a new dir_server_t for a fallback directory server at
* <b>addr</b>:<b>or_port</b>/<b>dir_port</b>, with identity key digest
* <b>id_digest</b> */
@@ -447,6 +585,10 @@ dir_server_free_(dir_server_t *ds)
if (!ds)
return;
+ if (ds->auth_dirports) {
+ SMARTLIST_FOREACH(ds->auth_dirports, auth_dirport_t *, p, tor_free(p));
+ smartlist_free(ds->auth_dirports);
+ }
tor_free(ds->nickname);
tor_free(ds->description);
tor_free(ds->address);
diff --git a/src/feature/nodelist/dirlist.h b/src/feature/nodelist/dirlist.h
index ae3debf4e5..3b4faf07af 100644
--- a/src/feature/nodelist/dirlist.h
+++ b/src/feature/nodelist/dirlist.h
@@ -1,6 +1,6 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -11,6 +11,28 @@
#ifndef TOR_DIRLIST_H
#define TOR_DIRLIST_H
+typedef struct auth_dirport_t auth_dirport_t;
+/**
+ * Different usages for an authority's HTTP directory port.
+ *
+ * Historically, only legacy ports existed; proposal 330 added multiple types
+ * of dirport to better enable authorities to offload work and resist DoS
+ * attacks.
+ **/
+typedef enum auth_dirport_usage_t {
+ /** Flag for an authority's dirport that is intended for misc/legacy
+ * usage. May be used when no other dirport is available. */
+ AUTH_USAGE_LEGACY,
+ /** Flag for an authority's dirport that is intended for descriptor uploads
+ * only. */
+ AUTH_USAGE_UPLOAD,
+ /** Flag for an authority's dirport that is intended for voting only */
+ AUTH_USAGE_VOTING,
+ /** Flag for an authority's dirport that is intended for relay downloads
+ * only. */
+ AUTH_USAGE_DOWNLOAD,
+} auth_dirport_usage_t;
+
int get_n_authorities(dirinfo_type_t type);
const smartlist_t *router_get_trusted_dir_servers(void);
const smartlist_t *router_get_fallback_dir_servers(void);
@@ -18,6 +40,8 @@ smartlist_t *router_get_trusted_dir_servers_mutable(void);
smartlist_t *router_get_fallback_dir_servers_mutable(void);
void mark_all_dirservers_up(smartlist_t *server_list);
+auth_dirport_usage_t auth_dirport_usage_for_purpose(int purpose);
+
dir_server_t *router_get_trusteddirserver_by_digest(const char *d);
dir_server_t *router_get_fallback_dirserver_by_digest(
const char *digest);
@@ -28,6 +52,14 @@ MOCK_DECL(dir_server_t *, trusteddirserver_get_by_v3_auth_digest,
MOCK_DECL(int, router_digest_is_trusted_dir_type,
(const char *digest, dirinfo_type_t type));
+const tor_addr_port_t *trusted_dir_server_get_dirport(const dir_server_t *ds,
+ auth_dirport_usage_t usage,
+ int addr_family);
+const tor_addr_port_t *trusted_dir_server_get_dirport_exact(
+ const dir_server_t *ds,
+ auth_dirport_usage_t usage,
+ int addr_family);
+
bool router_addr_is_trusted_dir_type(const tor_addr_t *addr,
dirinfo_type_t type);
#define router_addr_is_trusted_dir(d) \
@@ -41,6 +73,9 @@ dir_server_t *trusted_dir_server_new(const char *nickname, const char *address,
const tor_addr_port_t *addrport_ipv6,
const char *digest, const char *v3_auth_digest,
dirinfo_type_t type, double weight);
+void trusted_dir_server_add_dirport(dir_server_t *ds,
+ auth_dirport_usage_t usage,
+ const tor_addr_port_t *dirport);
dir_server_t *fallback_dir_server_new(const tor_addr_t *addr,
uint16_t dir_port, uint16_t or_port,
const tor_addr_port_t *addrport_ipv6,
diff --git a/src/feature/nodelist/document_signature_st.h b/src/feature/nodelist/document_signature_st.h
index 4bde9d89ec..63686c8572 100644
--- a/src/feature/nodelist/document_signature_st.h
+++ b/src/feature/nodelist/document_signature_st.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/nodelist/extrainfo_st.h b/src/feature/nodelist/extrainfo_st.h
index 6bd6232cd8..b0d94554a1 100644
--- a/src/feature/nodelist/extrainfo_st.h
+++ b/src/feature/nodelist/extrainfo_st.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/nodelist/fmt_routerstatus.c b/src/feature/nodelist/fmt_routerstatus.c
index 252b2e61fe..8c02a302af 100644
--- a/src/feature/nodelist/fmt_routerstatus.c
+++ b/src/feature/nodelist/fmt_routerstatus.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -15,11 +15,11 @@
#include "feature/nodelist/fmt_routerstatus.h"
#include "core/or/policies.h"
-#include "feature/nodelist/routerlist.h"
#include "feature/dirauth/dirvote.h"
-
#include "feature/nodelist/routerinfo_st.h"
+#include "feature/nodelist/routerlist.h"
#include "feature/nodelist/vote_routerstatus_st.h"
+#include "feature/stats/rephist.h"
#include "lib/crypt_ops/crypto_format.h"
@@ -87,7 +87,7 @@ routerstatus_format_entry(const routerstatus_t *rs, const char *version,
goto done;
smartlist_add_asprintf(chunks,
- "s%s%s%s%s%s%s%s%s%s%s%s\n",
+ "s%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
/* These must stay in alphabetical order. */
rs->is_authority?" Authority":"",
rs->is_bad_exit?" BadExit":"",
@@ -95,9 +95,11 @@ routerstatus_format_entry(const routerstatus_t *rs, const char *version,
rs->is_fast?" Fast":"",
rs->is_possible_guard?" Guard":"",
rs->is_hs_dir?" HSDir":"",
+ rs->is_middle_only?" MiddleOnly":"",
rs->is_flagged_running?" Running":"",
rs->is_stable?" Stable":"",
rs->is_staledesc?" StaleDesc":"",
+ rs->is_sybil?" Sybil":"",
rs->is_v2_dir?" V2Dir":"",
rs->is_valid?" Valid":"");
@@ -167,9 +169,20 @@ routerstatus_format_entry(const routerstatus_t *rs, const char *version,
smartlist_add_asprintf(chunks,
"w Bandwidth=%d", bw_kb);
+ /* Include the bandwidth weight from our external bandwidth
+ * authority, if we have one. */
if (format == NS_V3_VOTE && vrs && vrs->has_measured_bw) {
- smartlist_add_asprintf(chunks,
- " Measured=%d", vrs->measured_bw_kb);
+ if (!rs->is_authority) { /* normal case */
+ smartlist_add_asprintf(chunks,
+ " Measured=%d", vrs->measured_bw_kb);
+ } else {
+ /* dir auth special case: don't give it a Measured line, so we
+ * can reserve its attention for authority-specific activities.
+ * But do include the bwauth's opinion so it can be recorded for
+ * posterity. See #40698 for details. */
+ smartlist_add_asprintf(chunks,
+ " MeasuredButAuthority=%d", vrs->measured_bw_kb);
+ }
}
/* Write down guardfraction information if we have it. */
if (format == NS_V3_VOTE && vrs && vrs->status.has_guardfraction) {
@@ -194,6 +207,15 @@ routerstatus_format_entry(const routerstatus_t *rs, const char *version,
digest256_to_base64(ed_b64, (const char*)vrs->ed25519_id);
smartlist_add_asprintf(chunks, "id ed25519 %s\n", ed_b64);
}
+
+ /* We'll add a series of statistics to the vote per relays so we are
+ * able to assess what each authorities sees and help our health and
+ * performance work. */
+ time_t now = time(NULL);
+ smartlist_add_asprintf(chunks, "stats wfu=%.6f tk=%lu mtbf=%.0f\n",
+ rep_hist_get_weighted_fractional_uptime(rs->identity_digest, now),
+ rep_hist_get_weighted_time_known(rs->identity_digest, now),
+ rep_hist_get_stability(rs->identity_digest, now));
}
}
diff --git a/src/feature/nodelist/fmt_routerstatus.h b/src/feature/nodelist/fmt_routerstatus.h
index a007989af3..7482f373e1 100644
--- a/src/feature/nodelist/fmt_routerstatus.h
+++ b/src/feature/nodelist/fmt_routerstatus.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/nodelist/microdesc.c b/src/feature/nodelist/microdesc.c
index 01dccd160b..a95d535dc0 100644
--- a/src/feature/nodelist/microdesc.c
+++ b/src/feature/nodelist/microdesc.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2009-2020, The Tor Project, Inc. */
+/* Copyright (c) 2009-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/nodelist/microdesc.h b/src/feature/nodelist/microdesc.h
index b352f58e34..977c813911 100644
--- a/src/feature/nodelist/microdesc.h
+++ b/src/feature/nodelist/microdesc.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/nodelist/microdesc_st.h b/src/feature/nodelist/microdesc_st.h
index 410403e965..ad56b6d6c2 100644
--- a/src/feature/nodelist/microdesc_st.h
+++ b/src/feature/nodelist/microdesc_st.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/nodelist/networkstatus.c b/src/feature/nodelist/networkstatus.c
index 80940e6092..af3bde83a5 100644
--- a/src/feature/nodelist/networkstatus.c
+++ b/src/feature/nodelist/networkstatus.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -40,11 +40,14 @@
#include "core/or/or.h"
#include "app/config/config.h"
#include "core/mainloop/connection.h"
+#include "core/mainloop/cpuworker.h"
#include "core/mainloop/mainloop.h"
#include "core/mainloop/netstatus.h"
#include "core/or/channel.h"
#include "core/or/channelpadding.h"
#include "core/or/circuitpadding.h"
+#include "core/or/congestion_control_common.h"
+#include "core/or/congestion_control_flow.h"
#include "core/or/circuitmux.h"
#include "core/or/circuitmux_ewma.h"
#include "core/or/circuitstats.h"
@@ -80,6 +83,8 @@
#include "feature/nodelist/routerinfo.h"
#include "feature/nodelist/routerlist.h"
#include "feature/nodelist/torcert.h"
+#include "feature/relay/dns.h"
+#include "feature/relay/onion_queue.h"
#include "feature/relay/routermode.h"
#include "lib/crypt_ops/crypto_rand.h"
#include "lib/crypt_ops/crypto_util.h"
@@ -103,6 +108,7 @@
#include "feature/dirauth/vote_microdesc_hash_st.h"
#include "feature/nodelist/vote_routerstatus_st.h"
#include "feature/nodelist/routerstatus_st.h"
+#include "feature/stats/rephist.h"
#ifdef HAVE_UNISTD_H
#include <unistd.h>
@@ -240,7 +246,7 @@ networkstatus_get_cache_fname,(int flav,
}
/**
- * Read and and return the cached consensus of type <b>flavorname</b>. If
+ * Read and return the cached consensus of type <b>flavorname</b>. If
* <b>unverified</b> is false, get the one we haven't verified. Return NULL if
* the file isn't there. */
static tor_mmap_t *
@@ -1663,6 +1669,9 @@ notify_before_networkstatus_changes(const networkstatus_t *old_c,
dos_consensus_has_changed(new_c);
relay_consensus_has_changed(new_c);
hs_dos_consensus_has_changed(new_c);
+ rep_hist_consensus_has_changed(new_c);
+ cpuworker_consensus_has_changed(new_c);
+ onion_consensus_has_changed(new_c);
}
/* Called after a new consensus has been put in the global state. It is safe
@@ -1699,6 +1708,13 @@ notify_after_networkstatus_changes(void)
channelpadding_new_consensus_params(c);
circpad_new_consensus_params(c);
router_new_consensus_params(c);
+ congestion_control_new_consensus_params(c);
+ flow_control_new_consensus_params(c);
+ hs_service_new_consensus_params(c);
+ dns_new_consensus_params(c);
+
+ /* Maintenance of our L2 guard list */
+ maintain_layer2_guards();
}
/** Copy all the ancillary information (like router download status and so on)
diff --git a/src/feature/nodelist/networkstatus.h b/src/feature/nodelist/networkstatus.h
index ce050aeadc..0ffbd4d2ec 100644
--- a/src/feature/nodelist/networkstatus.h
+++ b/src/feature/nodelist/networkstatus.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/nodelist/networkstatus_sr_info_st.h b/src/feature/nodelist/networkstatus_sr_info_st.h
index 04d0dfe8f6..36f31f80b9 100644
--- a/src/feature/nodelist/networkstatus_sr_info_st.h
+++ b/src/feature/nodelist/networkstatus_sr_info_st.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/nodelist/networkstatus_st.h b/src/feature/nodelist/networkstatus_st.h
index 021168d3ca..4694750087 100644
--- a/src/feature/nodelist/networkstatus_st.h
+++ b/src/feature/nodelist/networkstatus_st.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/nodelist/networkstatus_voter_info_st.h b/src/feature/nodelist/networkstatus_voter_info_st.h
index a0fba2e1b5..cf38d1920b 100644
--- a/src/feature/nodelist/networkstatus_voter_info_st.h
+++ b/src/feature/nodelist/networkstatus_voter_info_st.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/nodelist/nickname.c b/src/feature/nodelist/nickname.c
index c022dd6bc4..6713f07320 100644
--- a/src/feature/nodelist/nickname.c
+++ b/src/feature/nodelist/nickname.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/nodelist/nickname.h b/src/feature/nodelist/nickname.h
index 11c6416f3a..052ffc2dd7 100644
--- a/src/feature/nodelist/nickname.h
+++ b/src/feature/nodelist/nickname.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/nodelist/node_select.c b/src/feature/nodelist/node_select.c
index ecb70aef14..13dfae1de3 100644
--- a/src/feature/nodelist/node_select.c
+++ b/src/feature/nodelist/node_select.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/nodelist/node_select.h b/src/feature/nodelist/node_select.h
index 1776d8ea1a..18a14ff0cb 100644
--- a/src/feature/nodelist/node_select.h
+++ b/src/feature/nodelist/node_select.h
@@ -1,6 +1,6 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/nodelist/node_st.h b/src/feature/nodelist/node_st.h
index 3769f9dc84..df67a47ada 100644
--- a/src/feature/nodelist/node_st.h
+++ b/src/feature/nodelist/node_st.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -70,6 +70,8 @@ struct node_t {
unsigned int is_exit:1; /**< Do we think this is an OK exit? */
unsigned int is_bad_exit:1; /**< Do we think this exit is censored, borked,
* or otherwise nasty? */
+ /** Is this unsuitable for use as anything besides a middle relay? */
+ unsigned int is_middle_only:1;
unsigned int is_hs_dir:1; /**< True iff this router is a hidden service
* directory according to the authorities. */
diff --git a/src/feature/nodelist/nodefamily.c b/src/feature/nodelist/nodefamily.c
index feaa3730dc..f1d52a53d2 100644
--- a/src/feature/nodelist/nodefamily.c
+++ b/src/feature/nodelist/nodefamily.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/nodelist/nodefamily.h b/src/feature/nodelist/nodefamily.h
index 16e161ba82..f9e82fa979 100644
--- a/src/feature/nodelist/nodefamily.h
+++ b/src/feature/nodelist/nodefamily.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/nodelist/nodefamily_st.h b/src/feature/nodelist/nodefamily_st.h
index c581c917a9..2c704ebe47 100644
--- a/src/feature/nodelist/nodefamily_st.h
+++ b/src/feature/nodelist/nodefamily_st.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/nodelist/nodelist.c b/src/feature/nodelist/nodelist.c
index 03b158e68d..b895a2c7f8 100644
--- a/src/feature/nodelist/nodelist.c
+++ b/src/feature/nodelist/nodelist.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -64,7 +64,6 @@
#include "feature/nodelist/routerlist.h"
#include "feature/nodelist/routerset.h"
#include "feature/nodelist/torcert.h"
-#include "feature/rend/rendservice.h"
#include "lib/encoding/binascii.h"
#include "lib/err/backtrace.h"
#include "lib/geoip/geoip.h"
@@ -1040,6 +1039,7 @@ nodelist_ensure_freshness(const networkstatus_t *ns)
nodelist_set_consensus(ns);
}
}
+
/** Return a list of a node_t * for every node we know about. The caller
* MUST NOT modify the list. (You can set and clear flags in the nodes if
* you must, but you must not add or remove nodes.) */
@@ -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
};
/** Return the protover_summary_flags for a given node. */
@@ -2470,7 +2470,6 @@ void
router_dir_info_changed(void)
{
need_to_update_have_min_dir_info = 1;
- rend_hsdir_routers_changed();
hs_service_dir_info_changed();
hs_client_dir_info_changed();
}
@@ -2821,6 +2820,7 @@ update_router_have_minimum_dir_info(void)
const networkstatus_t *consensus =
networkstatus_get_reasonably_live_consensus(now,usable_consensus_flavor());
int using_md;
+ static int be_loud_when_things_work_again = 0;
if (!consensus) {
if (!networkstatus_get_latest_consensus())
@@ -2876,8 +2876,9 @@ update_router_have_minimum_dir_info(void)
if (res && !have_min_dir_info) {
control_event_client_status(LOG_NOTICE, "ENOUGH_DIR_INFO");
control_event_boot_dir(BOOTSTRAP_STATUS_ENOUGH_DIRINFO, 0);
- log_info(LD_DIR,
- "We now have enough directory information to build circuits.");
+ tor_log(be_loud_when_things_work_again ? LOG_NOTICE : LOG_INFO, LD_DIR,
+ "We now have enough directory information to build circuits.");
+ be_loud_when_things_work_again = 0;
}
/* If paths have just become unavailable in this update. */
@@ -2886,6 +2887,10 @@ update_router_have_minimum_dir_info(void)
tor_log(quiet ? LOG_INFO : LOG_NOTICE, LD_DIR,
"Our directory information is no longer up-to-date "
"enough to build circuits: %s", dir_info_status);
+ if (!quiet) {
+ /* remember to do a notice-level log when things come back */
+ be_loud_when_things_work_again = 1;
+ }
/* a) make us log when we next complete a circuit, so we know when Tor
* is back up and usable, and b) disable some activities that Tor
diff --git a/src/feature/nodelist/nodelist.h b/src/feature/nodelist/nodelist.h
index 44b8918b06..5a45490dbb 100644
--- a/src/feature/nodelist/nodelist.h
+++ b/src/feature/nodelist/nodelist.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/nodelist/routerinfo.c b/src/feature/nodelist/routerinfo.c
index eb8eb74daa..7400ddd64c 100644
--- a/src/feature/nodelist/routerinfo.c
+++ b/src/feature/nodelist/routerinfo.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/nodelist/routerinfo.h b/src/feature/nodelist/routerinfo.h
index bc78beb402..0fbce8345e 100644
--- a/src/feature/nodelist/routerinfo.h
+++ b/src/feature/nodelist/routerinfo.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/nodelist/routerinfo_st.h b/src/feature/nodelist/routerinfo_st.h
index 7197c88c18..50134b2b96 100644
--- a/src/feature/nodelist/routerinfo_st.h
+++ b/src/feature/nodelist/routerinfo_st.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/nodelist/routerlist.c b/src/feature/nodelist/routerlist.c
index a1a348edb9..c00f7ffb26 100644
--- a/src/feature/nodelist/routerlist.c
+++ b/src/feature/nodelist/routerlist.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -1617,6 +1617,13 @@ router_add_to_routerlist(routerinfo_t *router, const char **msg,
"descriptor for router %s",
router_describe(router));
} else {
+ if (router->purpose == ROUTER_PURPOSE_BRIDGE) {
+ /* Even if we're not going to keep this descriptor, we need to
+ * let the bridge descriptor fetch subsystem know that we
+ * succeeded at getting it -- so we can adjust the retry schedule
+ * to stop trying for a while. */
+ learned_bridge_descriptor(router, from_cache, 0);
+ }
log_info(LD_DIR,
"Dropping descriptor that we already have for router %s",
router_describe(router));
@@ -2012,6 +2019,30 @@ routerlist_remove_old_routers(void)
router_rebuild_store(RRS_DONT_REMOVE_OLD,&routerlist->extrainfo_store);
}
+/* Drop every bridge descriptor in our routerlist. Used by the external
+ * 'bridgestrap' tool to discard bridge descriptors so that it can then
+ * do a clean reachability test. */
+void
+routerlist_drop_bridge_descriptors(void)
+{
+ routerinfo_t *router;
+ int i;
+
+ if (!routerlist)
+ return;
+
+ for (i = 0; i < smartlist_len(routerlist->routers); ++i) {
+ router = smartlist_get(routerlist->routers, i);
+ if (router->purpose == ROUTER_PURPOSE_BRIDGE) {
+ log_notice(LD_DIR,
+ "Dropping existing bridge descriptor for %s",
+ router_describe(router));
+ routerlist_remove(routerlist, router, 0, time(NULL));
+ i--;
+ }
+ }
+}
+
/** We just added a new set of descriptors. Take whatever extra steps
* we need. */
void
@@ -2023,7 +2054,7 @@ routerlist_descriptors_added(smartlist_t *sl, int from_cache)
control_event_descriptors_changed(sl);
SMARTLIST_FOREACH_BEGIN(sl, routerinfo_t *, ri) {
if (ri->purpose == ROUTER_PURPOSE_BRIDGE)
- learned_bridge_descriptor(ri, from_cache);
+ learned_bridge_descriptor(ri, from_cache, 1);
if (ri->needs_retest_if_added) {
ri->needs_retest_if_added = 0;
dirserv_single_reachability_test(approx_time(), ri);
diff --git a/src/feature/nodelist/routerlist.h b/src/feature/nodelist/routerlist.h
index 98472b2771..7ba305baf6 100644
--- a/src/feature/nodelist/routerlist.h
+++ b/src/feature/nodelist/routerlist.h
@@ -1,6 +1,6 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -145,6 +145,7 @@ was_router_added_t router_add_extrainfo_to_routerlist(
int from_cache, int from_fetch);
void routerlist_descriptors_added(smartlist_t *sl, int from_cache);
void routerlist_remove_old_routers(void);
+void routerlist_drop_bridge_descriptors(void);
int router_load_single_router(const char *s, uint8_t purpose, int cache,
const char **msg);
int router_load_routers_from_string(const char *s, const char *eos,
diff --git a/src/feature/nodelist/routerlist_st.h b/src/feature/nodelist/routerlist_st.h
index ec8933c7cb..28ede31a92 100644
--- a/src/feature/nodelist/routerlist_st.h
+++ b/src/feature/nodelist/routerlist_st.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/nodelist/routerset.c b/src/feature/nodelist/routerset.c
index 0d123956d9..1f26e472aa 100644
--- a/src/feature/nodelist/routerset.c
+++ b/src/feature/nodelist/routerset.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/nodelist/routerset.h b/src/feature/nodelist/routerset.h
index 18a0e31ba7..f80db52f7f 100644
--- a/src/feature/nodelist/routerset.h
+++ b/src/feature/nodelist/routerset.h
@@ -1,6 +1,6 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/nodelist/routerstatus_st.h b/src/feature/nodelist/routerstatus_st.h
index 254ba73f7f..55b76de581 100644
--- a/src/feature/nodelist/routerstatus_st.h
+++ b/src/feature/nodelist/routerstatus_st.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -51,6 +51,8 @@ struct routerstatus_t {
* choice as an entry guard. */
unsigned int is_bad_exit:1; /**< True iff this node is a bad choice for
* an exit node. */
+ unsigned int is_middle_only:1; /**< True iff this node is marked as bad
+ * for anything besides middle positions. */
unsigned int is_hs_dir:1; /**< True iff this router is a v2-or-later hidden
* service directory. */
unsigned int is_v2_dir:1; /** True iff this router publishes an open DirPort
@@ -58,6 +60,7 @@ struct routerstatus_t {
*/
unsigned int is_staledesc:1; /** True iff the authorities think this router
* should upload a new descriptor soon. */
+ unsigned int is_sybil:1; /** True iff this router is a sybil. */
unsigned int has_bandwidth:1; /**< The vote/consensus had bw info */
unsigned int has_exitsummary:1; /**< The vote/consensus had exit summaries */
diff --git a/src/feature/nodelist/signed_descriptor_st.h b/src/feature/nodelist/signed_descriptor_st.h
index 068f2a733c..e1982af29d 100644
--- a/src/feature/nodelist/signed_descriptor_st.h
+++ b/src/feature/nodelist/signed_descriptor_st.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/nodelist/torcert.c b/src/feature/nodelist/torcert.c
index dc36626122..8e115a2dc6 100644
--- a/src/feature/nodelist/torcert.c
+++ b/src/feature/nodelist/torcert.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2020, The Tor Project, Inc. */
+/* Copyright (c) 2014-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -13,7 +13,7 @@
* contents themselves may be another Ed25519 key, a digest of a
* RSA key, or some other material.
*
- * In this module there is also support for a crooss-certification of
+ * In this module there is also support for a cross-certification of
* Ed25519 identities using (older) RSA1024 identities.
*
* Tor uses other types of certificate too, beyond those described in this
diff --git a/src/feature/nodelist/torcert.h b/src/feature/nodelist/torcert.h
index 3314ee2550..edbe2564b6 100644
--- a/src/feature/nodelist/torcert.h
+++ b/src/feature/nodelist/torcert.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2020, The Tor Project, Inc. */
+/* Copyright (c) 2014-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/nodelist/vote_routerstatus_st.h b/src/feature/nodelist/vote_routerstatus_st.h
index ad0ee3f23b..6b2f7b92a9 100644
--- a/src/feature/nodelist/vote_routerstatus_st.h
+++ b/src/feature/nodelist/vote_routerstatus_st.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/relay/circuitbuild_relay.c b/src/feature/relay/circuitbuild_relay.c
index 289a5be557..5b1609a1af 100644
--- a/src/feature/relay/circuitbuild_relay.c
+++ b/src/feature/relay/circuitbuild_relay.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -392,7 +392,9 @@ circuit_open_connection_for_extend(const struct extend_cell_t *ec,
NULL, /*onion_key*/
NULL, /*curve25519_key*/
&chosen_ap->addr,
- chosen_ap->port);
+ chosen_ap->port,
+ NULL /* protover summary */,
+ false);
circ->n_chan_create_cell = tor_memdup(&ec->create_cell,
sizeof(ec->create_cell));
diff --git a/src/feature/relay/circuitbuild_relay.h b/src/feature/relay/circuitbuild_relay.h
index dc0b886a34..307825bb5c 100644
--- a/src/feature/relay/circuitbuild_relay.h
+++ b/src/feature/relay/circuitbuild_relay.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/relay/dns.c b/src/feature/relay/dns.c
index 8b684fd9eb..a38bf5cf5a 100644
--- a/src/feature/relay/dns.c
+++ b/src/feature/relay/dns.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -61,8 +61,10 @@
#include "core/or/relay.h"
#include "feature/control/control_events.h"
#include "feature/relay/dns.h"
+#include "feature/nodelist/networkstatus.h"
#include "feature/relay/router.h"
#include "feature/relay/routermode.h"
+#include "feature/stats/rephist.h"
#include "lib/crypt_ops/crypto_rand.h"
#include "lib/evloop/compat_libevent.h"
#include "lib/sandbox/sandbox.h"
@@ -109,6 +111,7 @@ static int answer_is_wildcarded(const char *ip);
static int evdns_err_is_transient(int err);
static void inform_pending_connections(cached_resolve_t *resolve);
static void make_pending_resolve_cached(cached_resolve_t *cached);
+static void configure_libevent_options(void);
#ifdef DEBUG_DNS_CACHE
static void assert_cache_ok_(void);
@@ -211,6 +214,19 @@ evdns_log_cb(int warn, const char *msg)
tor_log(severity, LD_EXIT, "eventdns: %s", msg);
}
+/** New consensus just appeared, take appropriate actions if need be. */
+void
+dns_new_consensus_params(const networkstatus_t *ns)
+{
+ (void) ns;
+
+ /* Consensus has parameters for the Exit relay DNS side and so we only reset
+ * the DNS nameservers if we are in server mode. */
+ if (server_mode(get_options())) {
+ configure_libevent_options();
+ }
+}
+
/** Initialize the DNS subsystem; called by the OR process. */
int
dns_init(void)
@@ -1352,6 +1368,111 @@ configured_nameserver_address(const size_t idx)
}
#endif /* defined(HAVE_EVDNS_BASE_GET_NAMESERVER_ADDR) */
+/** Return a pointer to a stack allocated buffer containing the string
+ * representation of the exit_dns_timeout consensus parameter. */
+static const char *
+get_consensus_param_exit_dns_timeout(void)
+{
+ static char str[4];
+
+ /* Get the Exit DNS timeout value from the consensus or default. This is in
+ * milliseconds. */
+#define EXIT_DNS_TIMEOUT_DEFAULT (1000)
+#define EXIT_DNS_TIMEOUT_MIN (1)
+#define EXIT_DNS_TIMEOUT_MAX (120000)
+ int32_t val = networkstatus_get_param(NULL, "exit_dns_timeout",
+ EXIT_DNS_TIMEOUT_DEFAULT,
+ EXIT_DNS_TIMEOUT_MIN,
+ EXIT_DNS_TIMEOUT_MAX);
+ /* NOTE: We convert it to seconds because libevent only supports that. In the
+ * future, if we support different resolver(s), we might want to specialize
+ * this call. */
+
+ /* NOTE: We also don't allow 0 and so we must cap the division to 1 second
+ * else all DNS request would fail if the consensus would ever tell us a
+ * value below 1000 (1 sec). */
+ val = MAX(1, val / 1000);
+
+ tor_snprintf(str, sizeof(str), "%d", val);
+ return str;
+}
+
+/** Return a pointer to a stack allocated buffer containing the string
+ * representation of the exit_dns_num_attempts consensus parameter. */
+static const char *
+get_consensus_param_exit_dns_attempts(void)
+{
+ static char str[4];
+
+ /* Get the Exit DNS number of attempt value from the consensus or default. */
+#define EXIT_DNS_NUM_ATTEMPTS_DEFAULT (2)
+#define EXIT_DNS_NUM_ATTEMPTS_MIN (0)
+#define EXIT_DNS_NUM_ATTEMPTS_MAX (255)
+ int32_t val = networkstatus_get_param(NULL, "exit_dns_num_attempts",
+ EXIT_DNS_NUM_ATTEMPTS_DEFAULT,
+ EXIT_DNS_NUM_ATTEMPTS_MIN,
+ EXIT_DNS_NUM_ATTEMPTS_MAX);
+ tor_snprintf(str, sizeof(str), "%d", val);
+ return str;
+}
+
+/** Configure the libevent options. This can safely be called after
+ * initialization or even if the evdns base is not set. */
+static void
+configure_libevent_options(void)
+{
+ /* This is possible because we can get called when a new consensus is set
+ * while the DNS subsystem is not initialized just yet. It should be
+ * harmless. */
+ if (!the_evdns_base) {
+ return;
+ }
+
+#define SET(k,v) evdns_base_set_option(the_evdns_base, (k), (v))
+
+ // If we only have one nameserver, it does not make sense to back off
+ // from it for a timeout. Unfortunately, the value for max-timeouts is
+ // currently clamped by libevent to 255, but it does not hurt to set
+ // it higher in case libevent gets a patch for this. Higher-than-
+ // default maximum of 3 with multiple nameservers to avoid spuriously
+ // marking one down on bursts of timeouts resulting from scans/attacks
+ // against non-responding authoritative DNS servers.
+ if (evdns_base_count_nameservers(the_evdns_base) == 1) {
+ SET("max-timeouts:", "1000000");
+ } else {
+ SET("max-timeouts:", "10");
+ }
+
+ // Elongate the queue of maximum inflight dns requests, so if a bunch
+ // remain pending at the resolver (happens commonly with Unbound) we won't
+ // stall every other DNS request. This potentially means some wasted
+ // CPU as there's a walk over a linear queue involved, but this is a
+ // much better tradeoff compared to just failing DNS requests because
+ // of a full queue.
+ SET("max-inflight:", "8192");
+
+ /* Set timeout to be 1 second. This tells libevent that it shouldn't wait
+ * more than N second to drop a DNS query and consider it "timed out". It is
+ * very important to differentiate here a libevent timeout and a DNS server
+ * timeout. And so, by setting this to N second, libevent sends back
+ * "DNS_ERR_TIMEOUT" if that N second is reached which does NOT indicate that
+ * 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
+ * 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. */
+ SET("attempts:", get_consensus_param_exit_dns_attempts());
+
+ if (get_options()->ServerDNSRandomizeCase)
+ SET("randomize-case:", "1");
+ else
+ SET("randomize-case:", "0");
+
+#undef SET
+}
+
/** Configure eventdns nameservers if force is true, or if the configuration
* has changed since the last time we called this function, or if we failed on
* our last attempt. On Unix, this reads from /etc/resolv.conf or
@@ -1465,43 +1586,10 @@ configure_nameservers(int force)
}
#endif /* defined(_WIN32) */
-#define SET(k,v) evdns_base_set_option(the_evdns_base, (k), (v))
-
- // If we only have one nameserver, it does not make sense to back off
- // from it for a timeout. Unfortunately, the value for max-timeouts is
- // currently clamped by libevent to 255, but it does not hurt to set
- // it higher in case libevent gets a patch for this. Higher-than-
- // default maximum of 3 with multiple nameservers to avoid spuriously
- // marking one down on bursts of timeouts resulting from scans/attacks
- // against non-responding authoritative DNS servers.
- if (evdns_base_count_nameservers(the_evdns_base) == 1) {
- SET("max-timeouts:", "1000000");
- } else {
- SET("max-timeouts:", "10");
- }
-
- // Elongate the queue of maximum inflight dns requests, so if a bunch
- // remain pending at the resolver (happens commonly with Unbound) we won't
- // stall every other DNS request. This potentially means some wasted
- // CPU as there's a walk over a linear queue involved, but this is a
- // much better tradeoff compared to just failing DNS requests because
- // of a full queue.
- SET("max-inflight:", "8192");
-
- // Two retries at 5 and 10 seconds for bind9/named which relies on
- // clients to handle retries. Second retry for retried circuits with
- // extended 15 second timeout. Superfluous with local-system Unbound
- // instance--has its own elaborate retry scheme.
- SET("timeout:", "5");
- SET("attempts:","3");
-
- if (options->ServerDNSRandomizeCase)
- SET("randomize-case:", "1");
- else
- SET("randomize-case:", "0");
-
-#undef SET
+ /* Setup libevent options. */
+ configure_libevent_options();
+ /* Relaunch periodical DNS check event. */
dns_servers_relaunch_checks();
nameservers_configured = 1;
@@ -1639,6 +1727,10 @@ evdns_callback(int result, char type, int count, int ttl, void *addresses,
dns_found_answer(string_address, orig_query_type,
result, &addr, hostname, clip_dns_fuzzy_ttl(ttl));
+ /* The result can be changed within this function thus why we note the result
+ * at the end. */
+ rep_hist_note_dns_error(type, result);
+
tor_free(arg_);
}
@@ -1657,6 +1749,9 @@ launch_one_resolve(const char *address, uint8_t query_type,
addr[0] = (char) query_type;
memcpy(addr+1, address, addr_len + 1);
+ /* Note the query for our statistics. */
+ rep_hist_note_dns_request(query_type);
+
switch (query_type) {
case DNS_IPv4_A:
req = evdns_base_resolve_ipv4(the_evdns_base,
diff --git a/src/feature/relay/dns.h b/src/feature/relay/dns.h
index 120b75bf8d..3f8519bd97 100644
--- a/src/feature/relay/dns.h
+++ b/src/feature/relay/dns.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -26,6 +26,7 @@ void dns_reset_correctness_checks(void);
size_t dns_cache_total_allocation(void);
void dump_dns_mem_usage(int severity);
size_t dns_cache_handle_oom(time_t now, size_t min_remove_bytes);
+void dns_new_consensus_params(const networkstatus_t *ns);
/* These functions are only used within the feature/relay module, and don't
* need stubs. */
@@ -47,6 +48,8 @@ void dns_launch_correctness_checks(void);
((void)(severity))
#define dns_cache_handle_oom(now, bytes) \
((void)(now), (void)(bytes), 0)
+#define dns_new_consensus_params(ns) \
+ ((void) ns)
#define connection_dns_remove(conn) \
STMT_BEGIN \
diff --git a/src/feature/relay/dns_structs.h b/src/feature/relay/dns_structs.h
index 27a791b9b3..d153629bf8 100644
--- a/src/feature/relay/dns_structs.h
+++ b/src/feature/relay/dns_structs.h
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/relay/ext_orport.c b/src/feature/relay/ext_orport.c
index 1bb8741e45..89b287b0b4 100644
--- a/src/feature/relay/ext_orport.c
+++ b/src/feature/relay/ext_orport.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2020, The Tor Project, Inc. */
+/* Copyright (c) 2012-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -656,77 +656,6 @@ connection_ext_or_start_auth(or_connection_t *or_conn)
return 0;
}
-/** Global map between Extended ORPort identifiers and OR
- * connections. */
-static digestmap_t *orconn_ext_or_id_map = NULL;
-
-/** Remove the Extended ORPort identifier of <b>conn</b> from the
- * global identifier list. Also, clear the identifier from the
- * connection itself. */
-void
-connection_or_remove_from_ext_or_id_map(or_connection_t *conn)
-{
- or_connection_t *tmp;
- if (!orconn_ext_or_id_map)
- return;
- if (!conn->ext_or_conn_id)
- return;
-
- tmp = digestmap_remove(orconn_ext_or_id_map, conn->ext_or_conn_id);
- if (!tor_digest_is_zero(conn->ext_or_conn_id))
- tor_assert(tmp == conn);
-
- memset(conn->ext_or_conn_id, 0, EXT_OR_CONN_ID_LEN);
-}
-
-#ifdef TOR_UNIT_TESTS
-/** Return the connection whose ext_or_id is <b>id</b>. Return NULL if no such
- * connection is found. */
-or_connection_t *
-connection_or_get_by_ext_or_id(const char *id)
-{
- if (!orconn_ext_or_id_map)
- return NULL;
- return digestmap_get(orconn_ext_or_id_map, id);
-}
-#endif /* defined(TOR_UNIT_TESTS) */
-
-/** Deallocate the global Extended ORPort identifier list */
-void
-connection_or_clear_ext_or_id_map(void)
-{
- digestmap_free(orconn_ext_or_id_map, NULL);
- orconn_ext_or_id_map = NULL;
-}
-
-/** Creates an Extended ORPort identifier for <b>conn</b> and deposits
- * it into the global list of identifiers. */
-void
-connection_or_set_ext_or_identifier(or_connection_t *conn)
-{
- char random_id[EXT_OR_CONN_ID_LEN];
- or_connection_t *tmp;
-
- if (!orconn_ext_or_id_map)
- orconn_ext_or_id_map = digestmap_new();
-
- /* Remove any previous identifiers: */
- if (conn->ext_or_conn_id && !tor_digest_is_zero(conn->ext_or_conn_id))
- connection_or_remove_from_ext_or_id_map(conn);
-
- do {
- crypto_rand(random_id, sizeof(random_id));
- } while (digestmap_get(orconn_ext_or_id_map, random_id));
-
- if (!conn->ext_or_conn_id)
- conn->ext_or_conn_id = tor_malloc_zero(EXT_OR_CONN_ID_LEN);
-
- memcpy(conn->ext_or_conn_id, random_id, EXT_OR_CONN_ID_LEN);
-
- tmp = digestmap_set(orconn_ext_or_id_map, random_id, conn);
- tor_assert(!tmp);
-}
-
/** Free any leftover allocated memory of the ext_orport.c subsystem. */
void
ext_orport_free_all(void)
diff --git a/src/feature/relay/ext_orport.h b/src/feature/relay/ext_orport.h
index 416c358397..5a9063d005 100644
--- a/src/feature/relay/ext_orport.h
+++ b/src/feature/relay/ext_orport.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -35,9 +35,6 @@
int connection_ext_or_start_auth(or_connection_t *or_conn);
-void connection_or_set_ext_or_identifier(or_connection_t *conn);
-void connection_or_remove_from_ext_or_id_map(or_connection_t *conn);
-void connection_or_clear_ext_or_id_map(void);
int connection_ext_or_finished_flushing(or_connection_t *conn);
int connection_ext_or_process_inbuf(or_connection_t *or_conn);
char *get_ext_or_auth_cookie_file_name(void);
@@ -69,13 +66,6 @@ connection_ext_or_process_inbuf(or_connection_t *conn)
tor_assert_nonfatal_unreached();
return -1;
}
-#define connection_or_set_ext_or_identifier(conn) \
- ((void)(conn))
-#define connection_or_remove_from_ext_or_id_map(conn) \
- ((void)(conn))
-#define connection_or_clear_ext_or_id_map() \
- STMT_NIL
-
#define get_ext_or_auth_cookie_file_name() \
(NULL)
@@ -94,7 +84,6 @@ STATIC int handle_client_auth_nonce(const char *client_nonce,
#ifdef TOR_UNIT_TESTS
extern uint8_t *ext_or_auth_cookie;
extern int ext_or_auth_cookie_is_set;
-or_connection_t *connection_or_get_by_ext_or_id(const char *id);
#endif
#endif /* defined(EXT_ORPORT_PRIVATE) */
diff --git a/src/feature/relay/include.am b/src/feature/relay/include.am
index 84bb1ff35e..8a121cef01 100644
--- a/src/feature/relay/include.am
+++ b/src/feature/relay/include.am
@@ -15,6 +15,7 @@ MODULE_RELAY_SOURCES = \
src/feature/relay/routermode.c \
src/feature/relay/relay_config.c \
src/feature/relay/relay_handshake.c \
+ src/feature/relay/relay_metrics.c \
src/feature/relay/relay_periodic.c \
src/feature/relay/relay_sys.c \
src/feature/relay/routerkeys.c \
@@ -30,6 +31,7 @@ noinst_HEADERS += \
src/feature/relay/onion_queue.h \
src/feature/relay/relay_config.h \
src/feature/relay/relay_handshake.h \
+ src/feature/relay/relay_metrics.h \
src/feature/relay/relay_periodic.h \
src/feature/relay/relay_sys.h \
src/feature/relay/relay_find_addr.h \
diff --git a/src/feature/relay/onion_queue.c b/src/feature/relay/onion_queue.c
index 3cbaa65d28..b844aefcd1 100644
--- a/src/feature/relay/onion_queue.c
+++ b/src/feature/relay/onion_queue.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -33,39 +33,104 @@
#include "core/or/circuitlist.h"
#include "core/or/onion.h"
#include "feature/nodelist/networkstatus.h"
+#include "feature/stats/rephist.h"
#include "core/or/or_circuit_st.h"
+#include "core/or/channel.h"
+
+/** Onion queue default, max and min. */
+
+/* In seconds. */
+#define ONION_QUEUE_WAIT_CUTOFF_DEFAULT 5
+#define ONION_QUEUE_WAIT_CUTOFF_MIN 0
+#define ONION_QUEUE_WAIT_CUTOFF_MAX INT32_MAX
+
+/* In msec. */
+#define ONION_QUEUE_MAX_DELAY_DEFAULT 1750
+#define ONION_QUEUE_MAX_DELAY_MIN 1
+#define ONION_QUEUE_MAX_DELAY_MAX INT32_MAX
+
+#define NUM_NTORS_PER_TAP_DEFAULT 10
+#define NUM_NTORS_PER_TAP_MIN 1
+#define NUM_NTORS_PER_TAP_MAX 100000
/** Type for a linked list of circuits that are waiting for a free CPU worker
* to process a waiting onion handshake. */
typedef struct onion_queue_t {
TOR_TAILQ_ENTRY(onion_queue_t) next;
or_circuit_t *circ;
- uint16_t handshake_type;
+ uint16_t queue_idx;
create_cell_t *onionskin;
time_t when_added;
} onion_queue_t;
-/** 5 seconds on the onion queue til we just send back a destroy */
-#define ONIONQUEUE_WAIT_CUTOFF 5
-
TOR_TAILQ_HEAD(onion_queue_head_t, onion_queue_t);
typedef struct onion_queue_head_t onion_queue_head_t;
+/** We have 3 queues: tap, fast, and ntor. (ntorv3 goes into ntor queue). */
+#define MAX_QUEUE_IDX ONION_HANDSHAKE_TYPE_NTOR
+
/** Array of queues of circuits waiting for CPU workers. An element is NULL
* if that queue is empty.*/
-static onion_queue_head_t ol_list[MAX_ONION_HANDSHAKE_TYPE+1] =
+static onion_queue_head_t ol_list[MAX_QUEUE_IDX+1] =
{ TOR_TAILQ_HEAD_INITIALIZER(ol_list[0]), /* tap */
TOR_TAILQ_HEAD_INITIALIZER(ol_list[1]), /* fast */
TOR_TAILQ_HEAD_INITIALIZER(ol_list[2]), /* ntor */
};
/** Number of entries of each type currently in each element of ol_list[]. */
-static int ol_entries[MAX_ONION_HANDSHAKE_TYPE+1];
+static int ol_entries[MAX_QUEUE_IDX+1];
-static int num_ntors_per_tap(void);
static void onion_queue_entry_remove(onion_queue_t *victim);
+/** Consensus parameters. */
+static int32_t ns_num_ntors_per_tap = NUM_NTORS_PER_TAP_DEFAULT;
+static time_t ns_onion_queue_wait_cutoff = ONION_QUEUE_WAIT_CUTOFF_DEFAULT;
+static uint32_t ns_onion_queue_max_delay = ONION_QUEUE_MAX_DELAY_DEFAULT;
+
+/** Return the number of ntors per tap from the cached parameter. */
+static inline int32_t
+get_num_ntors_per_tap(void)
+{
+ return ns_num_ntors_per_tap;
+}
+
+/** Return the onion queue wait cutoff value from the cached parameter. */
+static inline time_t
+get_onion_queue_wait_cutoff(void)
+{
+ return ns_onion_queue_wait_cutoff;
+}
+
+/** Return the max onion queue delay value either from the torrc options (if
+ * the user explicitly set it) else from the cached parameter. */
+static inline uint32_t
+get_onion_queue_max_delay(const or_options_t *options)
+{
+ if (options && options->MaxOnionQueueDelay > 0) {
+ return options->MaxOnionQueueDelay;
+ }
+ return ns_onion_queue_max_delay;
+}
+
+/**
+ * We combine ntorv3 and ntor into the same queue, so we must
+ * use this function to covert the cell type to a queue index.
+ */
+static inline uint16_t
+onionskin_type_to_queue(uint16_t type)
+{
+ if (type == ONION_HANDSHAKE_TYPE_NTOR_V3) {
+ return ONION_HANDSHAKE_TYPE_NTOR;
+ }
+
+ if (BUG(type > MAX_QUEUE_IDX)) {
+ return MAX_QUEUE_IDX; // use ntor if out of range
+ }
+
+ return type;
+}
+
/* XXXX Check lengths vs MAX_ONIONSKIN_{CHALLENGE,REPLY}_LEN.
*
* (By which I think I meant, "make sure that no
@@ -80,13 +145,22 @@ have_room_for_onionskin(uint16_t type)
{
const or_options_t *options = get_options();
int num_cpus;
+ uint64_t max_onion_queue_delay;
uint64_t tap_usec, ntor_usec;
uint64_t ntor_during_tap_usec, tap_during_ntor_usec;
/* If we've got fewer than 50 entries, we always have room for one more. */
if (ol_entries[type] < 50)
return 1;
- num_cpus = get_num_cpus(options);
+
+ /* If zero, this means our thread pool was never initialized meaning we can't
+ * really get here but make sure we don't have such value because we are
+ * using as a divisor. */
+ num_cpus = cpuworker_get_n_threads();
+ tor_assert(num_cpus > 0);
+
+ max_onion_queue_delay = get_onion_queue_max_delay(options);
+
/* Compute how many microseconds we'd expect to need to clear all
* onionskins in various combinations of the queues. */
@@ -104,32 +178,30 @@ have_room_for_onionskin(uint16_t type)
* process while draining the ntor queue? */
tap_during_ntor_usec = estimated_usec_for_onionskins(
MIN(ol_entries[ONION_HANDSHAKE_TYPE_TAP],
- ol_entries[ONION_HANDSHAKE_TYPE_NTOR] / num_ntors_per_tap()),
+ ol_entries[ONION_HANDSHAKE_TYPE_NTOR] / get_num_ntors_per_tap()),
ONION_HANDSHAKE_TYPE_TAP) / num_cpus;
/* How long would it take to process the ntor cells that we expect to
* process while draining the tap queue? */
ntor_during_tap_usec = estimated_usec_for_onionskins(
MIN(ol_entries[ONION_HANDSHAKE_TYPE_NTOR],
- ol_entries[ONION_HANDSHAKE_TYPE_TAP] * num_ntors_per_tap()),
+ ol_entries[ONION_HANDSHAKE_TYPE_TAP] * get_num_ntors_per_tap()),
ONION_HANDSHAKE_TYPE_NTOR) / num_cpus;
/* See whether that exceeds MaxOnionQueueDelay. If so, we can't queue
* this. */
if (type == ONION_HANDSHAKE_TYPE_NTOR &&
- (ntor_usec + tap_during_ntor_usec) / 1000 >
- (uint64_t)options->MaxOnionQueueDelay)
+ (ntor_usec + tap_during_ntor_usec) / 1000 > max_onion_queue_delay)
return 0;
if (type == ONION_HANDSHAKE_TYPE_TAP &&
- (tap_usec + ntor_during_tap_usec) / 1000 >
- (uint64_t)options->MaxOnionQueueDelay)
+ (tap_usec + ntor_during_tap_usec) / 1000 > max_onion_queue_delay)
return 0;
/* If we support the ntor handshake, then don't let TAP handshakes use
* more than 2/3 of the space on the queue. */
if (type == ONION_HANDSHAKE_TYPE_TAP &&
- tap_usec / 1000 > (uint64_t)options->MaxOnionQueueDelay * 2 / 3)
+ tap_usec / 1000 > max_onion_queue_delay * 2 / 3)
return 0;
return 1;
@@ -143,6 +215,7 @@ onion_pending_add(or_circuit_t *circ, create_cell_t *onionskin)
{
onion_queue_t *tmp;
time_t now = time(NULL);
+ uint16_t queue_idx = 0;
if (onionskin->handshake_type > MAX_ONION_HANDSHAKE_TYPE) {
/* LCOV_EXCL_START
@@ -153,43 +226,52 @@ onion_pending_add(or_circuit_t *circ, create_cell_t *onionskin)
/* LCOV_EXCL_STOP */
}
+ queue_idx = onionskin_type_to_queue(onionskin->handshake_type);
+
tmp = tor_malloc_zero(sizeof(onion_queue_t));
tmp->circ = circ;
- tmp->handshake_type = onionskin->handshake_type;
+ tmp->queue_idx = queue_idx;
tmp->onionskin = onionskin;
tmp->when_added = now;
- if (!have_room_for_onionskin(onionskin->handshake_type)) {
+ if (!have_room_for_onionskin(queue_idx)) {
#define WARN_TOO_MANY_CIRC_CREATIONS_INTERVAL (60)
static ratelim_t last_warned =
RATELIM_INIT(WARN_TOO_MANY_CIRC_CREATIONS_INTERVAL);
- char *m;
- if (onionskin->handshake_type == ONION_HANDSHAKE_TYPE_NTOR &&
- (m = rate_limit_log(&last_warned, approx_time()))) {
- log_warn(LD_GENERAL,
- "Your computer is too slow to handle this many circuit "
- "creation requests! Please consider using the "
- "MaxAdvertisedBandwidth config option or choosing a more "
- "restricted exit policy.%s",m);
- tor_free(m);
+ if (!channel_is_client(circ->p_chan)) {
+ // Avoid counting create cells from clients, to go with the same
+ // check in command_process_create_cell().
+ rep_hist_note_circuit_handshake_dropped(queue_idx);
+ }
+ if (queue_idx == ONION_HANDSHAKE_TYPE_NTOR) {
+ char *m;
+ if ((m = rate_limit_log(&last_warned, approx_time()))) {
+ log_warn(LD_GENERAL,
+ "Your computer is too slow to handle this many circuit "
+ "creation requests! Please consider using the "
+ "MaxAdvertisedBandwidth config option or choosing a more "
+ "restricted exit policy.%s",
+ m);
+ tor_free(m);
+ }
}
tor_free(tmp);
return -1;
}
- ++ol_entries[onionskin->handshake_type];
+ ++ol_entries[queue_idx];
log_info(LD_OR, "New create (%s). Queues now ntor=%d and tap=%d.",
- onionskin->handshake_type == ONION_HANDSHAKE_TYPE_NTOR ? "ntor" : "tap",
+ queue_idx == ONION_HANDSHAKE_TYPE_NTOR ? "ntor" : "tap",
ol_entries[ONION_HANDSHAKE_TYPE_NTOR],
ol_entries[ONION_HANDSHAKE_TYPE_TAP]);
circ->onionqueue_entry = tmp;
- TOR_TAILQ_INSERT_TAIL(&ol_list[onionskin->handshake_type], tmp, next);
+ TOR_TAILQ_INSERT_TAIL(&ol_list[queue_idx], tmp, next);
/* cull elderly requests. */
while (1) {
- onion_queue_t *head = TOR_TAILQ_FIRST(&ol_list[onionskin->handshake_type]);
- if (now - head->when_added < (time_t)ONIONQUEUE_WAIT_CUTOFF)
+ onion_queue_t *head = TOR_TAILQ_FIRST(&ol_list[queue_idx]);
+ if (now - head->when_added < get_onion_queue_wait_cutoff())
break;
circ = head->circ;
@@ -204,24 +286,6 @@ onion_pending_add(or_circuit_t *circ, create_cell_t *onionskin)
return 0;
}
-/** Return a fairness parameter, to prefer processing NTOR style
- * handshakes but still slowly drain the TAP queue so we don't starve
- * it entirely. */
-static int
-num_ntors_per_tap(void)
-{
-#define DEFAULT_NUM_NTORS_PER_TAP 10
-#define MIN_NUM_NTORS_PER_TAP 1
-#define MAX_NUM_NTORS_PER_TAP 100000
-
- int result = networkstatus_get_param(NULL, "NumNTorsPerTAP",
- DEFAULT_NUM_NTORS_PER_TAP,
- MIN_NUM_NTORS_PER_TAP,
- MAX_NUM_NTORS_PER_TAP);
- tor_assert(result > 0);
- return result;
-}
-
/** Choose which onion queue we'll pull from next. If one is empty choose
* the other; if they both have elements, load balance across them but
* favoring NTOR. */
@@ -245,7 +309,7 @@ decide_next_handshake_type(void)
* once tap is rare. We should reevaluate whether we like this decision
* once tap gets more rare. */
if (ol_entries[ONION_HANDSHAKE_TYPE_NTOR] &&
- recently_chosen_ntors <= num_ntors_per_tap())
+ recently_chosen_ntors <= get_num_ntors_per_tap())
++recently_chosen_ntors;
return ONION_HANDSHAKE_TYPE_NTOR; /* no taps? try ntor */
@@ -253,7 +317,7 @@ decide_next_handshake_type(void)
/* They both have something queued. Pick ntor if we haven't done that
* too much lately. */
- if (++recently_chosen_ntors <= num_ntors_per_tap()) {
+ if (++recently_chosen_ntors <= get_num_ntors_per_tap()) {
return ONION_HANDSHAKE_TYPE_NTOR;
}
@@ -276,15 +340,15 @@ onion_next_task(create_cell_t **onionskin_out)
return NULL; /* no onions pending, we're done */
tor_assert(head->circ);
- tor_assert(head->handshake_type <= MAX_ONION_HANDSHAKE_TYPE);
+ tor_assert(head->queue_idx <= MAX_QUEUE_IDX);
// tor_assert(head->circ->p_chan); /* make sure it's still valid */
/* XXX I only commented out the above line to make the unit tests
* more manageable. That's probably not good long-term. -RD */
circ = head->circ;
if (head->onionskin)
- --ol_entries[head->handshake_type];
+ --ol_entries[head->queue_idx];
log_info(LD_OR, "Processing create (%s). Queues now ntor=%d and tap=%d.",
- head->handshake_type == ONION_HANDSHAKE_TYPE_NTOR ? "ntor" : "tap",
+ head->queue_idx == ONION_HANDSHAKE_TYPE_NTOR ? "ntor" : "tap",
ol_entries[ONION_HANDSHAKE_TYPE_NTOR],
ol_entries[ONION_HANDSHAKE_TYPE_TAP]);
@@ -300,7 +364,7 @@ onion_next_task(create_cell_t **onionskin_out)
int
onion_num_pending(uint16_t handshake_type)
{
- return ol_entries[handshake_type];
+ return ol_entries[onionskin_type_to_queue(handshake_type)];
}
/** Go through ol_list, find the onion_queue_t element which points to
@@ -326,23 +390,23 @@ onion_pending_remove(or_circuit_t *circ)
static void
onion_queue_entry_remove(onion_queue_t *victim)
{
- if (victim->handshake_type > MAX_ONION_HANDSHAKE_TYPE) {
+ if (victim->queue_idx > MAX_QUEUE_IDX) {
/* LCOV_EXCL_START
* We should have rejected this far before this point */
log_warn(LD_BUG, "Handshake %d out of range! Dropping.",
- victim->handshake_type);
+ victim->queue_idx);
/* XXX leaks */
return;
/* LCOV_EXCL_STOP */
}
- TOR_TAILQ_REMOVE(&ol_list[victim->handshake_type], victim, next);
+ TOR_TAILQ_REMOVE(&ol_list[victim->queue_idx], victim, next);
if (victim->circ)
victim->circ->onionqueue_entry = NULL;
if (victim->onionskin)
- --ol_entries[victim->handshake_type];
+ --ol_entries[victim->queue_idx];
tor_free(victim->onionskin);
tor_free(victim);
@@ -354,7 +418,7 @@ clear_pending_onions(void)
{
onion_queue_t *victim, *next;
int i;
- for (i=0; i<=MAX_ONION_HANDSHAKE_TYPE; i++) {
+ for (i=0; i<=MAX_QUEUE_IDX; i++) {
for (victim = TOR_TAILQ_FIRST(&ol_list[i]); victim; victim = next) {
next = TOR_TAILQ_NEXT(victim,next);
onion_queue_entry_remove(victim);
@@ -363,3 +427,28 @@ clear_pending_onions(void)
}
memset(ol_entries, 0, sizeof(ol_entries));
}
+
+/** Consensus has changed, update the cached parameters. */
+void
+onion_consensus_has_changed(const networkstatus_t *ns)
+{
+ tor_assert(ns);
+
+ ns_onion_queue_max_delay =
+ networkstatus_get_param(ns, "MaxOnionQueueDelay",
+ ONION_QUEUE_MAX_DELAY_DEFAULT,
+ ONION_QUEUE_MAX_DELAY_MIN,
+ ONION_QUEUE_MAX_DELAY_MAX);
+
+ ns_onion_queue_wait_cutoff =
+ networkstatus_get_param(ns, "onion_queue_wait_cutoff",
+ ONION_QUEUE_WAIT_CUTOFF_DEFAULT,
+ ONION_QUEUE_WAIT_CUTOFF_MIN,
+ ONION_QUEUE_WAIT_CUTOFF_MAX);
+
+ ns_num_ntors_per_tap =
+ networkstatus_get_param(ns, "NumNTorsPerTAP",
+ NUM_NTORS_PER_TAP_DEFAULT,
+ NUM_NTORS_PER_TAP_MIN,
+ NUM_NTORS_PER_TAP_MAX);
+}
diff --git a/src/feature/relay/onion_queue.h b/src/feature/relay/onion_queue.h
index 08379b2c00..0c2b97c2b0 100644
--- a/src/feature/relay/onion_queue.h
+++ b/src/feature/relay/onion_queue.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -14,6 +14,8 @@
struct create_cell_t;
+void onion_consensus_has_changed(const networkstatus_t *ns);
+
int onion_pending_add(or_circuit_t *circ, struct create_cell_t *onionskin);
or_circuit_t *onion_next_task(struct create_cell_t **onionskin_out);
int onion_num_pending(uint16_t handshake_type);
diff --git a/src/feature/relay/relay_config.c b/src/feature/relay/relay_config.c
index 8ea0ad8397..85ccfc18a7 100644
--- a/src/feature/relay/relay_config.c
+++ b/src/feature/relay/relay_config.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -190,7 +190,7 @@ describe_relay_port(const port_cfg_t *port)
/** Return true iff port p1 is equal to p2.
*
- * This does a field by field comparaison. */
+ * This does a field by field comparison. */
static bool
port_cfg_eq(const port_cfg_t *p1, const port_cfg_t *p2)
{
diff --git a/src/feature/relay/relay_config.h b/src/feature/relay/relay_config.h
index d36863a1a1..cb08531782 100644
--- a/src/feature/relay/relay_config.h
+++ b/src/feature/relay/relay_config.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -93,7 +93,7 @@ STATIC int have_enough_mem_for_dircache(const struct or_options_t *options,
struct port_cfg_t;
STATIC const char *describe_relay_port(const struct port_cfg_t *port);
-#endif /* TOR_UNIT_TESTS */
+#endif /* defined(TOR_UNIT_TESTS) */
#endif /* defined(RELAY_CONFIG_PRIVATE) */
diff --git a/src/feature/relay/relay_find_addr.c b/src/feature/relay/relay_find_addr.c
index c43885af51..f4f9d40823 100644
--- a/src/feature/relay/relay_find_addr.c
+++ b/src/feature/relay/relay_find_addr.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2001-2020, The Tor Project, Inc. */
+/* Copyright (c) 2001-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -221,7 +221,7 @@ relay_addr_learn_from_dirauth(void)
"learn for now our address from them.");
return;
}
- extend_info_t *ei = extend_info_from_node(node, 1);
+ extend_info_t *ei = extend_info_from_node(node, 1, false);
if (BUG(!ei)) {
return;
}
diff --git a/src/feature/relay/relay_find_addr.h b/src/feature/relay/relay_find_addr.h
index f049d1bd20..5bb7f8736e 100644
--- a/src/feature/relay/relay_find_addr.h
+++ b/src/feature/relay/relay_find_addr.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2020, The Tor Project, Inc. */
+/* Copyright (c) 2020-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -28,5 +28,5 @@ void relay_addr_learn_from_dirauth(void);
#endif /* RELAY_FIND_ADDR_PRIVATE */
-#endif /* TOR_RELAY_FIND_ADDR_H */
+#endif /* !defined(TOR_RELAY_FIND_ADDR_H) */
diff --git a/src/feature/relay/relay_handshake.c b/src/feature/relay/relay_handshake.c
index 030dc94956..be7dba721a 100644
--- a/src/feature/relay/relay_handshake.c
+++ b/src/feature/relay/relay_handshake.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/relay/relay_handshake.h b/src/feature/relay/relay_handshake.h
index 99a658cbcc..87199c1c2d 100644
--- a/src/feature/relay/relay_handshake.h
+++ b/src/feature/relay/relay_handshake.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/relay/relay_metrics.c b/src/feature/relay/relay_metrics.c
new file mode 100644
index 0000000000..cdf34a3404
--- /dev/null
+++ b/src/feature/relay/relay_metrics.c
@@ -0,0 +1,1058 @@
+/* Copyright (c) 2021, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * @file relay_metrics.c
+ * @brief Relay metrics exposed through the MetricsPort
+ **/
+
+#define RELAY_METRICS_ENTRY_PRIVATE
+
+#include "orconfig.h"
+
+#include "core/or/or.h"
+#include "core/mainloop/connection.h"
+#include "core/mainloop/mainloop.h"
+#include "core/or/congestion_control_common.h"
+#include "core/or/congestion_control_vegas.h"
+#include "core/or/congestion_control_flow.h"
+#include "core/or/circuitlist.h"
+#include "core/or/dos.h"
+#include "core/or/relay.h"
+
+#include "app/config/config.h"
+
+#include "lib/container/smartlist.h"
+#include "lib/log/util_bug.h"
+#include "lib/malloc/malloc.h"
+#include "lib/math/fp.h"
+#include "lib/metrics/metrics_store.h"
+
+#include "feature/hs/hs_dos.h"
+#include "feature/nodelist/nodelist.h"
+#include "feature/nodelist/node_st.h"
+#include "feature/nodelist/routerstatus_st.h"
+#include "feature/relay/relay_metrics.h"
+#include "feature/relay/router.h"
+#include "feature/stats/rephist.h"
+
+#include <event2/dns.h>
+
+/** Declarations of each fill function for metrics defined in base_metrics. */
+static void fill_cc_counters_values(void);
+static void fill_cc_gauges_values(void);
+static void fill_circuits_values(void);
+static void fill_conn_counter_values(void);
+static void fill_conn_gauge_values(void);
+static void fill_dns_error_values(void);
+static void fill_dns_query_values(void);
+static void fill_dos_values(void);
+static void fill_global_bw_limit_values(void);
+static void fill_socket_values(void);
+static void fill_onionskins_values(void);
+static void fill_oom_values(void);
+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);
+
+/** The base metrics that is a static array of metrics added to the metrics
+ * store.
+ *
+ * The key member MUST be also the index of the entry in the array. */
+static const relay_metrics_entry_t base_metrics[] =
+{
+ {
+ .key = RELAY_METRICS_NUM_OOM_BYTES,
+ .type = METRICS_TYPE_COUNTER,
+ .name = METRICS_NAME(relay_load_oom_bytes_total),
+ .help = "Total number of bytes the OOM has freed by subsystem",
+ .fill_fn = fill_oom_values,
+ },
+ {
+ .key = RELAY_METRICS_NUM_ONIONSKINS,
+ .type = METRICS_TYPE_COUNTER,
+ .name = METRICS_NAME(relay_load_onionskins_total),
+ .help = "Total number of onionskins handled",
+ .fill_fn = fill_onionskins_values,
+ },
+ {
+ .key = RELAY_METRICS_NUM_SOCKETS,
+ .type = METRICS_TYPE_GAUGE,
+ .name = METRICS_NAME(relay_load_socket_total),
+ .help = "Total number of sockets",
+ .fill_fn = fill_socket_values,
+ },
+ {
+ .key = RELAY_METRICS_NUM_GLOBAL_RW_LIMIT,
+ .type = METRICS_TYPE_COUNTER,
+ .name = METRICS_NAME(relay_load_global_rate_limit_reached_total),
+ .help = "Total number of global connection bucket limit reached",
+ .fill_fn = fill_global_bw_limit_values,
+ },
+ {
+ .key = RELAY_METRICS_NUM_DNS,
+ .type = METRICS_TYPE_COUNTER,
+ .name = METRICS_NAME(relay_exit_dns_query_total),
+ .help = "Total number of DNS queries done by this relay",
+ .fill_fn = fill_dns_query_values,
+ },
+ {
+ .key = RELAY_METRICS_NUM_DNS_ERRORS,
+ .type = METRICS_TYPE_COUNTER,
+ .name = METRICS_NAME(relay_exit_dns_error_total),
+ .help = "Total number of DNS errors encountered by this relay",
+ .fill_fn = fill_dns_error_values,
+ },
+ {
+ .key = RELAY_METRICS_NUM_TCP_EXHAUSTION,
+ .type = METRICS_TYPE_COUNTER,
+ .name = METRICS_NAME(relay_load_tcp_exhaustion_total),
+ .help = "Total number of times we ran out of TCP ports",
+ .fill_fn = fill_tcp_exhaustion_values,
+ },
+ {
+ .key = RELAY_METRICS_CONN_COUNTERS,
+ .type = METRICS_TYPE_COUNTER,
+ .name = METRICS_NAME(relay_connections_total),
+ .help = "Total number of created/rejected connections",
+ .fill_fn = fill_conn_counter_values,
+ },
+ {
+ .key = RELAY_METRICS_CONN_GAUGES,
+ .type = METRICS_TYPE_GAUGE,
+ .name = METRICS_NAME(relay_connections),
+ .help = "Total number of opened connections",
+ .fill_fn = fill_conn_gauge_values,
+ },
+ {
+ .key = RELAY_METRICS_NUM_STREAMS,
+ .type = METRICS_TYPE_COUNTER,
+ .name = METRICS_NAME(relay_streams_total),
+ .help = "Total number of streams",
+ .fill_fn = fill_streams_values,
+ },
+ {
+ .key = RELAY_METRICS_CC_COUNTERS,
+ .type = METRICS_TYPE_COUNTER,
+ .name = METRICS_NAME(relay_congestion_control_total),
+ .help = "Congestion control related counters",
+ .fill_fn = fill_cc_counters_values,
+ },
+ {
+ .key = RELAY_METRICS_CC_GAUGES,
+ .type = METRICS_TYPE_GAUGE,
+ .name = METRICS_NAME(relay_congestion_control),
+ .help = "Congestion control related gauges",
+ .fill_fn = fill_cc_gauges_values,
+ },
+ {
+ .key = RELAY_METRICS_NUM_DOS,
+ .type = METRICS_TYPE_COUNTER,
+ .name = METRICS_NAME(relay_dos_total),
+ .help = "Denial of Service defenses related counters",
+ .fill_fn = fill_dos_values,
+ },
+ {
+ .key = RELAY_METRICS_NUM_TRAFFIC,
+ .type = METRICS_TYPE_COUNTER,
+ .name = METRICS_NAME(relay_traffic_bytes),
+ .help = "Traffic related counters",
+ .fill_fn = fill_traffic_values,
+ },
+ {
+ .key = RELAY_METRICS_RELAY_FLAGS,
+ .type = METRICS_TYPE_GAUGE,
+ .name = METRICS_NAME(relay_flag),
+ .help = "Relay flags from consensus",
+ .fill_fn = fill_relay_flags,
+ },
+ {
+ .key = RELAY_METRICS_NUM_CIRCUITS,
+ .type = METRICS_TYPE_GAUGE,
+ .name = METRICS_NAME(relay_circuits_total),
+ .help = "Total number of circuits",
+ .fill_fn = fill_circuits_values,
+ },
+};
+static const size_t num_base_metrics = ARRAY_LENGTH(base_metrics);
+
+/** The only and single store of all the relay metrics. */
+static metrics_store_t *the_store;
+
+/** Helper function to convert an handshake type into a string. */
+static inline const char *
+handshake_type_to_str(const uint16_t type)
+{
+ switch (type) {
+ case ONION_HANDSHAKE_TYPE_TAP:
+ return "tap";
+ case ONION_HANDSHAKE_TYPE_FAST:
+ return "fast";
+ case ONION_HANDSHAKE_TYPE_NTOR:
+ return "ntor";
+ case ONION_HANDSHAKE_TYPE_NTOR_V3:
+ return "ntor_v3";
+ default:
+ // LCOV_EXCL_START
+ tor_assert_unreached();
+ // LCOV_EXCL_STOP
+ }
+}
+
+/** Helper function to convert a socket family type into a string. */
+static inline const char *
+af_to_string(const int af)
+{
+ switch (af) {
+ case AF_INET:
+ return "ipv4";
+ case AF_INET6:
+ return "ipv6";
+ case AF_UNIX:
+ return "unix";
+ default:
+ return "<unknown>";
+ }
+}
+
+/** Fill function for the RELAY_METRICS_NUM_CIRCUITS metric. */
+static void
+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_add_label(sentry,
+ metrics_format_label("state", "opened"));
+ metrics_store_entry_update(sentry,
+ smartlist_len(circuit_get_global_list()));
+}
+
+/** Fill function for the RELAY_METRICS_RELAY_FLAGS metric. */
+static void
+fill_relay_flags(void)
+{
+ uint8_t is_fast = 0, is_exit = 0, is_authority = 0, is_stable = 0;
+ uint8_t is_running = 0, is_v2_dir = 0, is_guard = 0, is_sybil = 0;
+ uint8_t is_hs_dir = 0;
+
+ const node_t *me =
+ node_get_by_id((const char *) router_get_my_id_digest());
+ if (me && me->rs) {
+ is_fast = me->rs->is_fast;
+ is_exit = me->rs->is_exit;
+ is_authority = me->rs->is_authority;
+ is_stable = me->rs->is_stable;
+ is_running = me->rs->is_flagged_running;
+ is_v2_dir = me->rs->is_v2_dir;
+ is_guard = me->rs->is_possible_guard;
+ is_sybil = me->rs->is_sybil;
+ is_hs_dir = me->rs->is_hs_dir;
+ }
+
+ 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_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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("type", "Guard"));
+ metrics_store_entry_update(sentry, is_guard);
+}
+
+/** Fill function for the RELAY_METRICS_NUM_TRAFFIC metric. */
+static void
+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_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);
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("direction", "written"));
+ metrics_store_entry_update(sentry, get_bytes_written());
+}
+
+/** Fill function for the RELAY_METRICS_NUM_DOS metric. */
+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_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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("type", "introduce2_rejected"));
+ metrics_store_entry_update(sentry, hs_dos_get_intro2_rejected_count());
+}
+
+/** Fill function for the RELAY_METRICS_CC_COUNTERS metric. */
+static void
+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_add_label(sentry,
+ metrics_format_label("state", "starvation"));
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("action", "rtt_reset"));
+ metrics_store_entry_update(sentry, congestion_control_get_num_rtt_reset());
+
+ sentry = metrics_store_add(the_store, rentry->type, rentry->name,
+ rentry->help);
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("state", "clock_stalls"));
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("action", "rtt_skipped"));
+ metrics_store_entry_update(sentry,
+ congestion_control_get_num_clock_stalls());
+
+ sentry = metrics_store_add(the_store, rentry->type, rentry->name,
+ rentry->help);
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("state", "flow_control"));
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("action", "xoff_num_sent"));
+ metrics_store_entry_update(sentry,
+ cc_stats_flow_num_xoff_sent);
+
+ sentry = metrics_store_add(the_store, rentry->type, rentry->name,
+ rentry->help);
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("state", "flow_control"));
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("action", "xon_num_sent"));
+ metrics_store_entry_update(sentry,
+ cc_stats_flow_num_xon_sent);
+
+ sentry = metrics_store_add(the_store, rentry->type, rentry->name,
+ rentry->help);
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("state", "cc_limits"));
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("action", "above_delta"));
+ metrics_store_entry_update(sentry, cc_stats_vegas_above_delta);
+
+ sentry = metrics_store_add(the_store, rentry->type, rentry->name,
+ rentry->help);
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("state", "cc_limits"));
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("action", "above_ss_cwnd_max"));
+ metrics_store_entry_update(sentry, cc_stats_vegas_above_ss_cwnd_max);
+
+ sentry = metrics_store_add(the_store, rentry->type, rentry->name,
+ rentry->help);
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("state", "cc_limits"));
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("action", "below_ss_inc_floor"));
+ metrics_store_entry_update(sentry, cc_stats_vegas_below_ss_inc_floor);
+
+ sentry = metrics_store_add(the_store, rentry->type, rentry->name,
+ rentry->help);
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("state", "cc_circuits"));
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("action", "circs_created"));
+ metrics_store_entry_update(sentry, cc_stats_circs_created);
+
+ sentry = metrics_store_add(the_store, rentry->type, rentry->name,
+ rentry->help);
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("state", "cc_circuits"));
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("action", "circs_closed"));
+ metrics_store_entry_update(sentry, cc_stats_circs_closed);
+
+ sentry = metrics_store_add(the_store, rentry->type, rentry->name,
+ rentry->help);
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("state", "cc_circuits"));
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("action", "circs_exited_ss"));
+ metrics_store_entry_update(sentry, cc_stats_vegas_circ_exited_ss);
+}
+
+/** Fill function for the RELAY_METRICS_CC_GAUGES metric. */
+static void
+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_add_label(sentry,
+ metrics_format_label("state", "slow_start_exit"));
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("action", "cwnd"));
+ metrics_store_entry_update(sentry,
+ tor_llround(cc_stats_vegas_exit_ss_cwnd_ma));
+
+ sentry = metrics_store_add(the_store, rentry->type, rentry->name,
+ rentry->help);
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("state", "slow_start_exit"));
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("action", "bdp"));
+ metrics_store_entry_update(sentry,
+ tor_llround(cc_stats_vegas_exit_ss_bdp_ma));
+
+ sentry = metrics_store_add(the_store, rentry->type, rentry->name,
+ rentry->help);
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("state", "slow_start_exit"));
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("action", "inc"));
+ metrics_store_entry_update(sentry,
+ tor_llround(cc_stats_vegas_exit_ss_inc_ma));
+
+ sentry = metrics_store_add(the_store, rentry->type, rentry->name,
+ rentry->help);
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("state", "on_circ_close"));
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("action", "cwnd"));
+ metrics_store_entry_update(sentry,
+ tor_llround(cc_stats_circ_close_cwnd_ma));
+
+ sentry = metrics_store_add(the_store, rentry->type, rentry->name,
+ rentry->help);
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("state", "on_circ_close"));
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("action", "ss_cwnd"));
+ metrics_store_entry_update(sentry,
+ tor_llround(cc_stats_circ_close_ss_cwnd_ma));
+
+ sentry = metrics_store_add(the_store, rentry->type, rentry->name,
+ rentry->help);
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("state", "buffers"));
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("action", "xon_outbuf"));
+ metrics_store_entry_update(sentry,
+ tor_llround(cc_stats_flow_xon_outbuf_ma));
+
+ sentry = metrics_store_add(the_store, rentry->type, rentry->name,
+ rentry->help);
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("state", "buffers"));
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("action", "xoff_outbuf"));
+ metrics_store_entry_update(sentry,
+ tor_llround(cc_stats_flow_xoff_outbuf_ma));
+
+ sentry = metrics_store_add(the_store, rentry->type, rentry->name,
+ rentry->help);
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("state", "cc_backoff"));
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("action", "chan_blocked_pct"));
+ metrics_store_entry_update(sentry,
+ tor_llround(cc_stats_vegas_csig_blocked_ma));
+
+ sentry = metrics_store_add(the_store, rentry->type, rentry->name,
+ rentry->help);
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("state", "cc_backoff"));
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("action", "gamma_drop"));
+ metrics_store_entry_update(sentry,
+ tor_llround(cc_stats_vegas_gamma_drop_ma));
+
+ sentry = metrics_store_add(the_store, rentry->type, rentry->name,
+ rentry->help);
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("state", "cc_backoff"));
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("action", "delta_drop"));
+ metrics_store_entry_update(sentry,
+ tor_llround(cc_stats_vegas_delta_drop_ma));
+
+ sentry = metrics_store_add(the_store, rentry->type, rentry->name,
+ rentry->help);
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("state", "cc_backoff"));
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("action", "ss_chan_blocked_pct"));
+ metrics_store_entry_update(sentry,
+ tor_llround(cc_stats_vegas_ss_csig_blocked_ma));
+
+ sentry = metrics_store_add(the_store, rentry->type, rentry->name,
+ rentry->help);
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("state", "cc_cwnd_update"));
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("action", "alpha_pct"));
+ metrics_store_entry_update(sentry,
+ tor_llround(cc_stats_vegas_csig_alpha_ma));
+
+ sentry = metrics_store_add(the_store, rentry->type, rentry->name,
+ rentry->help);
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("state", "cc_cwnd_update"));
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("action", "beta_pct"));
+ metrics_store_entry_update(sentry,
+ tor_llround(cc_stats_vegas_csig_beta_ma));
+
+ sentry = metrics_store_add(the_store, rentry->type, rentry->name,
+ rentry->help);
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("state", "cc_cwnd_update"));
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("action", "delta_pct"));
+ metrics_store_entry_update(sentry,
+ tor_llround(cc_stats_vegas_csig_delta_ma));
+
+ sentry = metrics_store_add(the_store, rentry->type, rentry->name,
+ rentry->help);
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("state", "cc_estimates"));
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("action", "ss_queue"));
+ metrics_store_entry_update(sentry,
+ tor_llround(cc_stats_vegas_ss_queue_ma));
+
+ sentry = metrics_store_add(the_store, rentry->type, rentry->name,
+ rentry->help);
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("state", "cc_estimates"));
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("action", "queue"));
+ metrics_store_entry_update(sentry,
+ tor_llround(cc_stats_vegas_queue_ma));
+
+ sentry = metrics_store_add(the_store, rentry->type, rentry->name,
+ rentry->help);
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("state", "cc_estimates"));
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("action", "bdp"));
+ metrics_store_entry_update(sentry,
+ tor_llround(cc_stats_vegas_bdp_ma));
+}
+
+/** Helper: Fill in single stream metrics output. */
+static void
+fill_single_stream_value(metrics_store_entry_t *sentry, uint8_t cmd)
+{
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("type", relay_command_to_string(cmd)));
+ metrics_store_entry_update(sentry, rep_hist_get_exit_stream_seen(cmd));
+}
+
+/** Fill function for the RELAY_METRICS_NUM_STREAMS metric. */
+static void
+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);
+ fill_single_stream_value(sentry, RELAY_COMMAND_BEGIN);
+
+ sentry = metrics_store_add(the_store, rentry->type, rentry->name,
+ rentry->help);
+ fill_single_stream_value(sentry, RELAY_COMMAND_BEGIN_DIR);
+
+ sentry = metrics_store_add(the_store, rentry->type, rentry->name,
+ rentry->help);
+ fill_single_stream_value(sentry, RELAY_COMMAND_RESOLVE);
+}
+
+/** Helper: Fill in single connection metrics output. */
+static void
+fill_single_connection_value(metrics_store_entry_t *sentry,
+ unsigned int conn_type,
+ const char* direction,
+ const char* state,
+ int socket_family,
+ uint64_t value)
+{
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("type", conn_type_to_string(conn_type)));
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("direction", direction));
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("state", state));
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("family", af_to_string(socket_family)));
+ metrics_store_entry_update(sentry, value);
+}
+
+/** Fill function for the RELAY_METRICS_CONN_COUNTERS metric. */
+static void
+fill_conn_counter_values(void)
+{
+ const relay_metrics_entry_t *rentry =
+ &base_metrics[RELAY_METRICS_CONN_COUNTERS];
+
+ for (unsigned int i = CONN_TYPE_MIN_; i < CONN_TYPE_MAX_ ; i++) {
+ /* Type is unused. Ugly but else we clobber the output. */
+ if (i == 10) {
+ continue;
+ }
+ metrics_store_entry_t *sentry =
+ metrics_store_add(the_store, rentry->type, rentry->name, rentry->help);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ fill_single_connection_value(sentry, i, "received", "rejected", AF_INET6,
+ rep_hist_get_conn_rejected(i, AF_INET6));
+
+ /* No counter for "initiated" + "rejected" connections exists. */
+ }
+}
+
+/** Fill function for the RELAY_METRICS_CONN_GAUGES metric. */
+static void
+fill_conn_gauge_values(void)
+{
+ const relay_metrics_entry_t *rentry =
+ &base_metrics[RELAY_METRICS_CONN_GAUGES];
+
+ for (unsigned int i = CONN_TYPE_MIN_; i < CONN_TYPE_MAX_ ; i++) {
+ /* Type is unused. Ugly but else we clobber the output. */
+ if (i == 10) {
+ continue;
+ }
+ metrics_store_entry_t *sentry =
+ metrics_store_add(the_store, rentry->type, rentry->name, rentry->help);
+ 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);
+ 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);
+ 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);
+ fill_single_connection_value(sentry, i, "received", "opened", AF_INET6,
+ rep_hist_get_conn_opened(true, i, AF_INET6));
+ }
+}
+
+/** Fill function for the RELAY_METRICS_NUM_DNS metrics. */
+static void
+fill_tcp_exhaustion_values(void)
+{
+ metrics_store_entry_t *sentry;
+ const relay_metrics_entry_t *rentry =
+ &base_metrics[RELAY_METRICS_NUM_TCP_EXHAUSTION];
+
+ sentry = metrics_store_add(the_store, rentry->type, rentry->name,
+ rentry->help);
+ metrics_store_entry_update(sentry, rep_hist_get_n_tcp_exhaustion());
+}
+
+/* NOTE: Disable the record type label until libevent is fixed. */
+#if 0
+/** Helper array containing mapping for the name of the different DNS records
+ * and their corresponding libevent values. */
+static struct dns_type {
+ const char *name;
+ uint8_t type;
+} dns_types[] = {
+ { .name = "A", .type = DNS_IPv4_A },
+ { .name = "PTR", .type = DNS_PTR },
+ { .name = "AAAA", .type = DNS_IPv6_AAAA },
+};
+static const size_t num_dns_types = ARRAY_LENGTH(dns_types);
+#endif
+
+/** Fill function for the RELAY_METRICS_NUM_DNS_ERRORS metrics. */
+static void
+fill_dns_error_values(void)
+{
+ metrics_store_entry_t *sentry;
+ const relay_metrics_entry_t *rentry =
+ &base_metrics[RELAY_METRICS_NUM_DNS_ERRORS];
+
+ /* Helper array to map libeven DNS errors to their names and so we can
+ * iterate over this array to add all metrics. */
+ static struct dns_error {
+ const char *name;
+ uint8_t key;
+ } errors[] = {
+ { .name = "success", .key = DNS_ERR_NONE },
+ { .name = "format", .key = DNS_ERR_FORMAT },
+ { .name = "serverfailed", .key = DNS_ERR_SERVERFAILED },
+ { .name = "notexist", .key = DNS_ERR_NOTEXIST },
+ { .name = "notimpl", .key = DNS_ERR_NOTIMPL },
+ { .name = "refused", .key = DNS_ERR_REFUSED },
+ { .name = "truncated", .key = DNS_ERR_TRUNCATED },
+ { .name = "unknown", .key = DNS_ERR_UNKNOWN },
+ { .name = "tor_timeout", .key = DNS_ERR_TIMEOUT },
+ { .name = "shutdown", .key = DNS_ERR_SHUTDOWN },
+ { .name = "cancel", .key = DNS_ERR_CANCEL },
+ { .name = "nodata", .key = DNS_ERR_NODATA },
+ };
+ static const size_t num_errors = ARRAY_LENGTH(errors);
+
+ /* NOTE: Disable the record type label until libevent is fixed. */
+#if 0
+ for (size_t i = 0; i < num_dns_types; i++) {
+ /* Dup the label because metrics_format_label() returns a pointer to a
+ * string on the stack and we need that label for all metrics. */
+ char *record_label =
+ tor_strdup(metrics_format_label("record", dns_types[i].name));
+
+ for (size_t j = 0; j < num_errors; j++) {
+ sentry = metrics_store_add(the_store, rentry->type, rentry->name,
+ rentry->help);
+ metrics_store_entry_add_label(sentry, record_label);
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("reason", errors[j].name));
+ metrics_store_entry_update(sentry,
+ rep_hist_get_n_dns_error(dns_types[i].type, errors[j].key));
+ }
+ tor_free(record_label);
+ }
+#endif
+
+ /* 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);
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("reason", errors[j].name));
+ metrics_store_entry_update(sentry,
+ rep_hist_get_n_dns_error(0, errors[j].key));
+ }
+}
+
+/** Fill function for the RELAY_METRICS_NUM_DNS metrics. */
+static void
+fill_dns_query_values(void)
+{
+ metrics_store_entry_t *sentry;
+ const relay_metrics_entry_t *rentry =
+ &base_metrics[RELAY_METRICS_NUM_DNS];
+
+ /* NOTE: Disable the record type label until libevent is fixed (#40490). */
+#if 0
+ for (size_t i = 0; i < num_dns_types; i++) {
+ /* Dup the label because metrics_format_label() returns a pointer to a
+ * string on the stack and we need that label for all metrics. */
+ 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);
+ metrics_store_entry_add_label(sentry, record_label);
+ metrics_store_entry_update(sentry,
+ rep_hist_get_n_dns_request(dns_types[i].type));
+ tor_free(record_label);
+ }
+#endif
+
+ sentry = metrics_store_add(the_store, rentry->type, rentry->name,
+ rentry->help);
+ metrics_store_entry_update(sentry, rep_hist_get_n_dns_request(0));
+}
+
+/** Fill function for the RELAY_METRICS_NUM_GLOBAL_RW_LIMIT metrics. */
+static void
+fill_global_bw_limit_values(void)
+{
+ metrics_store_entry_t *sentry;
+ const relay_metrics_entry_t *rentry =
+ &base_metrics[RELAY_METRICS_NUM_GLOBAL_RW_LIMIT];
+
+ sentry = metrics_store_add(the_store, rentry->type, rentry->name,
+ rentry->help);
+ 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);
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("side", "write"));
+ metrics_store_entry_update(sentry, rep_hist_get_n_write_limit_reached());
+}
+
+/** Fill function for the RELAY_METRICS_NUM_SOCKETS metrics. */
+static void
+fill_socket_values(void)
+{
+ metrics_store_entry_t *sentry;
+ const relay_metrics_entry_t *rentry =
+ &base_metrics[RELAY_METRICS_NUM_SOCKETS];
+
+ sentry = metrics_store_add(the_store, rentry->type, rentry->name,
+ rentry->help);
+ 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);
+ metrics_store_entry_update(sentry, get_max_sockets());
+}
+
+/** Fill function for the RELAY_METRICS_NUM_ONIONSKINS metrics. */
+static void
+fill_onionskins_values(void)
+{
+ metrics_store_entry_t *sentry;
+ const relay_metrics_entry_t *rentry =
+ &base_metrics[RELAY_METRICS_NUM_ONIONSKINS];
+
+ for (uint16_t t = 0; t <= MAX_ONION_HANDSHAKE_TYPE; t++) {
+ /* Dup the label because metrics_format_label() returns a pointer to a
+ * string on the stack and we need that label for all metrics. */
+ 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);
+ metrics_store_entry_add_label(sentry, type_label);
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("action", "processed"));
+ metrics_store_entry_update(sentry,
+ rep_hist_get_circuit_n_handshake_assigned(t));
+
+ sentry = metrics_store_add(the_store, rentry->type, rentry->name,
+ rentry->help);
+ metrics_store_entry_add_label(sentry, type_label);
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("action", "dropped"));
+ metrics_store_entry_update(sentry,
+ rep_hist_get_circuit_n_handshake_dropped(t));
+ tor_free(type_label);
+ }
+}
+
+/** Fill function for the RELAY_METRICS_NUM_OOM_BYTES metrics. */
+static void
+fill_oom_values(void)
+{
+ metrics_store_entry_t *sentry;
+ const relay_metrics_entry_t *rentry =
+ &base_metrics[RELAY_METRICS_NUM_OOM_BYTES];
+
+ sentry = metrics_store_add(the_store, rentry->type, rentry->name,
+ rentry->help);
+ 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);
+ 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);
+ 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);
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("subsys", "hsdir"));
+ metrics_store_entry_update(sentry, oom_stats_n_bytes_removed_hsdir);
+}
+
+/** Reset the global store and fill it with all the metrics from base_metrics
+ * and their associated values.
+ *
+ * To pull this off, every metrics has a "fill" function that is called and in
+ * charge of adding the metrics to the store, appropriate labels and finally
+ * updating the value to report. */
+static void
+fill_store(void)
+{
+ /* Reset the current store, we are about to fill it with all the things. */
+ metrics_store_reset(the_store);
+
+ /* Call the fill function for each metrics. */
+ for (size_t i = 0; i < num_base_metrics; i++) {
+ if (BUG(!base_metrics[i].fill_fn)) {
+ continue;
+ }
+ base_metrics[i].fill_fn();
+ }
+}
+
+/** Return a list of all the relay metrics stores. This is the
+ * function attached to the .get_metrics() member of the subsys_t. */
+const smartlist_t *
+relay_metrics_get_stores(void)
+{
+ /* We can't have the caller to free the returned list so keep it static,
+ * simply update it. */
+ static smartlist_t *stores_list = NULL;
+
+ /* We dynamically fill the store with all the metrics upon a request. The
+ * reason for this is because the exposed metrics of a relay are often
+ * internal counters in the fast path and thus we fetch the value when a
+ * metrics port request arrives instead of keeping a local metrics store of
+ * those values. */
+ fill_store();
+
+ if (!stores_list) {
+ stores_list = smartlist_new();
+ smartlist_add(stores_list, the_store);
+ }
+
+ return stores_list;
+}
+
+/** Initialize the relay metrics. */
+void
+relay_metrics_init(void)
+{
+ if (BUG(the_store)) {
+ return;
+ }
+ the_store = metrics_store_new();
+}
+
+/** Free the relay metrics. */
+void
+relay_metrics_free(void)
+{
+ if (!the_store) {
+ return;
+ }
+ /* NULL is set with this call. */
+ metrics_store_free(the_store);
+}
diff --git a/src/feature/relay/relay_metrics.h b/src/feature/relay/relay_metrics.h
new file mode 100644
index 0000000000..1d2d649d8a
--- /dev/null
+++ b/src/feature/relay/relay_metrics.h
@@ -0,0 +1,73 @@
+/* Copyright (c) 2021, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * @file relay_metrics.h
+ * @brief Header for feature/relay/relay_metrics.c
+ **/
+
+#ifndef TOR_FEATURE_RELAY_RELAY_METRICS_H
+#define TOR_FEATURE_RELAY_RELAY_METRICS_H
+
+#include "lib/container/smartlist.h"
+#include "lib/metrics/metrics_common.h"
+
+/** Metrics key for each reported metrics. This key is also used as an index in
+ * the base_metrics array. */
+typedef enum {
+ /** Number of OOM invocation. */
+ RELAY_METRICS_NUM_OOM_BYTES,
+ /** Number of onionskines handled. */
+ RELAY_METRICS_NUM_ONIONSKINS,
+ /** Number of sockets. */
+ RELAY_METRICS_NUM_SOCKETS,
+ /** Number of global connection rate limit. */
+ RELAY_METRICS_NUM_GLOBAL_RW_LIMIT,
+ /** Number of DNS queries. */
+ RELAY_METRICS_NUM_DNS,
+ /** Number of DNS query errors. */
+ RELAY_METRICS_NUM_DNS_ERRORS,
+ /** Number of TCP exhaustion reached. */
+ RELAY_METRICS_NUM_TCP_EXHAUSTION,
+ /** Connections counters (always going up). */
+ RELAY_METRICS_CONN_COUNTERS,
+ /** Connections gauges. */
+ RELAY_METRICS_CONN_GAUGES,
+ /** Number of streams. */
+ RELAY_METRICS_NUM_STREAMS,
+ /** Congestion control counters. */
+ RELAY_METRICS_CC_COUNTERS,
+ /** Congestion control gauges. */
+ RELAY_METRICS_CC_GAUGES,
+ /** Denial of Service defenses subsystem. */
+ RELAY_METRICS_NUM_DOS,
+ /** Denial of Service defenses subsystem. */
+ RELAY_METRICS_NUM_TRAFFIC,
+ /** Relay flags. */
+ RELAY_METRICS_RELAY_FLAGS,
+ /** Numer of circuits. */
+ RELAY_METRICS_NUM_CIRCUITS,
+} relay_metrics_key_t;
+
+/** The metadata of a relay metric. */
+typedef struct relay_metrics_entry_t {
+ /* Metric key used as a static array index. */
+ relay_metrics_key_t key;
+ /* Metric type. */
+ metrics_type_t type;
+ /* Metrics output name. */
+ const char *name;
+ /* Metrics output help comment. */
+ const char *help;
+ /* Update value function. */
+ void (*fill_fn)(void);
+} relay_metrics_entry_t;
+
+/* Init. */
+void relay_metrics_init(void);
+void relay_metrics_free(void);
+
+/* Accessors. */
+const smartlist_t *relay_metrics_get_stores(void);
+
+#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 a917d90f1a..dd9be4e36f 100644
--- a/src/feature/relay/relay_periodic.c
+++ b/src/feature/relay/relay_periodic.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -164,9 +164,7 @@ check_for_reachability_bw_callback(time_t now, const or_options_t *options)
(have_completed_a_circuit() || !any_predicted_circuits(now)) &&
!net_is_disabled()) {
if (get_uptime() < TIMEOUT_UNTIL_UNREACHABILITY_COMPLAINT) {
- router_do_reachability_checks(1, dirport_reachability_count==0);
- if (++dirport_reachability_count > 5)
- dirport_reachability_count = 0;
+ router_do_reachability_checks();
return EARLY_CHECK_REACHABILITY_INTERVAL;
} else {
/* If we haven't checked for 12 hours and our bandwidth estimate is
@@ -221,7 +219,7 @@ reachability_warnings_callback(time_t now, const or_options_t *options)
tor_asprintf(&where4, "%s:%d", address4, me->ipv4_orport);
if (!v6_ok)
tor_asprintf(&where6, "[%s]:%d", address6, me->ipv6_orport);
- const char *opt_and = (!v4_ok && !v6_ok) ? "and" : "";
+ const char *opt_and = (!v4_ok && !v6_ok) ? " and " : "";
/* IPv4 reachability test worked but not the IPv6. We will _not_
* publish the descriptor if our IPv6 was configured. We will if it
@@ -264,20 +262,6 @@ reachability_warnings_callback(time_t now, const or_options_t *options)
tor_free(address4);
tor_free(address6);
}
-
- if (me && !router_dirport_seems_reachable(options)) {
- char *address4 = tor_addr_to_str_dup(&me->ipv4_addr);
- log_warn(LD_CONFIG,
- "Your server (%s:%d) has not managed to confirm that its "
- "DirPort is reachable. Relays do not publish descriptors "
- "until their ORPort and DirPort are reachable. Please check "
- "your firewalls, ports, address, /etc/hosts file, etc.",
- address4, me->ipv4_dirport);
- control_event_server_status(LOG_WARN,
- "REACHABILITY_FAILED DIRADDRESS=%s:%d",
- address4, me->ipv4_dirport);
- tor_free(address4);
- }
}
return TIMEOUT_UNTIL_UNREACHABILITY_COMPLAINT;
diff --git a/src/feature/relay/relay_periodic.h b/src/feature/relay/relay_periodic.h
index ccda9a440b..d3a13ec835 100644
--- a/src/feature/relay/relay_periodic.h
+++ b/src/feature/relay/relay_periodic.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/relay/relay_stub.c b/src/feature/relay/relay_stub.c
index 283aaf6e49..c7ac9093fa 100644
--- a/src/feature/relay/relay_stub.c
+++ b/src/feature/relay/relay_stub.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/relay/relay_sys.c b/src/feature/relay/relay_sys.c
index 2e90740925..9c43734b84 100644
--- a/src/feature/relay/relay_sys.c
+++ b/src/feature/relay/relay_sys.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -14,6 +14,7 @@
#include "feature/relay/dns.h"
#include "feature/relay/ext_orport.h"
+#include "feature/relay/relay_metrics.h"
#include "feature/relay/onion_queue.h"
#include "feature/relay/relay_periodic.h"
#include "feature/relay/relay_sys.h"
@@ -25,6 +26,7 @@
static int
subsys_relay_initialize(void)
{
+ relay_metrics_init();
relay_register_periodic_events();
return 0;
}
@@ -37,6 +39,7 @@ subsys_relay_shutdown(void)
clear_pending_onions();
routerkeys_free_all();
router_free_all();
+ relay_metrics_free();
}
const struct subsys_fns_t sys_relay = {
@@ -46,4 +49,6 @@ const struct subsys_fns_t sys_relay = {
.level = RELAY_SUBSYS_LEVEL,
.initialize = subsys_relay_initialize,
.shutdown = subsys_relay_shutdown,
+
+ .get_metrics = relay_metrics_get_stores,
};
diff --git a/src/feature/relay/relay_sys.h b/src/feature/relay/relay_sys.h
index 9bad93a6c9..2c5edb53dd 100644
--- a/src/feature/relay/relay_sys.h
+++ b/src/feature/relay/relay_sys.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/relay/router.c b/src/feature/relay/router.c
index fb26309dfa..bc98fd985c 100644
--- a/src/feature/relay/router.c
+++ b/src/feature/relay/router.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define ROUTER_PRIVATE
@@ -1357,8 +1357,8 @@ decide_to_advertise_dir_impl(const or_options_t *options,
int
router_should_advertise_dirport(const or_options_t *options, uint16_t dir_port)
{
- /* supports_tunnelled_dir_requests is not relevant, pass 0 */
- return decide_to_advertise_dir_impl(options, dir_port, 0) ? dir_port : 0;
+ /* Only authorities should advertise a DirPort now. */
+ return authdir_mode(options) ? dir_port : 0;
}
/** Front-end to decide_to_advertise_dir_impl(): return 0 if we don't want to
@@ -3062,6 +3062,15 @@ router_dump_router_to_string(routerinfo_t *router,
smartlist_add_strdup(chunks, "tunnelled-dir-server\n");
}
+ /* Overload general information. */
+ if (options->OverloadStatistics) {
+ char *overload_general = rep_hist_get_overload_general_line();
+
+ if (overload_general) {
+ smartlist_add(chunks, overload_general);
+ }
+ }
+
/* Sign the descriptor with Ed25519 */
if (emit_ed_sigs) {
smartlist_add_strdup(chunks, "router-sig-ed25519 ");
@@ -3345,6 +3354,11 @@ extrainfo_dump_to_string_stats_helper(smartlist_t *chunks,
"hidserv-stats-end", now, &contents) > 0) {
smartlist_add(chunks, contents);
}
+ if (options->HiddenServiceStatistics &&
+ load_stats_file("stats"PATH_SEPARATOR"hidserv-v3-stats",
+ "hidserv-v3-stats-end", now, &contents) > 0) {
+ smartlist_add(chunks, contents);
+ }
if (options->EntryStatistics &&
load_stats_file("stats"PATH_SEPARATOR"entry-stats",
"entry-stats-end", now, &contents) > 0) {
@@ -3370,6 +3384,12 @@ extrainfo_dump_to_string_stats_helper(smartlist_t *chunks,
if (contents)
smartlist_add(chunks, contents);
}
+ if (options->OverloadStatistics) {
+ contents = rep_hist_get_overload_stats_lines();
+ if (contents) {
+ smartlist_add(chunks, contents);
+ }
+ }
/* bridge statistics */
if (should_record_bridge_info(options)) {
const char *bridge_stats = geoip_get_bridge_stats_extrainfo(now);
diff --git a/src/feature/relay/router.h b/src/feature/relay/router.h
index 9556a66e68..b5b5a1fffa 100644
--- a/src/feature/relay/router.h
+++ b/src/feature/relay/router.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/relay/routerkeys.c b/src/feature/relay/routerkeys.c
index 116f0b4e3d..64ec38ed19 100644
--- a/src/feature/relay/routerkeys.c
+++ b/src/feature/relay/routerkeys.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2020, The Tor Project, Inc. */
+/* Copyright (c) 2014-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/relay/routerkeys.h b/src/feature/relay/routerkeys.h
index 1fb5d724e9..7b6d80773c 100644
--- a/src/feature/relay/routerkeys.h
+++ b/src/feature/relay/routerkeys.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2020, The Tor Project, Inc. */
+/* Copyright (c) 2014-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/relay/routermode.c b/src/feature/relay/routermode.c
index c4d8792b5b..15f66de8ba 100644
--- a/src/feature/relay/routermode.c
+++ b/src/feature/relay/routermode.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/relay/routermode.h b/src/feature/relay/routermode.h
index 6d7404968d..2c22c23c0f 100644
--- a/src/feature/relay/routermode.h
+++ b/src/feature/relay/routermode.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/relay/selftest.c b/src/feature/relay/selftest.c
index 46b4b20ffc..399b6bca6e 100644
--- a/src/feature/relay/selftest.c
+++ b/src/feature/relay/selftest.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -49,15 +49,12 @@
static bool have_orport_for_family(int family);
static void inform_testing_reachability(const tor_addr_t *addr,
- uint16_t port,
- bool is_dirport);
+ uint16_t port);
/** Whether we can reach our IPv4 ORPort from the outside. */
static bool can_reach_or_port_ipv4 = false;
/** Whether we can reach our IPv6 ORPort from the outside. */
static bool can_reach_or_port_ipv6 = false;
-/** Whether we can reach our DirPort from the outside. */
-static bool can_reach_dir_port = false;
/** Has informed_testing_reachable logged a message about testing our IPv4
* ORPort? */
@@ -65,18 +62,14 @@ static bool have_informed_testing_or_port_ipv4 = false;
/** Has informed_testing_reachable logged a message about testing our IPv6
* ORPort? */
static bool have_informed_testing_or_port_ipv6 = false;
-/** Has informed_testing_reachable logged a message about testing our
- * DirPort? */
-static bool have_informed_testing_dir_port = false;
/** Forget what we have learned about our reachability status. */
void
router_reset_reachability(void)
{
- can_reach_or_port_ipv4 = can_reach_or_port_ipv6 = can_reach_dir_port = false;
+ can_reach_or_port_ipv4 = can_reach_or_port_ipv6 = false;
have_informed_testing_or_port_ipv4 =
- have_informed_testing_or_port_ipv6 =
- have_informed_testing_dir_port = false;
+ have_informed_testing_or_port_ipv6 = false;
}
/** Return 1 if we won't do reachability checks, because:
@@ -137,31 +130,20 @@ router_orport_seems_reachable(const or_options_t *options,
return true;
}
-/** Return 0 if we need to do a DirPort reachability check, because:
- * - no reachability check has been done yet, or
- * - we've initiated reachability checks, but none have succeeded.
- * Return 1 if we don't need to do a DirPort reachability check, because:
- * - we've seen a successful reachability check, or
- * - there is no DirPort set, or
- * - AssumeReachable is set, or
- * - We're a dir auth (see ticket #40287), or
- * - the network is disabled.
- */
+/** Relay DirPorts are no longer used (though authorities are). In either case,
+ * reachability self test is done anymore, since network re-entry towards an
+ * authority DirPort is not allowed. Thus, consider it always reachable. */
int
router_dirport_seems_reachable(const or_options_t *options)
{
- int reach_checks_disabled = router_reachability_checks_disabled(options) ||
- authdir_mode(options) ||
- !options->DirPort_set;
- return reach_checks_disabled ||
- can_reach_dir_port;
+ (void) options;
+ return 1;
}
-/** See if we currently believe our ORPort or DirPort to be
- * unreachable. If so, return 1 else return 0.
- */
+/** See if we currently believe our ORPort to be unreachable. If so, return 1
+ * else return 0. */
static int
-router_should_check_reachability(int test_or, int test_dir)
+router_should_check_reachability(void)
{
const routerinfo_t *me = router_get_my_routerinfo();
const or_options_t *options = get_options();
@@ -174,15 +156,13 @@ router_should_check_reachability(int test_or, int test_dir)
options->StrictNodes) {
/* If we've excluded ourself, and StrictNodes is set, we can't test
* ourself. */
- if (test_or || test_dir) {
#define SELF_EXCLUDED_WARN_INTERVAL 3600
- static ratelim_t warning_limit=RATELIM_INIT(SELF_EXCLUDED_WARN_INTERVAL);
- log_fn_ratelim(&warning_limit, LOG_WARN, LD_CIRC,
- "Can't perform self-tests for this relay: we have "
- "listed ourself in ExcludeNodes, and StrictNodes is set. "
- "We cannot learn whether we are usable, and will not "
- "be able to advertise ourself.");
- }
+ static ratelim_t warning_limit=RATELIM_INIT(SELF_EXCLUDED_WARN_INTERVAL);
+ log_fn_ratelim(&warning_limit, LOG_WARN, LD_CIRC,
+ "Can't perform self-tests for this relay: we have "
+ "listed ourself in ExcludeNodes, and StrictNodes is set. "
+ "We cannot learn whether we are usable, and will not "
+ "be able to advertise ourself.");
return 0;
}
return 1;
@@ -248,7 +228,10 @@ extend_info_from_router(const routerinfo_t *r, int family)
info = extend_info_new(r->nickname, r->cache_info.identity_digest,
ed_id_key,
rsa_pubkey, r->onion_curve25519_pkey,
- &ap.addr, ap.port);
+ &ap.addr, ap.port,
+ /* TODO-324: Should self-test circuits use
+ * congestion control? */
+ NULL, false);
crypto_pk_free(rsa_pubkey);
return info;
}
@@ -274,6 +257,11 @@ router_do_orport_reachability_checks(const routerinfo_t *me,
if (ei) {
const char *family_name = fmt_af_family(family);
const tor_addr_port_t *ap = extend_info_get_orport(ei, family);
+ if (BUG(!ap)) {
+ /* Not much we can do here to recover apart from screaming loudly. */
+ extend_info_free(ei);
+ return;
+ }
log_info(LD_CIRC, "Testing %s of my %s ORPort: %s.",
!orport_reachable ? "reachability" : "bandwidth",
family_name, fmt_addrport_ap(ap));
@@ -281,8 +269,8 @@ router_do_orport_reachability_checks(const routerinfo_t *me,
if (!orport_reachable) {
/* Only log if we are actually doing a reachability test to learn if our
* ORPort is reachable. Else, this prints a log notice if we are simply
- * opening a bandwidth testing circuit even do we are reachable. */
- inform_testing_reachability(&ap->addr, ap->port, false);
+ * opening a bandwidth testing circuit even though we are reachable. */
+ inform_testing_reachability(&ap->addr, ap->port);
}
circuit_launch_by_extend_info(CIRCUIT_PURPOSE_TESTING, ei,
@@ -293,53 +281,15 @@ router_do_orport_reachability_checks(const routerinfo_t *me,
}
}
-/** Launch a self-testing circuit, and ask an exit to connect to our DirPort.
- * <b>me</b> is our own routerinfo.
+/** Some time has passed, or we just got new directory information. See if we
+ * currently believe our ORPort to be unreachable. If so, launch a new test
+ * for it.
*
- * Relays don't advertise IPv6 DirPorts, so this function only supports IPv4.
- *
- * See router_do_reachability_checks() for details. */
-static void
-router_do_dirport_reachability_checks(const routerinfo_t *me)
-{
- tor_addr_port_t my_dirport;
- tor_addr_copy(&my_dirport.addr, &me->ipv4_addr);
- my_dirport.port = me->ipv4_dirport;
-
- /* If there is already a pending connection, don't open another one. */
- if (!connection_get_by_type_addr_port_purpose(
- CONN_TYPE_DIR,
- &my_dirport.addr, my_dirport.port,
- DIR_PURPOSE_FETCH_SERVERDESC)) {
- /* ask myself, via tor, for my server descriptor. */
- directory_request_t *req =
- directory_request_new(DIR_PURPOSE_FETCH_SERVERDESC);
- directory_request_set_dir_addr_port(req, &my_dirport);
- directory_request_set_directory_id_digest(req,
- me->cache_info.identity_digest);
- /* ask via an anon circuit, connecting to our dirport. */
- directory_request_set_indirection(req, DIRIND_ANON_DIRPORT);
- directory_request_set_resource(req, "authority.z");
- directory_initiate_request(req);
- directory_request_free(req);
-
- inform_testing_reachability(&my_dirport.addr, my_dirport.port, true);
- }
-}
-
-/** Some time has passed, or we just got new directory information.
- * See if we currently believe our ORPort or DirPort to be
- * unreachable. If so, launch a new test for it.
- *
- * For ORPort, we simply try making a circuit that ends at ourselves.
- * Success is noticed in onionskin_answer().
- *
- * For DirPort, we make a connection via Tor to our DirPort and ask
- * for our own server descriptor.
- * Success is noticed in connection_dir_client_reached_eof().
+ * For ORPort, we simply try making a circuit that ends at ourselves. Success
+ * is noticed in onionskin_answer().
*/
void
-router_do_reachability_checks(int test_or, int test_dir)
+router_do_reachability_checks(void)
{
const routerinfo_t *me = router_get_my_routerinfo();
const or_options_t *options = get_options();
@@ -348,45 +298,34 @@ router_do_reachability_checks(int test_or, int test_dir)
int orport_reachable_v6 =
router_orport_seems_reachable(options, AF_INET6);
- if (router_should_check_reachability(test_or, test_dir)) {
+ if (router_should_check_reachability()) {
bool need_testing = !circuit_enough_testing_circs();
/* At the moment, tor relays believe that they are reachable when they
* receive any create cell on an inbound connection, if the address
* family is correct.
*/
- if (test_or && (!orport_reachable_v4 || need_testing)) {
+ if (!orport_reachable_v4 || need_testing) {
router_do_orport_reachability_checks(me, AF_INET, orport_reachable_v4);
}
- if (test_or && (!orport_reachable_v6 || need_testing)) {
+ if (!orport_reachable_v6 || need_testing) {
router_do_orport_reachability_checks(me, AF_INET6, orport_reachable_v6);
}
-
- if (test_dir && !router_dirport_seems_reachable(options)) {
- router_do_dirport_reachability_checks(me);
- }
}
}
/** Log a message informing the user that we are testing a port for
* reachability, if we have not already logged such a message.
*
- * If @a is_dirport is true, then the port is a DirPort; otherwise it is an
- * ORPort.
- *
* Calls to router_reset_reachability() will reset our view of whether we have
* logged this message for a given port. */
static void
-inform_testing_reachability(const tor_addr_t *addr,
- uint16_t port,
- bool is_dirport)
+inform_testing_reachability(const tor_addr_t *addr, uint16_t port)
{
if (!router_get_my_routerinfo())
return;
bool *have_informed_ptr;
- if (is_dirport) {
- have_informed_ptr = &have_informed_testing_dir_port;
- } else if (tor_addr_family(addr) == AF_INET) {
+ if (tor_addr_family(addr) == AF_INET) {
have_informed_ptr = &have_informed_testing_or_port_ipv4;
} else {
have_informed_ptr = &have_informed_testing_or_port_ipv6;
@@ -401,18 +340,16 @@ inform_testing_reachability(const tor_addr_t *addr,
char addr_buf[TOR_ADDRPORT_BUF_LEN];
strlcpy(addr_buf, fmt_addrport(addr, port), sizeof(addr_buf));
- const char *control_addr_type = is_dirport ? "DIRADDRESS" : "ORADDRESS";
- const char *port_type = is_dirport ? "DirPort" : "ORPort";
const char *afname = fmt_af_family(tor_addr_family(addr));
control_event_server_status(LOG_NOTICE,
- "CHECKING_REACHABILITY %s=%s",
- control_addr_type, addr_buf);
+ "CHECKING_REACHABILITY ORADDRESS=%s",
+ addr_buf);
- log_notice(LD_OR, "Now checking whether %s %s %s is reachable... "
+ log_notice(LD_OR, "Now checking whether %s ORPort %s is reachable... "
"(this may take up to %d minutes -- look for log "
"messages indicating success)",
- afname, port_type, addr_buf,
+ afname, addr_buf,
TIMEOUT_UNTIL_UNREACHABILITY_COMPLAINT/60);
*have_informed_ptr = true;
@@ -426,8 +363,7 @@ static bool
ready_to_publish(const or_options_t *options)
{
return options->PublishServerDescriptor_ != NO_DIRINFO &&
- router_dirport_seems_reachable(options) &&
- router_all_orports_seem_reachable(options);
+ router_all_orports_seem_reachable(options);
}
/** Annotate that we found our ORPort reachable with a given address
@@ -481,40 +417,6 @@ router_orport_found_reachable(int family)
}
}
-/** Annotate that we found our DirPort reachable. */
-void
-router_dirport_found_reachable(void)
-{
- const routerinfo_t *me = router_get_my_routerinfo();
- const or_options_t *options = get_options();
-
- if (!can_reach_dir_port && me) {
- char *address = tor_addr_to_str_dup(&me->ipv4_addr);
-
- if (!address)
- return;
-
- can_reach_dir_port = true;
- log_notice(LD_DIRSERV,"Self-testing indicates your DirPort is reachable "
- "from the outside. Excellent.%s",
- ready_to_publish(options) ?
- " Publishing server descriptor." : "");
-
- if (router_should_advertise_dirport(options, me->ipv4_dirport)) {
- mark_my_descriptor_dirty("DirPort found reachable");
- /* This is a significant enough change to upload immediately,
- * at least in a test network */
- if (options->TestingTorNetwork == 1) {
- reschedule_descriptor_update_check();
- }
- }
- control_event_server_status(LOG_NOTICE,
- "REACHABILITY_SUCCEEDED DIRADDRESS=%s:%d",
- address, me->ipv4_dirport);
- tor_free(address);
- }
-}
-
/** We have enough testing circuits open. Send a bunch of "drop"
* cells down each of them, to exercise our bandwidth.
*
@@ -530,8 +432,8 @@ router_perform_bandwidth_test(int num_circs, time_t now)
origin_circuit_t *circ = NULL;
log_notice(LD_OR,"Performing bandwidth self-test...done.");
- while ((circ = circuit_get_next_by_pk_and_purpose(circ, NULL,
- CIRCUIT_PURPOSE_TESTING))) {
+ while ((circ = circuit_get_next_by_purpose(circ,
+ CIRCUIT_PURPOSE_TESTING))) {
/* dump cells_per_circuit drop cells onto this circ */
int i = cells_per_circuit;
if (circ->base_.state != CIRCUIT_STATE_OPEN)
diff --git a/src/feature/relay/selftest.h b/src/feature/relay/selftest.h
index e09c0e7898..b662fe0fb0 100644
--- a/src/feature/relay/selftest.h
+++ b/src/feature/relay/selftest.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -23,11 +23,10 @@ int router_orport_seems_reachable(
int router_dirport_seems_reachable(
const struct or_options_t *options);
-void router_do_reachability_checks(int test_or, int test_dir);
+void router_do_reachability_checks(void);
void router_perform_bandwidth_test(int num_circs, time_t now);
void router_orport_found_reachable(int family);
-void router_dirport_found_reachable(void);
void router_reset_reachability(void);
@@ -41,10 +40,8 @@ void router_reset_reachability(void);
((void)(opts), 0)
static inline void
-router_do_reachability_checks(int test_or, int test_dir)
+router_do_reachability_checks(void)
{
- (void)test_or;
- (void)test_dir;
tor_assert_nonfatal_unreached();
}
static inline void
@@ -55,16 +52,16 @@ router_perform_bandwidth_test(int num_circs, time_t now)
tor_assert_nonfatal_unreached();
}
static inline int
-inform_testing_reachability(void)
+inform_testing_reachability(const tor_addr_t *addr, uint16_t port)
{
+ (void) addr;
+ (void) port;
tor_assert_nonfatal_unreached();
return 0;
}
#define router_orport_found_reachable() \
STMT_NIL
-#define router_dirport_found_reachable() \
- STMT_NIL
#define router_reset_reachability() \
STMT_NIL
diff --git a/src/feature/relay/transport_config.c b/src/feature/relay/transport_config.c
index 7dcce70e30..23e024fbee 100644
--- a/src/feature/relay/transport_config.c
+++ b/src/feature/relay/transport_config.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/relay/transport_config.h b/src/feature/relay/transport_config.h
index 6d956d9af1..6cf3142fb0 100644
--- a/src/feature/relay/transport_config.h
+++ b/src/feature/relay/transport_config.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/rend/feature_rend.md b/src/feature/rend/feature_rend.md
deleted file mode 100644
index bfd8ae3dbc..0000000000
--- a/src/feature/rend/feature_rend.md
+++ /dev/null
@@ -1,7 +0,0 @@
-@dir /feature/rend
-@brief feature/rend: version 2 (old) hidden services
-
-This directory implements the v2 onion service protocol,
-as specified in
-[rend-spec-v2.txt](https://gitweb.torproject.org/torspec.git/tree/rend-spec-v2.txt).
-
diff --git a/src/feature/rend/include.am b/src/feature/rend/include.am
index fb12439a90..d338869b5b 100644
--- a/src/feature/rend/include.am
+++ b/src/feature/rend/include.am
@@ -1,22 +1,10 @@
# ADD_C_FILE: INSERT SOURCES HERE.
LIBTOR_APP_A_SOURCES += \
- src/feature/rend/rendcache.c \
- src/feature/rend/rendclient.c \
src/feature/rend/rendcommon.c \
- src/feature/rend/rendmid.c \
- src/feature/rend/rendparse.c \
- src/feature/rend/rendservice.c
+ src/feature/rend/rendmid.c
# ADD_C_FILE: INSERT HEADERS HERE.
noinst_HEADERS += \
- src/feature/rend/rend_authorized_client_st.h \
- src/feature/rend/rend_encoded_v2_service_descriptor_st.h \
- src/feature/rend/rend_intro_point_st.h \
- src/feature/rend/rend_service_descriptor_st.h \
- src/feature/rend/rendcache.h \
- src/feature/rend/rendclient.h \
src/feature/rend/rendcommon.h \
- src/feature/rend/rendmid.h \
- src/feature/rend/rendparse.h \
- src/feature/rend/rendservice.h
+ src/feature/rend/rendmid.h
diff --git a/src/feature/rend/rend_authorized_client_st.h b/src/feature/rend/rend_authorized_client_st.h
deleted file mode 100644
index c6a6676da9..0000000000
--- a/src/feature/rend/rend_authorized_client_st.h
+++ /dev/null
@@ -1,22 +0,0 @@
-/* Copyright (c) 2001 Matej Pfajfar.
- * Copyright (c) 2001-2004, Roger Dingledine.
- * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
-/* See LICENSE for licensing information */
-
-/**
- * @file rend_authorized_client_st.h
- * @brief Hidden-service authorized client structure.
- **/
-
-#ifndef REND_AUTHORIZED_CLIENT_ST_H
-#define REND_AUTHORIZED_CLIENT_ST_H
-
-/** Hidden-service side configuration of client authorization. */
-struct rend_authorized_client_t {
- char *client_name;
- uint8_t descriptor_cookie[REND_DESC_COOKIE_LEN];
- crypto_pk_t *client_key;
-};
-
-#endif /* !defined(REND_AUTHORIZED_CLIENT_ST_H) */
diff --git a/src/feature/rend/rend_encoded_v2_service_descriptor_st.h b/src/feature/rend/rend_encoded_v2_service_descriptor_st.h
deleted file mode 100644
index fea91b876a..0000000000
--- a/src/feature/rend/rend_encoded_v2_service_descriptor_st.h
+++ /dev/null
@@ -1,21 +0,0 @@
-/* Copyright (c) 2001 Matej Pfajfar.
- * Copyright (c) 2001-2004, Roger Dingledine.
- * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
-/* See LICENSE for licensing information */
-
-/**
- * @file rend_encoded_v2_service_descriptor_st.h
- * @brief Encoded v2 HS descriptor structure.
- **/
-
-#ifndef REND_ENCODED_V2_SERVICE_DESCRIPTOR_ST_H
-#define REND_ENCODED_V2_SERVICE_DESCRIPTOR_ST_H
-
-/** ASCII-encoded v2 hidden service descriptor. */
-struct rend_encoded_v2_service_descriptor_t {
- char desc_id[DIGEST_LEN]; /**< Descriptor ID. */
- char *desc_str; /**< Descriptor string. */
-};
-
-#endif /* !defined(REND_ENCODED_V2_SERVICE_DESCRIPTOR_ST_H) */
diff --git a/src/feature/rend/rend_intro_point_st.h b/src/feature/rend/rend_intro_point_st.h
deleted file mode 100644
index 4f0aa01523..0000000000
--- a/src/feature/rend/rend_intro_point_st.h
+++ /dev/null
@@ -1,81 +0,0 @@
-/* Copyright (c) 2001 Matej Pfajfar.
- * Copyright (c) 2001-2004, Roger Dingledine.
- * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
-/* See LICENSE for licensing information */
-
-/**
- * @file rend_intro_point_st.h
- * @brief v2 hidden service introduction point structure.
- **/
-
-#ifndef REND_INTRO_POINT_ST_H
-#define REND_INTRO_POINT_ST_H
-
-struct replaycache_t;
-struct crypto_pk_t;
-
-/** Introduction point information. Used both in rend_service_t (on
- * the service side) and in rend_service_descriptor_t (on both the
- * client and service side). */
-struct rend_intro_point_t {
- extend_info_t *extend_info; /**< Extend info for connecting to this
- * introduction point via a multi-hop path. */
- struct crypto_pk_t *intro_key; /**< Introduction key that replaces the
- * service key, if this descriptor is V2. */
-
- /** (Client side only) Flag indicating that a timeout has occurred
- * after sending an INTRODUCE cell to this intro point. After a
- * timeout, an intro point should not be tried again during the same
- * hidden service connection attempt, but it may be tried again
- * during a future connection attempt. */
- unsigned int timed_out : 1;
-
- /** (Client side only) The number of times we have failed to build a
- * circuit to this intro point for some reason other than our
- * circuit-build timeout. See also MAX_INTRO_POINT_REACHABILITY_FAILURES. */
- unsigned int unreachable_count : 3;
-
- /** (Service side only) Flag indicating that this intro point was
- * included in the last HS descriptor we generated. */
- unsigned int listed_in_last_desc : 1;
-
- /** (Service side only) A replay cache recording the RSA-encrypted parts
- * of INTRODUCE2 cells this intro point's circuit has received. This is
- * used to prevent replay attacks. */
- struct replaycache_t *accepted_intro_rsa_parts;
-
- /** (Service side only) Count of INTRODUCE2 cells accepted from this
- * intro point.
- */
- int accepted_introduce2_count;
-
- /** (Service side only) Maximum number of INTRODUCE2 cells that this IP
- * will accept. This is a random value between
- * INTRO_POINT_MIN_LIFETIME_INTRODUCTIONS and
- * INTRO_POINT_MAX_LIFETIME_INTRODUCTIONS. */
- int max_introductions;
-
- /** (Service side only) The time at which this intro point was first
- * published, or -1 if this intro point has not yet been
- * published. */
- time_t time_published;
-
- /** (Service side only) The time at which this intro point should
- * (start to) expire, or -1 if we haven't decided when this intro
- * point should expire. */
- time_t time_to_expire;
-
- /** (Service side only) The amount of circuit creation we've made to this
- * intro point. This is incremented every time we do a circuit relaunch on
- * this object which is triggered when the circuit dies but the node is
- * still in the consensus. After MAX_INTRO_POINT_CIRCUIT_RETRIES, we give
- * up on it. */
- unsigned int circuit_retries;
-
- /** (Service side only) Set if this intro point has an established circuit
- * and unset if it doesn't. */
- unsigned int circuit_established:1;
-};
-
-#endif /* !defined(REND_INTRO_POINT_ST_H) */
diff --git a/src/feature/rend/rend_service_descriptor_st.h b/src/feature/rend/rend_service_descriptor_st.h
deleted file mode 100644
index 80c8034f46..0000000000
--- a/src/feature/rend/rend_service_descriptor_st.h
+++ /dev/null
@@ -1,38 +0,0 @@
-/* Copyright (c) 2001 Matej Pfajfar.
- * Copyright (c) 2001-2004, Roger Dingledine.
- * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
-/* See LICENSE for licensing information */
-
-/**
- * @file rend_service_descriptor_st.h
- * @brief Parsed v2 HS descriptor structure.
- **/
-
-#ifndef REND_SERVICE_DESCRIPTOR_ST_H
-#define REND_SERVICE_DESCRIPTOR_ST_H
-
-#define REND_PROTOCOL_VERSION_BITMASK_WIDTH 16
-
-/** Information used to connect to a hidden service. Used on both the
- * service side and the client side. */
-struct rend_service_descriptor_t {
- crypto_pk_t *pk; /**< This service's public key. */
- int version; /**< Version of the descriptor format: 0 or 2. */
- time_t timestamp; /**< Time when the descriptor was generated. */
- /** Bitmask: which introduce/rendezvous protocols are supported?
- * (We allow bits '0', '1', '2' and '3' to be set.) */
- unsigned protocols : REND_PROTOCOL_VERSION_BITMASK_WIDTH;
- /** List of the service's introduction points. Elements are removed if
- * introduction attempts fail. */
- smartlist_t *intro_nodes;
- /** Has descriptor been uploaded to all hidden service directories? */
- int all_uploads_performed;
- /** List of hidden service directories to which an upload request for
- * this descriptor could be sent. Smartlist exists only when at least one
- * of the previous upload requests failed (otherwise it's not important
- * to know which uploads succeeded and which not). */
- smartlist_t *successful_uploads;
-};
-
-#endif /* !defined(REND_SERVICE_DESCRIPTOR_ST_H) */
diff --git a/src/feature/rend/rendcache.c b/src/feature/rend/rendcache.c
deleted file mode 100644
index 04f6390a7f..0000000000
--- a/src/feature/rend/rendcache.c
+++ /dev/null
@@ -1,1029 +0,0 @@
-/* Copyright (c) 2015-2020, The Tor Project, Inc. */
-/* See LICENSE for licensing information */
-
-/**
- * \file rendcache.c
- * \brief Hidden service descriptor cache.
- **/
-
-#define RENDCACHE_PRIVATE
-#include "feature/rend/rendcache.h"
-
-#include "app/config/config.h"
-#include "feature/stats/rephist.h"
-#include "feature/nodelist/routerlist.h"
-#include "feature/rend/rendcommon.h"
-#include "feature/rend/rendparse.h"
-
-#include "core/or/extend_info_st.h"
-#include "feature/rend/rend_intro_point_st.h"
-#include "feature/rend/rend_service_descriptor_st.h"
-
-#include "lib/ctime/di_ops.h"
-
-/** Map from service id (as generated by rend_get_service_id) to
- * rend_cache_entry_t. */
-STATIC strmap_t *rend_cache = NULL;
-
-/** Map from service id to rend_cache_entry_t; only for hidden services. */
-static strmap_t *rend_cache_local_service = NULL;
-
-/** Map from descriptor id to rend_cache_entry_t; only for hidden service
- * directories. */
-STATIC digestmap_t *rend_cache_v2_dir = NULL;
-
-/** (Client side only) Map from service id to rend_cache_failure_t. This
- * cache is used to track intro point(IP) failures so we know when to keep
- * or discard a new descriptor we just fetched. Here is a description of the
- * cache behavior.
- *
- * Every time tor discards an IP (ex: receives a NACK), we add an entry to
- * this cache noting the identity digest of the IP and it's failure type for
- * the service ID. The reason we indexed this cache by service ID is to
- * differentiate errors that can occur only for a specific service like a
- * NACK for instance. It applies for one but maybe not for the others.
- *
- * Once a service descriptor is fetched and considered valid, each IP is
- * looked up in this cache and if present, it is discarded from the fetched
- * descriptor. At the end, all IP(s) in the cache, for a specific service
- * ID, that were NOT present in the descriptor are removed from this cache.
- * Which means that if at least one IP was not in this cache, thus usable,
- * it's considered a new descriptor so we keep it. Else, if all IPs were in
- * this cache, we discard the descriptor as it's considered unusable.
- *
- * Once a descriptor is removed from the rend cache or expires, the entry
- * in this cache is also removed for the service ID.
- *
- * This scheme allows us to not rely on the descriptor's timestamp (which
- * is rounded down to the hour) to know if we have a newer descriptor. We
- * only rely on the usability of intro points from an internal state. */
-STATIC strmap_t *rend_cache_failure = NULL;
-
-/* DOCDOC */
-STATIC size_t rend_cache_total_allocation = 0;
-
-/** Initializes the service descriptor cache.
-*/
-void
-rend_cache_init(void)
-{
- rend_cache = strmap_new();
- rend_cache_v2_dir = digestmap_new();
- rend_cache_local_service = strmap_new();
- rend_cache_failure = strmap_new();
-}
-
-/** Return the approximate number of bytes needed to hold <b>e</b>. */
-STATIC size_t
-rend_cache_entry_allocation(const rend_cache_entry_t *e)
-{
- if (!e)
- return 0;
-
- /* This doesn't count intro_nodes or key size */
- return sizeof(*e) + e->len + sizeof(*e->parsed);
-}
-
-/* DOCDOC */
-size_t
-rend_cache_get_total_allocation(void)
-{
- return rend_cache_total_allocation;
-}
-
-/** Decrement the total bytes attributed to the rendezvous cache by n. */
-void
-rend_cache_decrement_allocation(size_t n)
-{
- static int have_underflowed = 0;
-
- if (rend_cache_total_allocation >= n) {
- rend_cache_total_allocation -= n;
- } else {
- rend_cache_total_allocation = 0;
- if (! have_underflowed) {
- have_underflowed = 1;
- log_warn(LD_BUG, "Underflow in rend_cache_decrement_allocation");
- }
- }
-}
-
-/** Increase the total bytes attributed to the rendezvous cache by n. */
-void
-rend_cache_increment_allocation(size_t n)
-{
- static int have_overflowed = 0;
- if (rend_cache_total_allocation <= SIZE_MAX - n) {
- rend_cache_total_allocation += n;
- } else {
- rend_cache_total_allocation = SIZE_MAX;
- if (! have_overflowed) {
- have_overflowed = 1;
- log_warn(LD_BUG, "Overflow in rend_cache_increment_allocation");
- }
- }
-}
-
-/** Helper: free a rend cache failure intro object. */
-STATIC void
-rend_cache_failure_intro_entry_free_(rend_cache_failure_intro_t *entry)
-{
- if (entry == NULL) {
- return;
- }
- tor_free(entry);
-}
-
-static void
-rend_cache_failure_intro_entry_free_void(void *entry)
-{
- rend_cache_failure_intro_entry_free_(entry);
-}
-
-/** Allocate a rend cache failure intro object and return it. <b>failure</b>
- * is set into the object. This function can not fail. */
-STATIC rend_cache_failure_intro_t *
-rend_cache_failure_intro_entry_new(rend_intro_point_failure_t failure)
-{
- rend_cache_failure_intro_t *entry = tor_malloc(sizeof(*entry));
- entry->failure_type = failure;
- entry->created_ts = time(NULL);
- return entry;
-}
-
-/** Helper: free a rend cache failure object. */
-STATIC void
-rend_cache_failure_entry_free_(rend_cache_failure_t *entry)
-{
- if (entry == NULL) {
- return;
- }
-
- /* Free and remove every intro failure object. */
- digestmap_free(entry->intro_failures,
- rend_cache_failure_intro_entry_free_void);
-
- tor_free(entry);
-}
-
-/** Helper: deallocate a rend_cache_failure_t. (Used with strmap_free(),
- * which requires a function pointer whose argument is void*). */
-STATIC void
-rend_cache_failure_entry_free_void(void *entry)
-{
- rend_cache_failure_entry_free_(entry);
-}
-
-/** Allocate a rend cache failure object and return it. This function can
- * not fail. */
-STATIC rend_cache_failure_t *
-rend_cache_failure_entry_new(void)
-{
- rend_cache_failure_t *entry = tor_malloc(sizeof(*entry));
- entry->intro_failures = digestmap_new();
- return entry;
-}
-
-/** Remove failure cache entry for the service ID in the given descriptor
- * <b>desc</b>. */
-STATIC void
-rend_cache_failure_remove(rend_service_descriptor_t *desc)
-{
- char service_id[REND_SERVICE_ID_LEN_BASE32 + 1];
- rend_cache_failure_t *entry;
-
- if (desc == NULL) {
- return;
- }
- if (rend_get_service_id(desc->pk, service_id) < 0) {
- return;
- }
- entry = strmap_get_lc(rend_cache_failure, service_id);
- if (entry != NULL) {
- strmap_remove_lc(rend_cache_failure, service_id);
- rend_cache_failure_entry_free(entry);
- }
-}
-
-/** Helper: free storage held by a single service descriptor cache entry. */
-STATIC void
-rend_cache_entry_free_(rend_cache_entry_t *e)
-{
- if (!e)
- return;
- rend_cache_decrement_allocation(rend_cache_entry_allocation(e));
- /* We are about to remove a descriptor from the cache so remove the entry
- * in the failure cache. */
- rend_cache_failure_remove(e->parsed);
- rend_service_descriptor_free(e->parsed);
- tor_free(e->desc);
- tor_free(e);
-}
-
-/** Helper: deallocate a rend_cache_entry_t. (Used with strmap_free(), which
- * requires a function pointer whose argument is void*). */
-static void
-rend_cache_entry_free_void(void *p)
-{
- rend_cache_entry_free_(p);
-}
-
-/** Check if a failure cache entry exists for the given intro point. */
-bool
-rend_cache_intro_failure_exists(const char *service_id,
- const uint8_t *intro_identity)
-{
- tor_assert(service_id);
- tor_assert(intro_identity);
-
- return cache_failure_intro_lookup(intro_identity, service_id, NULL);
-}
-
-/** Free all storage held by the service descriptor cache. */
-void
-rend_cache_free_all(void)
-{
- strmap_free(rend_cache, rend_cache_entry_free_void);
- digestmap_free(rend_cache_v2_dir, rend_cache_entry_free_void);
- strmap_free(rend_cache_local_service, rend_cache_entry_free_void);
- strmap_free(rend_cache_failure, rend_cache_failure_entry_free_void);
- rend_cache = NULL;
- rend_cache_v2_dir = NULL;
- rend_cache_local_service = NULL;
- rend_cache_failure = NULL;
- rend_cache_total_allocation = 0;
-}
-
-/** Remove all entries that re REND_CACHE_FAILURE_MAX_AGE old. This is
- * called every second.
- *
- * We have to clean these regularly else if for whatever reasons an hidden
- * service goes offline and a client tries to connect to it during that
- * time, a failure entry is created and the client will be unable to connect
- * for a while even though the service has return online. */
-void
-rend_cache_failure_clean(time_t now)
-{
- time_t cutoff = now - REND_CACHE_FAILURE_MAX_AGE;
- STRMAP_FOREACH_MODIFY(rend_cache_failure, key,
- rend_cache_failure_t *, ent) {
- /* Free and remove every intro failure object that match the cutoff. */
- DIGESTMAP_FOREACH_MODIFY(ent->intro_failures, ip_key,
- rend_cache_failure_intro_t *, ip_ent) {
- if (ip_ent->created_ts < cutoff) {
- rend_cache_failure_intro_entry_free(ip_ent);
- MAP_DEL_CURRENT(ip_key);
- }
- } DIGESTMAP_FOREACH_END;
- /* If the entry is now empty of intro point failures, remove it. */
- if (digestmap_isempty(ent->intro_failures)) {
- rend_cache_failure_entry_free(ent);
- MAP_DEL_CURRENT(key);
- }
- } STRMAP_FOREACH_END;
-}
-
-/** Removes all old entries from the client or service descriptor cache.
-*/
-void
-rend_cache_clean(time_t now, rend_cache_type_t cache_type)
-{
- strmap_iter_t *iter;
- const char *key;
- void *val;
- rend_cache_entry_t *ent;
- time_t cutoff = now - REND_CACHE_MAX_AGE - REND_CACHE_MAX_SKEW;
- strmap_t *cache = NULL;
-
- if (cache_type == REND_CACHE_TYPE_CLIENT) {
- cache = rend_cache;
- } else if (cache_type == REND_CACHE_TYPE_SERVICE) {
- cache = rend_cache_local_service;
- }
- tor_assert(cache);
-
- for (iter = strmap_iter_init(cache); !strmap_iter_done(iter); ) {
- strmap_iter_get(iter, &key, &val);
- ent = (rend_cache_entry_t*)val;
- if (ent->parsed->timestamp < cutoff) {
- iter = strmap_iter_next_rmv(cache, iter);
- rend_cache_entry_free(ent);
- } else {
- iter = strmap_iter_next(cache, iter);
- }
- }
-}
-
-/** Remove ALL entries from the rendezvous service descriptor cache.
-*/
-void
-rend_cache_purge(void)
-{
- if (rend_cache) {
- log_info(LD_REND, "Purging HS v2 descriptor cache");
- strmap_free(rend_cache, rend_cache_entry_free_void);
- }
- rend_cache = strmap_new();
-}
-
-/** Remove ALL entries from the failure cache. This is also called when a
- * NEWNYM signal is received. */
-void
-rend_cache_failure_purge(void)
-{
- if (rend_cache_failure) {
- log_info(LD_REND, "Purging HS v2 failure cache");
- strmap_free(rend_cache_failure, rend_cache_failure_entry_free_void);
- }
- rend_cache_failure = strmap_new();
-}
-
-/** Lookup the rend failure cache using a relay identity digest in
- * <b>identity</b> which has DIGEST_LEN bytes and service ID <b>service_id</b>
- * which is a null-terminated string. If @a intro_entry is provided, then it
- * is set to the entry on success, and to NULL on failure.
- * Return 1 iff found else 0. */
-STATIC int
-cache_failure_intro_lookup(const uint8_t *identity, const char *service_id,
- rend_cache_failure_intro_t **intro_entry)
-{
- rend_cache_failure_t *elem;
- rend_cache_failure_intro_t *intro_elem;
-
- tor_assert(rend_cache_failure);
-
- if (intro_entry) {
- *intro_entry = NULL;
- }
-
- /* Lookup descriptor and return it. */
- elem = strmap_get_lc(rend_cache_failure, service_id);
- if (elem == NULL) {
- goto not_found;
- }
- intro_elem = digestmap_get(elem->intro_failures, (char *) identity);
- if (intro_elem == NULL) {
- goto not_found;
- }
- if (intro_entry) {
- *intro_entry = intro_elem;
- }
- return 1;
- not_found:
- return 0;
-}
-
-/** Allocate a new cache failure intro object and copy the content from
- * <b>entry</b> to this newly allocated object. Return it. */
-static rend_cache_failure_intro_t *
-cache_failure_intro_dup(const rend_cache_failure_intro_t *entry)
-{
- rend_cache_failure_intro_t *ent_dup =
- rend_cache_failure_intro_entry_new(entry->failure_type);
- ent_dup->created_ts = entry->created_ts;
- return ent_dup;
-}
-
-/** Add an intro point failure to the failure cache using the relay
- * <b>identity</b> and service ID <b>service_id</b>. Record the
- * <b>failure</b> in that object. */
-STATIC void
-cache_failure_intro_add(const uint8_t *identity, const char *service_id,
- rend_intro_point_failure_t failure)
-{
- rend_cache_failure_t *fail_entry;
- rend_cache_failure_intro_t *entry, *old_entry;
-
- /* Make sure we have a failure object for this service ID and if not,
- * create it with this new intro failure entry. */
- fail_entry = strmap_get_lc(rend_cache_failure, service_id);
- if (fail_entry == NULL) {
- fail_entry = rend_cache_failure_entry_new();
- /* Add failure entry to global rend failure cache. */
- strmap_set_lc(rend_cache_failure, service_id, fail_entry);
- }
- entry = rend_cache_failure_intro_entry_new(failure);
- old_entry = digestmap_set(fail_entry->intro_failures,
- (char *) identity, entry);
- /* This _should_ be NULL, but in case it isn't, free it. */
- rend_cache_failure_intro_entry_free(old_entry);
-}
-
-/** Using a parsed descriptor <b>desc</b>, check if the introduction points
- * are present in the failure cache and if so they are removed from the
- * descriptor and kept into the failure cache. Then, each intro points that
- * are NOT in the descriptor but in the failure cache for the given
- * <b>service_id</b> are removed from the failure cache. */
-STATIC void
-validate_intro_point_failure(const rend_service_descriptor_t *desc,
- const char *service_id)
-{
- rend_cache_failure_t *new_entry, *cur_entry;
- /* New entry for the service ID that will be replacing the one in the
- * failure cache since we have a new descriptor. In the case where all
- * intro points are removed, we are assured that the new entry is the same
- * as the current one. */
- new_entry = tor_malloc(sizeof(*new_entry));
- new_entry->intro_failures = digestmap_new();
-
- tor_assert(desc);
-
- SMARTLIST_FOREACH_BEGIN(desc->intro_nodes, rend_intro_point_t *, intro) {
- int found;
- rend_cache_failure_intro_t *entry;
- const uint8_t *identity =
- (uint8_t *) intro->extend_info->identity_digest;
-
- found = cache_failure_intro_lookup(identity, service_id, &entry);
- if (found) {
- /* Dup here since it will be freed at the end when removing the
- * original entry in the cache. */
- rend_cache_failure_intro_t *ent_dup = cache_failure_intro_dup(entry);
- /* This intro point is in our cache, discard it from the descriptor
- * because chances are that it's unusable. */
- SMARTLIST_DEL_CURRENT(desc->intro_nodes, intro);
- /* Keep it for our new entry. */
- digestmap_set(new_entry->intro_failures, (char *) identity, ent_dup);
- /* Only free it when we're done looking at it. */
- rend_intro_point_free(intro);
- continue;
- }
- } SMARTLIST_FOREACH_END(intro);
-
- /* Swap the failure entry in the cache and free the current one. */
- cur_entry = strmap_get_lc(rend_cache_failure, service_id);
- if (cur_entry != NULL) {
- rend_cache_failure_entry_free(cur_entry);
- }
- strmap_set_lc(rend_cache_failure, service_id, new_entry);
-}
-
-/** Note down an intro failure in the rend failure cache using the type of
- * failure in <b>failure</b> for the relay identity digest in
- * <b>identity</b> and service ID <b>service_id</b>. If an entry already
- * exists in the cache, the failure type is changed with <b>failure</b>. */
-void
-rend_cache_intro_failure_note(rend_intro_point_failure_t failure,
- const uint8_t *identity,
- const char *service_id)
-{
- int found;
- rend_cache_failure_intro_t *entry;
-
- found = cache_failure_intro_lookup(identity, service_id, &entry);
- if (!found) {
- cache_failure_intro_add(identity, service_id, failure);
- } else {
- /* Replace introduction point failure with this one. */
- entry->failure_type = failure;
- }
-}
-
-/** Remove all old v2 descriptors and those for which this hidden service
- * directory is not responsible for any more. The cutoff is the time limit for
- * which we want to keep the cache entry. In other words, any entry created
- * before will be removed. */
-size_t
-rend_cache_clean_v2_descs_as_dir(time_t cutoff)
-{
- digestmap_iter_t *iter;
- size_t bytes_removed = 0;
-
- for (iter = digestmap_iter_init(rend_cache_v2_dir);
- !digestmap_iter_done(iter); ) {
- const char *key;
- void *val;
- rend_cache_entry_t *ent;
- digestmap_iter_get(iter, &key, &val);
- ent = val;
- if (ent->parsed->timestamp < cutoff) {
- char key_base32[REND_DESC_ID_V2_LEN_BASE32 + 1];
- base32_encode(key_base32, sizeof(key_base32), key, DIGEST_LEN);
- log_info(LD_REND, "Removing descriptor with ID '%s' from cache",
- safe_str_client(key_base32));
- bytes_removed += rend_cache_entry_allocation(ent);
- iter = digestmap_iter_next_rmv(rend_cache_v2_dir, iter);
- rend_cache_entry_free(ent);
- } else {
- iter = digestmap_iter_next(rend_cache_v2_dir, iter);
- }
- }
-
- return bytes_removed;
-}
-
-/** Lookup in the client cache the given service ID <b>query</b> for
- * <b>version</b>.
- *
- * Return 0 if found and if <b>e</b> is non NULL, set it with the entry
- * found. Else, a negative value is returned and <b>e</b> is untouched.
- * -EINVAL means that <b>query</b> is not a valid service id.
- * -ENOENT means that no entry in the cache was found. */
-int
-rend_cache_lookup_entry(const char *query, int version, rend_cache_entry_t **e)
-{
- int ret = 0;
- char key[REND_SERVICE_ID_LEN_BASE32 + 2]; /* <version><query>\0 */
- rend_cache_entry_t *entry = NULL;
- static const int default_version = 2;
-
- tor_assert(query);
-
- /* This is possible if we are in the shutdown process and the cache was
- * freed while some other subsystem might do a lookup to the cache for
- * cleanup reasons such HS circuit cleanup for instance. */
- if (!rend_cache) {
- ret = -ENOENT;
- goto end;
- }
-
- if (!rend_valid_v2_service_id(query)) {
- ret = -EINVAL;
- goto end;
- }
-
- switch (version) {
- case 0:
- log_warn(LD_REND, "Cache lookup of a v0 renddesc is deprecated.");
- break;
- case 2:
- /* Default is version 2. */
- default:
- tor_snprintf(key, sizeof(key), "%d%s", default_version, query);
- entry = strmap_get_lc(rend_cache, key);
- break;
- }
- if (!entry) {
- ret = -ENOENT;
- goto end;
- }
- tor_assert(entry->parsed && entry->parsed->intro_nodes);
-
- if (e) {
- *e = entry;
- }
-
- end:
- return ret;
-}
-
-/*
- * Lookup the v2 service descriptor with the service ID <b>query</b> in the
- * local service descriptor cache. Return 0 if found and if <b>e</b> is
- * non NULL, set it with the entry found. Else, a negative value is returned
- * and <b>e</b> is untouched.
- * -EINVAL means that <b>query</b> is not a valid service id.
- * -ENOENT means that no entry in the cache was found. */
-int
-rend_cache_lookup_v2_desc_as_service(const char *query, rend_cache_entry_t **e)
-{
- int ret = 0;
- rend_cache_entry_t *entry = NULL;
-
- tor_assert(rend_cache_local_service);
- tor_assert(query);
-
- if (!rend_valid_v2_service_id(query)) {
- ret = -EINVAL;
- goto end;
- }
-
- /* Lookup descriptor and return. */
- entry = strmap_get_lc(rend_cache_local_service, query);
- if (!entry) {
- ret = -ENOENT;
- goto end;
- }
-
- if (e) {
- *e = entry;
- }
-
- end:
- return ret;
-}
-
-/** Lookup the v2 service descriptor with base32-encoded <b>desc_id</b> and
- * copy the pointer to it to *<b>desc</b>. Return 1 on success, 0 on
- * well-formed-but-not-found, and -1 on failure.
- */
-int
-rend_cache_lookup_v2_desc_as_dir(const char *desc_id, const char **desc)
-{
- rend_cache_entry_t *e;
- char desc_id_digest[DIGEST_LEN];
- tor_assert(rend_cache_v2_dir);
- if (base32_decode(desc_id_digest, DIGEST_LEN,
- desc_id, REND_DESC_ID_V2_LEN_BASE32) != DIGEST_LEN) {
- log_fn(LOG_PROTOCOL_WARN, LD_REND,
- "Rejecting v2 rendezvous descriptor request -- descriptor ID "
- "has wrong length or illegal characters: %s",
- safe_str(desc_id));
- return -1;
- }
- /* Lookup descriptor and return. */
- e = digestmap_get(rend_cache_v2_dir, desc_id_digest);
- if (e) {
- *desc = e->desc;
- e->last_served = approx_time();
- return 1;
- }
- return 0;
-}
-
-/** Parse the v2 service descriptor(s) in <b>desc</b> and store it/them to the
- * local rend cache. Don't attempt to decrypt the included list of introduction
- * points (as we don't have a descriptor cookie for it).
- *
- * If we have a newer descriptor with the same ID, ignore this one.
- * If we have an older descriptor with the same ID, replace it.
- *
- * Return 0 on success, or -1 if we couldn't parse any of them.
- *
- * We should only call this function for public (e.g. non bridge) relays.
- */
-int
-rend_cache_store_v2_desc_as_dir(const char *desc)
-{
- const or_options_t *options = get_options();
- rend_service_descriptor_t *parsed;
- char desc_id[DIGEST_LEN];
- char *intro_content;
- size_t intro_size;
- size_t encoded_size;
- char desc_id_base32[REND_DESC_ID_V2_LEN_BASE32 + 1];
- int number_parsed = 0, number_stored = 0;
- const char *current_desc = desc;
- const char *next_desc;
- rend_cache_entry_t *e;
- time_t now = time(NULL);
- tor_assert(rend_cache_v2_dir);
- tor_assert(desc);
- while (rend_parse_v2_service_descriptor(&parsed, desc_id, &intro_content,
- &intro_size, &encoded_size,
- &next_desc, current_desc, 1) >= 0) {
- number_parsed++;
- /* We don't care about the introduction points. */
- tor_free(intro_content);
- /* For pretty log statements. */
- base32_encode(desc_id_base32, sizeof(desc_id_base32),
- desc_id, DIGEST_LEN);
- /* Is descriptor too old? */
- if (parsed->timestamp < now - REND_CACHE_MAX_AGE-REND_CACHE_MAX_SKEW) {
- log_info(LD_REND, "Service descriptor with desc ID %s is too old.",
- safe_str(desc_id_base32));
- goto skip;
- }
- /* Is descriptor too far in the future? */
- if (parsed->timestamp > now + REND_CACHE_MAX_SKEW) {
- log_info(LD_REND, "Service descriptor with desc ID %s is too far in the "
- "future.",
- safe_str(desc_id_base32));
- goto skip;
- }
- /* Do we already have a newer descriptor? */
- e = digestmap_get(rend_cache_v2_dir, desc_id);
- if (e && e->parsed->timestamp > parsed->timestamp) {
- log_info(LD_REND, "We already have a newer service descriptor with the "
- "same desc ID %s and version.",
- safe_str(desc_id_base32));
- goto skip;
- }
- /* Do we already have this descriptor? */
- if (e && !strcmp(desc, e->desc)) {
- log_info(LD_REND, "We already have this service descriptor with desc "
- "ID %s.", safe_str(desc_id_base32));
- goto skip;
- }
- /* Store received descriptor. */
- if (!e) {
- e = tor_malloc_zero(sizeof(rend_cache_entry_t));
- digestmap_set(rend_cache_v2_dir, desc_id, e);
- /* Treat something just uploaded as having been served a little
- * while ago, so that flooding with new descriptors doesn't help
- * too much.
- */
- e->last_served = approx_time() - 3600;
- } else {
- rend_cache_decrement_allocation(rend_cache_entry_allocation(e));
- rend_service_descriptor_free(e->parsed);
- tor_free(e->desc);
- }
- e->parsed = parsed;
- e->desc = tor_strndup(current_desc, encoded_size);
- e->len = encoded_size;
- rend_cache_increment_allocation(rend_cache_entry_allocation(e));
- log_info(LD_REND, "Successfully stored service descriptor with desc ID "
- "'%s' and len %d.",
- safe_str(desc_id_base32), (int)encoded_size);
- /* Statistics: Note down this potentially new HS. */
- if (options->HiddenServiceStatistics) {
- rep_hist_stored_maybe_new_hs(e->parsed->pk);
- }
-
- number_stored++;
- goto advance;
- skip:
- rend_service_descriptor_free(parsed);
- advance:
- /* advance to next descriptor, if available. */
- current_desc = next_desc;
- /* check if there is a next descriptor. */
- if (!current_desc ||
- strcmpstart(current_desc, "rendezvous-service-descriptor "))
- break;
- }
- if (!number_parsed) {
- log_info(LD_REND, "Could not parse any descriptor.");
- return -1;
- }
- log_info(LD_REND, "Parsed %d and added %d descriptor%s.",
- number_parsed, number_stored, number_stored != 1 ? "s" : "");
- return 0;
-}
-
-/** Parse the v2 service descriptor in <b>desc</b> and store it to the
-* local service rend cache. Don't attempt to decrypt the included list of
-* introduction points.
-*
-* If we have a newer descriptor with the same ID, ignore this one.
-* If we have an older descriptor with the same ID, replace it.
-*
-* Return 0 on success, or -1 if we couldn't understand the descriptor.
-*/
-int
-rend_cache_store_v2_desc_as_service(const char *desc)
-{
- rend_service_descriptor_t *parsed = NULL;
- char desc_id[DIGEST_LEN];
- char *intro_content = NULL;
- size_t intro_size;
- size_t encoded_size;
- const char *next_desc;
- char service_id[REND_SERVICE_ID_LEN_BASE32+1];
- rend_cache_entry_t *e;
- int retval = -1;
- tor_assert(rend_cache_local_service);
- tor_assert(desc);
-
- /* Parse the descriptor. */
- if (rend_parse_v2_service_descriptor(&parsed, desc_id, &intro_content,
- &intro_size, &encoded_size,
- &next_desc, desc, 0) < 0) {
- log_warn(LD_REND, "Could not parse descriptor.");
- goto err;
- }
- /* Compute service ID from public key. */
- if (rend_get_service_id(parsed->pk, service_id)<0) {
- log_warn(LD_REND, "Couldn't compute service ID.");
- goto err;
- }
-
- /* Do we already have a newer descriptor? Allow new descriptors with a
- rounded timestamp equal to or newer than the current descriptor */
- e = (rend_cache_entry_t*) strmap_get_lc(rend_cache_local_service,
- service_id);
- if (e && e->parsed->timestamp > parsed->timestamp) {
- log_info(LD_REND, "We already have a newer service descriptor for "
- "service ID %s.", safe_str_client(service_id));
- goto okay;
- }
- /* We don't care about the introduction points. */
- tor_free(intro_content);
- if (!e) {
- e = tor_malloc_zero(sizeof(rend_cache_entry_t));
- strmap_set_lc(rend_cache_local_service, service_id, e);
- } else {
- rend_cache_decrement_allocation(rend_cache_entry_allocation(e));
- rend_service_descriptor_free(e->parsed);
- tor_free(e->desc);
- }
- e->parsed = parsed;
- e->desc = tor_malloc_zero(encoded_size + 1);
- strlcpy(e->desc, desc, encoded_size + 1);
- e->len = encoded_size;
- rend_cache_increment_allocation(rend_cache_entry_allocation(e));
- log_debug(LD_REND,"Successfully stored rend desc '%s', len %d.",
- safe_str_client(service_id), (int)encoded_size);
- return 0;
-
- okay:
- retval = 0;
-
- err:
- rend_service_descriptor_free(parsed);
- tor_free(intro_content);
- return retval;
-}
-
-/** Parse the v2 service descriptor in <b>desc</b>, decrypt the included list
- * of introduction points with <b>descriptor_cookie</b> (which may also be
- * <b>NULL</b> if decryption is not necessary), and store the descriptor to
- * the local cache under its version and service id.
- *
- * If we have a newer v2 descriptor with the same ID, ignore this one.
- * If we have an older descriptor with the same ID, replace it.
- * If the descriptor's service ID does not match
- * <b>rend_query</b>-\>onion_address, reject it.
- *
- * If the descriptor's descriptor ID doesn't match <b>desc_id_base32</b>,
- * reject it.
- *
- * Return 0 on success, or -1 if we rejected the descriptor.
- * If entry is not NULL, set it with the cache entry pointer of the descriptor.
- */
-int
-rend_cache_store_v2_desc_as_client(const char *desc,
- const char *desc_id_base32,
- const rend_data_t *rend_query,
- rend_cache_entry_t **entry)
-{
- /*XXXX this seems to have a bit of duplicate code with
- * rend_cache_store_v2_desc_as_dir(). Fix that. */
- /* Though having similar elements, both functions were separated on
- * purpose:
- * - dirs don't care about encoded/encrypted introduction points, clients
- * do.
- * - dirs store descriptors in a separate cache by descriptor ID, whereas
- * clients store them by service ID; both caches are different data
- * structures and have different access methods.
- * - dirs store a descriptor only if they are responsible for its ID,
- * clients do so in every way (because they have requested it before).
- * - dirs can process multiple concatenated descriptors which is required
- * for replication, whereas clients only accept a single descriptor.
- * Thus, combining both methods would result in a lot of if statements
- * which probably would not improve, but worsen code readability. -KL */
- rend_service_descriptor_t *parsed = NULL;
- char desc_id[DIGEST_LEN];
- char *intro_content = NULL;
- size_t intro_size;
- size_t encoded_size;
- const char *next_desc;
- time_t now = time(NULL);
- char key[REND_SERVICE_ID_LEN_BASE32+2];
- char service_id[REND_SERVICE_ID_LEN_BASE32+1];
- char want_desc_id[DIGEST_LEN];
- rend_cache_entry_t *e;
- int retval = -1;
- rend_data_v2_t *rend_data = TO_REND_DATA_V2(rend_query);
-
- tor_assert(rend_cache);
- tor_assert(desc);
- tor_assert(desc_id_base32);
- memset(want_desc_id, 0, sizeof(want_desc_id));
- if (entry) {
- *entry = NULL;
- }
- if (base32_decode(want_desc_id, sizeof(want_desc_id),
- desc_id_base32, strlen(desc_id_base32)) !=
- sizeof(want_desc_id)) {
- log_warn(LD_BUG, "Couldn't decode base32 %s for descriptor id.",
- escaped_safe_str_client(desc_id_base32));
- goto err;
- }
- /* Parse the descriptor. */
- if (rend_parse_v2_service_descriptor(&parsed, desc_id, &intro_content,
- &intro_size, &encoded_size,
- &next_desc, desc, 0) < 0) {
- log_warn(LD_REND, "Could not parse descriptor.");
- goto err;
- }
- /* Compute service ID from public key. */
- if (rend_get_service_id(parsed->pk, service_id)<0) {
- log_warn(LD_REND, "Couldn't compute service ID.");
- goto err;
- }
- if (rend_data->onion_address[0] != '\0' &&
- strcmp(rend_data->onion_address, service_id)) {
- log_warn(LD_REND, "Received service descriptor for service ID %s; "
- "expected descriptor for service ID %s.",
- service_id, safe_str(rend_data->onion_address));
- goto err;
- }
- if (tor_memneq(desc_id, want_desc_id, DIGEST_LEN)) {
- log_warn(LD_REND, "Received service descriptor for %s with incorrect "
- "descriptor ID.", service_id);
- goto err;
- }
-
- /* Decode/decrypt introduction points. */
- if (intro_content && intro_size > 0) {
- int n_intro_points;
- if (rend_data->auth_type != REND_NO_AUTH &&
- !safe_mem_is_zero(rend_data->descriptor_cookie,
- sizeof(rend_data->descriptor_cookie))) {
- char *ipos_decrypted = NULL;
- size_t ipos_decrypted_size;
- if (rend_decrypt_introduction_points(&ipos_decrypted,
- &ipos_decrypted_size,
- rend_data->descriptor_cookie,
- intro_content,
- intro_size) < 0) {
- log_warn(LD_REND, "Failed to decrypt introduction points. We are "
- "probably unable to parse the encoded introduction points.");
- } else {
- /* Replace encrypted with decrypted introduction points. */
- log_info(LD_REND, "Successfully decrypted introduction points.");
- tor_free(intro_content);
- intro_content = ipos_decrypted;
- intro_size = ipos_decrypted_size;
- }
- }
- n_intro_points = rend_parse_introduction_points(parsed, intro_content,
- intro_size);
- if (n_intro_points <= 0) {
- log_warn(LD_REND, "Failed to parse introduction points. Either the "
- "service has published a corrupt descriptor or you have "
- "provided invalid authorization data.");
- goto err;
- } else if (n_intro_points > MAX_INTRO_POINTS) {
- log_warn(LD_REND, "Found too many introduction points on a hidden "
- "service descriptor for %s. This is probably a (misguided) "
- "attempt to improve reliability, but it could also be an "
- "attempt to do a guard enumeration attack. Rejecting.",
- safe_str_client(service_id));
-
- goto err;
- }
- } else {
- log_info(LD_REND, "Descriptor does not contain any introduction points.");
- parsed->intro_nodes = smartlist_new();
- }
- /* We don't need the encoded/encrypted introduction points any longer. */
- tor_free(intro_content);
- /* Is descriptor too old? */
- if (parsed->timestamp < now - REND_CACHE_MAX_AGE-REND_CACHE_MAX_SKEW) {
- log_warn(LD_REND, "Service descriptor with service ID %s is too old.",
- safe_str_client(service_id));
- goto err;
- }
- /* Is descriptor too far in the future? */
- if (parsed->timestamp > now + REND_CACHE_MAX_SKEW) {
- log_warn(LD_REND, "Service descriptor with service ID %s is too far in "
- "the future.", safe_str_client(service_id));
- goto err;
- }
- /* Do we have the same exact copy already in our cache? */
- tor_snprintf(key, sizeof(key), "2%s", service_id);
- e = (rend_cache_entry_t*) strmap_get_lc(rend_cache, key);
- if (e && !strcmp(desc, e->desc)) {
- log_info(LD_REND,"We already have this service descriptor %s.",
- safe_str_client(service_id));
- goto okay;
- }
- /* Verify that we are not replacing an older descriptor. It's important to
- * avoid an evil HSDir serving old descriptor. We validate if the
- * timestamp is greater than and not equal because it's a rounded down
- * timestamp to the hour so if the descriptor changed in the same hour,
- * the rend cache failure will tell us if we have a new descriptor. */
- if (e && e->parsed->timestamp > parsed->timestamp) {
- log_info(LD_REND, "We already have a new enough service descriptor for "
- "service ID %s with the same desc ID and version.",
- safe_str_client(service_id));
- goto okay;
- }
- /* Lookup our failure cache for intro point that might be unusable. */
- validate_intro_point_failure(parsed, service_id);
- /* It's now possible that our intro point list is empty, which means that
- * this descriptor is useless to us because intro points have all failed
- * somehow before. Discard the descriptor. */
- if (smartlist_len(parsed->intro_nodes) == 0) {
- log_info(LD_REND, "Service descriptor with service ID %s has no "
- "usable intro points. Discarding it.",
- safe_str_client(service_id));
- goto err;
- }
- /* Now either purge the current one and replace its content or create a
- * new one and add it to the rend cache. */
- if (!e) {
- e = tor_malloc_zero(sizeof(rend_cache_entry_t));
- strmap_set_lc(rend_cache, key, e);
- } else {
- rend_cache_decrement_allocation(rend_cache_entry_allocation(e));
- rend_cache_failure_remove(e->parsed);
- rend_service_descriptor_free(e->parsed);
- tor_free(e->desc);
- }
- e->parsed = parsed;
- e->desc = tor_malloc_zero(encoded_size + 1);
- strlcpy(e->desc, desc, encoded_size + 1);
- e->len = encoded_size;
- rend_cache_increment_allocation(rend_cache_entry_allocation(e));
- log_debug(LD_REND,"Successfully stored rend desc '%s', len %d.",
- safe_str_client(service_id), (int)encoded_size);
- if (entry) {
- *entry = e;
- }
- return 0;
-
- okay:
- if (entry) {
- *entry = e;
- }
- retval = 0;
-
- err:
- rend_service_descriptor_free(parsed);
- tor_free(intro_content);
- return retval;
-}
diff --git a/src/feature/rend/rendcache.h b/src/feature/rend/rendcache.h
deleted file mode 100644
index 45410610b4..0000000000
--- a/src/feature/rend/rendcache.h
+++ /dev/null
@@ -1,132 +0,0 @@
-/* Copyright (c) 2015-2020, The Tor Project, Inc. */
-/* See LICENSE for licensing information */
-
-/**
- * \file rendcache.h
- * \brief Header file for rendcache.c
- **/
-
-#ifndef TOR_RENDCACHE_H
-#define TOR_RENDCACHE_H
-
-#include "core/or/or.h"
-#include "feature/rend/rendcommon.h"
-
-/** How old do we let hidden service descriptors get before discarding
- * them as too old? */
-#define REND_CACHE_MAX_AGE (2*24*60*60)
-/** How wrong do we assume our clock may be when checking whether hidden
- * services are too old or too new? */
-#define REND_CACHE_MAX_SKEW (24*60*60)
-/** How old do we keep an intro point failure entry in the failure cache? */
-#define REND_CACHE_FAILURE_MAX_AGE (5*60)
-
-/* Do not allow more than this many introduction points in a hidden service
- * descriptor */
-#define MAX_INTRO_POINTS 10
-
-/** A cached rendezvous descriptor. */
-typedef struct rend_cache_entry_t {
- size_t len; /**< Length of <b>desc</b> */
- time_t last_served; /**< When did we last write this one to somebody?
- * (HSDir only) */
- char *desc; /**< Service descriptor */
- rend_service_descriptor_t *parsed; /**< Parsed value of 'desc' */
-} rend_cache_entry_t;
-
-/* Introduction point failure type. */
-typedef struct rend_cache_failure_intro_t {
- /* When this intro point failure occurred thus we allocated this object and
- * cache it. */
- time_t created_ts;
- rend_intro_point_failure_t failure_type;
-} rend_cache_failure_intro_t;
-
-/** Cache failure object indexed by service ID. */
-typedef struct rend_cache_failure_t {
- /* Contains rend_cache_failure_intro_t indexed by identity digest. */
- digestmap_t *intro_failures;
-} rend_cache_failure_t;
-
-typedef enum {
- REND_CACHE_TYPE_CLIENT = 1,
- REND_CACHE_TYPE_SERVICE = 2,
-} rend_cache_type_t;
-
-/* Return maximum lifetime in seconds of a cache entry. */
-static inline time_t
-rend_cache_max_entry_lifetime(void)
-{
- return REND_CACHE_MAX_AGE + REND_CACHE_MAX_SKEW;
-}
-
-void rend_cache_init(void);
-void rend_cache_clean(time_t now, rend_cache_type_t cache_type);
-void rend_cache_failure_clean(time_t now);
-size_t rend_cache_clean_v2_descs_as_dir(time_t cutoff);
-void rend_cache_purge(void);
-void rend_cache_free_all(void);
-int rend_cache_lookup_entry(const char *query, int version,
- rend_cache_entry_t **entry_out);
-int rend_cache_lookup_v2_desc_as_service(const char *query,
- rend_cache_entry_t **entry_out);
-int rend_cache_lookup_v2_desc_as_dir(const char *query, const char **desc);
-
-int rend_cache_store_v2_desc_as_dir(const char *desc);
-int rend_cache_store_v2_desc_as_service(const char *desc);
-int rend_cache_store_v2_desc_as_client(const char *desc,
- const char *desc_id_base32,
- const rend_data_t *rend_query,
- rend_cache_entry_t **entry);
-size_t rend_cache_get_total_allocation(void);
-
-bool rend_cache_intro_failure_exists(const char *service_id,
- const uint8_t *intro_identity);
-void rend_cache_intro_failure_note(rend_intro_point_failure_t failure,
- const uint8_t *identity,
- const char *service_id);
-void rend_cache_failure_purge(void);
-void rend_cache_decrement_allocation(size_t n);
-void rend_cache_increment_allocation(size_t n);
-
-#ifdef RENDCACHE_PRIVATE
-
-STATIC size_t rend_cache_entry_allocation(const rend_cache_entry_t *e);
-STATIC void rend_cache_entry_free_(rend_cache_entry_t *e);
-#define rend_cache_entry_free(e) \
- FREE_AND_NULL(rend_cache_entry_t, rend_cache_entry_free_, (e))
-STATIC void rend_cache_failure_intro_entry_free_(rend_cache_failure_intro_t
- *entry);
-#define rend_cache_failure_intro_entry_free(e) \
- FREE_AND_NULL(rend_cache_failure_intro_t, \
- rend_cache_failure_intro_entry_free_, (e))
-STATIC void rend_cache_failure_entry_free_(rend_cache_failure_t *entry);
-#define rend_cache_failure_entry_free(e) \
- FREE_AND_NULL(rend_cache_failure_t, \
- rend_cache_failure_entry_free_, (e))
-STATIC int cache_failure_intro_lookup(const uint8_t *identity,
- const char *service_id,
- rend_cache_failure_intro_t
- **intro_entry);
-STATIC rend_cache_failure_intro_t *rend_cache_failure_intro_entry_new(
- rend_intro_point_failure_t failure);
-STATIC rend_cache_failure_t *rend_cache_failure_entry_new(void);
-STATIC void rend_cache_failure_remove(rend_service_descriptor_t *desc);
-STATIC void cache_failure_intro_add(const uint8_t *identity,
- const char *service_id,
- rend_intro_point_failure_t failure);
-STATIC void validate_intro_point_failure(const rend_service_descriptor_t *desc,
- const char *service_id);
-
-STATIC void rend_cache_failure_entry_free_void(void *entry);
-
-#ifdef TOR_UNIT_TESTS
-extern strmap_t *rend_cache;
-extern strmap_t *rend_cache_failure;
-extern digestmap_t *rend_cache_v2_dir;
-extern size_t rend_cache_total_allocation;
-#endif /* defined(TOR_UNIT_TESTS) */
-#endif /* defined(RENDCACHE_PRIVATE) */
-
-#endif /* !defined(TOR_RENDCACHE_H) */
-
diff --git a/src/feature/rend/rendclient.c b/src/feature/rend/rendclient.c
deleted file mode 100644
index 3dda7cd46d..0000000000
--- a/src/feature/rend/rendclient.c
+++ /dev/null
@@ -1,1322 +0,0 @@
-/* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
-/* See LICENSE for licensing information */
-
-/**
- * \file rendclient.c
- * \brief Client code to access location-hidden services.
- **/
-
-#include "core/or/or.h"
-#include "app/config/config.h"
-#include "core/mainloop/connection.h"
-#include "core/mainloop/mainloop.h"
-#include "core/or/circuitbuild.h"
-#include "core/or/circuitlist.h"
-#include "core/or/circuituse.h"
-#include "core/or/connection_edge.h"
-#include "core/or/extendinfo.h"
-#include "core/or/relay.h"
-#include "feature/client/circpathbias.h"
-#include "feature/control/control_events.h"
-#include "feature/dirclient/dirclient.h"
-#include "feature/dircommon/directory.h"
-#include "feature/hs/hs_circuit.h"
-#include "feature/hs/hs_client.h"
-#include "feature/hs/hs_common.h"
-#include "feature/nodelist/describe.h"
-#include "feature/nodelist/networkstatus.h"
-#include "feature/nodelist/nodelist.h"
-#include "feature/nodelist/routerlist.h"
-#include "feature/nodelist/routerset.h"
-#include "feature/rend/rendclient.h"
-#include "feature/rend/rendcommon.h"
-#include "feature/stats/rephist.h"
-#include "lib/crypt_ops/crypto_dh.h"
-#include "lib/crypt_ops/crypto_rand.h"
-#include "lib/crypt_ops/crypto_util.h"
-#include "lib/encoding/confline.h"
-
-#include "core/or/cpath_build_state_st.h"
-#include "core/or/crypt_path_st.h"
-#include "feature/dircommon/dir_connection_st.h"
-#include "core/or/entry_connection_st.h"
-#include "core/or/extend_info_st.h"
-#include "core/or/origin_circuit_st.h"
-#include "feature/rend/rend_intro_point_st.h"
-#include "feature/rend/rend_service_descriptor_st.h"
-#include "feature/nodelist/routerstatus_st.h"
-
-static extend_info_t *rend_client_get_random_intro_impl(
- const rend_cache_entry_t *rend_query,
- const int strict, const int warnings);
-
-/** Purge all potentially remotely-detectable state held in the hidden
- * service client code. Called on SIGNAL NEWNYM. */
-void
-rend_client_purge_state(void)
-{
- rend_cache_purge();
- rend_cache_failure_purge();
- rend_client_cancel_descriptor_fetches();
- hs_purge_last_hid_serv_requests();
-}
-
-/** Called when we've established a circuit to an introduction point:
- * send the introduction request. */
-void
-rend_client_introcirc_has_opened(origin_circuit_t *circ)
-{
- tor_assert(circ->base_.purpose == CIRCUIT_PURPOSE_C_INTRODUCING);
- tor_assert(circ->cpath);
-
- log_info(LD_REND,"introcirc is open");
- connection_ap_attach_pending(1);
-}
-
-/** Send the establish-rendezvous cell along a rendezvous circuit. if
- * it fails, mark the circ for close and return -1. else return 0.
- */
-static int
-rend_client_send_establish_rendezvous(origin_circuit_t *circ)
-{
- tor_assert(circ->base_.purpose == CIRCUIT_PURPOSE_C_ESTABLISH_REND);
- tor_assert(circ->rend_data);
- log_info(LD_REND, "Sending an ESTABLISH_RENDEZVOUS cell");
-
- crypto_rand(circ->rend_data->rend_cookie, REND_COOKIE_LEN);
-
- /* Set timestamp_dirty, because circuit_expire_building expects it,
- * and the rend cookie also means we've used the circ. */
- circ->base_.timestamp_dirty = time(NULL);
-
- /* We've attempted to use this circuit. Probe it if we fail */
- pathbias_count_use_attempt(circ);
-
- if (relay_send_command_from_edge(0, TO_CIRCUIT(circ),
- RELAY_COMMAND_ESTABLISH_RENDEZVOUS,
- circ->rend_data->rend_cookie,
- REND_COOKIE_LEN,
- circ->cpath->prev)<0) {
- /* circ is already marked for close */
- log_warn(LD_GENERAL, "Couldn't send ESTABLISH_RENDEZVOUS cell");
- return -1;
- }
-
- return 0;
-}
-
-/** Called when we're trying to connect an ap conn; sends an INTRODUCE1 cell
- * down introcirc if possible.
- */
-int
-rend_client_send_introduction(origin_circuit_t *introcirc,
- origin_circuit_t *rendcirc)
-{
- const or_options_t *options = get_options();
- size_t payload_len;
- int r, v3_shift = 0;
- char payload[RELAY_PAYLOAD_SIZE];
- char tmp[RELAY_PAYLOAD_SIZE];
- rend_cache_entry_t *entry = NULL;
- crypt_path_t *cpath;
- ptrdiff_t dh_offset;
- crypto_pk_t *intro_key = NULL;
- int status = 0;
- const char *onion_address;
-
- tor_assert(introcirc->base_.purpose == CIRCUIT_PURPOSE_C_INTRODUCING);
- tor_assert(rendcirc->base_.purpose == CIRCUIT_PURPOSE_C_REND_READY);
- tor_assert(introcirc->rend_data);
- tor_assert(rendcirc->rend_data);
- tor_assert(!rend_cmp_service_ids(rend_data_get_address(introcirc->rend_data),
- rend_data_get_address(rendcirc->rend_data)));
- assert_circ_anonymity_ok(introcirc, options);
- assert_circ_anonymity_ok(rendcirc, options);
- onion_address = rend_data_get_address(introcirc->rend_data);
-
- r = rend_cache_lookup_entry(onion_address, -1, &entry);
- /* An invalid onion address is not possible else we have a big issue. */
- tor_assert(r != -EINVAL);
- if (r < 0 || !rend_client_any_intro_points_usable(entry)) {
- /* If the descriptor is not found or the intro points are not usable
- * anymore, trigger a fetch. */
- log_info(LD_REND,
- "query %s didn't have valid rend desc in cache. "
- "Refetching descriptor.",
- safe_str_client(onion_address));
- rend_client_refetch_v2_renddesc(introcirc->rend_data);
- {
- connection_t *conn;
-
- while ((conn = connection_get_by_type_state_rendquery(CONN_TYPE_AP,
- AP_CONN_STATE_CIRCUIT_WAIT, onion_address))) {
- connection_ap_mark_as_waiting_for_renddesc(TO_ENTRY_CONN(conn));
- }
- }
-
- status = -1;
- goto cleanup;
- }
-
- /* first 20 bytes of payload are the hash of the service's pk */
- intro_key = NULL;
- SMARTLIST_FOREACH(entry->parsed->intro_nodes, rend_intro_point_t *,
- intro, {
- if (tor_memeq(introcirc->build_state->chosen_exit->identity_digest,
- intro->extend_info->identity_digest, DIGEST_LEN)) {
- intro_key = intro->intro_key;
- break;
- }
- });
- if (!intro_key) {
- log_info(LD_REND, "Could not find intro key for %s at %s; we "
- "have a v2 rend desc with %d intro points. "
- "Trying a different intro point...",
- safe_str_client(onion_address),
- safe_str_client(extend_info_describe(
- introcirc->build_state->chosen_exit)),
- smartlist_len(entry->parsed->intro_nodes));
-
- if (hs_client_reextend_intro_circuit(introcirc)) {
- status = -2;
- goto perm_err;
- } else {
- status = -1;
- goto cleanup;
- }
- }
- if (crypto_pk_get_digest(intro_key, payload)<0) {
- log_warn(LD_BUG, "Internal error: couldn't hash public key.");
- status = -2;
- goto perm_err;
- }
-
- /* Initialize the pending_final_cpath and start the DH handshake. */
- cpath = rendcirc->build_state->pending_final_cpath;
- if (!cpath) {
- cpath = rendcirc->build_state->pending_final_cpath =
- tor_malloc_zero(sizeof(crypt_path_t));
- cpath->magic = CRYPT_PATH_MAGIC;
- if (!(cpath->rend_dh_handshake_state = crypto_dh_new(DH_TYPE_REND))) {
- log_warn(LD_BUG, "Internal error: couldn't allocate DH.");
- status = -2;
- goto perm_err;
- }
- if (crypto_dh_generate_public(cpath->rend_dh_handshake_state)<0) {
- log_warn(LD_BUG, "Internal error: couldn't generate g^x.");
- status = -2;
- goto perm_err;
- }
- }
-
- /* If version is 3, write (optional) auth data and timestamp. */
- if (entry->parsed->protocols & (1<<3)) {
- tmp[0] = 3; /* version 3 of the cell format */
- /* auth type, if any */
- tmp[1] = (uint8_t) TO_REND_DATA_V2(introcirc->rend_data)->auth_type;
- v3_shift = 1;
- if (tmp[1] != REND_NO_AUTH) {
- set_uint16(tmp+2, htons(REND_DESC_COOKIE_LEN));
- memcpy(tmp+4, TO_REND_DATA_V2(introcirc->rend_data)->descriptor_cookie,
- REND_DESC_COOKIE_LEN);
- v3_shift += 2+REND_DESC_COOKIE_LEN;
- }
- /* Once this held a timestamp. */
- set_uint32(tmp+v3_shift+1, 0);
- v3_shift += 4;
- } /* if version 2 only write version number */
- else if (entry->parsed->protocols & (1<<2)) {
- tmp[0] = 2; /* version 2 of the cell format */
- }
-
- /* write the remaining items into tmp */
- if (entry->parsed->protocols & (1<<3) || entry->parsed->protocols & (1<<2)) {
- /* version 2 format */
- extend_info_t *extend_info = rendcirc->build_state->chosen_exit;
- int klen;
- const tor_addr_port_t *orport =
- extend_info_get_orport(extend_info, AF_INET);
- IF_BUG_ONCE(! orport) {
- /* we should never put an IPv6 address here. */
- goto perm_err;
- }
- /* nul pads */
- set_uint32(tmp+v3_shift+1, tor_addr_to_ipv4n(&orport->addr));
- set_uint16(tmp+v3_shift+5, htons(orport->port));
- memcpy(tmp+v3_shift+7, extend_info->identity_digest, DIGEST_LEN);
- klen = crypto_pk_asn1_encode(extend_info->onion_key,
- tmp+v3_shift+7+DIGEST_LEN+2,
- sizeof(tmp)-(v3_shift+7+DIGEST_LEN+2));
- if (klen < 0) {
- log_warn(LD_BUG,"Internal error: can't encode public key.");
- status = -2;
- goto perm_err;
- }
- set_uint16(tmp+v3_shift+7+DIGEST_LEN, htons(klen));
- memcpy(tmp+v3_shift+7+DIGEST_LEN+2+klen, rendcirc->rend_data->rend_cookie,
- REND_COOKIE_LEN);
- dh_offset = v3_shift+7+DIGEST_LEN+2+klen+REND_COOKIE_LEN;
- } else {
- /* Version 0. */
-
- /* Some compilers are smart enough to work out that nickname can be more
- * than 19 characters, when it's a hexdigest. They warn that strncpy()
- * will truncate hexdigests without NUL-terminating them. But we only put
- * hexdigests in HSDir and general circuit exits. */
- if (BUG(strlen(rendcirc->build_state->chosen_exit->nickname)
- > MAX_NICKNAME_LEN)) {
- goto perm_err;
- }
- strlcpy(tmp, rendcirc->build_state->chosen_exit->nickname,
- sizeof(tmp));
- memcpy(tmp+MAX_NICKNAME_LEN+1, rendcirc->rend_data->rend_cookie,
- REND_COOKIE_LEN);
- dh_offset = MAX_NICKNAME_LEN+1+REND_COOKIE_LEN;
- }
-
- if (crypto_dh_get_public(cpath->rend_dh_handshake_state, tmp+dh_offset,
- DH1024_KEY_LEN)<0) {
- log_warn(LD_BUG, "Internal error: couldn't extract g^x.");
- status = -2;
- goto perm_err;
- }
-
- /*XXX maybe give crypto_pk_obsolete_public_hybrid_encrypt a max_len arg,
- * to avoid buffer overflows? */
- r = crypto_pk_obsolete_public_hybrid_encrypt(intro_key, payload+DIGEST_LEN,
- sizeof(payload)-DIGEST_LEN,
- tmp,
- (int)(dh_offset+DH1024_KEY_LEN),
- PK_PKCS1_OAEP_PADDING, 0);
- if (r<0) {
- log_warn(LD_BUG,"Internal error: hybrid pk encrypt failed.");
- status = -2;
- goto perm_err;
- }
-
- payload_len = DIGEST_LEN + r;
- tor_assert(payload_len <= RELAY_PAYLOAD_SIZE); /* we overran something */
-
- /* Copy the rendezvous cookie from rendcirc to introcirc, so that
- * when introcirc gets an ack, we can change the state of the right
- * rendezvous circuit. */
- memcpy(introcirc->rend_data->rend_cookie, rendcirc->rend_data->rend_cookie,
- REND_COOKIE_LEN);
-
- log_info(LD_REND, "Sending an INTRODUCE1 cell");
- if (relay_send_command_from_edge(0, TO_CIRCUIT(introcirc),
- RELAY_COMMAND_INTRODUCE1,
- payload, payload_len,
- introcirc->cpath->prev)<0) {
- /* introcirc is already marked for close. leave rendcirc alone. */
- log_warn(LD_BUG, "Couldn't send INTRODUCE1 cell");
- status = -2;
- goto cleanup;
- }
-
- /* Now, we wait for an ACK or NAK on this circuit. */
- circuit_change_purpose(TO_CIRCUIT(introcirc),
- 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. */
- introcirc->base_.timestamp_dirty = time(NULL);
-
- pathbias_count_use_attempt(introcirc);
-
- goto cleanup;
-
- perm_err:
- if (!introcirc->base_.marked_for_close)
- circuit_mark_for_close(TO_CIRCUIT(introcirc), END_CIRC_REASON_INTERNAL);
- circuit_mark_for_close(TO_CIRCUIT(rendcirc), END_CIRC_REASON_INTERNAL);
- cleanup:
- memwipe(payload, 0, sizeof(payload));
- memwipe(tmp, 0, sizeof(tmp));
-
- return status;
-}
-
-/** Called when a rendezvous circuit is open; sends a establish
- * rendezvous circuit as appropriate. */
-void
-rend_client_rendcirc_has_opened(origin_circuit_t *circ)
-{
- tor_assert(circ->base_.purpose == CIRCUIT_PURPOSE_C_ESTABLISH_REND);
-
- log_info(LD_REND,"rendcirc is open");
-
- /* generate a rendezvous cookie, store it in circ */
- if (rend_client_send_establish_rendezvous(circ) < 0) {
- return;
- }
-}
-
-/**
- * Called to close other intro circuits we launched in parallel.
- */
-static void
-rend_client_close_other_intros(const uint8_t *rend_pk_digest)
-{
- /* abort parallel intro circs, if any */
- SMARTLIST_FOREACH_BEGIN(circuit_get_global_list(), circuit_t *, c) {
- if ((c->purpose == CIRCUIT_PURPOSE_C_INTRODUCING ||
- c->purpose == CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT) &&
- !c->marked_for_close && CIRCUIT_IS_ORIGIN(c)) {
- origin_circuit_t *oc = TO_ORIGIN_CIRCUIT(c);
- if (oc->rend_data &&
- rend_circuit_pk_digest_eq(oc, rend_pk_digest)) {
- log_info(LD_REND|LD_CIRC, "Closing introduction circuit %d that we "
- "built in parallel (Purpose %d).", oc->global_identifier,
- c->purpose);
- circuit_mark_for_close(c, END_CIRC_REASON_IP_NOW_REDUNDANT);
- }
- }
- }
- SMARTLIST_FOREACH_END(c);
-}
-
-/** Called when get an ACK or a NAK for a REND_INTRODUCE1 cell.
- */
-int
-rend_client_introduction_acked(origin_circuit_t *circ,
- const uint8_t *request, size_t request_len)
-{
- const or_options_t *options = get_options();
- origin_circuit_t *rendcirc;
- (void) request; // XXXX Use this.
-
- tor_assert(circ->build_state);
- tor_assert(circ->build_state->chosen_exit);
- assert_circ_anonymity_ok(circ, options);
- tor_assert(circ->rend_data);
-
- if (request_len == 0) {
- /* It's an ACK; the introduction point relayed our introduction request. */
- /* Locate the rend circ which is waiting to hear about this ack,
- * and tell it.
- */
- log_info(LD_REND,"Received ack. Telling rend circ...");
- rendcirc = circuit_get_ready_rend_circ_by_rend_data(circ->rend_data);
- if (rendcirc) { /* remember the ack */
- assert_circ_anonymity_ok(rendcirc, options);
- circuit_change_purpose(TO_CIRCUIT(rendcirc),
- CIRCUIT_PURPOSE_C_REND_READY_INTRO_ACKED);
- /* Set timestamp_dirty, because circuit_expire_building expects
- * it to specify when a circuit entered the
- * _C_REND_READY_INTRO_ACKED state. */
- rendcirc->base_.timestamp_dirty = time(NULL);
- } else {
- log_info(LD_REND,"...Found no rend circ. Dropping on the floor.");
- }
- /* Save the rend data digest to a temporary object so that we don't access
- * it after we mark the circuit for close. */
- const uint8_t *rend_digest_tmp = NULL;
- size_t digest_len;
- uint8_t *cached_rend_digest = NULL;
- rend_digest_tmp = rend_data_get_pk_digest(circ->rend_data, &digest_len);
- cached_rend_digest = tor_malloc_zero(digest_len);
- memcpy(cached_rend_digest, rend_digest_tmp, digest_len);
-
- /* close the circuit: we won't need it anymore. */
- circuit_change_purpose(TO_CIRCUIT(circ),
- CIRCUIT_PURPOSE_C_INTRODUCE_ACKED);
- circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_FINISHED);
-
- /* close any other intros launched in parallel */
- rend_client_close_other_intros(cached_rend_digest);
- tor_free(cached_rend_digest); /* free the temporary digest */
- } else {
- /* It's a NAK; the introduction point didn't relay our request. */
- circuit_change_purpose(TO_CIRCUIT(circ), CIRCUIT_PURPOSE_C_INTRODUCING);
- /* Remove this intro point from the set of viable introduction
- * points. If any remain, extend to a new one and try again.
- * If none remain, refetch the service descriptor.
- */
- log_info(LD_REND, "Got nack for %s from %s...",
- safe_str_client(rend_data_get_address(circ->rend_data)),
- safe_str_client(extend_info_describe(circ->build_state->chosen_exit)));
- if (rend_client_report_intro_point_failure(circ->build_state->chosen_exit,
- circ->rend_data,
- INTRO_POINT_FAILURE_GENERIC)>0) {
- /* There are introduction points left. Re-extend the circuit to
- * another intro point and try again. */
- int result = hs_client_reextend_intro_circuit(circ);
- /* XXXX If that call failed, should we close the rend circuit,
- * too? */
- return result;
- } else {
- /* Close circuit because no more intro points are usable thus not
- * useful anymore. Change it's purpose before so we don't report an
- * intro point failure again triggering an extra descriptor fetch. */
- circuit_change_purpose(TO_CIRCUIT(circ),
- CIRCUIT_PURPOSE_C_INTRODUCE_ACKED);
- circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_FINISHED);
- }
- }
- return 0;
-}
-
-/** Determine the responsible hidden service directories for <b>desc_id</b>
- * and fetch the descriptor with that ID from one of them. Only
- * send a request to a hidden service directory that we have not yet tried
- * during this attempt to connect to this hidden service; on success, return 1,
- * in the case that no hidden service directory is left to ask for the
- * descriptor, return 0, and in case of a failure -1. */
-static int
-directory_get_from_hs_dir(const char *desc_id,
- const rend_data_t *rend_query,
- routerstatus_t *rs_hsdir)
-{
- routerstatus_t *hs_dir = rs_hsdir;
- char *hsdir_fp;
- char desc_id_base32[REND_DESC_ID_V2_LEN_BASE32 + 1];
- char descriptor_cookie_base64[3*REND_DESC_COOKIE_LEN_BASE64];
- const rend_data_v2_t *rend_data;
- const int how_to_fetch = DIRIND_ANONYMOUS;
-
- tor_assert(desc_id);
- tor_assert(rend_query);
- rend_data = TO_REND_DATA_V2(rend_query);
-
- base32_encode(desc_id_base32, sizeof(desc_id_base32),
- desc_id, DIGEST_LEN);
-
- /* Automatically pick an hs dir if none given. */
- if (!rs_hsdir) {
- bool rate_limited = false;
-
- /* Determine responsible dirs. Even if we can't get all we want, work with
- * the ones we have. If it's empty, we'll notice in hs_pick_hsdir(). */
- smartlist_t *responsible_dirs = smartlist_new();
- hid_serv_get_responsible_directories(responsible_dirs, desc_id);
-
- hs_dir = hs_pick_hsdir(responsible_dirs, desc_id_base32, &rate_limited);
- if (!hs_dir) {
- /* No suitable hs dir can be found, stop right now. */
- const char *query_response = (rate_limited) ? "QUERY_RATE_LIMITED" :
- "QUERY_NO_HSDIR";
- control_event_hsv2_descriptor_failed(rend_query, NULL, query_response);
- control_event_hs_descriptor_content(rend_data_get_address(rend_query),
- desc_id_base32, NULL, NULL);
- return 0;
- }
- }
-
- /* Add a copy of the HSDir identity digest to the query so we can track it
- * on the control port. */
- hsdir_fp = tor_memdup(hs_dir->identity_digest,
- sizeof(hs_dir->identity_digest));
- smartlist_add(rend_query->hsdirs_fp, hsdir_fp);
-
- /* Encode descriptor cookie for logging purposes. Also, if the cookie is
- * malformed, no fetch is triggered thus this needs to be done before the
- * fetch request. */
- if (rend_data->auth_type != REND_NO_AUTH) {
- if (base64_encode(descriptor_cookie_base64,
- sizeof(descriptor_cookie_base64),
- rend_data->descriptor_cookie,
- REND_DESC_COOKIE_LEN,
- 0)<0) {
- log_warn(LD_BUG, "Could not base64-encode descriptor cookie.");
- control_event_hsv2_descriptor_failed(rend_query, hsdir_fp, "BAD_DESC");
- control_event_hs_descriptor_content(rend_data_get_address(rend_query),
- desc_id_base32, hsdir_fp, NULL);
- return 0;
- }
- /* Remove == signs. */
- descriptor_cookie_base64[strlen(descriptor_cookie_base64)-2] = '\0';
- } else {
- strlcpy(descriptor_cookie_base64, "(none)",
- sizeof(descriptor_cookie_base64));
- }
-
- /* Send fetch request. (Pass query and possibly descriptor cookie so that
- * they can be written to the directory connection and be referred to when
- * the response arrives. */
- directory_request_t *req =
- directory_request_new(DIR_PURPOSE_FETCH_RENDDESC_V2);
- directory_request_set_routerstatus(req, hs_dir);
- directory_request_set_indirection(req, how_to_fetch);
- directory_request_set_resource(req, desc_id_base32);
- directory_request_set_rend_query(req, rend_query);
- directory_initiate_request(req);
- directory_request_free(req);
-
- log_info(LD_REND, "Sending fetch request for v2 descriptor for "
- "service '%s' with descriptor ID '%s', auth type %d, "
- "and descriptor cookie '%s' to hidden service "
- "directory %s",
- rend_data->onion_address, desc_id_base32,
- rend_data->auth_type,
- (rend_data->auth_type == REND_NO_AUTH ? "[none]" :
- escaped_safe_str_client(descriptor_cookie_base64)),
- routerstatus_describe(hs_dir));
- control_event_hs_descriptor_requested(rend_data->onion_address,
- rend_data->auth_type,
- hs_dir->identity_digest,
- desc_id_base32, NULL);
- return 1;
-}
-
-/** Remove tracked HSDir requests from our history for this hidden service
- * descriptor <b>desc_id</b> (of size DIGEST_LEN) */
-static void
-purge_v2_hidserv_req(const char *desc_id)
-{
- char desc_id_base32[REND_DESC_ID_V2_LEN_BASE32 + 1];
-
- /* The hsdir request tracker stores v2 keys using the base32 encoded
- desc_id. Do it: */
- base32_encode(desc_id_base32, sizeof(desc_id_base32), desc_id,
- DIGEST_LEN);
- hs_purge_hid_serv_from_last_hid_serv_requests(desc_id_base32);
-}
-
-/** Fetch a v2 descriptor using the given descriptor id. If any hsdir(s) are
- * given, they will be used instead.
- *
- * On success, 1 is returned. If no hidden service is left to ask, return 0.
- * On error, -1 is returned. */
-static int
-fetch_v2_desc_by_descid(const char *desc_id,
- const rend_data_t *rend_query, smartlist_t *hsdirs)
-{
- int ret;
-
- tor_assert(rend_query);
-
- if (!hsdirs) {
- ret = directory_get_from_hs_dir(desc_id, rend_query, NULL);
- goto end; /* either success or failure, but we're done */
- }
-
- /* Using the given hsdir list, trigger a fetch on each of them. */
- SMARTLIST_FOREACH_BEGIN(hsdirs, routerstatus_t *, hs_dir) {
- /* This should always be a success. */
- ret = directory_get_from_hs_dir(desc_id, rend_query, hs_dir);
- tor_assert(ret);
- } SMARTLIST_FOREACH_END(hs_dir);
-
- /* Everything went well. */
- ret = 0;
-
- end:
- return ret;
-}
-
-/** Fetch a v2 descriptor using the onion address in the given query object.
- * This will compute the descriptor id for each replicas and fetch it on the
- * given hsdir(s) if any or the responsible ones that are chosen
- * automatically.
- *
- * On success, 1 is returned. If no hidden service is left to ask, return 0.
- * On error, -1 is returned. */
-static int
-fetch_v2_desc_by_addr(rend_data_t *rend_query, smartlist_t *hsdirs)
-{
- char descriptor_id[DIGEST_LEN];
- int replicas_left_to_try[REND_NUMBER_OF_NON_CONSECUTIVE_REPLICAS];
- int i, tries_left, ret;
- rend_data_v2_t *rend_data = TO_REND_DATA_V2(rend_query);
-
- /* Randomly iterate over the replicas until a descriptor can be fetched
- * from one of the consecutive nodes, or no options are left. */
- for (i = 0; i < REND_NUMBER_OF_NON_CONSECUTIVE_REPLICAS; i++) {
- replicas_left_to_try[i] = i;
- }
-
- tries_left = REND_NUMBER_OF_NON_CONSECUTIVE_REPLICAS;
- while (tries_left > 0) {
- int rand_val = crypto_rand_int(tries_left);
- int chosen_replica = replicas_left_to_try[rand_val];
- replicas_left_to_try[rand_val] = replicas_left_to_try[--tries_left];
-
- ret = rend_compute_v2_desc_id(descriptor_id,
- rend_data->onion_address,
- rend_data->auth_type == REND_STEALTH_AUTH ?
- rend_data->descriptor_cookie : NULL,
- time(NULL), chosen_replica);
- if (ret < 0) {
- /* Normally, on failure the descriptor_id is untouched but let's be
- * safe in general in case the function changes at some point. */
- goto end;
- }
-
- if (tor_memcmp(descriptor_id, rend_data->descriptor_id[chosen_replica],
- sizeof(descriptor_id)) != 0) {
- /* Not equal from what we currently have so purge the last hid serv
- * request cache and update the descriptor ID with the new value. */
- purge_v2_hidserv_req(rend_data->descriptor_id[chosen_replica]);
- memcpy(rend_data->descriptor_id[chosen_replica], descriptor_id,
- sizeof(rend_data->descriptor_id[chosen_replica]));
- }
-
- /* Trigger the fetch with the computed descriptor ID. */
- ret = fetch_v2_desc_by_descid(descriptor_id, rend_query, hsdirs);
- if (ret != 0) {
- /* Either on success or failure, as long as we tried a fetch we are
- * done here. */
- goto end;
- }
- }
-
- /* If we come here, there are no hidden service directories left. */
- log_info(LD_REND, "Could not pick one of the responsible hidden "
- "service directories to fetch descriptors, because "
- "we already tried them all unsuccessfully.");
- ret = 0;
-
- end:
- memwipe(descriptor_id, 0, sizeof(descriptor_id));
- return ret;
-}
-
-/** Fetch a v2 descriptor using the given query. If any hsdir are specified,
- * use them for the fetch.
- *
- * On success, 1 is returned. If no hidden service is left to ask, return 0.
- * On error, -1 is returned. */
-int
-rend_client_fetch_v2_desc(rend_data_t *query, smartlist_t *hsdirs)
-{
- int ret;
- rend_data_v2_t *rend_data;
- const char *onion_address;
-
- tor_assert(query);
-
- /* Get the version 2 data structure of the query. */
- rend_data = TO_REND_DATA_V2(query);
- onion_address = rend_data_get_address(query);
-
- /* Depending on what's available in the rend data query object, we will
- * trigger a fetch by HS address or using a descriptor ID. */
-
- if (onion_address[0] != '\0') {
- ret = fetch_v2_desc_by_addr(query, hsdirs);
- } else if (!tor_digest_is_zero(rend_data->desc_id_fetch)) {
- ret = fetch_v2_desc_by_descid(rend_data->desc_id_fetch, query,
- hsdirs);
- } else {
- /* Query data is invalid. */
- ret = -1;
- goto error;
- }
-
- error:
- return ret;
-}
-
-/** Unless we already have a descriptor for <b>rend_query</b> with at least
- * one (possibly) working introduction point in it, start a connection to a
- * hidden service directory to fetch a v2 rendezvous service descriptor. */
-void
-rend_client_refetch_v2_renddesc(rend_data_t *rend_query)
-{
- rend_cache_entry_t *e = NULL;
- const char *onion_address = rend_data_get_address(rend_query);
-
- tor_assert(rend_query);
- /* Before fetching, check if we already have a usable descriptor here. */
- if (rend_cache_lookup_entry(onion_address, -1, &e) == 0 &&
- rend_client_any_intro_points_usable(e)) {
- log_info(LD_REND, "We would fetch a v2 rendezvous descriptor, but we "
- "already have a usable descriptor here. Not fetching.");
- return;
- }
- /* Are we configured to fetch descriptors? */
- if (!get_options()->FetchHidServDescriptors) {
- log_warn(LD_REND, "We received an onion address for a v2 rendezvous "
- "service descriptor, but are not fetching service descriptors.");
- return;
- }
- log_debug(LD_REND, "Fetching v2 rendezvous descriptor for service %s",
- safe_str_client(onion_address));
-
- rend_client_fetch_v2_desc(rend_query, NULL);
- /* We don't need to look the error code because either on failure or
- * success, the necessary steps to continue the HS connection will be
- * triggered once the descriptor arrives or if all fetch failed. */
- return;
-}
-
-/** Cancel all rendezvous descriptor fetches currently in progress.
- */
-void
-rend_client_cancel_descriptor_fetches(void)
-{
- smartlist_t *connection_array = get_connection_array();
-
- SMARTLIST_FOREACH_BEGIN(connection_array, connection_t *, conn) {
- if (conn->type == CONN_TYPE_DIR &&
- conn->purpose == DIR_PURPOSE_FETCH_RENDDESC_V2) {
- /* It's a rendezvous descriptor fetch in progress -- cancel it
- * by marking the connection for close.
- *
- * Even if this connection has already reached EOF, this is
- * enough to make sure that if the descriptor hasn't been
- * processed yet, it won't be. See the end of
- * connection_handle_read; connection_reached_eof (indirectly)
- * processes whatever response the connection received. */
-
- const rend_data_t *rd = (TO_DIR_CONN(conn))->rend_data;
- if (!rd) {
- log_warn(LD_BUG | LD_REND,
- "Marking for close dir conn fetching rendezvous "
- "descriptor for unknown service!");
- } else {
- log_debug(LD_REND, "Marking for close dir conn fetching "
- "rendezvous descriptor for service %s",
- safe_str(rend_data_get_address(rd)));
- }
- connection_mark_for_close(conn);
- }
- } SMARTLIST_FOREACH_END(conn);
-}
-
-/** Mark <b>failed_intro</b> as a failed introduction point for the
- * hidden service specified by <b>rend_query</b>. If the HS now has no
- * usable intro points, or we do not have an HS descriptor for it,
- * then launch a new renddesc fetch.
- *
- * If <b>failure_type</b> is INTRO_POINT_FAILURE_GENERIC, remove the
- * intro point from (our parsed copy of) the HS descriptor.
- *
- * If <b>failure_type</b> is INTRO_POINT_FAILURE_TIMEOUT, mark the
- * intro point as 'timed out'; it will not be retried until the
- * current hidden service connection attempt has ended or it has
- * appeared in a newly fetched rendezvous descriptor.
- *
- * If <b>failure_type</b> is INTRO_POINT_FAILURE_UNREACHABLE,
- * increment the intro point's reachability-failure count; if it has
- * now failed MAX_INTRO_POINT_REACHABILITY_FAILURES or more times,
- * remove the intro point from (our parsed copy of) the HS descriptor.
- *
- * Return -1 if error, 0 if no usable intro points remain or service
- * unrecognized, 1 if recognized and some intro points remain.
- */
-int
-rend_client_report_intro_point_failure(extend_info_t *failed_intro,
- rend_data_t *rend_data,
- unsigned int failure_type)
-{
- int i, r;
- rend_cache_entry_t *ent;
- connection_t *conn;
- const char *onion_address = rend_data_get_address(rend_data);
-
- r = rend_cache_lookup_entry(onion_address, -1, &ent);
- if (r < 0) {
- /* Either invalid onion address or cache entry not found. */
- switch (-r) {
- case EINVAL:
- log_warn(LD_BUG, "Malformed service ID %s.",
- escaped_safe_str_client(onion_address));
- return -1;
- case ENOENT:
- log_info(LD_REND, "Unknown service %s. Re-fetching descriptor.",
- escaped_safe_str_client(onion_address));
- rend_client_refetch_v2_renddesc(rend_data);
- return 0;
- default:
- log_warn(LD_BUG, "Unknown cache lookup returned code: %d", r);
- return -1;
- }
- }
- /* The intro points are not checked here if they are usable or not because
- * this is called when an intro point circuit is closed thus there must be
- * at least one intro point that is usable and is about to be flagged. */
-
- for (i = 0; i < smartlist_len(ent->parsed->intro_nodes); i++) {
- rend_intro_point_t *intro = smartlist_get(ent->parsed->intro_nodes, i);
- if (tor_memeq(failed_intro->identity_digest,
- intro->extend_info->identity_digest, DIGEST_LEN)) {
- switch (failure_type) {
- default:
- log_warn(LD_BUG, "Unknown failure type %u. Removing intro point.",
- failure_type);
- tor_fragile_assert();
- FALLTHROUGH_UNLESS_ALL_BUGS_ARE_FATAL;
- case INTRO_POINT_FAILURE_GENERIC:
- rend_cache_intro_failure_note(failure_type,
- (uint8_t *)failed_intro->identity_digest,
- onion_address);
- rend_intro_point_free(intro);
- smartlist_del(ent->parsed->intro_nodes, i);
- break;
- case INTRO_POINT_FAILURE_TIMEOUT:
- intro->timed_out = 1;
- break;
- case INTRO_POINT_FAILURE_UNREACHABLE:
- ++(intro->unreachable_count);
- {
- int zap_intro_point =
- intro->unreachable_count >= MAX_INTRO_POINT_REACHABILITY_FAILURES;
- log_info(LD_REND, "Failed to reach this intro point %u times.%s",
- intro->unreachable_count,
- zap_intro_point ? " Removing from descriptor.": "");
- if (zap_intro_point) {
- rend_cache_intro_failure_note(
- failure_type,
- (uint8_t *) failed_intro->identity_digest, onion_address);
- rend_intro_point_free(intro);
- smartlist_del(ent->parsed->intro_nodes, i);
- }
- }
- break;
- }
- break;
- }
- }
-
- if (! rend_client_any_intro_points_usable(ent)) {
- log_info(LD_REND,
- "No more intro points remain for %s. Re-fetching descriptor.",
- escaped_safe_str_client(onion_address));
- rend_client_refetch_v2_renddesc(rend_data);
-
- /* move all pending streams back to renddesc_wait */
- /* NOTE: We can now do this faster, if we use pending_entry_connections */
- while ((conn = connection_get_by_type_state_rendquery(CONN_TYPE_AP,
- AP_CONN_STATE_CIRCUIT_WAIT,
- onion_address))) {
- connection_ap_mark_as_waiting_for_renddesc(TO_ENTRY_CONN(conn));
- }
-
- return 0;
- }
- log_info(LD_REND,"%d options left for %s.",
- smartlist_len(ent->parsed->intro_nodes),
- escaped_safe_str_client(onion_address));
- return 1;
-}
-
-/** The service sent us a rendezvous cell; join the circuits. */
-int
-rend_client_receive_rendezvous(origin_circuit_t *circ, const uint8_t *request,
- size_t request_len)
-{
- if (request_len != DH1024_KEY_LEN+DIGEST_LEN) {
- log_warn(LD_PROTOCOL,"Incorrect length (%d) on RENDEZVOUS2 cell.",
- (int)request_len);
- goto err;
- }
-
- if (hs_circuit_setup_e2e_rend_circ_legacy_client(circ, request) < 0) {
- log_warn(LD_GENERAL, "Failed to setup circ");
- goto err;
- }
- return 0;
-
- err:
- circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_TORPROTOCOL);
- return -1;
-}
-
-/** Find all the apconns in state AP_CONN_STATE_RENDDESC_WAIT that are
- * waiting on <b>query</b>. If there's a working cache entry here with at
- * least one intro point, move them to the next state. */
-void
-rend_client_desc_trynow(const char *query)
-{
- entry_connection_t *conn;
- rend_cache_entry_t *entry;
- const rend_data_t *rend_data;
- time_t now = time(NULL);
-
- smartlist_t *conns = get_connection_array();
- SMARTLIST_FOREACH_BEGIN(conns, connection_t *, base_conn) {
- if (base_conn->type != CONN_TYPE_AP ||
- base_conn->state != AP_CONN_STATE_RENDDESC_WAIT ||
- base_conn->marked_for_close)
- continue;
- conn = TO_ENTRY_CONN(base_conn);
- rend_data = ENTRY_TO_EDGE_CONN(conn)->rend_data;
- if (!rend_data)
- continue;
- const char *onion_address = rend_data_get_address(rend_data);
- if (rend_cmp_service_ids(query, onion_address))
- continue;
- assert_connection_ok(base_conn, now);
- if (rend_cache_lookup_entry(onion_address, -1,
- &entry) == 0 &&
- rend_client_any_intro_points_usable(entry)) {
- /* either this fetch worked, or it failed but there was a
- * valid entry from before which we should reuse */
- log_info(LD_REND,"Rend desc is usable. Launching circuits.");
- base_conn->state = AP_CONN_STATE_CIRCUIT_WAIT;
-
- /* restart their timeout values, so they get a fair shake at
- * connecting to the hidden service. */
- base_conn->timestamp_created = now;
- base_conn->timestamp_last_read_allowed = now;
- base_conn->timestamp_last_write_allowed = now;
-
- connection_ap_mark_as_pending_circuit(conn);
- } else { /* 404, or fetch didn't get that far */
- log_notice(LD_REND,"Closing stream for '%s.onion': hidden service is "
- "unavailable (try again later).",
- safe_str_client(query));
- connection_mark_unattached_ap(conn, END_STREAM_REASON_RESOLVEFAILED);
- rend_client_note_connection_attempt_ended(rend_data);
- }
- } SMARTLIST_FOREACH_END(base_conn);
-}
-
-/** Clear temporary state used only during an attempt to connect to the
- * hidden service with <b>rend_data</b>. Called when a connection attempt
- * has ended; it is possible for this to be called multiple times while
- * handling an ended connection attempt, and any future changes to this
- * function must ensure it remains idempotent. */
-void
-rend_client_note_connection_attempt_ended(const rend_data_t *rend_data)
-{
- unsigned int have_onion = 0;
- rend_cache_entry_t *cache_entry = NULL;
- const char *onion_address = rend_data_get_address(rend_data);
- rend_data_v2_t *rend_data_v2 = TO_REND_DATA_V2(rend_data);
-
- if (onion_address[0] != '\0') {
- /* Ignore return value; we find an entry, or we don't. */
- (void) rend_cache_lookup_entry(onion_address, -1, &cache_entry);
- have_onion = 1;
- }
-
- /* Clear the timed_out flag on all remaining intro points for this HS. */
- if (cache_entry != NULL) {
- SMARTLIST_FOREACH(cache_entry->parsed->intro_nodes,
- rend_intro_point_t *, ip,
- ip->timed_out = 0; );
- }
-
- /* Remove the HS's entries in last_hid_serv_requests. */
- if (have_onion) {
- unsigned int replica;
- for (replica = 0; replica < ARRAY_LENGTH(rend_data_v2->descriptor_id);
- replica++) {
- const char *desc_id = rend_data_v2->descriptor_id[replica];
- purge_v2_hidserv_req(desc_id);
- }
- log_info(LD_REND, "Connection attempt for %s has ended; "
- "cleaning up temporary state.",
- safe_str_client(onion_address));
- } else {
- /* We only have an ID for a fetch. Probably used by HSFETCH. */
- purge_v2_hidserv_req(rend_data_v2->desc_id_fetch);
- }
-}
-
-/** Return a newly allocated extend_info_t* for a randomly chosen introduction
- * point for the named hidden service. Return NULL if all introduction points
- * have been tried and failed.
- */
-extend_info_t *
-rend_client_get_random_intro(const rend_data_t *rend_query)
-{
- int ret;
- extend_info_t *result;
- rend_cache_entry_t *entry;
- const char *onion_address = rend_data_get_address(rend_query);
-
- ret = rend_cache_lookup_entry(onion_address, -1, &entry);
- if (ret < 0 || !rend_client_any_intro_points_usable(entry)) {
- log_warn(LD_REND,
- "Query '%s' didn't have valid rend desc in cache. Failing.",
- safe_str_client(onion_address));
- /* XXX: Should we refetch the descriptor here if the IPs are not usable
- * anymore ?. */
- return NULL;
- }
-
- /* See if we can get a node that complies with ExcludeNodes */
- if ((result = rend_client_get_random_intro_impl(entry, 1, 1)))
- return result;
- /* If not, and StrictNodes is not set, see if we can return any old node
- */
- if (!get_options()->StrictNodes)
- return rend_client_get_random_intro_impl(entry, 0, 1);
- return NULL;
-}
-
-/** As rend_client_get_random_intro, except assume that StrictNodes is set
- * iff <b>strict</b> is true. If <b>warnings</b> is false, don't complain
- * to the user when we're out of nodes, even if StrictNodes is true.
- */
-static extend_info_t *
-rend_client_get_random_intro_impl(const rend_cache_entry_t *entry,
- const int strict,
- const int warnings)
-{
- int i;
-
- rend_intro_point_t *intro;
- const or_options_t *options = get_options();
- smartlist_t *usable_nodes;
- int n_excluded = 0;
- char service_id[REND_SERVICE_ID_LEN_BASE32 + 1];
-
- /* We'll keep a separate list of the usable nodes. If this becomes empty,
- * no nodes are usable. */
- usable_nodes = smartlist_new();
- smartlist_add_all(usable_nodes, entry->parsed->intro_nodes);
-
- /* Get service ID so we can use it to query the failure cache. If we fail to
- * parse it, this cache entry is no good. */
- if (BUG(rend_get_service_id(entry->parsed->pk, service_id) < 0)) {
- smartlist_free(usable_nodes);
- return NULL;
- }
-
- /* Remove the intro points that have timed out during this HS
- * connection attempt from our list of usable nodes. */
- SMARTLIST_FOREACH_BEGIN(usable_nodes, const rend_intro_point_t *, ip) {
- bool failed_intro =
- rend_cache_intro_failure_exists(service_id,
- (const uint8_t *) ip->extend_info->identity_digest);
- if (ip->timed_out || failed_intro) {
- SMARTLIST_DEL_CURRENT(usable_nodes, ip);
- };
- } SMARTLIST_FOREACH_END(ip);
-
- again:
- if (smartlist_len(usable_nodes) == 0) {
- if (n_excluded && get_options()->StrictNodes && warnings) {
- /* We only want to warn if StrictNodes is really set. Otherwise
- * we're just about to retry anyways.
- */
- log_warn(LD_REND, "All introduction points for hidden service are "
- "at excluded relays, and StrictNodes is set. Skipping.");
- }
- smartlist_free(usable_nodes);
- return NULL;
- }
-
- i = crypto_rand_int(smartlist_len(usable_nodes));
- intro = smartlist_get(usable_nodes, i);
- if (BUG(!intro->extend_info)) {
- /* This should never happen, but it isn't fatal, just try another */
- smartlist_del(usable_nodes, i);
- goto again;
- }
- /* All version 2 HS descriptors come with a TAP onion key.
- * Clients used to try to get the TAP onion key from the consensus, but this
- * meant that hidden services could discover which consensus clients have. */
- if (!extend_info_supports_tap(intro->extend_info)) {
- log_info(LD_REND, "The HS descriptor is missing a TAP onion key for the "
- "intro-point relay '%s'; trying another.",
- safe_str_client(extend_info_describe(intro->extend_info)));
- smartlist_del(usable_nodes, i);
- goto again;
- }
- /* Check if we should refuse to talk to this router. */
- if (strict &&
- routerset_contains_extendinfo(options->ExcludeNodes,
- intro->extend_info)) {
- n_excluded++;
- smartlist_del(usable_nodes, i);
- goto again;
- }
-
- smartlist_free(usable_nodes);
- return extend_info_dup(intro->extend_info);
-}
-
-/** Return true iff any introduction points still listed in <b>entry</b> are
- * usable. */
-int
-rend_client_any_intro_points_usable(const rend_cache_entry_t *entry)
-{
- extend_info_t *extend_info =
- rend_client_get_random_intro_impl(entry, get_options()->StrictNodes, 0);
-
- int rv = (extend_info != NULL);
-
- extend_info_free(extend_info);
- return rv;
-}
-
-/** Client-side authorizations for hidden services; map of onion address to
- * rend_service_authorization_t*. */
-static strmap_t *auth_hid_servs = NULL;
-
-/** Look up the client-side authorization for the hidden service with
- * <b>onion_address</b>. Return NULL if no authorization is available for
- * that address. */
-rend_service_authorization_t*
-rend_client_lookup_service_authorization(const char *onion_address)
-{
- tor_assert(onion_address);
- if (!auth_hid_servs) return NULL;
- return strmap_get(auth_hid_servs, onion_address);
-}
-
-#define rend_service_authorization_free(val) \
- FREE_AND_NULL(rend_service_authorization_t, \
- rend_service_authorization_free_, (val))
-
-/** Helper: Free storage held by rend_service_authorization_t. */
-static void
-rend_service_authorization_free_(rend_service_authorization_t *auth)
-{
- tor_free(auth);
-}
-
-/** Helper for strmap_free. */
-static void
-rend_service_authorization_free_void(void *service_auth)
-{
- rend_service_authorization_free_(service_auth);
-}
-
-/** Release all the storage held in auth_hid_servs.
- */
-void
-rend_service_authorization_free_all(void)
-{
- if (!auth_hid_servs) {
- return;
- }
- strmap_free(auth_hid_servs, rend_service_authorization_free_void);
- auth_hid_servs = NULL;
-}
-
-/** Parse <b>config_line</b> as a client-side authorization for a hidden
- * service and add it to the local map of hidden service authorizations.
- * Return 0 for success and -1 for failure. */
-int
-rend_parse_service_authorization(const or_options_t *options,
- int validate_only)
-{
- config_line_t *line;
- int res = -1;
- strmap_t *parsed = strmap_new();
- smartlist_t *sl = smartlist_new();
- rend_service_authorization_t *auth = NULL;
- char *err_msg = NULL;
-
- for (line = options->HidServAuth; line; line = line->next) {
- char *onion_address, *descriptor_cookie;
- auth = NULL;
- SMARTLIST_FOREACH(sl, char *, c, tor_free(c););
- smartlist_clear(sl);
- smartlist_split_string(sl, line->value, " ",
- SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 3);
- if (smartlist_len(sl) < 2) {
- log_warn(LD_CONFIG, "Configuration line does not consist of "
- "\"onion-address authorization-cookie [service-name]\": "
- "'%s'", line->value);
- goto err;
- }
- auth = tor_malloc_zero(sizeof(rend_service_authorization_t));
- /* Parse onion address. */
- onion_address = smartlist_get(sl, 0);
- if (strlen(onion_address) != REND_SERVICE_ADDRESS_LEN ||
- strcmpend(onion_address, ".onion")) {
- log_warn(LD_CONFIG, "Onion address has wrong format: '%s'",
- onion_address);
- goto err;
- }
- strlcpy(auth->onion_address, onion_address, REND_SERVICE_ID_LEN_BASE32+1);
- if (!rend_valid_v2_service_id(auth->onion_address)) {
- log_warn(LD_CONFIG, "Onion address has wrong format: '%s'",
- onion_address);
- goto err;
- }
- /* Parse descriptor cookie. */
- descriptor_cookie = smartlist_get(sl, 1);
- if (rend_auth_decode_cookie(descriptor_cookie, auth->descriptor_cookie,
- &auth->auth_type, &err_msg) < 0) {
- tor_assert(err_msg);
- log_warn(LD_CONFIG, "%s", err_msg);
- tor_free(err_msg);
- goto err;
- }
- if (strmap_get(parsed, auth->onion_address)) {
- log_warn(LD_CONFIG, "Duplicate authorization for the same hidden "
- "service.");
- goto err;
- }
- strmap_set(parsed, auth->onion_address, auth);
- auth = NULL;
- }
- res = 0;
- goto done;
- err:
- res = -1;
- done:
- rend_service_authorization_free(auth);
- SMARTLIST_FOREACH(sl, char *, c, tor_free(c););
- smartlist_free(sl);
- if (!validate_only && res == 0) {
- rend_service_authorization_free_all();
- auth_hid_servs = parsed;
- } else {
- strmap_free(parsed, rend_service_authorization_free_void);
- }
- return res;
-}
-
-/** The given circuit is being freed. Take appropriate action if it is of
- * interest to the client subsystem. */
-void
-rend_client_circuit_cleanup_on_free(const circuit_t *circ)
-{
- int reason, orig_reason;
- bool has_timed_out, ip_is_redundant;
- const origin_circuit_t *ocirc = NULL;
-
- tor_assert(circ);
- tor_assert(CIRCUIT_IS_ORIGIN(circ));
-
- reason = circ->marked_for_close_reason;
- orig_reason = circ->marked_for_close_orig_reason;
- ocirc = CONST_TO_ORIGIN_CIRCUIT(circ);
- tor_assert(ocirc->rend_data);
-
- has_timed_out = (reason == END_CIRC_REASON_TIMEOUT);
- ip_is_redundant = (orig_reason == END_CIRC_REASON_IP_NOW_REDUNDANT);
-
- switch (circ->purpose) {
- case CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT:
- {
- if (ip_is_redundant) {
- break;
- }
- tor_assert(circ->state == CIRCUIT_STATE_OPEN);
- tor_assert(ocirc->build_state->chosen_exit);
- /* Treat this like getting a nack from it */
- log_info(LD_REND, "Failed intro circ %s to %s (awaiting ack). %s",
- safe_str_client(rend_data_get_address(ocirc->rend_data)),
- safe_str_client(build_state_get_exit_nickname(ocirc->build_state)),
- has_timed_out ? "Recording timeout." : "Removing from descriptor.");
- rend_client_report_intro_point_failure(ocirc->build_state->chosen_exit,
- ocirc->rend_data,
- has_timed_out ?
- INTRO_POINT_FAILURE_TIMEOUT :
- INTRO_POINT_FAILURE_GENERIC);
- break;
- }
- case CIRCUIT_PURPOSE_C_INTRODUCING:
- {
- /* Ignore if we were introducing and it timed out, we didn't pick an exit
- * point yet (IP) or the reason indicate that it was a redundant IP. */
- if (has_timed_out || !ocirc->build_state->chosen_exit || ip_is_redundant) {
- break;
- }
- log_info(LD_REND, "Failed intro circ %s to %s "
- "(building circuit to intro point). "
- "Marking intro point as possibly unreachable.",
- safe_str_client(rend_data_get_address(ocirc->rend_data)),
- safe_str_client(build_state_get_exit_nickname(
- ocirc->build_state)));
- rend_client_report_intro_point_failure(ocirc->build_state->chosen_exit,
- ocirc->rend_data,
- INTRO_POINT_FAILURE_UNREACHABLE);
- break;
- }
- default:
- break;
- }
-}
diff --git a/src/feature/rend/rendclient.h b/src/feature/rend/rendclient.h
deleted file mode 100644
index b7aa212487..0000000000
--- a/src/feature/rend/rendclient.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/* Copyright (c) 2001 Matej Pfajfar.
- * Copyright (c) 2001-2004, Roger Dingledine.
- * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
-/* See LICENSE for licensing information */
-
-/**
- * \file rendclient.h
- * \brief Header file for rendclient.c.
- **/
-
-#ifndef TOR_RENDCLIENT_H
-#define TOR_RENDCLIENT_H
-
-#include "feature/hs/hs_circuit.h"
-#include "feature/rend/rendcache.h"
-
-void rend_client_purge_state(void);
-
-void rend_client_introcirc_has_opened(origin_circuit_t *circ);
-void rend_client_rendcirc_has_opened(origin_circuit_t *circ);
-int rend_client_introduction_acked(origin_circuit_t *circ,
- const uint8_t *request,
- size_t request_len);
-void rend_client_refetch_v2_renddesc(rend_data_t *rend_query);
-int rend_client_fetch_v2_desc(rend_data_t *query, smartlist_t *hsdirs);
-void rend_client_cancel_descriptor_fetches(void);
-
-int rend_client_report_intro_point_failure(extend_info_t *failed_intro,
- rend_data_t *rend_data,
- unsigned int failure_type);
-
-int rend_client_receive_rendezvous(origin_circuit_t *circ,
- const uint8_t *request,
- size_t request_len);
-void rend_client_desc_trynow(const char *query);
-
-void rend_client_note_connection_attempt_ended(const rend_data_t *rend_data);
-
-extend_info_t *rend_client_get_random_intro(const rend_data_t *rend_query);
-int rend_client_any_intro_points_usable(const rend_cache_entry_t *entry);
-
-int rend_client_send_introduction(origin_circuit_t *introcirc,
- origin_circuit_t *rendcirc);
-int rend_parse_service_authorization(const or_options_t *options,
- int validate_only);
-rend_service_authorization_t *rend_client_lookup_service_authorization(
- const char *onion_address);
-void rend_service_authorization_free_all(void);
-
-void rend_client_circuit_cleanup_on_free(const circuit_t *circ);
-
-#endif /* !defined(TOR_RENDCLIENT_H) */
-
diff --git a/src/feature/rend/rendcommon.c b/src/feature/rend/rendcommon.c
index 775d487805..0628422812 100644
--- a/src/feature/rend/rendcommon.c
+++ b/src/feature/rend/rendcommon.c
@@ -1,5 +1,5 @@
/* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -11,761 +11,22 @@
#define RENDCOMMON_PRIVATE
#include "core/or/or.h"
-#include "core/or/circuitbuild.h"
+
+#include "app/config/config.h"
+
#include "core/or/circuitlist.h"
#include "core/or/circuituse.h"
-#include "core/or/extendinfo.h"
-#include "app/config/config.h"
-#include "feature/control/control_events.h"
-#include "lib/crypt_ops/crypto_rand.h"
-#include "lib/crypt_ops/crypto_util.h"
+
#include "feature/hs/hs_client.h"
#include "feature/hs/hs_common.h"
#include "feature/hs/hs_intropoint.h"
-#include "feature/nodelist/networkstatus.h"
-#include "feature/rend/rendclient.h"
#include "feature/rend/rendcommon.h"
#include "feature/rend/rendmid.h"
-#include "feature/rend/rendparse.h"
-#include "feature/rend/rendservice.h"
-#include "feature/stats/rephist.h"
-#include "feature/hs_common/replaycache.h"
-#include "feature/relay/router.h"
-#include "feature/nodelist/routerlist.h"
-#include "feature/dirparse/signing.h"
+#include "core/or/circuit_st.h"
#include "core/or/cpath_build_state_st.h"
#include "core/or/crypt_path_st.h"
-#include "core/or/extend_info_st.h"
-#include "feature/nodelist/networkstatus_st.h"
#include "core/or/origin_circuit_st.h"
-#include "feature/rend/rend_encoded_v2_service_descriptor_st.h"
-#include "feature/rend/rend_intro_point_st.h"
-#include "feature/rend/rend_service_descriptor_st.h"
-#include "feature/nodelist/routerstatus_st.h"
-
-/** Return 0 if one and two are the same service ids, else -1 or 1 */
-int
-rend_cmp_service_ids(const char *one, const char *two)
-{
- return strcasecmp(one,two);
-}
-
-/** Free the storage held by the service descriptor <b>desc</b>.
- */
-void
-rend_service_descriptor_free_(rend_service_descriptor_t *desc)
-{
- if (!desc)
- return;
- if (desc->pk)
- crypto_pk_free(desc->pk);
- if (desc->intro_nodes) {
- SMARTLIST_FOREACH(desc->intro_nodes, rend_intro_point_t *, intro,
- rend_intro_point_free(intro););
- smartlist_free(desc->intro_nodes);
- }
- if (desc->successful_uploads) {
- SMARTLIST_FOREACH(desc->successful_uploads, char *, c, tor_free(c););
- smartlist_free(desc->successful_uploads);
- }
- tor_free(desc);
-}
-
-/** Length of the descriptor cookie that is used for versioned hidden
- * service descriptors. */
-#define REND_DESC_COOKIE_LEN 16
-
-/** Length of the replica number that is used to determine the secret ID
- * part of versioned hidden service descriptors. */
-#define REND_REPLICA_LEN 1
-
-/** Compute the descriptor ID for <b>service_id</b> of length
- * <b>REND_SERVICE_ID_LEN</b> and <b>secret_id_part</b> of length
- * <b>DIGEST_LEN</b>, and write it to <b>descriptor_id_out</b> of length
- * <b>DIGEST_LEN</b>. */
-void
-rend_get_descriptor_id_bytes(char *descriptor_id_out,
- const char *service_id,
- const char *secret_id_part)
-{
- crypto_digest_t *digest = crypto_digest_new();
- crypto_digest_add_bytes(digest, service_id, REND_SERVICE_ID_LEN);
- crypto_digest_add_bytes(digest, secret_id_part, DIGEST_LEN);
- crypto_digest_get_digest(digest, descriptor_id_out, DIGEST_LEN);
- crypto_digest_free(digest);
-}
-
-/** Compute the secret ID part for time_period,
- * a <b>descriptor_cookie</b> of length
- * <b>REND_DESC_COOKIE_LEN</b> which may also be <b>NULL</b> if no
- * descriptor_cookie shall be used, and <b>replica</b>, and write it to
- * <b>secret_id_part</b> of length DIGEST_LEN. */
-static void
-get_secret_id_part_bytes(char *secret_id_part, uint32_t time_period,
- const char *descriptor_cookie, uint8_t replica)
-{
- crypto_digest_t *digest = crypto_digest_new();
- time_period = htonl(time_period);
- crypto_digest_add_bytes(digest, (char*)&time_period, sizeof(uint32_t));
- if (descriptor_cookie) {
- crypto_digest_add_bytes(digest, descriptor_cookie,
- REND_DESC_COOKIE_LEN);
- }
- crypto_digest_add_bytes(digest, (const char *)&replica, REND_REPLICA_LEN);
- crypto_digest_get_digest(digest, secret_id_part, DIGEST_LEN);
- crypto_digest_free(digest);
-}
-
-/** Return the time period for time <b>now</b> plus a potentially
- * intended <b>deviation</b> of one or more periods, based on the first byte
- * of <b>service_id</b>. */
-static uint32_t
-get_time_period(time_t now, uint8_t deviation, const char *service_id)
-{
- /* The time period is the number of REND_TIME_PERIOD_V2_DESC_VALIDITY
- * intervals that have passed since the epoch, offset slightly so that
- * each service's time periods start and end at a fraction of that
- * period based on their first byte. */
- return (uint32_t)
- (now + ((uint8_t) *service_id) * REND_TIME_PERIOD_V2_DESC_VALIDITY / 256)
- / REND_TIME_PERIOD_V2_DESC_VALIDITY + deviation;
-}
-
-/** Compute the time in seconds that a descriptor that is generated
- * <b>now</b> for <b>service_id</b> will be valid. */
-static uint32_t
-get_seconds_valid(time_t now, const char *service_id)
-{
- uint32_t result = REND_TIME_PERIOD_V2_DESC_VALIDITY -
- ((uint32_t)
- (now + ((uint8_t) *service_id) * REND_TIME_PERIOD_V2_DESC_VALIDITY / 256)
- % REND_TIME_PERIOD_V2_DESC_VALIDITY);
- return result;
-}
-
-/** Compute the binary <b>desc_id_out</b> (DIGEST_LEN bytes long) for a given
- * base32-encoded <b>service_id</b> and optional unencoded
- * <b>descriptor_cookie</b> of length REND_DESC_COOKIE_LEN,
- * at time <b>now</b> for replica number
- * <b>replica</b>. <b>desc_id</b> needs to have <b>DIGEST_LEN</b> bytes
- * free. Return 0 for success, -1 otherwise. */
-int
-rend_compute_v2_desc_id(char *desc_id_out, const char *service_id,
- const char *descriptor_cookie, time_t now,
- uint8_t replica)
-{
- char service_id_binary[REND_SERVICE_ID_LEN];
- char secret_id_part[DIGEST_LEN];
- uint32_t time_period;
- if (!service_id ||
- strlen(service_id) != REND_SERVICE_ID_LEN_BASE32) {
- log_warn(LD_REND, "Could not compute v2 descriptor ID: "
- "Illegal service ID: %s",
- safe_str(service_id));
- return -1;
- }
- if (replica >= REND_NUMBER_OF_NON_CONSECUTIVE_REPLICAS) {
- log_warn(LD_REND, "Could not compute v2 descriptor ID: "
- "Replica number out of range: %d", replica);
- return -1;
- }
- /* Convert service ID to binary. */
- if (base32_decode(service_id_binary, REND_SERVICE_ID_LEN,
- service_id, REND_SERVICE_ID_LEN_BASE32) !=
- REND_SERVICE_ID_LEN) {
- log_warn(LD_REND, "Could not compute v2 descriptor ID: "
- "Illegal characters or wrong length for service ID: %s",
- safe_str_client(service_id));
- return -1;
- }
- /* Calculate current time-period. */
- time_period = get_time_period(now, 0, service_id_binary);
- /* Calculate secret-id-part = h(time-period | desc-cookie | replica). */
- get_secret_id_part_bytes(secret_id_part, time_period, descriptor_cookie,
- replica);
- /* Calculate descriptor ID: H(permanent-id | secret-id-part) */
- rend_get_descriptor_id_bytes(desc_id_out, service_id_binary, secret_id_part);
- return 0;
-}
-
-/** Encode the introduction points in <b>desc</b> and write the result to a
- * newly allocated string pointed to by <b>encoded</b>. Return 0 for
- * success, -1 otherwise. */
-static int
-rend_encode_v2_intro_points(char **encoded, rend_service_descriptor_t *desc)
-{
- size_t unenc_len;
- char *unenc = NULL;
- size_t unenc_written = 0;
- int i;
- int r = -1;
- /* Assemble unencrypted list of introduction points. */
- unenc_len = smartlist_len(desc->intro_nodes) * 1000; /* too long, but ok. */
- unenc = tor_malloc_zero(unenc_len);
- for (i = 0; i < smartlist_len(desc->intro_nodes); i++) {
- char id_base32[REND_INTRO_POINT_ID_LEN_BASE32 + 1];
- char *onion_key = NULL;
- size_t onion_key_len;
- crypto_pk_t *intro_key;
- char *service_key = NULL;
- char *address = NULL;
- size_t service_key_len;
- int res;
- rend_intro_point_t *intro = smartlist_get(desc->intro_nodes, i);
- /* Obtain extend info with introduction point details. */
- extend_info_t *info = intro->extend_info;
- /* Encode introduction point ID. */
- base32_encode(id_base32, sizeof(id_base32),
- info->identity_digest, DIGEST_LEN);
- /* Encode onion key. */
- if (crypto_pk_write_public_key_to_string(info->onion_key, &onion_key,
- &onion_key_len) < 0) {
- log_warn(LD_REND, "Could not write onion key.");
- goto done;
- }
- /* Encode intro key. */
- intro_key = intro->intro_key;
- if (!intro_key ||
- crypto_pk_write_public_key_to_string(intro_key, &service_key,
- &service_key_len) < 0) {
- log_warn(LD_REND, "Could not write intro key.");
- tor_free(onion_key);
- goto done;
- }
- /* Assemble everything for this introduction point. */
- const tor_addr_port_t *orport = extend_info_get_orport(info, AF_INET);
- IF_BUG_ONCE(!orport) {
- /* There must be an IPv4 address for v2 hs. */
- goto done;
- }
- address = tor_addr_to_str_dup(&orport->addr);
- res = tor_snprintf(unenc + unenc_written, unenc_len - unenc_written,
- "introduction-point %s\n"
- "ip-address %s\n"
- "onion-port %d\n"
- "onion-key\n%s"
- "service-key\n%s",
- id_base32,
- address,
- orport->port,
- onion_key,
- service_key);
- tor_free(address);
- tor_free(onion_key);
- tor_free(service_key);
- if (res < 0) {
- log_warn(LD_REND, "Not enough space for writing introduction point "
- "string.");
- goto done;
- }
- /* Update total number of written bytes for unencrypted intro points. */
- unenc_written += res;
- }
- /* Finalize unencrypted introduction points. */
- if (unenc_len < unenc_written + 2) {
- log_warn(LD_REND, "Not enough space for finalizing introduction point "
- "string.");
- goto done;
- }
- unenc[unenc_written++] = '\n';
- unenc[unenc_written++] = 0;
- *encoded = unenc;
- r = 0;
- done:
- if (r<0)
- tor_free(unenc);
- return r;
-}
-
-/** Encrypt the encoded introduction points in <b>encoded</b> using
- * authorization type 'basic' with <b>client_cookies</b> and write the
- * result to a newly allocated string pointed to by <b>encrypted_out</b> of
- * length <b>encrypted_len_out</b>. Return 0 for success, -1 otherwise. */
-static int
-rend_encrypt_v2_intro_points_basic(char **encrypted_out,
- size_t *encrypted_len_out,
- const char *encoded,
- smartlist_t *client_cookies)
-{
- int r = -1, i, pos, enclen, client_blocks;
- size_t len, client_entries_len;
- char *enc = NULL, iv[CIPHER_IV_LEN], *client_part = NULL,
- session_key[CIPHER_KEY_LEN];
- smartlist_t *encrypted_session_keys = NULL;
- crypto_digest_t *digest;
- crypto_cipher_t *cipher;
- tor_assert(encoded);
- tor_assert(client_cookies && smartlist_len(client_cookies) > 0);
-
- /* Generate session key. */
- crypto_rand(session_key, CIPHER_KEY_LEN);
-
- /* Determine length of encrypted introduction points including session
- * keys. */
- client_blocks = 1 + ((smartlist_len(client_cookies) - 1) /
- REND_BASIC_AUTH_CLIENT_MULTIPLE);
- client_entries_len = client_blocks * REND_BASIC_AUTH_CLIENT_MULTIPLE *
- REND_BASIC_AUTH_CLIENT_ENTRY_LEN;
- len = 2 + client_entries_len + CIPHER_IV_LEN + strlen(encoded);
- if (client_blocks >= 256) {
- log_warn(LD_REND, "Too many clients in introduction point string.");
- goto done;
- }
- enc = tor_malloc_zero(len);
- enc[0] = 0x01; /* type of authorization. */
- enc[1] = (uint8_t)client_blocks;
-
- /* Encrypt with random session key. */
- enclen = crypto_cipher_encrypt_with_iv(session_key,
- enc + 2 + client_entries_len,
- CIPHER_IV_LEN + strlen(encoded), encoded, strlen(encoded));
-
- if (enclen < 0) {
- log_warn(LD_REND, "Could not encrypt introduction point string.");
- goto done;
- }
- memcpy(iv, enc + 2 + client_entries_len, CIPHER_IV_LEN);
-
- /* Encrypt session key for cookies, determine client IDs, and put both
- * in a smartlist. */
- encrypted_session_keys = smartlist_new();
- SMARTLIST_FOREACH_BEGIN(client_cookies, const char *, cookie) {
- client_part = tor_malloc_zero(REND_BASIC_AUTH_CLIENT_ENTRY_LEN);
- /* Encrypt session key. */
- cipher = crypto_cipher_new(cookie);
- if (crypto_cipher_encrypt(cipher, client_part +
- REND_BASIC_AUTH_CLIENT_ID_LEN,
- session_key, CIPHER_KEY_LEN) < 0) {
- log_warn(LD_REND, "Could not encrypt session key for client.");
- crypto_cipher_free(cipher);
- tor_free(client_part);
- goto done;
- }
- crypto_cipher_free(cipher);
-
- /* Determine client ID. */
- digest = crypto_digest_new();
- crypto_digest_add_bytes(digest, cookie, REND_DESC_COOKIE_LEN);
- crypto_digest_add_bytes(digest, iv, CIPHER_IV_LEN);
- crypto_digest_get_digest(digest, client_part,
- REND_BASIC_AUTH_CLIENT_ID_LEN);
- crypto_digest_free(digest);
-
- /* Put both together. */
- smartlist_add(encrypted_session_keys, client_part);
- } SMARTLIST_FOREACH_END(cookie);
-
- /* Add some fake client IDs and encrypted session keys. */
- for (i = (smartlist_len(client_cookies) - 1) %
- REND_BASIC_AUTH_CLIENT_MULTIPLE;
- i < REND_BASIC_AUTH_CLIENT_MULTIPLE - 1; i++) {
- client_part = tor_malloc_zero(REND_BASIC_AUTH_CLIENT_ENTRY_LEN);
- crypto_rand(client_part, REND_BASIC_AUTH_CLIENT_ENTRY_LEN);
- smartlist_add(encrypted_session_keys, client_part);
- }
- /* Sort smartlist and put elements in result in order. */
- smartlist_sort_digests(encrypted_session_keys);
- pos = 2;
- SMARTLIST_FOREACH(encrypted_session_keys, const char *, entry, {
- memcpy(enc + pos, entry, REND_BASIC_AUTH_CLIENT_ENTRY_LEN);
- pos += REND_BASIC_AUTH_CLIENT_ENTRY_LEN;
- });
- *encrypted_out = enc;
- *encrypted_len_out = len;
- enc = NULL; /* prevent free. */
- r = 0;
- done:
- tor_free(enc);
- if (encrypted_session_keys) {
- SMARTLIST_FOREACH(encrypted_session_keys, char *, d, tor_free(d););
- smartlist_free(encrypted_session_keys);
- }
- return r;
-}
-
-/** Encrypt the encoded introduction points in <b>encoded</b> using
- * authorization type 'stealth' with <b>descriptor_cookie</b> of length
- * REND_DESC_COOKIE_LEN and write the result to a newly allocated string
- * pointed to by <b>encrypted_out</b> of length <b>encrypted_len_out</b>.
- * Return 0 for success, -1 otherwise. */
-static int
-rend_encrypt_v2_intro_points_stealth(char **encrypted_out,
- size_t *encrypted_len_out,
- const char *encoded,
- const char *descriptor_cookie)
-{
- int r = -1, enclen;
- char *enc;
- tor_assert(encoded);
- tor_assert(descriptor_cookie);
-
- enc = tor_malloc_zero(1 + CIPHER_IV_LEN + strlen(encoded));
- enc[0] = 0x02; /* Auth type */
- enclen = crypto_cipher_encrypt_with_iv(descriptor_cookie,
- enc + 1,
- CIPHER_IV_LEN+strlen(encoded),
- encoded, strlen(encoded));
- if (enclen < 0) {
- log_warn(LD_REND, "Could not encrypt introduction point string.");
- goto done;
- }
- *encrypted_out = enc;
- *encrypted_len_out = enclen;
- enc = NULL; /* prevent free */
- r = 0;
- done:
- tor_free(enc);
- return r;
-}
-
-/** Attempt to parse the given <b>desc_str</b> and return true if this
- * succeeds, false otherwise. */
-STATIC int
-rend_desc_v2_is_parsable(rend_encoded_v2_service_descriptor_t *desc)
-{
- rend_service_descriptor_t *test_parsed = NULL;
- char test_desc_id[DIGEST_LEN];
- char *test_intro_content = NULL;
- size_t test_intro_size;
- size_t test_encoded_size;
- const char *test_next;
- int res = rend_parse_v2_service_descriptor(&test_parsed, test_desc_id,
- &test_intro_content,
- &test_intro_size,
- &test_encoded_size,
- &test_next, desc->desc_str, 1);
- rend_service_descriptor_free(test_parsed);
- tor_free(test_intro_content);
- return (res >= 0);
-}
-
-/** Free the storage held by an encoded v2 service descriptor. */
-void
-rend_encoded_v2_service_descriptor_free_(
- rend_encoded_v2_service_descriptor_t *desc)
-{
- if (!desc)
- return;
- tor_free(desc->desc_str);
- tor_free(desc);
-}
-
-/** Free the storage held by an introduction point info. */
-void
-rend_intro_point_free_(rend_intro_point_t *intro)
-{
- if (!intro)
- return;
-
- extend_info_free(intro->extend_info);
- crypto_pk_free(intro->intro_key);
-
- if (intro->accepted_intro_rsa_parts != NULL) {
- replaycache_free(intro->accepted_intro_rsa_parts);
- }
-
- tor_free(intro);
-}
-
-/** Encode a set of rend_encoded_v2_service_descriptor_t's for <b>desc</b>
- * at time <b>now</b> using <b>service_key</b>, depending on
- * <b>auth_type</b> a <b>descriptor_cookie</b> and a list of
- * <b>client_cookies</b> (which are both <b>NULL</b> if no client
- * authorization is performed), and <b>period</b> (e.g. 0 for the current
- * period, 1 for the next period, etc.) and add them to the existing list
- * <b>descs_out</b>; return the number of seconds that the descriptors will
- * be found by clients, or -1 if the encoding was not successful. */
-int
-rend_encode_v2_descriptors(smartlist_t *descs_out,
- rend_service_descriptor_t *desc, time_t now,
- uint8_t period, rend_auth_type_t auth_type,
- crypto_pk_t *client_key,
- smartlist_t *client_cookies)
-{
- char service_id[DIGEST_LEN];
- char service_id_base32[REND_SERVICE_ID_LEN_BASE32+1];
- uint32_t time_period;
- char *ipos_base64 = NULL, *ipos = NULL, *ipos_encrypted = NULL,
- *descriptor_cookie = NULL;
- size_t ipos_len = 0, ipos_encrypted_len = 0;
- int k;
- uint32_t seconds_valid;
- crypto_pk_t *service_key;
- if (!desc) {
- log_warn(LD_BUG, "Could not encode v2 descriptor: No desc given.");
- return -1;
- }
- service_key = (auth_type == REND_STEALTH_AUTH) ? client_key : desc->pk;
- tor_assert(service_key);
- if (auth_type == REND_STEALTH_AUTH) {
- descriptor_cookie = smartlist_get(client_cookies, 0);
- tor_assert(descriptor_cookie);
- }
- /* Obtain service_id from public key. */
- if (crypto_pk_get_digest(service_key, service_id) < 0) {
- log_warn(LD_BUG, "Couldn't compute service key digest.");
- return -1;
- }
- /* Calculate current time-period. */
- time_period = get_time_period(now, period, service_id);
- /* Determine how many seconds the descriptor will be valid. */
- seconds_valid = period * REND_TIME_PERIOD_V2_DESC_VALIDITY +
- get_seconds_valid(now, service_id);
- /* Assemble, possibly encrypt, and encode introduction points. */
- if (smartlist_len(desc->intro_nodes) > 0) {
- if (rend_encode_v2_intro_points(&ipos, desc) < 0) {
- log_warn(LD_REND, "Encoding of introduction points did not succeed.");
- return -1;
- }
- switch (auth_type) {
- case REND_NO_AUTH:
- ipos_len = strlen(ipos);
- break;
- case REND_BASIC_AUTH:
- if (rend_encrypt_v2_intro_points_basic(&ipos_encrypted,
- &ipos_encrypted_len, ipos,
- client_cookies) < 0) {
- log_warn(LD_REND, "Encrypting of introduction points did not "
- "succeed.");
- tor_free(ipos);
- return -1;
- }
- tor_free(ipos);
- ipos = ipos_encrypted;
- ipos_len = ipos_encrypted_len;
- break;
- case REND_STEALTH_AUTH:
- if (rend_encrypt_v2_intro_points_stealth(&ipos_encrypted,
- &ipos_encrypted_len, ipos,
- descriptor_cookie) < 0) {
- log_warn(LD_REND, "Encrypting of introduction points did not "
- "succeed.");
- tor_free(ipos);
- return -1;
- }
- tor_free(ipos);
- ipos = ipos_encrypted;
- ipos_len = ipos_encrypted_len;
- break;
- default:
- log_warn(LD_REND|LD_BUG, "Unrecognized authorization type %d",
- (int)auth_type);
- tor_free(ipos);
- return -1;
- }
- /* Base64-encode introduction points. */
- ipos_base64 = tor_calloc(ipos_len, 2);
- if (base64_encode(ipos_base64, ipos_len * 2, ipos, ipos_len,
- BASE64_ENCODE_MULTILINE)<0) {
- log_warn(LD_REND, "Could not encode introduction point string to "
- "base64. length=%d", (int)ipos_len);
- tor_free(ipos_base64);
- tor_free(ipos);
- return -1;
- }
- tor_free(ipos);
- }
- /* Encode REND_NUMBER_OF_NON_CONSECUTIVE_REPLICAS descriptors. */
- for (k = 0; k < REND_NUMBER_OF_NON_CONSECUTIVE_REPLICAS; k++) {
- char secret_id_part[DIGEST_LEN];
- char secret_id_part_base32[REND_SECRET_ID_PART_LEN_BASE32 + 1];
- char desc_id_base32[REND_DESC_ID_V2_LEN_BASE32 + 1];
- char *permanent_key = NULL;
- size_t permanent_key_len;
- char published[ISO_TIME_LEN+1];
- int i;
- char protocol_versions_string[16]; /* max len: "0,1,2,3,4,5,6,7\0" */
- size_t protocol_versions_written;
- size_t desc_len;
- char *desc_str = NULL;
- int result = 0;
- size_t written = 0;
- char desc_digest[DIGEST_LEN];
- rend_encoded_v2_service_descriptor_t *enc =
- tor_malloc_zero(sizeof(rend_encoded_v2_service_descriptor_t));
- /* Calculate secret-id-part = h(time-period | cookie | replica). */
- get_secret_id_part_bytes(secret_id_part, time_period, descriptor_cookie,
- k);
- base32_encode(secret_id_part_base32, sizeof(secret_id_part_base32),
- secret_id_part, DIGEST_LEN);
- /* Calculate descriptor ID. */
- rend_get_descriptor_id_bytes(enc->desc_id, service_id, secret_id_part);
- base32_encode(desc_id_base32, sizeof(desc_id_base32),
- enc->desc_id, DIGEST_LEN);
- /* PEM-encode the public key */
- if (crypto_pk_write_public_key_to_string(service_key, &permanent_key,
- &permanent_key_len) < 0) {
- log_warn(LD_BUG, "Could not write public key to string.");
- rend_encoded_v2_service_descriptor_free(enc);
- goto err;
- }
- /* Encode timestamp. */
- format_iso_time(published, desc->timestamp);
- /* Write protocol-versions bitmask to comma-separated value string. */
- protocol_versions_written = 0;
- for (i = 0; i < 8; i++) {
- if (desc->protocols & 1 << i) {
- tor_snprintf(protocol_versions_string + protocol_versions_written,
- 16 - protocol_versions_written, "%d,", i);
- protocol_versions_written += 2;
- }
- }
- if (protocol_versions_written)
- protocol_versions_string[protocol_versions_written - 1] = '\0';
- else
- protocol_versions_string[0]= '\0';
- /* Assemble complete descriptor. */
- desc_len = 2000 + smartlist_len(desc->intro_nodes) * 1000; /* far too long,
- but okay.*/
- enc->desc_str = desc_str = tor_malloc_zero(desc_len);
- result = tor_snprintf(desc_str, desc_len,
- "rendezvous-service-descriptor %s\n"
- "version 2\n"
- "permanent-key\n%s"
- "secret-id-part %s\n"
- "publication-time %s\n"
- "protocol-versions %s\n",
- desc_id_base32,
- permanent_key,
- secret_id_part_base32,
- published,
- protocol_versions_string);
- tor_free(permanent_key);
- if (result < 0) {
- log_warn(LD_BUG, "Descriptor ran out of room.");
- rend_encoded_v2_service_descriptor_free(enc);
- goto err;
- }
- written = result;
- /* Add introduction points. */
- if (ipos_base64) {
- result = tor_snprintf(desc_str + written, desc_len - written,
- "introduction-points\n"
- "-----BEGIN MESSAGE-----\n%s"
- "-----END MESSAGE-----\n",
- ipos_base64);
- if (result < 0) {
- log_warn(LD_BUG, "could not write introduction points.");
- rend_encoded_v2_service_descriptor_free(enc);
- goto err;
- }
- written += result;
- }
- /* Add signature. */
- strlcpy(desc_str + written, "signature\n", desc_len - written);
- written += strlen(desc_str + written);
- if (crypto_digest(desc_digest, desc_str, written) < 0) {
- log_warn(LD_BUG, "could not create digest.");
- rend_encoded_v2_service_descriptor_free(enc);
- goto err;
- }
- if (router_append_dirobj_signature(desc_str + written,
- desc_len - written,
- desc_digest, DIGEST_LEN,
- service_key) < 0) {
- log_warn(LD_BUG, "Couldn't sign desc.");
- rend_encoded_v2_service_descriptor_free(enc);
- goto err;
- }
- written += strlen(desc_str+written);
- if (written+2 > desc_len) {
- log_warn(LD_BUG, "Could not finish desc.");
- rend_encoded_v2_service_descriptor_free(enc);
- goto err;
- }
- desc_str[written++] = 0;
- /* Check if we can parse our own descriptor. */
- if (!rend_desc_v2_is_parsable(enc)) {
- log_warn(LD_BUG, "Could not parse my own descriptor: %s", desc_str);
- rend_encoded_v2_service_descriptor_free(enc);
- goto err;
- }
- smartlist_add(descs_out, enc);
- /* Add the uploaded descriptor to the local service's descriptor cache */
- rend_cache_store_v2_desc_as_service(enc->desc_str);
- base32_encode(service_id_base32, sizeof(service_id_base32),
- service_id, REND_SERVICE_ID_LEN);
- control_event_hs_descriptor_created(service_id_base32, desc_id_base32, k);
- }
-
- log_info(LD_REND, "Successfully encoded a v2 descriptor and "
- "confirmed that it is parsable.");
- goto done;
-
- err:
- SMARTLIST_FOREACH(descs_out, rend_encoded_v2_service_descriptor_t *, d,
- rend_encoded_v2_service_descriptor_free(d););
- smartlist_clear(descs_out);
- seconds_valid = -1;
-
- done:
- tor_free(ipos_base64);
- return seconds_valid;
-}
-
-/** Sets <b>out</b> to the first 10 bytes of the digest of <b>pk</b>,
- * base32 encoded. NUL-terminates out. (We use this string to
- * identify services in directory requests and .onion URLs.)
- */
-int
-rend_get_service_id(crypto_pk_t *pk, char *out)
-{
- char buf[DIGEST_LEN];
- tor_assert(pk);
- if (crypto_pk_get_digest(pk, buf) < 0)
- return -1;
- base32_encode(out, REND_SERVICE_ID_LEN_BASE32+1, buf, REND_SERVICE_ID_LEN);
- return 0;
-}
-
-/** Return true iff <b>query</b> is a syntactically valid service ID (as
- * generated by rend_get_service_id). */
-int
-rend_valid_v2_service_id(const char *query)
-{
- if (strlen(query) != REND_SERVICE_ID_LEN_BASE32)
- return 0;
-
- if (strspn(query, BASE32_CHARS) != REND_SERVICE_ID_LEN_BASE32)
- return 0;
-
- return 1;
-}
-
-/** Return true iff <b>query</b> is a syntactically valid descriptor ID.
- * (as generated by rend_get_descriptor_id_bytes). */
-int
-rend_valid_descriptor_id(const char *query)
-{
- if (strlen(query) != REND_DESC_ID_V2_LEN_BASE32) {
- goto invalid;
- }
- if (strspn(query, BASE32_CHARS) != REND_DESC_ID_V2_LEN_BASE32) {
- goto invalid;
- }
-
- return 1;
-
- invalid:
- return 0;
-}
-
-/** Return true iff <b>client_name</b> is a syntactically valid name
- * for rendezvous client authentication. */
-int
-rend_valid_client_name(const char *client_name)
-{
- size_t len = strlen(client_name);
- if (len < 1 || len > REND_CLIENTNAME_MAX_LEN) {
- return 0;
- }
- if (strspn(client_name, REND_LEGAL_CLIENTNAME_CHARACTERS) != len) {
- return 0;
- }
-
- return 1;
-}
/** Called when we get a rendezvous-related relay cell on circuit
* <b>circ</b>. Dispatch on rendezvous relay command. */
@@ -840,168 +101,6 @@ rend_process_relay_cell(circuit_t *circ, const crypt_path_t *layer_hint,
command);
}
-/** Determine the routers that are responsible for <b>id</b> (binary) and
- * add pointers to those routers' routerstatus_t to <b>responsible_dirs</b>.
- * Return -1 if we're returning an empty smartlist, else return 0.
- */
-int
-hid_serv_get_responsible_directories(smartlist_t *responsible_dirs,
- const char *id)
-{
- int start, found, n_added = 0, i;
- networkstatus_t *c = networkstatus_get_latest_consensus();
- if (!c || !smartlist_len(c->routerstatus_list)) {
- log_info(LD_REND, "We don't have a consensus, so we can't perform v2 "
- "rendezvous operations.");
- return -1;
- }
- tor_assert(id);
- start = networkstatus_vote_find_entry_idx(c, id, &found);
- if (start == smartlist_len(c->routerstatus_list)) start = 0;
- i = start;
- do {
- routerstatus_t *r = smartlist_get(c->routerstatus_list, i);
- if (r->is_hs_dir) {
- smartlist_add(responsible_dirs, r);
- if (++n_added == REND_NUMBER_OF_CONSECUTIVE_REPLICAS)
- return 0;
- }
- if (++i == smartlist_len(c->routerstatus_list))
- i = 0;
- } while (i != start);
-
- /* Even though we don't have the desired number of hidden service
- * directories, be happy if we got any. */
- return smartlist_len(responsible_dirs) ? 0 : -1;
-}
-
-/* Length of the 'extended' auth cookie used to encode auth type before
- * base64 encoding. */
-#define REND_DESC_COOKIE_LEN_EXT (REND_DESC_COOKIE_LEN + 1)
-/* Length of the zero-padded auth cookie when base64 encoded. These two
- * padding bytes always (A=) are stripped off of the returned cookie. */
-#define REND_DESC_COOKIE_LEN_EXT_BASE64 (REND_DESC_COOKIE_LEN_BASE64 + 2)
-
-/** Encode a client authorization descriptor cookie.
- * The result of this function is suitable for use in the HidServAuth
- * option. The trailing padding characters are removed, and the
- * auth type is encoded into the cookie.
- *
- * Returns a new base64-encoded cookie. This function cannot fail.
- * The caller is responsible for freeing the returned value.
- */
-char *
-rend_auth_encode_cookie(const uint8_t *cookie_in, rend_auth_type_t auth_type)
-{
- uint8_t extended_cookie[REND_DESC_COOKIE_LEN_EXT];
- char *cookie_out = tor_malloc_zero(REND_DESC_COOKIE_LEN_EXT_BASE64 + 1);
- int re;
-
- tor_assert(cookie_in);
-
- memcpy(extended_cookie, cookie_in, REND_DESC_COOKIE_LEN);
- extended_cookie[REND_DESC_COOKIE_LEN] = ((int)auth_type - 1) << 4;
- re = base64_encode(cookie_out, REND_DESC_COOKIE_LEN_EXT_BASE64 + 1,
- (const char *) extended_cookie, REND_DESC_COOKIE_LEN_EXT,
- 0);
- tor_assert(re == REND_DESC_COOKIE_LEN_EXT_BASE64);
-
- /* Remove the trailing 'A='. Auth type is encoded in the high bits
- * of the last byte, so the last base64 character will always be zero
- * (A). This is subtly different behavior from base64_encode_nopad. */
- cookie_out[REND_DESC_COOKIE_LEN_BASE64] = '\0';
- memwipe(extended_cookie, 0, sizeof(extended_cookie));
- return cookie_out;
-}
-
-/** Decode a base64-encoded client authorization descriptor cookie.
- * The descriptor_cookie can be truncated to REND_DESC_COOKIE_LEN_BASE64
- * characters (as given to clients), or may include the two padding
- * characters (as stored by the service).
- *
- * The result is stored in REND_DESC_COOKIE_LEN bytes of cookie_out.
- * The rend_auth_type_t decoded from the cookie is stored in the
- * optional auth_type_out parameter.
- *
- * Return 0 on success, or -1 on error. The caller is responsible for
- * freeing the returned err_msg.
- */
-int
-rend_auth_decode_cookie(const char *cookie_in, uint8_t *cookie_out,
- rend_auth_type_t *auth_type_out, char **err_msg_out)
-{
- uint8_t descriptor_cookie_decoded[REND_DESC_COOKIE_LEN_EXT + 1] = { 0 };
- char descriptor_cookie_base64ext[REND_DESC_COOKIE_LEN_EXT_BASE64 + 1];
- const char *descriptor_cookie = cookie_in;
- char *err_msg = NULL;
- int auth_type_val = 0;
- int res = -1;
- int decoded_len;
-
- size_t len = strlen(descriptor_cookie);
- if (len == REND_DESC_COOKIE_LEN_BASE64) {
- /* Add a trailing zero byte to make base64-decoding happy. */
- tor_snprintf(descriptor_cookie_base64ext,
- sizeof(descriptor_cookie_base64ext),
- "%sA=", descriptor_cookie);
- descriptor_cookie = descriptor_cookie_base64ext;
- } else if (len != REND_DESC_COOKIE_LEN_EXT_BASE64) {
- tor_asprintf(&err_msg, "Authorization cookie has wrong length: %s",
- escaped(cookie_in));
- goto err;
- }
-
- decoded_len = base64_decode((char *) descriptor_cookie_decoded,
- sizeof(descriptor_cookie_decoded),
- descriptor_cookie,
- REND_DESC_COOKIE_LEN_EXT_BASE64);
- if (decoded_len != REND_DESC_COOKIE_LEN &&
- decoded_len != REND_DESC_COOKIE_LEN_EXT) {
- tor_asprintf(&err_msg, "Authorization cookie has invalid characters: %s",
- escaped(cookie_in));
- goto err;
- }
-
- if (auth_type_out) {
- auth_type_val = (descriptor_cookie_decoded[REND_DESC_COOKIE_LEN] >> 4) + 1;
- if (auth_type_val < 1 || auth_type_val > 2) {
- tor_asprintf(&err_msg, "Authorization cookie type is unknown: %s",
- escaped(cookie_in));
- goto err;
- }
- *auth_type_out = auth_type_val == 1 ? REND_BASIC_AUTH : REND_STEALTH_AUTH;
- }
-
- memcpy(cookie_out, descriptor_cookie_decoded, REND_DESC_COOKIE_LEN);
- res = 0;
- err:
- if (err_msg_out) {
- *err_msg_out = err_msg;
- } else {
- tor_free(err_msg);
- }
- memwipe(descriptor_cookie_decoded, 0, sizeof(descriptor_cookie_decoded));
- memwipe(descriptor_cookie_base64ext, 0, sizeof(descriptor_cookie_base64ext));
- return res;
-}
-
-/* Is this a rend client or server that allows direct (non-anonymous)
- * connections?
- * Onion services can be configured to start in this mode for single onion. */
-int
-rend_allow_non_anonymous_connection(const or_options_t* options)
-{
- return rend_service_allow_non_anonymous_connection(options);
-}
-
-/* Is this a rend client or server in non-anonymous mode?
- * Onion services can be configured to start in this mode for single onion. */
-int
-rend_non_anonymous_mode_enabled(const or_options_t *options)
-{
- return rend_service_non_anonymous_mode_enabled(options);
-}
-
/* Make sure that tor only builds one-hop circuits when they would not
* compromise user anonymity.
*
@@ -1020,35 +119,6 @@ assert_circ_anonymity_ok(const origin_circuit_t *circ,
tor_assert(circ->build_state);
if (circ->build_state->onehop_tunnel) {
- tor_assert(rend_allow_non_anonymous_connection(options));
- }
-}
-
-/* Return 1 iff the given <b>digest</b> of a permenanent hidden service key is
- * equal to the digest in the origin circuit <b>ocirc</b> of its rend data .
- * If the rend data doesn't exist, 0 is returned. This function is agnostic to
- * the rend data version. */
-int
-rend_circuit_pk_digest_eq(const origin_circuit_t *ocirc,
- const uint8_t *digest)
-{
- size_t rend_pk_digest_len;
- const uint8_t *rend_pk_digest;
-
- tor_assert(ocirc);
- tor_assert(digest);
-
- if (ocirc->rend_data == NULL) {
- goto no_match;
- }
-
- rend_pk_digest = rend_data_get_pk_digest(ocirc->rend_data,
- &rend_pk_digest_len);
- if (tor_memeq(rend_pk_digest, digest, rend_pk_digest_len)) {
- goto match;
+ tor_assert(hs_service_allow_non_anonymous_connection(options));
}
- no_match:
- return 0;
- match:
- return 1;
}
diff --git a/src/feature/rend/rendcommon.h b/src/feature/rend/rendcommon.h
index d8281e0578..113438e6fc 100644
--- a/src/feature/rend/rendcommon.h
+++ b/src/feature/rend/rendcommon.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -18,65 +18,12 @@ typedef enum rend_intro_point_failure_t {
INTRO_POINT_FAILURE_UNREACHABLE = 2,
} rend_intro_point_failure_t;
-int rend_cmp_service_ids(const char *one, const char *two);
-
void rend_process_relay_cell(circuit_t *circ, const crypt_path_t *layer_hint,
int command, size_t length,
const uint8_t *payload);
-void rend_service_descriptor_free_(rend_service_descriptor_t *desc);
-#define rend_service_descriptor_free(desc) \
- FREE_AND_NULL(rend_service_descriptor_t, rend_service_descriptor_free_, \
- (desc))
-int rend_get_service_id(crypto_pk_t *pk, char *out);
-void rend_encoded_v2_service_descriptor_free_(
- rend_encoded_v2_service_descriptor_t *desc);
-#define rend_encoded_v2_service_descriptor_free(desc) \
- FREE_AND_NULL(rend_encoded_v2_service_descriptor_t, \
- rend_encoded_v2_service_descriptor_free_, (desc))
-void rend_intro_point_free_(rend_intro_point_t *intro);
-#define rend_intro_point_free(intro) \
- FREE_AND_NULL(rend_intro_point_t, rend_intro_point_free_, (intro))
-
-int rend_valid_v2_service_id(const char *query);
-int rend_valid_descriptor_id(const char *query);
-int rend_valid_client_name(const char *client_name);
-int rend_encode_v2_descriptors(smartlist_t *descs_out,
- rend_service_descriptor_t *desc, time_t now,
- uint8_t period, rend_auth_type_t auth_type,
- crypto_pk_t *client_key,
- smartlist_t *client_cookies);
-int rend_compute_v2_desc_id(char *desc_id_out, const char *service_id,
- const char *descriptor_cookie,
- time_t now, uint8_t replica);
-void rend_get_descriptor_id_bytes(char *descriptor_id_out,
- const char *service_id,
- const char *secret_id_part);
-int hid_serv_get_responsible_directories(smartlist_t *responsible_dirs,
- const char *id);
-
-int rend_circuit_pk_digest_eq(const origin_circuit_t *ocirc,
- const uint8_t *digest);
-
-char *rend_auth_encode_cookie(const uint8_t *cookie_in,
- rend_auth_type_t auth_type);
-int rend_auth_decode_cookie(const char *cookie_in,
- uint8_t *cookie_out,
- rend_auth_type_t *auth_type_out,
- char **err_msg_out);
-
-int rend_allow_non_anonymous_connection(const or_options_t* options);
-int rend_non_anonymous_mode_enabled(const or_options_t *options);
-
void assert_circ_anonymity_ok(const origin_circuit_t *circ,
const or_options_t *options);
-#ifdef RENDCOMMON_PRIVATE
-
-STATIC int
-rend_desc_v2_is_parsable(rend_encoded_v2_service_descriptor_t *desc);
-
-#endif /* defined(RENDCOMMON_PRIVATE) */
-
#endif /* !defined(TOR_RENDCOMMON_H) */
diff --git a/src/feature/rend/rendmid.c b/src/feature/rend/rendmid.c
index b497362857..8f6a45dfef 100644
--- a/src/feature/rend/rendmid.c
+++ b/src/feature/rend/rendmid.c
@@ -1,5 +1,5 @@
/* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -16,217 +16,12 @@
#include "core/or/dos.h"
#include "core/or/relay.h"
#include "feature/rend/rendmid.h"
-#include "feature/stats/rephist.h"
#include "feature/hs/hs_circuitmap.h"
#include "feature/hs/hs_dos.h"
#include "feature/hs/hs_intropoint.h"
#include "core/or/or_circuit_st.h"
-/** Respond to an ESTABLISH_INTRO cell by checking the signed data and
- * setting the circuit's purpose and service pk digest.
- */
-int
-rend_mid_establish_intro_legacy(or_circuit_t *circ, const uint8_t *request,
- size_t request_len)
-{
- crypto_pk_t *pk = NULL;
- char buf[DIGEST_LEN+9];
- char expected_digest[DIGEST_LEN];
- char pk_digest[DIGEST_LEN];
- size_t asn1len;
- or_circuit_t *c;
- char serviceid[REND_SERVICE_ID_LEN_BASE32+1];
- int reason = END_CIRC_REASON_INTERNAL;
-
- log_info(LD_REND,
- "Received a legacy ESTABLISH_INTRO request on circuit %u",
- (unsigned) circ->p_circ_id);
-
- if (!hs_intro_circuit_is_suitable_for_establish_intro(circ)) {
- reason = END_CIRC_REASON_TORPROTOCOL;
- goto err;
- }
-
- if (request_len < 2+DIGEST_LEN)
- goto truncated;
- /* First 2 bytes: length of asn1-encoded key. */
- asn1len = ntohs(get_uint16(request));
-
- /* Next asn1len bytes: asn1-encoded key. */
- if (request_len < 2+DIGEST_LEN+asn1len)
- goto truncated;
- pk = crypto_pk_asn1_decode((char*)(request+2), asn1len);
- if (!pk) {
- reason = END_CIRC_REASON_TORPROTOCOL;
- log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "Couldn't decode public key.");
- goto err;
- }
-
- /* Next 20 bytes: Hash of rend_circ_nonce | "INTRODUCE" */
- memcpy(buf, circ->rend_circ_nonce, DIGEST_LEN);
- memcpy(buf+DIGEST_LEN, "INTRODUCE", 9);
- if (crypto_digest(expected_digest, buf, DIGEST_LEN+9) < 0) {
- log_warn(LD_BUG, "Internal error computing digest.");
- goto err;
- }
- if (tor_memneq(expected_digest, request+2+asn1len, DIGEST_LEN)) {
- log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
- "Hash of session info was not as expected.");
- reason = END_CIRC_REASON_TORPROTOCOL;
- goto err;
- }
- /* Rest of body: signature of previous data */
- if (crypto_pk_public_checksig_digest(pk,
- (char*)request, 2+asn1len+DIGEST_LEN,
- (char*)(request+2+DIGEST_LEN+asn1len),
- request_len-(2+DIGEST_LEN+asn1len))<0) {
- log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
- "Incorrect signature on ESTABLISH_INTRO cell; rejecting.");
- reason = END_CIRC_REASON_TORPROTOCOL;
- goto err;
- }
-
- /* The request is valid. First, compute the hash of the service's PK.*/
- if (crypto_pk_get_digest(pk, pk_digest)<0) {
- log_warn(LD_BUG, "Internal error: couldn't hash public key.");
- goto err;
- }
-
- crypto_pk_free(pk); /* don't need it anymore */
- pk = NULL; /* so we don't free it again if err */
-
- base32_encode(serviceid, REND_SERVICE_ID_LEN_BASE32+1,
- pk_digest, REND_SERVICE_ID_LEN);
-
- /* Close any other intro circuits with the same pk. */
- c = NULL;
- while ((c = hs_circuitmap_get_intro_circ_v2_relay_side(
- (const uint8_t *)pk_digest))) {
- log_info(LD_REND, "Replacing old circuit for service %s",
- safe_str(serviceid));
- circuit_mark_for_close(TO_CIRCUIT(c), END_CIRC_REASON_FINISHED);
- /* Now it's marked, and it won't be returned next time. */
- }
-
- /* Acknowledge the request. */
- if (hs_intro_send_intro_established_cell(circ) < 0) {
- log_info(LD_GENERAL, "Couldn't send INTRO_ESTABLISHED cell.");
- goto err_no_close;
- }
-
- /* Now, set up this circuit. */
- circuit_change_purpose(TO_CIRCUIT(circ), CIRCUIT_PURPOSE_INTRO_POINT);
- hs_circuitmap_register_intro_circ_v2_relay_side(circ, (uint8_t *)pk_digest);
- hs_dos_setup_default_intro2_defenses(circ);
-
- log_info(LD_REND,
- "Established introduction point on circuit %u for service %s",
- (unsigned) circ->p_circ_id, safe_str(serviceid));
-
- return 0;
- truncated:
- log_warn(LD_PROTOCOL, "Rejecting truncated ESTABLISH_INTRO cell.");
- reason = END_CIRC_REASON_TORPROTOCOL;
- err:
- circuit_mark_for_close(TO_CIRCUIT(circ), reason);
- err_no_close:
- if (pk) crypto_pk_free(pk);
- return -1;
-}
-
-/** Process an INTRODUCE1 cell by finding the corresponding introduction
- * circuit, and relaying the body of the INTRODUCE1 cell inside an
- * INTRODUCE2 cell.
- */
-int
-rend_mid_introduce_legacy(or_circuit_t *circ, const uint8_t *request,
- size_t request_len)
-{
- or_circuit_t *intro_circ;
- char serviceid[REND_SERVICE_ID_LEN_BASE32+1];
- char nak_body[1];
-
- log_info(LD_REND, "Received an INTRODUCE1 request on circuit %u",
- (unsigned)circ->p_circ_id);
-
- /* At this point, we know that the circuit is valid for an INTRODUCE1
- * because the validation has been made before calling this function. */
- tor_assert(circ->base_.purpose == CIRCUIT_PURPOSE_OR);
- tor_assert(!circ->base_.n_chan);
-
- /* We could change this to MAX_HEX_NICKNAME_LEN now that 0.0.9.x is
- * obsolete; however, there isn't much reason to do so, and we're going
- * to revise this protocol anyway.
- */
- if (request_len < (DIGEST_LEN+(MAX_NICKNAME_LEN+1)+REND_COOKIE_LEN+
- DH1024_KEY_LEN+CIPHER_KEY_LEN+
- PKCS1_OAEP_PADDING_OVERHEAD)) {
- log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
- "Impossibly short INTRODUCE1 cell on circuit %u; "
- "responding with nack.", (unsigned)circ->p_circ_id);
- goto err;
- }
-
- base32_encode(serviceid, REND_SERVICE_ID_LEN_BASE32+1,
- (char*)request, REND_SERVICE_ID_LEN);
-
- /* The first 20 bytes are all we look at: they have a hash of the service's
- * PK. */
- intro_circ = hs_circuitmap_get_intro_circ_v2_relay_side(
- (const uint8_t*)request);
- if (!intro_circ) {
- log_info(LD_REND,
- "No intro circ found for INTRODUCE1 cell (%s) from circuit %u; "
- "responding with nack.",
- safe_str(serviceid), (unsigned)circ->p_circ_id);
- goto err;
- }
-
- /* Before sending, lets make sure this cell can be sent on the service
- * circuit asking the DoS defenses. */
- if (!hs_dos_can_send_intro2(intro_circ)) {
- log_info(LD_PROTOCOL, "Can't relay INTRODUCE1 v2 cell due to DoS "
- "limitations. Sending NACK to client.");
- goto err;
- }
-
- log_info(LD_REND,
- "Sending introduction request for service %s "
- "from circ %u to circ %u",
- safe_str(serviceid), (unsigned)circ->p_circ_id,
- (unsigned)intro_circ->p_circ_id);
-
- /* Great. Now we just relay the cell down the circuit. */
- if (relay_send_command_from_edge(0, TO_CIRCUIT(intro_circ),
- RELAY_COMMAND_INTRODUCE2,
- (char*)request, request_len, NULL)) {
- log_warn(LD_GENERAL,
- "Unable to send INTRODUCE2 cell to Tor client.");
- /* Stop right now, the circuit has been closed. */
- return -1;
- }
- /* And send an ack down the client's circuit. Empty body means succeeded. */
- if (relay_send_command_from_edge(0,TO_CIRCUIT(circ),
- RELAY_COMMAND_INTRODUCE_ACK,
- NULL,0,NULL)) {
- log_warn(LD_GENERAL, "Unable to send INTRODUCE_ACK cell to Tor client.");
- /* Stop right now, the circuit has been closed. */
- return -1;
- }
-
- return 0;
- err:
- /* Send the client a NACK */
- nak_body[0] = 1;
- if (relay_send_command_from_edge(0,TO_CIRCUIT(circ),
- RELAY_COMMAND_INTRODUCE_ACK,
- nak_body, 1, NULL)) {
- log_warn(LD_GENERAL, "Unable to send NAK to Tor client.");
- }
- return -1;
-}
-
/** Process an ESTABLISH_RENDEZVOUS cell by setting the circuit's purpose and
* rendezvous cookie.
*/
@@ -336,7 +131,11 @@ rend_mid_rendezvous(or_circuit_t *circ, const uint8_t *request,
rend_circ = hs_circuitmap_get_rend_circ_relay_side(request);
if (!rend_circ) {
- log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
+ /* Once this was a LOG_PROTOCOL_WARN, but it can happen naturally if a
+ * client gives up on a rendezvous circuit after sending INTRODUCE1, but
+ * before the onion service sends the RENDEZVOUS1 cell.
+ */
+ log_fn(LOG_DEBUG, LD_PROTOCOL,
"Rejecting RENDEZVOUS1 cell with unrecognized rendezvous cookie %s.",
hexid);
reason = END_CIRC_REASON_TORPROTOCOL;
diff --git a/src/feature/rend/rendmid.h b/src/feature/rend/rendmid.h
index 789596d855..d42d5cfa05 100644
--- a/src/feature/rend/rendmid.h
+++ b/src/feature/rend/rendmid.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/rend/rendparse.c b/src/feature/rend/rendparse.c
deleted file mode 100644
index c28add5ca9..0000000000
--- a/src/feature/rend/rendparse.c
+++ /dev/null
@@ -1,612 +0,0 @@
-/* Copyright (c) 2001 Matej Pfajfar.
- * Copyright (c) 2001-2004, Roger Dingledine.
- * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
-/* See LICENSE for licensing information */
-
-/**
- * \file rendparse.c
- * \brief Code to parse and validate v2 hidden service descriptors.
- **/
-
-#include "core/or/or.h"
-#include "core/or/extendinfo.h"
-#include "feature/dirparse/parsecommon.h"
-#include "feature/dirparse/sigcommon.h"
-#include "feature/rend/rendcommon.h"
-#include "feature/rend/rendparse.h"
-#include "lib/memarea/memarea.h"
-
-#include "core/or/extend_info_st.h"
-#include "feature/rend/rend_authorized_client_st.h"
-#include "feature/rend/rend_intro_point_st.h"
-#include "feature/rend/rend_service_descriptor_st.h"
-
-/** List of tokens recognized in rendezvous service descriptors */
-static token_rule_t desc_token_table[] = {
- T1_START("rendezvous-service-descriptor", R_RENDEZVOUS_SERVICE_DESCRIPTOR,
- EQ(1), NO_OBJ),
- T1("version", R_VERSION, EQ(1), NO_OBJ),
- T1("permanent-key", R_PERMANENT_KEY, NO_ARGS, NEED_KEY_1024),
- T1("secret-id-part", R_SECRET_ID_PART, EQ(1), NO_OBJ),
- T1("publication-time", R_PUBLICATION_TIME, CONCAT_ARGS, NO_OBJ),
- T1("protocol-versions", R_PROTOCOL_VERSIONS, EQ(1), NO_OBJ),
- T01("introduction-points", R_INTRODUCTION_POINTS, NO_ARGS, NEED_OBJ),
- T1_END("signature", R_SIGNATURE, NO_ARGS, NEED_OBJ),
- END_OF_TABLE
-};
-
-/** List of tokens recognized in the (encrypted) list of introduction points of
- * rendezvous service descriptors */
-static token_rule_t ipo_token_table[] = {
- T1_START("introduction-point", R_IPO_IDENTIFIER, EQ(1), NO_OBJ),
- T1("ip-address", R_IPO_IP_ADDRESS, EQ(1), NO_OBJ),
- T1("onion-port", R_IPO_ONION_PORT, EQ(1), NO_OBJ),
- T1("onion-key", R_IPO_ONION_KEY, NO_ARGS, NEED_KEY_1024),
- T1("service-key", R_IPO_SERVICE_KEY, NO_ARGS, NEED_KEY_1024),
- END_OF_TABLE
-};
-
-/** List of tokens recognized in the (possibly encrypted) list of introduction
- * points of rendezvous service descriptors */
-static token_rule_t client_keys_token_table[] = {
- T1_START("client-name", C_CLIENT_NAME, CONCAT_ARGS, NO_OBJ),
- T1("descriptor-cookie", C_DESCRIPTOR_COOKIE, EQ(1), NO_OBJ),
- T01("client-key", C_CLIENT_KEY, NO_ARGS, NEED_SKEY_1024),
- END_OF_TABLE
-};
-
-/** Parse and validate the ASCII-encoded v2 descriptor in <b>desc</b>,
- * write the parsed descriptor to the newly allocated *<b>parsed_out</b>, the
- * binary descriptor ID of length DIGEST_LEN to <b>desc_id_out</b>, the
- * encrypted introduction points to the newly allocated
- * *<b>intro_points_encrypted_out</b>, their encrypted size to
- * *<b>intro_points_encrypted_size_out</b>, the size of the encoded descriptor
- * to *<b>encoded_size_out</b>, and a pointer to the possibly next
- * descriptor to *<b>next_out</b>; return 0 for success (including validation)
- * and -1 for failure.
- *
- * If <b>as_hsdir</b> is 1, we're parsing this as an HSDir, and we should
- * be strict about time formats.
- */
-int
-rend_parse_v2_service_descriptor(rend_service_descriptor_t **parsed_out,
- char *desc_id_out,
- char **intro_points_encrypted_out,
- size_t *intro_points_encrypted_size_out,
- size_t *encoded_size_out,
- const char **next_out, const char *desc,
- int as_hsdir)
-{
- rend_service_descriptor_t *result =
- tor_malloc_zero(sizeof(rend_service_descriptor_t));
- char desc_hash[DIGEST_LEN];
- const char *eos;
- smartlist_t *tokens = smartlist_new();
- directory_token_t *tok;
- char secret_id_part[DIGEST_LEN];
- int i, version, num_ok=1;
- smartlist_t *versions;
- char public_key_hash[DIGEST_LEN];
- char test_desc_id[DIGEST_LEN];
- memarea_t *area = NULL;
- const int strict_time_fmt = as_hsdir;
-
- tor_assert(desc);
- /* Check if desc starts correctly. */
- if (strcmpstart(desc, "rendezvous-service-descriptor ")) {
- log_info(LD_REND, "Descriptor does not start correctly.");
- goto err;
- }
- /* Compute descriptor hash for later validation. */
- if (router_get_hash_impl(desc, strlen(desc), desc_hash,
- "rendezvous-service-descriptor ",
- "\nsignature", '\n', DIGEST_SHA1) < 0) {
- log_warn(LD_REND, "Couldn't compute descriptor hash.");
- goto err;
- }
- /* Determine end of string. */
- eos = strstr(desc, "\nrendezvous-service-descriptor ");
- if (!eos)
- eos = desc + strlen(desc);
- else
- eos = eos + 1;
- /* Check length. */
- if (eos-desc > REND_DESC_MAX_SIZE) {
- /* XXXX+ If we are parsing this descriptor as a server, this
- * should be a protocol warning. */
- log_warn(LD_REND, "Descriptor length is %d which exceeds "
- "maximum rendezvous descriptor size of %d bytes.",
- (int)(eos-desc), REND_DESC_MAX_SIZE);
- goto err;
- }
- /* Tokenize descriptor. */
- area = memarea_new();
- if (tokenize_string(area, desc, eos, tokens, desc_token_table, 0)) {
- log_warn(LD_REND, "Error tokenizing descriptor.");
- goto err;
- }
- /* Set next to next descriptor, if available. */
- *next_out = eos;
- /* Set length of encoded descriptor. */
- *encoded_size_out = eos - desc;
- /* Check min allowed length of token list. */
- if (smartlist_len(tokens) < 7) {
- log_warn(LD_REND, "Impossibly short descriptor.");
- goto err;
- }
- /* Parse base32-encoded descriptor ID. */
- tok = find_by_keyword(tokens, R_RENDEZVOUS_SERVICE_DESCRIPTOR);
- tor_assert(tok == smartlist_get(tokens, 0));
- tor_assert(tok->n_args == 1);
- if (!rend_valid_descriptor_id(tok->args[0])) {
- log_warn(LD_REND, "Invalid descriptor ID: '%s'", tok->args[0]);
- goto err;
- }
- if (base32_decode(desc_id_out, DIGEST_LEN,
- tok->args[0], REND_DESC_ID_V2_LEN_BASE32) != DIGEST_LEN) {
- log_warn(LD_REND,
- "Descriptor ID has wrong length or illegal characters: %s",
- tok->args[0]);
- goto err;
- }
- /* Parse descriptor version. */
- tok = find_by_keyword(tokens, R_VERSION);
- tor_assert(tok->n_args == 1);
- result->version =
- (int) tor_parse_long(tok->args[0], 10, 0, INT_MAX, &num_ok, NULL);
- if (result->version != 2 || !num_ok) {
- /* If it's <2, it shouldn't be under this format. If the number
- * is greater than 2, we bumped it because we broke backward
- * compatibility. See how version numbers in our other formats
- * work. */
- log_warn(LD_REND, "Unrecognized descriptor version: %s",
- escaped(tok->args[0]));
- goto err;
- }
- /* Parse public key. */
- tok = find_by_keyword(tokens, R_PERMANENT_KEY);
- result->pk = tok->key;
- tok->key = NULL; /* Prevent free */
- /* Parse secret ID part. */
- tok = find_by_keyword(tokens, R_SECRET_ID_PART);
- tor_assert(tok->n_args == 1);
- if (strlen(tok->args[0]) != REND_SECRET_ID_PART_LEN_BASE32 ||
- strspn(tok->args[0], BASE32_CHARS) != REND_SECRET_ID_PART_LEN_BASE32) {
- log_warn(LD_REND, "Invalid secret ID part: '%s'", tok->args[0]);
- goto err;
- }
- if (base32_decode(secret_id_part, DIGEST_LEN, tok->args[0], 32) !=
- DIGEST_LEN) {
- log_warn(LD_REND,
- "Secret ID part has wrong length or illegal characters: %s",
- tok->args[0]);
- goto err;
- }
- /* Parse publication time -- up-to-date check is done when storing the
- * descriptor. */
- tok = find_by_keyword(tokens, R_PUBLICATION_TIME);
- tor_assert(tok->n_args == 1);
- if (parse_iso_time_(tok->args[0], &result->timestamp,
- strict_time_fmt, 0) < 0) {
- log_warn(LD_REND, "Invalid publication time: '%s'", tok->args[0]);
- goto err;
- }
- /* Parse protocol versions. */
- tok = find_by_keyword(tokens, R_PROTOCOL_VERSIONS);
- tor_assert(tok->n_args == 1);
- versions = smartlist_new();
- smartlist_split_string(versions, tok->args[0], ",",
- SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
- for (i = 0; i < smartlist_len(versions); i++) {
- version = (int) tor_parse_long(smartlist_get(versions, i),
- 10, 0, INT_MAX, &num_ok, NULL);
- if (!num_ok) /* It's a string; let's ignore it. */
- continue;
- if (version >= REND_PROTOCOL_VERSION_BITMASK_WIDTH)
- /* Avoid undefined left-shift behaviour. */
- continue;
- result->protocols |= 1 << version;
- }
- SMARTLIST_FOREACH(versions, char *, cp, tor_free(cp));
- smartlist_free(versions);
- /* Parse encrypted introduction points. Don't verify. */
- tok = find_opt_by_keyword(tokens, R_INTRODUCTION_POINTS);
- if (tok) {
- if (strcmp(tok->object_type, "MESSAGE")) {
- log_warn(LD_DIR, "Bad object type: introduction points should be of "
- "type MESSAGE");
- goto err;
- }
- *intro_points_encrypted_out = tor_memdup(tok->object_body,
- tok->object_size);
- *intro_points_encrypted_size_out = tok->object_size;
- } else {
- *intro_points_encrypted_out = NULL;
- *intro_points_encrypted_size_out = 0;
- }
- /* Parse and verify signature. */
- tok = find_by_keyword(tokens, R_SIGNATURE);
- if (check_signature_token(desc_hash, DIGEST_LEN, tok, result->pk, 0,
- "v2 rendezvous service descriptor") < 0)
- goto err;
- /* Verify that descriptor ID belongs to public key and secret ID part. */
- if (crypto_pk_get_digest(result->pk, public_key_hash) < 0) {
- log_warn(LD_REND, "Unable to compute rend descriptor public key digest");
- goto err;
- }
- rend_get_descriptor_id_bytes(test_desc_id, public_key_hash,
- secret_id_part);
- if (tor_memneq(desc_id_out, test_desc_id, DIGEST_LEN)) {
- log_warn(LD_REND, "Parsed descriptor ID does not match "
- "computed descriptor ID.");
- goto err;
- }
- goto done;
- err:
- rend_service_descriptor_free(result);
- result = NULL;
- done:
- if (tokens) {
- SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_clear(t));
- smartlist_free(tokens);
- }
- if (area)
- memarea_drop_all(area);
- *parsed_out = result;
- if (result)
- return 0;
- return -1;
-}
-
-/** Decrypt the encrypted introduction points in <b>ipos_encrypted</b> of
- * length <b>ipos_encrypted_size</b> using <b>descriptor_cookie</b> and
- * write the result to a newly allocated string that is pointed to by
- * <b>ipos_decrypted</b> and its length to <b>ipos_decrypted_size</b>.
- * Return 0 if decryption was successful and -1 otherwise. */
-int
-rend_decrypt_introduction_points(char **ipos_decrypted,
- size_t *ipos_decrypted_size,
- const char *descriptor_cookie,
- const char *ipos_encrypted,
- size_t ipos_encrypted_size)
-{
- tor_assert(ipos_encrypted);
- tor_assert(descriptor_cookie);
- if (ipos_encrypted_size < 2) {
- log_warn(LD_REND, "Size of encrypted introduction points is too "
- "small.");
- return -1;
- }
- if (ipos_encrypted[0] == (int)REND_BASIC_AUTH) {
- char iv[CIPHER_IV_LEN], client_id[REND_BASIC_AUTH_CLIENT_ID_LEN],
- session_key[CIPHER_KEY_LEN], *dec;
- int declen, client_blocks;
- size_t pos = 0, len, client_entries_len;
- crypto_digest_t *digest;
- crypto_cipher_t *cipher;
- client_blocks = (int) ipos_encrypted[1];
- client_entries_len = client_blocks * REND_BASIC_AUTH_CLIENT_MULTIPLE *
- REND_BASIC_AUTH_CLIENT_ENTRY_LEN;
- if (ipos_encrypted_size < 2 + client_entries_len + CIPHER_IV_LEN + 1) {
- log_warn(LD_REND, "Size of encrypted introduction points is too "
- "small.");
- return -1;
- }
- memcpy(iv, ipos_encrypted + 2 + client_entries_len, CIPHER_IV_LEN);
- digest = crypto_digest_new();
- crypto_digest_add_bytes(digest, descriptor_cookie, REND_DESC_COOKIE_LEN);
- crypto_digest_add_bytes(digest, iv, CIPHER_IV_LEN);
- crypto_digest_get_digest(digest, client_id,
- REND_BASIC_AUTH_CLIENT_ID_LEN);
- crypto_digest_free(digest);
- for (pos = 2; pos < 2 + client_entries_len;
- pos += REND_BASIC_AUTH_CLIENT_ENTRY_LEN) {
- if (tor_memeq(ipos_encrypted + pos, client_id,
- REND_BASIC_AUTH_CLIENT_ID_LEN)) {
- /* Attempt to decrypt introduction points. */
- cipher = crypto_cipher_new(descriptor_cookie);
- if (crypto_cipher_decrypt(cipher, session_key, ipos_encrypted
- + pos + REND_BASIC_AUTH_CLIENT_ID_LEN,
- CIPHER_KEY_LEN) < 0) {
- log_warn(LD_REND, "Could not decrypt session key for client.");
- crypto_cipher_free(cipher);
- return -1;
- }
- crypto_cipher_free(cipher);
-
- len = ipos_encrypted_size - 2 - client_entries_len - CIPHER_IV_LEN;
- dec = tor_malloc_zero(len + 1);
- declen = crypto_cipher_decrypt_with_iv(session_key, dec, len,
- ipos_encrypted + 2 + client_entries_len,
- ipos_encrypted_size - 2 - client_entries_len);
-
- if (declen < 0) {
- log_warn(LD_REND, "Could not decrypt introduction point string.");
- tor_free(dec);
- return -1;
- }
- if (fast_memcmpstart(dec, declen, "introduction-point ")) {
- log_warn(LD_REND, "Decrypted introduction points don't "
- "look like we could parse them.");
- tor_free(dec);
- continue;
- }
- *ipos_decrypted = dec;
- *ipos_decrypted_size = declen;
- return 0;
- }
- }
- log_warn(LD_REND, "Could not decrypt introduction points. Please "
- "check your authorization for this service!");
- return -1;
- } else if (ipos_encrypted[0] == (int)REND_STEALTH_AUTH) {
- char *dec;
- int declen;
- if (ipos_encrypted_size < CIPHER_IV_LEN + 2) {
- log_warn(LD_REND, "Size of encrypted introduction points is too "
- "small.");
- return -1;
- }
- dec = tor_malloc_zero(ipos_encrypted_size - CIPHER_IV_LEN - 1 + 1);
-
- declen = crypto_cipher_decrypt_with_iv(descriptor_cookie, dec,
- ipos_encrypted_size -
- CIPHER_IV_LEN - 1,
- ipos_encrypted + 1,
- ipos_encrypted_size - 1);
-
- if (declen < 0) {
- log_warn(LD_REND, "Decrypting introduction points failed!");
- tor_free(dec);
- return -1;
- }
- *ipos_decrypted = dec;
- *ipos_decrypted_size = declen;
- return 0;
- } else {
- log_warn(LD_REND, "Unknown authorization type number: %d",
- ipos_encrypted[0]);
- return -1;
- }
-}
-
-/** Parse the encoded introduction points in <b>intro_points_encoded</b> of
- * length <b>intro_points_encoded_size</b> and write the result to the
- * descriptor in <b>parsed</b>; return the number of successfully parsed
- * introduction points or -1 in case of a failure. */
-int
-rend_parse_introduction_points(rend_service_descriptor_t *parsed,
- const char *intro_points_encoded,
- size_t intro_points_encoded_size)
-{
- const char *current_ipo, *end_of_intro_points;
- smartlist_t *tokens = NULL;
- directory_token_t *tok;
- rend_intro_point_t *intro;
- extend_info_t *info;
- int result, num_ok=1;
- memarea_t *area = NULL;
- tor_assert(parsed);
- /** Function may only be invoked once. */
- tor_assert(!parsed->intro_nodes);
- if (!intro_points_encoded || intro_points_encoded_size == 0) {
- log_warn(LD_REND, "Empty or zero size introduction point list");
- goto err;
- }
- /* Consider one intro point after the other. */
- current_ipo = intro_points_encoded;
- end_of_intro_points = intro_points_encoded + intro_points_encoded_size;
- tokens = smartlist_new();
- parsed->intro_nodes = smartlist_new();
- area = memarea_new();
-
- while (!fast_memcmpstart(current_ipo, end_of_intro_points-current_ipo,
- "introduction-point ")) {
- /* Determine end of string. */
- const char *eos = tor_memstr(current_ipo, end_of_intro_points-current_ipo,
- "\nintroduction-point ");
- if (!eos)
- eos = end_of_intro_points;
- else
- eos = eos+1;
- tor_assert(eos <= intro_points_encoded+intro_points_encoded_size);
- /* Free tokens and clear token list. */
- SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_clear(t));
- smartlist_clear(tokens);
- memarea_clear(area);
- /* Tokenize string. */
- if (tokenize_string(area, current_ipo, eos, tokens, ipo_token_table, 0)) {
- log_warn(LD_REND, "Error tokenizing introduction point");
- goto err;
- }
- /* Advance to next introduction point, if available. */
- current_ipo = eos;
- /* Check minimum allowed length of introduction point. */
- if (smartlist_len(tokens) < 5) {
- log_warn(LD_REND, "Impossibly short introduction point.");
- goto err;
- }
- /* Allocate new intro point and extend info. */
- intro = tor_malloc_zero(sizeof(rend_intro_point_t));
- info = intro->extend_info =
- extend_info_new(NULL, NULL, NULL, NULL, NULL, NULL, 0);
- /* Parse identifier. */
- tok = find_by_keyword(tokens, R_IPO_IDENTIFIER);
- if (base32_decode(info->identity_digest, DIGEST_LEN,
- tok->args[0], REND_INTRO_POINT_ID_LEN_BASE32) !=
- DIGEST_LEN) {
- log_warn(LD_REND,
- "Identity digest has wrong length or illegal characters: %s",
- tok->args[0]);
- rend_intro_point_free(intro);
- goto err;
- }
- /* Write identifier to nickname. */
- info->nickname[0] = '$';
- base16_encode(info->nickname + 1, sizeof(info->nickname) - 1,
- info->identity_digest, DIGEST_LEN);
- /* Parse IP address. */
- tok = find_by_keyword(tokens, R_IPO_IP_ADDRESS);
- tor_addr_t addr;
- if (tor_addr_parse(&addr, tok->args[0])<0) {
- log_warn(LD_REND, "Could not parse introduction point address.");
- rend_intro_point_free(intro);
- goto err;
- }
- if (tor_addr_family(&addr) != AF_INET) {
- log_warn(LD_REND, "Introduction point address was not ipv4.");
- rend_intro_point_free(intro);
- goto err;
- }
-
- /* Parse onion port. */
- tok = find_by_keyword(tokens, R_IPO_ONION_PORT);
- uint16_t port = (uint16_t) tor_parse_long(tok->args[0],10,1,65535,
- &num_ok,NULL);
- if (!port || !num_ok) {
- log_warn(LD_REND, "Introduction point onion port %s is invalid",
- escaped(tok->args[0]));
- rend_intro_point_free(intro);
- goto err;
- }
-
- /* Add the address and port. */
- extend_info_add_orport(info, &addr, port);
-
- /* Parse onion key. */
- tok = find_by_keyword(tokens, R_IPO_ONION_KEY);
- if (!crypto_pk_public_exponent_ok(tok->key)) {
- log_warn(LD_REND,
- "Introduction point's onion key had invalid exponent.");
- rend_intro_point_free(intro);
- goto err;
- }
- info->onion_key = tok->key;
- tok->key = NULL; /* Prevent free */
- /* Parse service key. */
- tok = find_by_keyword(tokens, R_IPO_SERVICE_KEY);
- if (!crypto_pk_public_exponent_ok(tok->key)) {
- log_warn(LD_REND,
- "Introduction point key had invalid exponent.");
- rend_intro_point_free(intro);
- goto err;
- }
- intro->intro_key = tok->key;
- tok->key = NULL; /* Prevent free */
- /* Add extend info to list of introduction points. */
- smartlist_add(parsed->intro_nodes, intro);
- }
- result = smartlist_len(parsed->intro_nodes);
- goto done;
-
- err:
- result = -1;
-
- done:
- /* Free tokens and clear token list. */
- if (tokens) {
- SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_clear(t));
- smartlist_free(tokens);
- }
- if (area)
- memarea_drop_all(area);
-
- return result;
-}
-
-/** Parse the content of a client_key file in <b>ckstr</b> and add
- * rend_authorized_client_t's for each parsed client to
- * <b>parsed_clients</b>. Return the number of parsed clients as result
- * or -1 for failure. */
-int
-rend_parse_client_keys(strmap_t *parsed_clients, const char *ckstr)
-{
- int result = -1;
- smartlist_t *tokens;
- directory_token_t *tok;
- const char *current_entry = NULL;
- memarea_t *area = NULL;
- char *err_msg = NULL;
- if (!ckstr || strlen(ckstr) == 0)
- return -1;
- tokens = smartlist_new();
- /* Begin parsing with first entry, skipping comments or whitespace at the
- * beginning. */
- area = memarea_new();
- current_entry = eat_whitespace(ckstr);
- while (!strcmpstart(current_entry, "client-name ")) {
- rend_authorized_client_t *parsed_entry;
- /* Determine end of string. */
- const char *eos = strstr(current_entry, "\nclient-name ");
- if (!eos)
- eos = current_entry + strlen(current_entry);
- else
- eos = eos + 1;
- /* Free tokens and clear token list. */
- SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_clear(t));
- smartlist_clear(tokens);
- memarea_clear(area);
- /* Tokenize string. */
- if (tokenize_string(area, current_entry, eos, tokens,
- client_keys_token_table, 0)) {
- log_warn(LD_REND, "Error tokenizing client keys file.");
- goto err;
- }
- /* Advance to next entry, if available. */
- current_entry = eos;
- /* Check minimum allowed length of token list. */
- if (smartlist_len(tokens) < 2) {
- log_warn(LD_REND, "Impossibly short client key entry.");
- goto err;
- }
- /* Parse client name. */
- tok = find_by_keyword(tokens, C_CLIENT_NAME);
- tor_assert(tok == smartlist_get(tokens, 0));
- tor_assert(tok->n_args == 1);
-
- if (!rend_valid_client_name(tok->args[0])) {
- log_warn(LD_CONFIG, "Illegal client name: %s. (Length must be "
- "between 1 and %d, and valid characters are "
- "[A-Za-z0-9+-_].)", tok->args[0], REND_CLIENTNAME_MAX_LEN);
- goto err;
- }
- /* Check if client name is duplicate. */
- if (strmap_get(parsed_clients, tok->args[0])) {
- log_warn(LD_CONFIG, "HiddenServiceAuthorizeClient contains a "
- "duplicate client name: '%s'. Ignoring.", tok->args[0]);
- goto err;
- }
- parsed_entry = tor_malloc_zero(sizeof(rend_authorized_client_t));
- parsed_entry->client_name = tor_strdup(tok->args[0]);
- strmap_set(parsed_clients, parsed_entry->client_name, parsed_entry);
- /* Parse client key. */
- tok = find_opt_by_keyword(tokens, C_CLIENT_KEY);
- if (tok) {
- parsed_entry->client_key = tok->key;
- tok->key = NULL; /* Prevent free */
- }
-
- /* Parse descriptor cookie. */
- tok = find_by_keyword(tokens, C_DESCRIPTOR_COOKIE);
- tor_assert(tok->n_args == 1);
- if (rend_auth_decode_cookie(tok->args[0], parsed_entry->descriptor_cookie,
- NULL, &err_msg) < 0) {
- tor_assert(err_msg);
- log_warn(LD_REND, "%s", err_msg);
- tor_free(err_msg);
- goto err;
- }
- }
- result = strmap_size(parsed_clients);
- goto done;
- err:
- result = -1;
- done:
- /* Free tokens and clear token list. */
- SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_clear(t));
- smartlist_free(tokens);
- if (area)
- memarea_drop_all(area);
- return result;
-}
diff --git a/src/feature/rend/rendparse.h b/src/feature/rend/rendparse.h
deleted file mode 100644
index 75109c204d..0000000000
--- a/src/feature/rend/rendparse.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/* Copyright (c) 2001 Matej Pfajfar.
- * Copyright (c) 2001-2004, Roger Dingledine.
- * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
-/* See LICENSE for licensing information */
-
-/**
- * \file rendparse.h
- * \brief Header file for rendparse.c.
- **/
-
-#ifndef TOR_REND_PARSE_H
-#define TOR_REND_PARSE_H
-
-int rend_parse_v2_service_descriptor(rend_service_descriptor_t **parsed_out,
- char *desc_id_out,
- char **intro_points_encrypted_out,
- size_t *intro_points_encrypted_size_out,
- size_t *encoded_size_out,
- const char **next_out, const char *desc,
- int as_hsdir);
-int rend_decrypt_introduction_points(char **ipos_decrypted,
- size_t *ipos_decrypted_size,
- const char *descriptor_cookie,
- const char *ipos_encrypted,
- size_t ipos_encrypted_size);
-int rend_parse_introduction_points(rend_service_descriptor_t *parsed,
- const char *intro_points_encoded,
- size_t intro_points_encoded_size);
-int rend_parse_client_keys(strmap_t *parsed_clients, const char *str);
-
-#endif /* !defined(TOR_REND_PARSE_H) */
diff --git a/src/feature/rend/rendservice.c b/src/feature/rend/rendservice.c
deleted file mode 100644
index a2be900e2a..0000000000
--- a/src/feature/rend/rendservice.c
+++ /dev/null
@@ -1,4535 +0,0 @@
-/* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
-/* See LICENSE for licensing information */
-
-/**
- * \file rendservice.c
- * \brief The hidden-service side of rendezvous functionality.
- **/
-
-#define RENDSERVICE_PRIVATE
-
-#include "core/or/or.h"
-
-#include "app/config/config.h"
-#include "core/mainloop/mainloop.h"
-#include "core/or/circuitbuild.h"
-#include "core/or/circuitlist.h"
-#include "core/or/circuituse.h"
-#include "core/or/extendinfo.h"
-#include "core/or/policies.h"
-#include "core/or/relay.h"
-#include "core/or/crypt_path.h"
-#include "feature/client/circpathbias.h"
-#include "feature/control/control_events.h"
-#include "feature/dirclient/dirclient.h"
-#include "feature/dircommon/directory.h"
-#include "feature/hs/hs_common.h"
-#include "feature/hs/hs_config.h"
-#include "feature/hs_common/replaycache.h"
-#include "feature/keymgt/loadkey.h"
-#include "feature/nodelist/describe.h"
-#include "feature/nodelist/networkstatus.h"
-#include "feature/nodelist/nickname.h"
-#include "feature/nodelist/node_select.h"
-#include "feature/nodelist/nodelist.h"
-#include "feature/nodelist/routerset.h"
-#include "feature/rend/rendclient.h"
-#include "feature/rend/rendcommon.h"
-#include "feature/rend/rendparse.h"
-#include "feature/rend/rendservice.h"
-#include "feature/stats/predict_ports.h"
-#include "lib/crypt_ops/crypto_dh.h"
-#include "lib/crypt_ops/crypto_rand.h"
-#include "lib/crypt_ops/crypto_util.h"
-#include "lib/encoding/confline.h"
-#include "lib/net/resolve.h"
-
-#include "core/or/cpath_build_state_st.h"
-#include "core/or/crypt_path_st.h"
-#include "core/or/crypt_path_reference_st.h"
-#include "core/or/edge_connection_st.h"
-#include "core/or/extend_info_st.h"
-#include "feature/hs/hs_opts_st.h"
-#include "feature/nodelist/networkstatus_st.h"
-#include "core/or/origin_circuit_st.h"
-#include "feature/rend/rend_authorized_client_st.h"
-#include "feature/rend/rend_encoded_v2_service_descriptor_st.h"
-#include "feature/rend/rend_intro_point_st.h"
-#include "feature/rend/rend_service_descriptor_st.h"
-#include "feature/nodelist/routerstatus_st.h"
-
-#ifdef HAVE_FCNTL_H
-#include <fcntl.h>
-#endif
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-#ifdef HAVE_SYS_STAT_H
-#include <sys/stat.h>
-#endif
-
-struct rend_service_t;
-static origin_circuit_t *find_intro_circuit(rend_intro_point_t *intro,
- const char *pk_digest);
-static rend_intro_point_t *find_intro_point(origin_circuit_t *circ);
-static rend_intro_point_t *find_expiring_intro_point(
- struct rend_service_t *service, origin_circuit_t *circ);
-
-static extend_info_t *find_rp_for_intro(
- const rend_intro_cell_t *intro,
- char **err_msg_out);
-
-static int intro_point_accepted_intro_count(rend_intro_point_t *intro);
-static int intro_point_should_expire_now(rend_intro_point_t *intro,
- time_t now);
-static int rend_service_derive_key_digests(struct rend_service_t *s);
-static int rend_service_load_keys(struct rend_service_t *s);
-static int rend_service_load_auth_keys(struct rend_service_t *s,
- const char *hfname);
-static struct rend_service_t *rend_service_get_by_pk_digest(
- const char* digest);
-static struct rend_service_t *rend_service_get_by_service_id(const char *id);
-static const char *rend_service_escaped_dir(
- const struct rend_service_t *s);
-
-static ssize_t rend_service_parse_intro_for_v0_or_v1(
- rend_intro_cell_t *intro,
- const uint8_t *buf,
- size_t plaintext_len,
- char **err_msg_out);
-static ssize_t rend_service_parse_intro_for_v2(
- rend_intro_cell_t *intro,
- const uint8_t *buf,
- size_t plaintext_len,
- char **err_msg_out);
-static ssize_t rend_service_parse_intro_for_v3(
- rend_intro_cell_t *intro,
- const uint8_t *buf,
- size_t plaintext_len,
- char **err_msg_out);
-
-static int rend_service_check_private_dir(const or_options_t *options,
- const rend_service_t *s,
- int create);
-static const smartlist_t* rend_get_service_list(
- const smartlist_t* substitute_service_list);
-static smartlist_t* rend_get_service_list_mutable(
- smartlist_t* substitute_service_list);
-static int rend_max_intro_circs_per_period(unsigned int n_intro_points_wanted);
-
-/* Hidden service directory file names:
- * new file names should be added to rend_service_add_filenames_to_list()
- * for sandboxing purposes. */
-static const char *private_key_fname = "private_key";
-static const char *hostname_fname = "hostname";
-static const char *client_keys_fname = "client_keys";
-static const char *sos_poison_fname = "onion_service_non_anonymous";
-
-/** A list of rend_service_t's for services run on this OP. */
-static smartlist_t *rend_service_list = NULL;
-/** A list of rend_service_t's for services run on this OP which is used as a
- * staging area before they are put in the main list in order to prune dying
- * service on config reload. */
-static smartlist_t *rend_service_staging_list = NULL;
-
-/** Helper: log the deprecation warning for version 2 only once. */
-static void
-log_once_deprecation_warning(void)
-{
- static bool logged_once = false;
- if (!logged_once) {
- log_warn(LD_REND, "DEPRECATED: Onion service version 2 are deprecated. "
- "Please use version 3 which is the default now. "
- "Currently, version 2 is planned to be obsolete in "
- "the Tor version 0.4.6 stable series.");
- logged_once = true;
- }
-}
-/** Macro to make it very explicit that we are warning about deprecation. */
-#define WARN_ONCE_DEPRECATION() log_once_deprecation_warning()
-
-/* Like rend_get_service_list_mutable, but returns a read-only list. */
-static const smartlist_t*
-rend_get_service_list(const smartlist_t* substitute_service_list)
-{
- /* It is safe to cast away the const here, because
- * rend_get_service_list_mutable does not actually modify the list */
- return rend_get_service_list_mutable((smartlist_t*)substitute_service_list);
-}
-
-/* Return a mutable list of hidden services.
- * If substitute_service_list is not NULL, return it.
- * Otherwise, check if the global rend_service_list is non-NULL, and if so,
- * return it.
- * Otherwise, log a BUG message and return NULL.
- * */
-static smartlist_t*
-rend_get_service_list_mutable(smartlist_t* substitute_service_list)
-{
- if (substitute_service_list) {
- return substitute_service_list;
- }
-
- /* If no special service list is provided, then just use the global one. */
-
- if (BUG(!rend_service_list)) {
- /* No global HS list, which is a programmer error. */
- return NULL;
- }
-
- return rend_service_list;
-}
-
-/** Tells if onion service <b>s</b> is ephemeral.
- */
-static unsigned int
-rend_service_is_ephemeral(const struct rend_service_t *s)
-{
- return (s->directory == NULL);
-}
-
-/** Returns a escaped string representation of the service, <b>s</b>.
- */
-static const char *
-rend_service_escaped_dir(const struct rend_service_t *s)
-{
- return rend_service_is_ephemeral(s) ? "[EPHEMERAL]" : escaped(s->directory);
-}
-
-/** Return the number of rendezvous services we have configured. */
-int
-rend_num_services(void)
-{
- if (!rend_service_list)
- return 0;
- return smartlist_len(rend_service_list);
-}
-
-/** Helper: free storage held by a single service authorized client entry. */
-void
-rend_authorized_client_free_(rend_authorized_client_t *client)
-{
- if (!client)
- return;
- if (client->client_key)
- crypto_pk_free(client->client_key);
- if (client->client_name)
- memwipe(client->client_name, 0, strlen(client->client_name));
- tor_free(client->client_name);
- memwipe(client->descriptor_cookie, 0, sizeof(client->descriptor_cookie));
- tor_free(client);
-}
-
-/** Helper for strmap_free. */
-static void
-rend_authorized_client_free_void(void *authorized_client)
-{
- rend_authorized_client_free_(authorized_client);
-}
-
-/** Release the storage held by <b>service</b>.
- */
-STATIC void
-rend_service_free_(rend_service_t *service)
-{
- if (!service)
- return;
-
- tor_free(service->directory);
- if (service->ports) {
- SMARTLIST_FOREACH(service->ports, rend_service_port_config_t*, p,
- rend_service_port_config_free(p));
- smartlist_free(service->ports);
- }
- if (service->private_key)
- crypto_pk_free(service->private_key);
- if (service->intro_nodes) {
- SMARTLIST_FOREACH(service->intro_nodes, rend_intro_point_t *, intro,
- rend_intro_point_free(intro););
- smartlist_free(service->intro_nodes);
- }
- if (service->expiring_nodes) {
- SMARTLIST_FOREACH(service->expiring_nodes, rend_intro_point_t *, intro,
- rend_intro_point_free(intro););
- smartlist_free(service->expiring_nodes);
- }
-
- rend_service_descriptor_free(service->desc);
- if (service->clients) {
- SMARTLIST_FOREACH(service->clients, rend_authorized_client_t *, c,
- rend_authorized_client_free(c););
- smartlist_free(service->clients);
- }
- if (service->accepted_intro_dh_parts) {
- replaycache_free(service->accepted_intro_dh_parts);
- }
- tor_free(service);
-}
-
-/* Release all the storage held in rend_service_staging_list. */
-void
-rend_service_free_staging_list(void)
-{
- if (rend_service_staging_list) {
- SMARTLIST_FOREACH(rend_service_staging_list, rend_service_t*, ptr,
- rend_service_free(ptr));
- smartlist_free(rend_service_staging_list);
- rend_service_staging_list = NULL;
- }
-}
-
-/** Release all the storage held in both rend_service_list and
- * rend_service_staging_list. */
-void
-rend_service_free_all(void)
-{
- if (rend_service_list) {
- SMARTLIST_FOREACH(rend_service_list, rend_service_t*, ptr,
- rend_service_free(ptr));
- smartlist_free(rend_service_list);
- rend_service_list = NULL;
- }
- rend_service_free_staging_list();
-}
-
-/* Initialize the subsystem. */
-void
-rend_service_init(void)
-{
- tor_assert(!rend_service_list);
- tor_assert(!rend_service_staging_list);
-
- rend_service_list = smartlist_new();
- rend_service_staging_list = smartlist_new();
-}
-
-/* Validate a <b>service</b>. Use the <b>service_list</b> to make sure there
- * is no duplicate entry for the given service object. Return 0 if valid else
- * -1 if not.*/
-static int
-rend_validate_service(const smartlist_t *service_list,
- const rend_service_t *service)
-{
- tor_assert(service_list);
- tor_assert(service);
-
- if (service->max_streams_per_circuit < 0) {
- log_warn(LD_CONFIG, "Hidden service (%s) configured with negative max "
- "streams per circuit.",
- rend_service_escaped_dir(service));
- goto invalid;
- }
-
- if (service->max_streams_close_circuit < 0 ||
- service->max_streams_close_circuit > 1) {
- log_warn(LD_CONFIG, "Hidden service (%s) configured with invalid "
- "max streams handling.",
- rend_service_escaped_dir(service));
- goto invalid;
- }
-
- if (service->auth_type != REND_NO_AUTH &&
- (!service->clients || smartlist_len(service->clients) == 0)) {
- log_warn(LD_CONFIG, "Hidden service (%s) with client authorization but "
- "no clients.",
- rend_service_escaped_dir(service));
- goto invalid;
- }
-
- if (!service->ports || !smartlist_len(service->ports)) {
- log_warn(LD_CONFIG, "Hidden service (%s) with no ports configured.",
- rend_service_escaped_dir(service));
- goto invalid;
- }
-
- /* Valid. */
- return 0;
- invalid:
- return -1;
-}
-
-/** Add it to <b>service_list</b>, or to the global rend_service_list if
- * <b>service_list</b> is NULL. Return 0 on success. On failure, free
- * <b>service</b> and return -1. Takes ownership of <b>service</b>. */
-static int
-rend_add_service(smartlist_t *service_list, rend_service_t *service)
-{
- int i;
- rend_service_port_config_t *p;
-
- tor_assert(service);
-
- smartlist_t *s_list = rend_get_service_list_mutable(service_list);
- /* We must have a service list, even if it's a temporary one, so we can
- * check for duplicate services */
- if (BUG(!s_list)) {
- rend_service_free(service);
- return -1;
- }
-
- service->intro_nodes = smartlist_new();
- service->expiring_nodes = smartlist_new();
-
- log_debug(LD_REND,"Configuring service with directory %s",
- rend_service_escaped_dir(service));
- for (i = 0; i < smartlist_len(service->ports); ++i) {
- p = smartlist_get(service->ports, i);
- if (!(p->is_unix_addr)) {
- log_debug(LD_REND,
- "Service maps port %d to %s",
- p->virtual_port,
- fmt_addrport(&p->real_addr, p->real_port));
- } else {
-#ifdef HAVE_SYS_UN_H
- log_debug(LD_REND,
- "Service maps port %d to socket at \"%s\"",
- p->virtual_port, p->unix_addr);
-#else
- log_warn(LD_BUG,
- "Service maps port %d to an AF_UNIX socket, but we "
- "have no AF_UNIX support on this platform. This is "
- "probably a bug.",
- p->virtual_port);
- rend_service_free(service);
- return -1;
-#endif /* defined(HAVE_SYS_UN_H) */
- }
- }
- /* The service passed all the checks */
- tor_assert(s_list);
- smartlist_add(s_list, service);
-
- /* Notify that our global service list has changed only if this new service
- * went into our global list. If not, when we move service from the staging
- * list to the new list, a notify is triggered. */
- if (s_list == rend_service_list) {
- hs_service_map_has_changed();
- }
- return 0;
-}
-
-/** Return a new rend_service_port_config_t with its path set to
- * <b>socket_path</b> or empty if <b>socket_path</b> is NULL */
-static rend_service_port_config_t *
-rend_service_port_config_new(const char *socket_path)
-{
- if (!socket_path)
- return tor_malloc_zero(sizeof(rend_service_port_config_t) + 1);
-
- const size_t pathlen = strlen(socket_path) + 1;
- rend_service_port_config_t *conf =
- tor_malloc_zero(sizeof(rend_service_port_config_t) + pathlen);
- memcpy(conf->unix_addr, socket_path, pathlen);
- conf->is_unix_addr = 1;
- return conf;
-}
-
-/** Parses a virtual-port to real-port/socket mapping separated by
- * the provided separator and returns a new rend_service_port_config_t,
- * or NULL and an optional error string on failure.
- *
- * The format is: VirtualPort SEP (IP|RealPort|IP:RealPort|'socket':path)?
- *
- * IP defaults to 127.0.0.1; RealPort defaults to VirtualPort.
- */
-rend_service_port_config_t *
-rend_service_parse_port_config(const char *string, const char *sep,
- char **err_msg_out)
-{
- smartlist_t *sl;
- int virtport;
- int realport = 0;
- uint16_t p;
- tor_addr_t addr;
- rend_service_port_config_t *result = NULL;
- unsigned int is_unix_addr = 0;
- const char *socket_path = NULL;
- char *err_msg = NULL;
- char *addrport = NULL;
-
- sl = smartlist_new();
- smartlist_split_string(sl, string, sep,
- SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 2);
- if (smartlist_len(sl) < 1 || BUG(smartlist_len(sl) > 2)) {
- err_msg = tor_strdup("Bad syntax in hidden service port configuration.");
- goto err;
- }
- virtport = (int)tor_parse_long(smartlist_get(sl,0), 10, 1, 65535, NULL,NULL);
- if (!virtport) {
- tor_asprintf(&err_msg, "Missing or invalid port %s in hidden service "
- "port configuration", escaped(smartlist_get(sl,0)));
-
- goto err;
- }
- if (smartlist_len(sl) == 1) {
- /* No addr:port part; use default. */
- realport = virtport;
- tor_addr_from_ipv4h(&addr, 0x7F000001u); /* 127.0.0.1 */
- } else {
- int ret;
-
- const char *addrport_element = smartlist_get(sl,1);
- const char *rest = NULL;
- int is_unix;
- ret = port_cfg_line_extract_addrport(addrport_element, &addrport,
- &is_unix, &rest);
-
- if (ret < 0) {
- tor_asprintf(&err_msg, "Couldn't process address <%s> from hidden "
- "service configuration", addrport_element);
- goto err;
- }
-
- if (rest && strlen(rest)) {
- err_msg = tor_strdup("HiddenServicePort parse error: invalid port "
- "mapping");
- goto err;
- }
-
- if (is_unix) {
- socket_path = addrport;
- is_unix_addr = 1;
- } else if (strchr(addrport, ':') || strchr(addrport, '.')) {
- /* else try it as an IP:port pair if it has a : or . in it */
- if (tor_addr_port_lookup(addrport, &addr, &p)<0) {
- err_msg = tor_strdup("Unparseable address in hidden service port "
- "configuration.");
- goto err;
- }
- realport = p?p:virtport;
- } else {
- /* No addr:port, no addr -- must be port. */
- realport = (int)tor_parse_long(addrport, 10, 1, 65535, NULL, NULL);
- if (!realport) {
- tor_asprintf(&err_msg, "Unparseable or out-of-range port %s in "
- "hidden service port configuration.",
- escaped(addrport));
- goto err;
- }
- tor_addr_from_ipv4h(&addr, 0x7F000001u); /* Default to 127.0.0.1 */
- }
- }
-
- /* Allow room for unix_addr */
- result = rend_service_port_config_new(socket_path);
- result->virtual_port = virtport;
- result->is_unix_addr = is_unix_addr;
- if (!is_unix_addr) {
- result->real_port = realport;
- tor_addr_copy(&result->real_addr, &addr);
- result->unix_addr[0] = '\0';
- }
-
- err:
- tor_free(addrport);
- if (err_msg_out != NULL) {
- *err_msg_out = err_msg;
- } else {
- tor_free(err_msg);
- }
- SMARTLIST_FOREACH(sl, char *, c, tor_free(c));
- smartlist_free(sl);
-
- return result;
-}
-
-/** Release all storage held in a rend_service_port_config_t. */
-void
-rend_service_port_config_free_(rend_service_port_config_t *p)
-{
- tor_free(p);
-}
-
-/* Copy relevant data from service src to dst while pruning the service lists.
- * This should only be called during the pruning process which takes existing
- * services and copy their data to the newly configured services. The src
- * service replaycache will be set to NULL after this call. */
-static void
-copy_service_on_prunning(rend_service_t *dst, rend_service_t *src)
-{
- tor_assert(dst);
- tor_assert(src);
-
- /* Keep the timestamps for when the content changed and the next upload
- * time so we can properly upload the descriptor if needed for the new
- * service object. */
- dst->desc_is_dirty = src->desc_is_dirty;
- dst->next_upload_time = src->next_upload_time;
- /* Move the replaycache to the new object. */
- dst->accepted_intro_dh_parts = src->accepted_intro_dh_parts;
- src->accepted_intro_dh_parts = NULL;
- /* Copy intro point information to destination service. */
- dst->intro_period_started = src->intro_period_started;
- dst->n_intro_circuits_launched = src->n_intro_circuits_launched;
- dst->n_intro_points_wanted = src->n_intro_points_wanted;
-}
-
-/* Helper: Actual implementation of the pruning on reload which we've
- * decoupled in order to make the unit test workeable without ugly hacks.
- * Furthermore, this function does NOT free any memory but will nullify the
- * temporary list pointer whatever happens. */
-STATIC void
-rend_service_prune_list_impl_(void)
-{
- origin_circuit_t *ocirc = NULL;
- smartlist_t *surviving_services, *old_service_list, *new_service_list;
-
- /* When pruning our current service list, we must have a staging list that
- * contains what we want to check else it's a code flow error. */
- tor_assert(rend_service_staging_list);
-
- /* We are about to prune the current list of its dead service so set the
- * semantic for that list to be the "old" one. */
- old_service_list = rend_service_list;
- /* The staging list is now the "new" list so set this semantic. */
- new_service_list = rend_service_staging_list;
- /* After this, whatever happens, we'll use our new list. */
- rend_service_list = new_service_list;
- /* Finally, nullify the staging list pointer as we don't need it anymore
- * and it needs to be NULL before the next reload. */
- rend_service_staging_list = NULL;
- /* Nothing to prune if we have no service list so stop right away. */
- if (!old_service_list) {
- return;
- }
-
- /* This contains all _existing_ services that survives the relaod that is
- * that haven't been removed from the configuration. The difference between
- * this list and the new service list is that the new list can possibly
- * contain newly configured service that have no introduction points opened
- * yet nor key material loaded or generated. */
- surviving_services = smartlist_new();
-
- /* Preserve the existing ephemeral services.
- *
- * This is the ephemeral service equivalent of the "Copy introduction
- * points to new services" block, except there's no copy required since
- * the service structure isn't regenerated.
- *
- * After this is done, all ephemeral services will be:
- * * Removed from old_service_list, so the equivalent non-ephemeral code
- * will not attempt to preserve them.
- * * Added to the new_service_list (that previously only had the
- * services listed in the configuration).
- * * Added to surviving_services, which is the list of services that
- * will NOT have their intro point closed.
- */
- SMARTLIST_FOREACH_BEGIN(old_service_list, rend_service_t *, old) {
- if (rend_service_is_ephemeral(old)) {
- SMARTLIST_DEL_CURRENT(old_service_list, old);
- smartlist_add(surviving_services, old);
- smartlist_add(new_service_list, old);
- }
- } SMARTLIST_FOREACH_END(old);
-
- /* Copy introduction points to new services. This is O(n^2), but it's only
- * called on reconfigure, so it's ok performance wise. */
- SMARTLIST_FOREACH_BEGIN(new_service_list, rend_service_t *, new) {
- SMARTLIST_FOREACH_BEGIN(old_service_list, rend_service_t *, old) {
- /* Skip ephemeral services as we only want to copy introduction points
- * from current services to newly configured one that already exists.
- * The same directory means it's the same service. */
- if (rend_service_is_ephemeral(new) || rend_service_is_ephemeral(old) ||
- strcmp(old->directory, new->directory)) {
- continue;
- }
- smartlist_add_all(new->intro_nodes, old->intro_nodes);
- smartlist_clear(old->intro_nodes);
- smartlist_add_all(new->expiring_nodes, old->expiring_nodes);
- smartlist_clear(old->expiring_nodes);
-
- /* Copy needed information from old to new. */
- copy_service_on_prunning(new, old);
-
- /* This regular service will survive the closing IPs step after. */
- smartlist_add(surviving_services, old);
- break;
- } SMARTLIST_FOREACH_END(old);
- } SMARTLIST_FOREACH_END(new);
-
- /* For every service introduction circuit we can find, see if we have a
- * matching surviving configured service. If not, close the circuit. */
- while ((ocirc = circuit_get_next_intro_circ(ocirc, false))) {
- int keep_it = 0;
- if (ocirc->rend_data == NULL) {
- /* This is a v3 circuit, ignore it. */
- continue;
- }
- SMARTLIST_FOREACH_BEGIN(surviving_services, const rend_service_t *, s) {
- if (rend_circuit_pk_digest_eq(ocirc, (uint8_t *) s->pk_digest)) {
- /* Keep this circuit as we have a matching configured service. */
- keep_it = 1;
- break;
- }
- } SMARTLIST_FOREACH_END(s);
- if (keep_it) {
- continue;
- }
- log_info(LD_REND, "Closing intro point %s for service %s.",
- safe_str_client(extend_info_describe(
- ocirc->build_state->chosen_exit)),
- safe_str_client(rend_data_get_address(ocirc->rend_data)));
- /* Reason is FINISHED because service has been removed and thus the
- * circuit is considered old/unneeded. */
- circuit_mark_for_close(TO_CIRCUIT(ocirc), END_CIRC_REASON_FINISHED);
- }
- smartlist_free(surviving_services);
- /* Notify that our global service list has changed. */
- hs_service_map_has_changed();
-}
-
-/* Try to prune our main service list using the temporary one that we just
- * loaded and parsed successfully. The pruning process decides which onion
- * services to keep and which to discard after a reload. */
-void
-rend_service_prune_list(void)
-{
- smartlist_t *old_service_list = rend_service_list;
-
- if (!rend_service_staging_list) {
- rend_service_staging_list = smartlist_new();
- }
-
- rend_service_prune_list_impl_();
- if (old_service_list) {
- /* Every remaining service in the old list have been removed from the
- * configuration so clean them up safely. */
- SMARTLIST_FOREACH(old_service_list, rend_service_t *, s,
- rend_service_free(s));
- smartlist_free(old_service_list);
- }
-}
-
-/* Copy all the relevant data that the hs_service object contains over to the
- * rend_service_t object. The reason to do so is because when configuring a
- * service, we go through a generic handler that creates an hs_service_t
- * object which so we have to copy the parsed values to a rend service object
- * which is version 2 specific. */
-static void
-service_config_shadow_copy(rend_service_t *service,
- hs_service_config_t *config)
-{
- tor_assert(service);
- tor_assert(config);
-
- service->directory = tor_strdup(config->directory_path);
- service->dir_group_readable = config->dir_group_readable;
- service->allow_unknown_ports = config->allow_unknown_ports;
- /* This value can't go above HS_CONFIG_MAX_STREAMS_PER_RDV_CIRCUIT (65535)
- * if the code flow is right so this cast is safe. But just in case, we'll
- * check it. */
- service->max_streams_per_circuit = (int) config->max_streams_per_rdv_circuit;
- if (BUG(config->max_streams_per_rdv_circuit >
- HS_CONFIG_MAX_STREAMS_PER_RDV_CIRCUIT)) {
- service->max_streams_per_circuit = HS_CONFIG_MAX_STREAMS_PER_RDV_CIRCUIT;
- }
- service->max_streams_close_circuit = config->max_streams_close_circuit;
- service->n_intro_points_wanted = config->num_intro_points;
- /* Switching ownership of the ports to the rend service object. */
- smartlist_add_all(service->ports, config->ports);
- smartlist_free(config->ports);
- config->ports = NULL;
-}
-
-/* Parse the hidden service configuration from <b>hs_opts</b> using the
- * already configured generic service configuration in <b>config</b>. This
- * function will translate the config object to a rend_service_t and add it to
- * the temporary list if valid. If <b>validate_only</b> is set, parse, warn
- * and return as normal but don't actually add the service to the list. */
-int
-rend_config_service(const hs_opts_t *hs_opts,
- const or_options_t *options,
- hs_service_config_t *config)
-{
- rend_service_t *service = NULL;
-
- tor_assert(options);
- tor_assert(hs_opts);
- tor_assert(config);
-
- /* We are about to configure a version 2 service. Warn of deprecation. */
- WARN_ONCE_DEPRECATION();
-
- /* Use the staging service list so that we can check then do the pruning
- * process using the main list at the end. */
- if (rend_service_staging_list == NULL) {
- rend_service_staging_list = smartlist_new();
- }
-
- /* Initialize service. */
- service = tor_malloc_zero(sizeof(rend_service_t));
- service->intro_period_started = time(NULL);
- service->ports = smartlist_new();
- /* From the hs_service object which has been used to load the generic
- * options, we'll copy over the useful data to the rend_service_t object. */
- service_config_shadow_copy(service, config);
-
- /* Number of introduction points. */
- if (hs_opts->HiddenServiceNumIntroductionPoints > NUM_INTRO_POINTS_MAX) {
- log_warn(LD_CONFIG, "HiddenServiceNumIntroductionPoints must be "
- "between 0 and %d, not %d.",
- NUM_INTRO_POINTS_MAX,
- hs_opts->HiddenServiceNumIntroductionPoints);
- goto err;
- }
- service->n_intro_points_wanted = hs_opts->HiddenServiceNumIntroductionPoints;
- log_info(LD_CONFIG, "HiddenServiceNumIntroductionPoints=%d for %s",
- service->n_intro_points_wanted, escaped(service->directory));
-
- /* Client authorization */
- if (hs_opts->HiddenServiceAuthorizeClient) {
- /* Parse auth type and comma-separated list of client names and add a
- * rend_authorized_client_t for each client to the service's list
- * of authorized clients. */
- smartlist_t *type_names_split, *clients;
- const char *authname;
- type_names_split = smartlist_new();
- smartlist_split_string(type_names_split,
- hs_opts->HiddenServiceAuthorizeClient, " ", 0, 2);
- if (smartlist_len(type_names_split) < 1) {
- log_warn(LD_BUG, "HiddenServiceAuthorizeClient has no value. This "
- "should have been prevented when parsing the "
- "configuration.");
- smartlist_free(type_names_split);
- goto err;
- }
- authname = smartlist_get(type_names_split, 0);
- if (!strcasecmp(authname, "basic")) {
- service->auth_type = REND_BASIC_AUTH;
- } else if (!strcasecmp(authname, "stealth")) {
- service->auth_type = REND_STEALTH_AUTH;
- } else {
- log_warn(LD_CONFIG, "HiddenServiceAuthorizeClient contains "
- "unrecognized auth-type '%s'. Only 'basic' or 'stealth' "
- "are recognized.",
- (char *) smartlist_get(type_names_split, 0));
- SMARTLIST_FOREACH(type_names_split, char *, cp, tor_free(cp));
- smartlist_free(type_names_split);
- goto err;
- }
- service->clients = smartlist_new();
- if (smartlist_len(type_names_split) < 2) {
- log_warn(LD_CONFIG, "HiddenServiceAuthorizeClient contains "
- "auth-type '%s', but no client names.",
- service->auth_type == REND_BASIC_AUTH ? "basic" : "stealth");
- SMARTLIST_FOREACH(type_names_split, char *, cp, tor_free(cp));
- smartlist_free(type_names_split);
- goto err;
- }
- clients = smartlist_new();
- smartlist_split_string(clients, smartlist_get(type_names_split, 1),
- ",", SPLIT_SKIP_SPACE, 0);
- SMARTLIST_FOREACH(type_names_split, char *, cp, tor_free(cp));
- smartlist_free(type_names_split);
- /* Remove duplicate client names. */
- {
- int num_clients = smartlist_len(clients);
- smartlist_sort_strings(clients);
- smartlist_uniq_strings(clients);
- if (smartlist_len(clients) < num_clients) {
- log_info(LD_CONFIG, "HiddenServiceAuthorizeClient contains %d "
- "duplicate client name(s); removing.",
- num_clients - smartlist_len(clients));
- }
- }
- SMARTLIST_FOREACH_BEGIN(clients, const char *, client_name) {
- rend_authorized_client_t *client;
- if (!rend_valid_client_name(client_name)) {
- log_warn(LD_CONFIG, "HiddenServiceAuthorizeClient contains an "
- "illegal client name: '%s'. Names must be "
- "between 1 and %d characters and contain "
- "only [A-Za-z0-9+_-].",
- client_name, REND_CLIENTNAME_MAX_LEN);
- SMARTLIST_FOREACH(clients, char *, cp, tor_free(cp));
- smartlist_free(clients);
- goto err;
- }
- client = tor_malloc_zero(sizeof(rend_authorized_client_t));
- client->client_name = tor_strdup(client_name);
- smartlist_add(service->clients, client);
- log_debug(LD_REND, "Adding client name '%s'", client_name);
- } SMARTLIST_FOREACH_END(client_name);
- SMARTLIST_FOREACH(clients, char *, cp, tor_free(cp));
- smartlist_free(clients);
- /* Ensure maximum number of clients. */
- if ((service->auth_type == REND_BASIC_AUTH &&
- smartlist_len(service->clients) > 512) ||
- (service->auth_type == REND_STEALTH_AUTH &&
- smartlist_len(service->clients) > 16)) {
- log_warn(LD_CONFIG, "HiddenServiceAuthorizeClient contains %d "
- "client authorization entries, but only a "
- "maximum of %d entries is allowed for "
- "authorization type '%s'.",
- smartlist_len(service->clients),
- service->auth_type == REND_BASIC_AUTH ? 512 : 16,
- service->auth_type == REND_BASIC_AUTH ? "basic" : "stealth");
- goto err;
- }
- }
-
- /* Validate the service just parsed. */
- if (rend_validate_service(rend_service_staging_list, service) < 0) {
- /* Service is in the staging list so don't try to free it. */
- goto err;
- }
-
- /* Add it to the temporary list which we will use to prune our current
- * list if any after configuring all services. */
- if (rend_add_service(rend_service_staging_list, service) < 0) {
- /* The object has been freed on error already. */
- service = NULL;
- goto err;
- }
-
- return 0;
- err:
- rend_service_free(service);
- return -1;
-}
-
-/** Add the ephemeral service <b>pk</b>/<b>ports</b> if possible, using
- * client authorization <b>auth_type</b> and an optional list of
- * rend_authorized_client_t in <b>auth_clients</b>, with
- * <b>max_streams_per_circuit</b> streams allowed per rendezvous circuit,
- * and circuit closure on max streams being exceeded set by
- * <b>max_streams_close_circuit</b>.
- *
- * Ownership of pk, ports, and auth_clients is passed to this routine.
- * Regardless of success/failure, callers should not touch these values
- * after calling this routine, and may assume that correct cleanup has
- * been done on failure.
- *
- * Return an appropriate hs_service_add_ephemeral_status_t.
- */
-hs_service_add_ephemeral_status_t
-rend_service_add_ephemeral(crypto_pk_t *pk,
- smartlist_t *ports,
- int max_streams_per_circuit,
- int max_streams_close_circuit,
- rend_auth_type_t auth_type,
- smartlist_t *auth_clients,
- char **service_id_out)
-{
- *service_id_out = NULL;
- /* Allocate the service structure, and initialize the key, and key derived
- * parameters.
- */
- rend_service_t *s = tor_malloc_zero(sizeof(rend_service_t));
- s->directory = NULL; /* This indicates the service is ephemeral. */
- s->private_key = pk;
- s->auth_type = auth_type;
- s->clients = auth_clients;
- s->ports = ports;
- s->intro_period_started = time(NULL);
- s->n_intro_points_wanted = NUM_INTRO_POINTS_DEFAULT;
- s->max_streams_per_circuit = max_streams_per_circuit;
- s->max_streams_close_circuit = max_streams_close_circuit;
- if (rend_service_derive_key_digests(s) < 0) {
- rend_service_free(s);
- return RSAE_BADPRIVKEY;
- }
-
- if (!s->ports || smartlist_len(s->ports) == 0) {
- log_warn(LD_CONFIG, "At least one VIRTPORT/TARGET must be specified.");
- rend_service_free(s);
- return RSAE_BADVIRTPORT;
- }
- if (s->auth_type != REND_NO_AUTH &&
- (!s->clients || smartlist_len(s->clients) == 0)) {
- log_warn(LD_CONFIG, "At least one authorized client must be specified.");
- rend_service_free(s);
- return RSAE_BADAUTH;
- }
-
- /* Enforcing pk/id uniqueness should be done by rend_service_load_keys(), but
- * it's not, see #14828.
- */
- if (rend_service_get_by_pk_digest(s->pk_digest)) {
- log_warn(LD_CONFIG, "Onion Service private key collides with an "
- "existing service.");
- rend_service_free(s);
- return RSAE_ADDREXISTS;
- }
- if (rend_service_get_by_service_id(s->service_id)) {
- log_warn(LD_CONFIG, "Onion Service id collides with an existing service.");
- rend_service_free(s);
- return RSAE_ADDREXISTS;
- }
-
- /* Initialize the service. */
- if (rend_add_service(NULL, s)) {
- return RSAE_INTERNAL;
- }
- *service_id_out = tor_strdup(s->service_id);
-
- log_debug(LD_CONFIG, "Added ephemeral Onion Service: %s", s->service_id);
- return RSAE_OKAY;
-}
-
-/** Remove the ephemeral service <b>service_id</b> if possible. Returns 0 on
- * success, and -1 on failure.
- */
-int
-rend_service_del_ephemeral(const char *service_id)
-{
- rend_service_t *s;
- if (!rend_valid_v2_service_id(service_id)) {
- log_warn(LD_CONFIG, "Requested malformed Onion Service id for removal.");
- return -1;
- }
- if ((s = rend_service_get_by_service_id(service_id)) == NULL) {
- log_warn(LD_CONFIG, "Requested non-existent Onion Service id for "
- "removal.");
- return -1;
- }
- if (!rend_service_is_ephemeral(s)) {
- log_warn(LD_CONFIG, "Requested non-ephemeral Onion Service for removal.");
- return -1;
- }
-
- /* Kill the intro point circuit for the Onion Service, and remove it from
- * the list. Closing existing connections is the application's problem.
- *
- * XXX: As with the comment in rend_config_services(), a nice abstraction
- * would be ideal here, but for now just duplicate the code.
- */
- SMARTLIST_FOREACH_BEGIN(circuit_get_global_list(), circuit_t *, circ) {
- if (!circ->marked_for_close &&
- (circ->purpose == CIRCUIT_PURPOSE_S_ESTABLISH_INTRO ||
- circ->purpose == CIRCUIT_PURPOSE_S_INTRO)) {
- origin_circuit_t *oc = TO_ORIGIN_CIRCUIT(circ);
- if (oc->rend_data == NULL ||
- !rend_circuit_pk_digest_eq(oc, (uint8_t *) s->pk_digest)) {
- continue;
- }
- log_debug(LD_REND, "Closing intro point %s for service %s.",
- safe_str_client(extend_info_describe(
- oc->build_state->chosen_exit)),
- rend_data_get_address(oc->rend_data));
- circuit_mark_for_close(circ, END_CIRC_REASON_FINISHED);
- }
- } SMARTLIST_FOREACH_END(circ);
- smartlist_remove(rend_service_list, s);
- /* Notify that we just removed a service from our global list. */
- hs_service_map_has_changed();
- rend_service_free(s);
-
- log_debug(LD_CONFIG, "Removed ephemeral Onion Service: %s", service_id);
-
- return 0;
-}
-
-/* There can be 1 second's delay due to second_elapsed_callback, and perhaps
- * another few seconds due to blocking calls. */
-#define INTRO_CIRC_RETRY_PERIOD_SLOP 10
-
-/** Log information about the intro point creation rate and current intro
- * points for service, upgrading the log level from min_severity to warn if
- * we have stopped launching new intro point circuits. */
-static void
-rend_log_intro_limit(const rend_service_t *service, int min_severity)
-{
- int exceeded_limit = (service->n_intro_circuits_launched >=
- rend_max_intro_circs_per_period(
- service->n_intro_points_wanted));
- int severity = min_severity;
- /* We stopped creating circuits */
- if (exceeded_limit) {
- severity = LOG_WARN;
- }
- time_t intro_period_elapsed = time(NULL) - service->intro_period_started;
- tor_assert_nonfatal(intro_period_elapsed >= 0);
- {
- char *msg;
- static ratelim_t rlimit = RATELIM_INIT(INTRO_CIRC_RETRY_PERIOD);
- if ((msg = rate_limit_log(&rlimit, approx_time()))) {
- log_fn(severity, LD_REND,
- "Hidden service %s %s %d intro points in the last %d seconds. "
- "Intro circuit launches are limited to %d per %d seconds.%s",
- service->service_id,
- exceeded_limit ? "exceeded launch limit with" : "launched",
- service->n_intro_circuits_launched,
- (int)intro_period_elapsed,
- rend_max_intro_circs_per_period(service->n_intro_points_wanted),
- INTRO_CIRC_RETRY_PERIOD, msg);
- rend_service_dump_stats(severity);
- tor_free(msg);
- }
- }
-}
-
-/** Replace the old value of <b>service</b>-\>desc with one that reflects
- * the other fields in service.
- */
-static void
-rend_service_update_descriptor(rend_service_t *service)
-{
- rend_service_descriptor_t *d;
- int i;
-
- rend_service_descriptor_free(service->desc);
- service->desc = NULL;
-
- d = service->desc = tor_malloc_zero(sizeof(rend_service_descriptor_t));
- d->pk = crypto_pk_dup_key(service->private_key);
- d->timestamp = time(NULL);
- d->timestamp -= d->timestamp % 3600; /* Round down to nearest hour */
- d->intro_nodes = smartlist_new();
- /* Support intro protocols 2 and 3. */
- d->protocols = (1 << 2) + (1 << 3);
-
- for (i = 0; i < smartlist_len(service->intro_nodes); ++i) {
- rend_intro_point_t *intro_svc = smartlist_get(service->intro_nodes, i);
- rend_intro_point_t *intro_desc;
-
- /* This intro point won't be listed in the descriptor... */
- intro_svc->listed_in_last_desc = 0;
-
- /* circuit_established is set in rend_service_intro_established(), and
- * checked every second in rend_consider_services_intro_points(), so it's
- * safe to use it here */
- if (!intro_svc->circuit_established) {
- continue;
- }
-
- /* ...unless this intro point is listed in the descriptor. */
- intro_svc->listed_in_last_desc = 1;
-
- /* We have an entirely established intro circuit. Publish it in
- * our descriptor. */
- intro_desc = tor_malloc_zero(sizeof(rend_intro_point_t));
- intro_desc->extend_info = extend_info_dup(intro_svc->extend_info);
- if (intro_svc->intro_key)
- intro_desc->intro_key = crypto_pk_dup_key(intro_svc->intro_key);
- smartlist_add(d->intro_nodes, intro_desc);
-
- if (intro_svc->time_published == -1) {
- /* We are publishing this intro point in a descriptor for the
- * first time -- note the current time in the service's copy of
- * the intro point. */
- intro_svc->time_published = time(NULL);
- }
- }
-
- /* Check that we have the right number of intro points */
- unsigned int have_intro = (unsigned int)smartlist_len(d->intro_nodes);
- if (have_intro != service->n_intro_points_wanted) {
- int severity;
- /* Getting less than we wanted or more than we're allowed is serious */
- if (have_intro < service->n_intro_points_wanted ||
- have_intro > NUM_INTRO_POINTS_MAX) {
- severity = LOG_WARN;
- } else {
- /* Getting more than we wanted is weird, but less of a problem */
- severity = LOG_NOTICE;
- }
- log_fn(severity, LD_REND, "Hidden service %s wanted %d intro points, but "
- "descriptor was updated with %d instead.",
- service->service_id,
- service->n_intro_points_wanted, have_intro);
- /* Now log an informative message about how we might have got here. */
- rend_log_intro_limit(service, severity);
- }
-}
-
-/* Allocate and return a string containing the path to file_name in
- * service->directory. Asserts that service has a directory.
- * This function will never return NULL.
- * The caller must free this path. */
-static char *
-rend_service_path(const rend_service_t *service, const char *file_name)
-{
- tor_assert(service->directory);
- return hs_path_from_filename(service->directory, file_name);
-}
-
-/* Allocate and return a string containing the path to the single onion
- * service poison file in service->directory. Asserts that service has a
- * directory.
- * The caller must free this path. */
-STATIC char *
-rend_service_sos_poison_path(const rend_service_t *service)
-{
- return rend_service_path(service, sos_poison_fname);
-}
-
-/** Return True if hidden services <b>service</b> has been poisoned by single
- * onion mode. */
-static int
-service_is_single_onion_poisoned(const rend_service_t *service)
-{
- char *poison_fname = NULL;
- file_status_t fstatus;
-
- /* Passing a NULL service is a bug */
- if (BUG(!service)) {
- return 0;
- }
-
- if (rend_service_is_ephemeral(service)) {
- return 0;
- }
-
- poison_fname = rend_service_sos_poison_path(service);
-
- fstatus = file_status(poison_fname);
- tor_free(poison_fname);
-
- /* If this fname is occupied, the hidden service has been poisoned.
- * fstatus can be FN_ERROR if the service directory does not exist, in that
- * case, there is obviously no private key. */
- if (fstatus == FN_FILE || fstatus == FN_EMPTY) {
- return 1;
- }
-
- return 0;
-}
-
-/* Return 1 if the private key file for service exists and has a non-zero size,
- * and 0 otherwise. */
-static int
-rend_service_private_key_exists(const rend_service_t *service)
-{
- char *private_key_path = rend_service_path(service, private_key_fname);
- const file_status_t private_key_status = file_status(private_key_path);
- tor_free(private_key_path);
- /* Only non-empty regular private key files could have been used before.
- * fstatus can be FN_ERROR if the service directory does not exist, in that
- * case, there is obviously no private key. */
- return private_key_status == FN_FILE;
-}
-
-/** Check the single onion service poison state of the directory for s:
- * - If the service is poisoned, and we are in Single Onion Mode,
- * return 0,
- * - If the service is not poisoned, and we are not in Single Onion Mode,
- * return 0,
- * - Otherwise, the poison state is invalid: the service was created in one
- * mode, and is being used in the other, return -1.
- * Hidden service directories without keys are always considered consistent.
- * They will be poisoned after their directory is created (if needed). */
-STATIC int
-rend_service_verify_single_onion_poison(const rend_service_t* s,
- const or_options_t* options)
-{
- /* Passing a NULL service is a bug */
- if (BUG(!s)) {
- return -1;
- }
-
- /* Ephemeral services are checked at ADD_ONION time */
- if (BUG(rend_service_is_ephemeral(s))) {
- return -1;
- }
-
- /* Service is expected to have a directory */
- if (BUG(!s->directory)) {
- return -1;
- }
-
- /* Services without keys are always ok - their keys will only ever be used
- * in the current mode */
- if (!rend_service_private_key_exists(s)) {
- return 0;
- }
-
- /* The key has been used before in a different mode */
- if (service_is_single_onion_poisoned(s) !=
- rend_service_non_anonymous_mode_enabled(options)) {
- return -1;
- }
-
- /* The key exists and is consistent with the current mode */
- return 0;
-}
-
-/*** Helper for rend_service_poison_new_single_onion_dir(). Add a file to
- * the hidden service directory for s that marks it as a single onion service.
- * Tor must be in single onion mode before calling this function, and the
- * service directory must already have been created.
- * Returns 0 when a directory is successfully poisoned, or if it is already
- * poisoned. Returns -1 on a failure to read the directory or write the poison
- * file, or if there is an existing private key file in the directory. (The
- * service should have been poisoned when the key was created.) */
-static int
-poison_new_single_onion_hidden_service_dir_impl(const rend_service_t *service,
- const or_options_t* options)
-{
- /* Passing a NULL service is a bug */
- if (BUG(!service)) {
- return -1;
- }
-
- /* We must only poison directories if we're in Single Onion mode */
- tor_assert(rend_service_non_anonymous_mode_enabled(options));
-
- int fd;
- int retval = -1;
- char *poison_fname = NULL;
-
- if (rend_service_is_ephemeral(service)) {
- log_info(LD_REND, "Ephemeral HS started in non-anonymous mode.");
- return 0;
- }
-
- /* Make sure we're only poisoning new hidden service directories */
- if (rend_service_private_key_exists(service)) {
- log_warn(LD_BUG, "Tried to single onion poison a service directory after "
- "the private key was created.");
- return -1;
- }
-
- /* Make sure the directory was created before calling this function. */
- if (BUG(hs_check_service_private_dir(options->User, service->directory,
- service->dir_group_readable, 0) < 0))
- return -1;
-
- poison_fname = rend_service_sos_poison_path(service);
-
- switch (file_status(poison_fname)) {
- case FN_DIR:
- case FN_ERROR:
- log_warn(LD_FS, "Can't read single onion poison file \"%s\"",
- poison_fname);
- goto done;
- case FN_FILE: /* single onion poison file already exists. NOP. */
- case FN_EMPTY: /* single onion poison file already exists. NOP. */
- log_debug(LD_FS, "Tried to re-poison a single onion poisoned file \"%s\"",
- poison_fname);
- break;
- case FN_NOENT:
- fd = tor_open_cloexec(poison_fname, O_RDWR|O_CREAT|O_TRUNC, 0600);
- if (fd < 0) {
- log_warn(LD_FS, "Could not create single onion poison file %s",
- poison_fname);
- goto done;
- }
- close(fd);
- break;
- default:
- tor_assert(0);
- }
-
- retval = 0;
-
- done:
- tor_free(poison_fname);
-
- return retval;
-}
-
-/** We just got launched in Single Onion Mode. That's a non-anonymous mode for
- * hidden services. If s is new, we should mark its hidden service
- * directory appropriately so that it is never launched as a location-private
- * hidden service. (New directories don't have private key files.)
- * Return 0 on success, -1 on fail. */
-STATIC int
-rend_service_poison_new_single_onion_dir(const rend_service_t *s,
- const or_options_t* options)
-{
- /* Passing a NULL service is a bug */
- if (BUG(!s)) {
- return -1;
- }
-
- /* We must only poison directories if we're in Single Onion mode */
- tor_assert(rend_service_non_anonymous_mode_enabled(options));
-
- /* Ephemeral services aren't allowed in non-anonymous mode */
- if (BUG(rend_service_is_ephemeral(s))) {
- return -1;
- }
-
- /* Service is expected to have a directory */
- if (BUG(!s->directory)) {
- return -1;
- }
-
- if (!rend_service_private_key_exists(s)) {
- if (poison_new_single_onion_hidden_service_dir_impl(s, options)
- < 0) {
- return -1;
- }
- }
-
- return 0;
-}
-
-/* Return true iff the given service identity key is present on disk. This is
- * used to try to learn the service version during configuration time. */
-int
-rend_service_key_on_disk(const char *directory_path)
-{
- int ret = 0;
- char *fname;
- crypto_pk_t *pk = NULL;
-
- tor_assert(directory_path);
-
- /* Load key */
- fname = hs_path_from_filename(directory_path, private_key_fname);
- pk = init_key_from_file(fname, 0, LOG_DEBUG, NULL);
- if (pk) {
- ret = 1;
- }
-
- crypto_pk_free(pk);
- tor_free(fname);
- return ret;
-}
-
-/** Load and/or generate private keys for all hidden services, possibly
- * including keys for client authorization.
- * If a <b>service_list</b> is provided, treat it as the list of hidden
- * services (used in unittests). Otherwise, require that rend_service_list is
- * not NULL.
- * Return 0 on success, -1 on failure. */
-int
-rend_service_load_all_keys(const smartlist_t *service_list)
-{
- /* Use service_list for unit tests */
- const smartlist_t *s_list = rend_get_service_list(service_list);
- if (BUG(!s_list)) {
- return -1;
- }
-
- SMARTLIST_FOREACH_BEGIN(s_list, rend_service_t *, s) {
- if (s->private_key)
- continue;
- log_info(LD_REND, "Loading hidden-service keys from %s",
- rend_service_escaped_dir(s));
-
- if (rend_service_load_keys(s) < 0)
- return -1;
- } SMARTLIST_FOREACH_END(s);
-
- return 0;
-}
-
-/** Add to <b>lst</b> every filename used by <b>s</b>. */
-static void
-rend_service_add_filenames_to_list(smartlist_t *lst, const rend_service_t *s)
-{
- tor_assert(lst);
- tor_assert(s);
- tor_assert(s->directory);
- smartlist_add(lst, rend_service_path(s, private_key_fname));
- smartlist_add(lst, rend_service_path(s, hostname_fname));
- smartlist_add(lst, rend_service_path(s, client_keys_fname));
- smartlist_add(lst, rend_service_sos_poison_path(s));
-}
-
-/** Add to <b>open_lst</b> every filename used by a configured hidden service,
- * and to <b>stat_lst</b> every directory used by a configured hidden
- * service */
-void
-rend_services_add_filenames_to_lists(smartlist_t *open_lst,
- smartlist_t *stat_lst)
-{
- if (!rend_service_list)
- return;
- SMARTLIST_FOREACH_BEGIN(rend_service_list, rend_service_t *, s) {
- if (!rend_service_is_ephemeral(s)) {
- rend_service_add_filenames_to_list(open_lst, s);
- smartlist_add_strdup(stat_lst, s->directory);
- }
- } SMARTLIST_FOREACH_END(s);
-}
-
-/** Derive all rend_service_t internal material based on the service's key.
- * Returns 0 on success, -1 on failure.
- */
-static int
-rend_service_derive_key_digests(struct rend_service_t *s)
-{
- if (rend_get_service_id(s->private_key, s->service_id)<0) {
- log_warn(LD_BUG, "Internal error: couldn't encode service ID.");
- return -1;
- }
- if (crypto_pk_get_digest(s->private_key, s->pk_digest)<0) {
- log_warn(LD_BUG, "Couldn't compute hash of public key.");
- return -1;
- }
-
- return 0;
-}
-
-/** Make sure that the directory for <b>s</b> is private, using the config in
- * <b>options</b>.
- * If <b>create</b> is true:
- * - if the directory exists, change permissions if needed,
- * - if the directory does not exist, create it with the correct permissions.
- * If <b>create</b> is false:
- * - if the directory exists, check permissions,
- * - if the directory does not exist, check if we think we can create it.
- * Return 0 on success, -1 on failure. */
-static int
-rend_service_check_private_dir(const or_options_t *options,
- const rend_service_t *s,
- int create)
-{
- /* Passing a NULL service is a bug */
- if (BUG(!s)) {
- return -1;
- }
-
- /* Check/create directory */
- if (hs_check_service_private_dir(options->User, s->directory,
- s->dir_group_readable, create) < 0) {
- return -1;
- }
-
- /* Check if the hidden service key exists, and was created in a different
- * single onion service mode, and refuse to launch if it has.
- * This is safe to call even when create is false, as it ignores missing
- * keys and directories: they are always valid.
- */
- if (rend_service_verify_single_onion_poison(s, options) < 0) {
- /* We can't use s->service_id here, as the key may not have been loaded */
- log_warn(LD_GENERAL, "We are configured with "
- "HiddenServiceNonAnonymousMode %d, but the hidden "
- "service key in directory %s was created in %s mode. "
- "This is not allowed.",
- rend_service_non_anonymous_mode_enabled(options) ? 1 : 0,
- rend_service_escaped_dir(s),
- rend_service_non_anonymous_mode_enabled(options) ?
- "an anonymous" : "a non-anonymous"
- );
- return -1;
- }
-
- /* Poison new single onion directories immediately after they are created,
- * so that we never accidentally launch non-anonymous hidden services
- * thinking they are anonymous. Any keys created later will end up with the
- * correct poisoning state.
- */
- if (create && rend_service_non_anonymous_mode_enabled(options)) {
- static int logged_warning = 0;
-
- if (rend_service_poison_new_single_onion_dir(s, options) < 0) {
- log_warn(LD_GENERAL,"Failed to mark new hidden services as non-anonymous"
- ".");
- return -1;
- }
-
- if (!logged_warning) {
- /* The keys for these services are linked to the server IP address */
- log_notice(LD_REND, "The configured onion service directories have been "
- "used in single onion mode. They can not be used for "
- "anonymous hidden services.");
- logged_warning = 1;
- }
- }
-
- return 0;
-}
-
-/** Load and/or generate private keys for the hidden service <b>s</b>,
- * possibly including keys for client authorization. Return 0 on success, -1
- * on failure. */
-static int
-rend_service_load_keys(rend_service_t *s)
-{
- char *fname = NULL;
- char buf[128];
-
- /* Create the directory if needed which will also poison it in case of
- * single onion service. */
- if (rend_service_check_private_dir(get_options(), s, 1) < 0)
- goto err;
-
- /* Load key */
- fname = rend_service_path(s, private_key_fname);
- s->private_key = init_key_from_file(fname, 1, LOG_ERR, NULL);
-
- if (!s->private_key)
- goto err;
-
- if (rend_service_derive_key_digests(s) < 0)
- goto err;
-
- tor_free(fname);
- /* Create service file */
- fname = rend_service_path(s, hostname_fname);
-
- tor_snprintf(buf, sizeof(buf),"%s.onion\n", s->service_id);
- if (write_str_to_file_if_not_equal(fname, buf)) {
- log_warn(LD_CONFIG, "Could not write onion address to hostname file.");
- goto err;
- }
-#ifndef _WIN32
- if (s->dir_group_readable) {
- /* Also verify hostname file created with group read. */
- if (chmod(fname, 0640))
- log_warn(LD_FS,"Unable to make hidden hostname file %s group-readable.",
- fname);
- }
-#endif /* !defined(_WIN32) */
-
- /* If client authorization is configured, load or generate keys. */
- if (s->auth_type != REND_NO_AUTH) {
- if (rend_service_load_auth_keys(s, fname) < 0) {
- goto err;
- }
- }
-
- int r = 0;
- goto done;
- err:
- r = -1;
- done:
- memwipe(buf, 0, sizeof(buf));
- tor_free(fname);
- return r;
-}
-
-/** Load and/or generate client authorization keys for the hidden service
- * <b>s</b>, which stores its hostname in <b>hfname</b>. Return 0 on success,
- * -1 on failure. */
-static int
-rend_service_load_auth_keys(rend_service_t *s, const char *hfname)
-{
- int r = 0;
- char *cfname = NULL;
- char *client_keys_str = NULL;
- strmap_t *parsed_clients = strmap_new();
- FILE *cfile, *hfile;
- open_file_t *open_cfile = NULL, *open_hfile = NULL;
- char desc_cook_out[3*REND_DESC_COOKIE_LEN_BASE64+1];
- char service_id[16+1];
- char buf[1500];
-
- /* Load client keys and descriptor cookies, if available. */
- cfname = rend_service_path(s, client_keys_fname);
- client_keys_str = read_file_to_str(cfname, RFTS_IGNORE_MISSING, NULL);
- if (client_keys_str) {
- if (rend_parse_client_keys(parsed_clients, client_keys_str) < 0) {
- log_warn(LD_CONFIG, "Previously stored client_keys file could not "
- "be parsed.");
- goto err;
- } else {
- log_info(LD_CONFIG, "Parsed %d previously stored client entries.",
- strmap_size(parsed_clients));
- }
- }
-
- /* Prepare client_keys and hostname files. */
- if (!(cfile = start_writing_to_stdio_file(cfname,
- OPEN_FLAGS_REPLACE | O_TEXT,
- 0600, &open_cfile))) {
- log_warn(LD_CONFIG, "Could not open client_keys file %s",
- escaped(cfname));
- goto err;
- }
-
- if (!(hfile = start_writing_to_stdio_file(hfname,
- OPEN_FLAGS_REPLACE | O_TEXT,
- 0600, &open_hfile))) {
- log_warn(LD_CONFIG, "Could not open hostname file %s", escaped(hfname));
- goto err;
- }
-
- /* Either use loaded keys for configured clients or generate new
- * ones if a client is new. */
- SMARTLIST_FOREACH_BEGIN(s->clients, rend_authorized_client_t *, client) {
- rend_authorized_client_t *parsed =
- strmap_get(parsed_clients, client->client_name);
- int written;
- size_t len;
- /* Copy descriptor cookie from parsed entry or create new one. */
- if (parsed) {
- memcpy(client->descriptor_cookie, parsed->descriptor_cookie,
- REND_DESC_COOKIE_LEN);
- } else {
- crypto_rand((char *) client->descriptor_cookie, REND_DESC_COOKIE_LEN);
- }
- /* For compatibility with older tor clients, this does not
- * truncate the padding characters, unlike rend_auth_encode_cookie. */
- if (base64_encode(desc_cook_out, 3*REND_DESC_COOKIE_LEN_BASE64+1,
- (char *) client->descriptor_cookie,
- REND_DESC_COOKIE_LEN, 0) < 0) {
- log_warn(LD_BUG, "Could not base64-encode descriptor cookie.");
- goto err;
- }
- /* Copy client key from parsed entry or create new one if required. */
- if (parsed && parsed->client_key) {
- client->client_key = crypto_pk_dup_key(parsed->client_key);
- } else if (s->auth_type == REND_STEALTH_AUTH) {
- /* Create private key for client. */
- crypto_pk_t *prkey = NULL;
- if (!(prkey = crypto_pk_new())) {
- log_warn(LD_BUG,"Error constructing client key");
- goto err;
- }
- if (crypto_pk_generate_key(prkey)) {
- log_warn(LD_BUG,"Error generating client key");
- crypto_pk_free(prkey);
- goto err;
- }
- if (! crypto_pk_is_valid_private_key(prkey)) {
- log_warn(LD_BUG,"Generated client key seems invalid");
- crypto_pk_free(prkey);
- goto err;
- }
- client->client_key = prkey;
- }
- /* Add entry to client_keys file. */
- written = tor_snprintf(buf, sizeof(buf),
- "client-name %s\ndescriptor-cookie %s\n",
- client->client_name, desc_cook_out);
- if (written < 0) {
- log_warn(LD_BUG, "Could not write client entry.");
- goto err;
- }
- if (client->client_key) {
- char *client_key_out = NULL;
- if (crypto_pk_write_private_key_to_string(client->client_key,
- &client_key_out, &len) != 0) {
- log_warn(LD_BUG, "Internal error: "
- "crypto_pk_write_private_key_to_string() failed.");
- goto err;
- }
- if (rend_get_service_id(client->client_key, service_id)<0) {
- log_warn(LD_BUG, "Internal error: couldn't encode service ID.");
- /*
- * len is string length, not buffer length, but last byte is NUL
- * anyway.
- */
- memwipe(client_key_out, 0, len);
- tor_free(client_key_out);
- goto err;
- }
- written = tor_snprintf(buf + written, sizeof(buf) - written,
- "client-key\n%s", client_key_out);
- memwipe(client_key_out, 0, len);
- tor_free(client_key_out);
- if (written < 0) {
- log_warn(LD_BUG, "Could not write client entry.");
- goto err;
- }
- } else {
- strlcpy(service_id, s->service_id, sizeof(service_id));
- }
-
- if (fputs(buf, cfile) < 0) {
- log_warn(LD_FS, "Could not append client entry to file: %s",
- strerror(errno));
- goto err;
- }
-
- /* Add line to hostname file. This is not the same encoding as in
- * client_keys. */
- char *encoded_cookie = rend_auth_encode_cookie(client->descriptor_cookie,
- s->auth_type);
- if (!encoded_cookie) {
- log_warn(LD_BUG, "Could not base64-encode descriptor cookie.");
- goto err;
- }
- tor_snprintf(buf, sizeof(buf), "%s.onion %s # client: %s\n",
- service_id, encoded_cookie, client->client_name);
- memwipe(encoded_cookie, 0, strlen(encoded_cookie));
- tor_free(encoded_cookie);
-
- if (fputs(buf, hfile)<0) {
- log_warn(LD_FS, "Could not append host entry to file: %s",
- strerror(errno));
- goto err;
- }
- } SMARTLIST_FOREACH_END(client);
-
- finish_writing_to_file(open_cfile);
- finish_writing_to_file(open_hfile);
-
- goto done;
- err:
- r = -1;
- if (open_cfile)
- abort_writing_to_file(open_cfile);
- if (open_hfile)
- abort_writing_to_file(open_hfile);
- done:
- if (client_keys_str) {
- memwipe(client_keys_str, 0, strlen(client_keys_str));
- tor_free(client_keys_str);
- }
- strmap_free(parsed_clients, rend_authorized_client_free_void);
-
- if (cfname) {
- memwipe(cfname, 0, strlen(cfname));
- tor_free(cfname);
- }
-
- /* Clear stack buffers that held key-derived material. */
- memwipe(buf, 0, sizeof(buf));
- memwipe(desc_cook_out, 0, sizeof(desc_cook_out));
- memwipe(service_id, 0, sizeof(service_id));
-
- return r;
-}
-
-/** Return the service whose public key has a digest of <b>digest</b>, or
- * NULL if no such service exists.
- */
-static rend_service_t *
-rend_service_get_by_pk_digest(const char* digest)
-{
- SMARTLIST_FOREACH(rend_service_list, rend_service_t*, s,
- if (tor_memeq(s->pk_digest,digest,DIGEST_LEN))
- return s);
- return NULL;
-}
-
-/** Return the service whose service id is <b>id</b>, or NULL if no such
- * service exists.
- */
-static struct rend_service_t *
-rend_service_get_by_service_id(const char *id)
-{
- tor_assert(strlen(id) == REND_SERVICE_ID_LEN_BASE32);
- SMARTLIST_FOREACH(rend_service_list, rend_service_t*, s, {
- if (tor_memeq(s->service_id, id, REND_SERVICE_ID_LEN_BASE32))
- return s;
- });
- return NULL;
-}
-
-/** Check client authorization of a given <b>descriptor_cookie</b> of
- * length <b>cookie_len</b> for <b>service</b>. Return 1 for success
- * and 0 for failure. */
-static int
-rend_check_authorization(rend_service_t *service,
- const char *descriptor_cookie,
- size_t cookie_len)
-{
- rend_authorized_client_t *auth_client = NULL;
- tor_assert(service);
- tor_assert(descriptor_cookie);
- if (!service->clients) {
- log_warn(LD_BUG, "Can't check authorization for a service that has no "
- "authorized clients configured.");
- return 0;
- }
-
- if (cookie_len != REND_DESC_COOKIE_LEN) {
- log_info(LD_REND, "Descriptor cookie is %lu bytes, but we expected "
- "%lu bytes. Dropping cell.",
- (unsigned long)cookie_len, (unsigned long)REND_DESC_COOKIE_LEN);
- return 0;
- }
-
- /* Look up client authorization by descriptor cookie. */
- SMARTLIST_FOREACH(service->clients, rend_authorized_client_t *, client, {
- if (tor_memeq(client->descriptor_cookie, descriptor_cookie,
- REND_DESC_COOKIE_LEN)) {
- auth_client = client;
- break;
- }
- });
- if (!auth_client) {
- char descriptor_cookie_base64[3*REND_DESC_COOKIE_LEN_BASE64];
- base64_encode(descriptor_cookie_base64, sizeof(descriptor_cookie_base64),
- descriptor_cookie, REND_DESC_COOKIE_LEN, 0);
- log_info(LD_REND, "No authorization found for descriptor cookie '%s'! "
- "Dropping cell!",
- descriptor_cookie_base64);
- return 0;
- }
-
- /* Allow the request. */
- log_info(LD_REND, "Client %s authorized for service %s.",
- auth_client->client_name, service->service_id);
- return 1;
-}
-
-/* Can this service make a direct connection to ei?
- * It must be a single onion service, and the firewall rules must allow ei. */
-static int
-rend_service_use_direct_connection(const or_options_t* options,
- const extend_info_t* ei)
-{
- /* We'll connect directly all reachable addresses, whether preferred or not.
- * The prefer_ipv6 argument to reachable_addr_allows_addr is
- * ignored, because pref_only is 0. */
- const tor_addr_port_t *ap = extend_info_get_orport(ei, AF_INET);
- if (!ap)
- return 0;
- return (rend_service_allow_non_anonymous_connection(options) &&
- reachable_addr_allows_addr(&ap->addr, ap->port,
- FIREWALL_OR_CONNECTION, 0, 0));
-}
-
-/* Like rend_service_use_direct_connection, but to a node. */
-static int
-rend_service_use_direct_connection_node(const or_options_t* options,
- const node_t* node)
-{
- /* We'll connect directly all reachable addresses, whether preferred or not.
- */
- return (rend_service_allow_non_anonymous_connection(options) &&
- reachable_addr_allows_node(node, FIREWALL_OR_CONNECTION, 0));
-}
-
-/******
- * Handle cells
- ******/
-
-/** Respond to an INTRODUCE2 cell by launching a circuit to the chosen
- * rendezvous point.
- */
-int
-rend_service_receive_introduction(origin_circuit_t *circuit,
- const uint8_t *request,
- size_t request_len)
-{
- /* Global status stuff */
- int status = 0, result;
- const or_options_t *options = get_options();
- char *err_msg = NULL;
- int err_msg_severity = LOG_WARN;
- const char *stage_descr = NULL, *rend_pk_digest;
- int reason = END_CIRC_REASON_TORPROTOCOL;
- /* Service/circuit/key stuff we can learn before parsing */
- char serviceid[REND_SERVICE_ID_LEN_BASE32+1];
- rend_service_t *service = NULL;
- rend_intro_point_t *intro_point = NULL;
- crypto_pk_t *intro_key = NULL;
- /* Parsed cell */
- rend_intro_cell_t *parsed_req = NULL;
- /* Rendezvous point */
- extend_info_t *rp = NULL;
- /* XXX not handled yet */
- char buf[RELAY_PAYLOAD_SIZE];
- char keys[DIGEST_LEN+CPATH_KEY_MATERIAL_LEN]; /* Holds KH, Df, Db, Kf, Kb */
- int i;
- crypto_dh_t *dh = NULL;
- origin_circuit_t *launched = NULL;
- crypt_path_t *cpath = NULL;
- char hexcookie[9];
- int circ_needs_uptime;
- time_t now = time(NULL);
- time_t elapsed;
- int replay;
- ssize_t keylen;
-
- /* Do some initial validation and logging before we parse the cell */
- if (circuit->base_.purpose != CIRCUIT_PURPOSE_S_INTRO) {
- log_warn(LD_PROTOCOL,
- "Got an INTRODUCE2 over a non-introduction circuit %u.",
- (unsigned) circuit->base_.n_circ_id);
- goto err;
- }
-
- assert_circ_anonymity_ok(circuit, options);
- tor_assert(circuit->rend_data);
- /* XXX: This is version 2 specific (only one supported). */
- rend_pk_digest = (char *) rend_data_get_pk_digest(circuit->rend_data, NULL);
-
- /* We'll use this in a bazillion log messages */
- base32_encode(serviceid, REND_SERVICE_ID_LEN_BASE32+1,
- rend_pk_digest, REND_SERVICE_ID_LEN);
-
- /* look up service depending on circuit. */
- service = rend_service_get_by_pk_digest(rend_pk_digest);
- if (!service) {
- log_warn(LD_BUG,
- "Internal error: Got an INTRODUCE2 cell on an intro "
- "circ for an unrecognized service %s.",
- escaped(serviceid));
- goto err;
- }
-
- intro_point = find_intro_point(circuit);
- if (intro_point == NULL) {
- intro_point = find_expiring_intro_point(service, circuit);
- if (intro_point == NULL) {
- log_warn(LD_BUG,
- "Internal error: Got an INTRODUCE2 cell on an "
- "intro circ (for service %s) with no corresponding "
- "rend_intro_point_t.",
- escaped(serviceid));
- goto err;
- }
- }
-
- log_info(LD_REND, "Received INTRODUCE2 cell for service %s on circ %u.",
- escaped(serviceid), (unsigned)circuit->base_.n_circ_id);
-
- /* use intro key instead of service key. */
- intro_key = circuit->intro_key;
-
- tor_free(err_msg);
- stage_descr = NULL;
-
- stage_descr = "early parsing";
- /* Early parsing pass (get pk, ciphertext); type 2 is INTRODUCE2 */
- parsed_req =
- rend_service_begin_parse_intro(request, request_len, 2, &err_msg);
- if (!parsed_req) {
- goto log_error;
- } else if (err_msg) {
- log_info(LD_REND, "%s on circ %u.", err_msg,
- (unsigned)circuit->base_.n_circ_id);
- tor_free(err_msg);
- }
-
- /* make sure service replay caches are present */
- if (!service->accepted_intro_dh_parts) {
- service->accepted_intro_dh_parts =
- replaycache_new(REND_REPLAY_TIME_INTERVAL,
- REND_REPLAY_TIME_INTERVAL);
- }
-
- if (!intro_point->accepted_intro_rsa_parts) {
- intro_point->accepted_intro_rsa_parts = replaycache_new(0, 0);
- }
-
- /* check for replay of PK-encrypted portion. */
- keylen = crypto_pk_keysize(intro_key);
- replay = replaycache_add_test_and_elapsed(
- intro_point->accepted_intro_rsa_parts,
- parsed_req->ciphertext, MIN(parsed_req->ciphertext_len, keylen),
- &elapsed);
-
- if (replay) {
- log_warn(LD_REND,
- "Possible replay detected! We received an "
- "INTRODUCE2 cell with same PK-encrypted part %d "
- "seconds ago. Dropping cell.",
- (int)elapsed);
- goto err;
- }
-
- stage_descr = "decryption";
- /* Now try to decrypt it */
- result = rend_service_decrypt_intro(parsed_req, intro_key, &err_msg);
- if (result < 0) {
- goto log_error;
- } else if (err_msg) {
- log_info(LD_REND, "%s on circ %u.", err_msg,
- (unsigned)circuit->base_.n_circ_id);
- tor_free(err_msg);
- }
-
- stage_descr = "late parsing";
- /* Parse the plaintext */
- result = rend_service_parse_intro_plaintext(parsed_req, &err_msg);
- if (result < 0) {
- goto log_error;
- } else if (err_msg) {
- log_info(LD_REND, "%s on circ %u.", err_msg,
- (unsigned)circuit->base_.n_circ_id);
- tor_free(err_msg);
- }
-
- stage_descr = "late validation";
- /* Validate the parsed plaintext parts */
- result = rend_service_validate_intro_late(parsed_req, &err_msg);
- if (result < 0) {
- goto log_error;
- } else if (err_msg) {
- log_info(LD_REND, "%s on circ %u.", err_msg,
- (unsigned)circuit->base_.n_circ_id);
- tor_free(err_msg);
- }
- stage_descr = NULL;
-
- /* Increment INTRODUCE2 counter */
- ++(intro_point->accepted_introduce2_count);
-
- /* Find the rendezvous point */
- rp = find_rp_for_intro(parsed_req, &err_msg);
- if (!rp) {
- err_msg_severity = LOG_PROTOCOL_WARN;
- goto log_error;
- }
-
- /* Check if we'd refuse to talk to this router */
- if (options->StrictNodes &&
- routerset_contains_extendinfo(options->ExcludeNodes, rp)) {
- log_warn(LD_REND, "Client asked to rendezvous at a relay that we "
- "exclude, and StrictNodes is set. Refusing service.");
- reason = END_CIRC_REASON_INTERNAL; /* XXX might leak why we refused */
- goto err;
- }
-
- base16_encode(hexcookie, 9, (const char *)(parsed_req->rc), 4);
-
- /* Check whether there is a past request with the same Diffie-Hellman,
- * part 1. */
- replay = replaycache_add_test_and_elapsed(
- service->accepted_intro_dh_parts,
- parsed_req->dh, DH1024_KEY_LEN,
- &elapsed);
-
- if (replay) {
- /* A Tor client will send a new INTRODUCE1 cell with the same rend
- * cookie and DH public key as its previous one if its intro circ
- * times out while in state CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT .
- * If we received the first INTRODUCE1 cell (the intro-point relay
- * converts it into an INTRODUCE2 cell), we are already trying to
- * connect to that rend point (and may have already succeeded);
- * drop this cell. */
- log_info(LD_REND, "We received an "
- "INTRODUCE2 cell with same first part of "
- "Diffie-Hellman handshake %d seconds ago. Dropping "
- "cell.",
- (int) elapsed);
- goto err;
- }
-
- /* If the service performs client authorization, check included auth data. */
- if (service->clients) {
- if (parsed_req->version == 3 && parsed_req->u.v3.auth_len > 0) {
- if (rend_check_authorization(service,
- (const char*)parsed_req->u.v3.auth_data,
- parsed_req->u.v3.auth_len)) {
- log_info(LD_REND, "Authorization data in INTRODUCE2 cell are valid.");
- } else {
- log_info(LD_REND, "The authorization data that are contained in "
- "the INTRODUCE2 cell are invalid. Dropping cell.");
- reason = END_CIRC_REASON_CONNECTFAILED;
- goto err;
- }
- } else {
- log_info(LD_REND, "INTRODUCE2 cell does not contain authentication "
- "data, but we require client authorization. Dropping cell.");
- reason = END_CIRC_REASON_CONNECTFAILED;
- goto err;
- }
- }
-
- /* Try DH handshake... */
- dh = crypto_dh_new(DH_TYPE_REND);
- if (!dh || crypto_dh_generate_public(dh)<0) {
- log_warn(LD_BUG,"Internal error: couldn't build DH state "
- "or generate public key.");
- reason = END_CIRC_REASON_INTERNAL;
- goto err;
- }
- if (crypto_dh_compute_secret(LOG_PROTOCOL_WARN, dh,
- (char *)(parsed_req->dh),
- DH1024_KEY_LEN, keys,
- DIGEST_LEN+CPATH_KEY_MATERIAL_LEN)<0) {
- log_warn(LD_BUG, "Internal error: couldn't complete DH handshake");
- reason = END_CIRC_REASON_INTERNAL;
- goto err;
- }
-
- circ_needs_uptime = hs_service_requires_uptime_circ(service->ports);
-
- /* help predict this next time */
- rep_hist_note_used_internal(now, circ_needs_uptime, 1);
-
- /* Launch a circuit to the client's chosen rendezvous point.
- */
- int max_rend_failures=hs_get_service_max_rend_failures();
- for (i=0;i<max_rend_failures;i++) {
- int flags = CIRCLAUNCH_NEED_CAPACITY | CIRCLAUNCH_IS_INTERNAL;
- if (circ_needs_uptime) flags |= CIRCLAUNCH_NEED_UPTIME;
- /* A Single Onion Service only uses a direct connection if its
- * firewall rules permit direct connections to the address.
- *
- * We only use a one-hop path on the first attempt. If the first attempt
- * fails, we use a 3-hop path for reachability / reliability.
- * See the comment in rend_service_relaunch_rendezvous() for details. */
- if (rend_service_use_direct_connection(options, rp) && i == 0) {
- flags = flags | CIRCLAUNCH_ONEHOP_TUNNEL;
- }
- launched = circuit_launch_by_extend_info(
- CIRCUIT_PURPOSE_S_CONNECT_REND, rp, flags);
-
- if (launched)
- break;
- }
- if (!launched) { /* give up */
- log_warn(LD_REND, "Giving up launching first hop of circuit to rendezvous "
- "point %s for service %s.",
- safe_str_client(extend_info_describe(rp)),
- serviceid);
- reason = END_CIRC_REASON_CONNECTFAILED;
- goto err;
- }
- log_info(LD_REND,
- "Accepted intro; launching circuit to %s "
- "(cookie %s) for service %s.",
- safe_str_client(extend_info_describe(rp)),
- hexcookie, serviceid);
- tor_assert(launched->build_state);
- /* Fill in the circuit's state. */
-
- launched->rend_data =
- rend_data_service_create(service->service_id, rend_pk_digest,
- parsed_req->rc, service->auth_type);
-
- launched->build_state->service_pending_final_cpath_ref =
- tor_malloc_zero(sizeof(crypt_path_reference_t));
- launched->build_state->service_pending_final_cpath_ref->refcount = 1;
-
- launched->build_state->service_pending_final_cpath_ref->cpath = cpath =
- tor_malloc_zero(sizeof(crypt_path_t));
- cpath->magic = CRYPT_PATH_MAGIC;
- launched->build_state->expiry_time = now + MAX_REND_TIMEOUT;
-
- cpath->rend_dh_handshake_state = dh;
- dh = NULL;
- if (cpath_init_circuit_crypto(cpath,
- keys+DIGEST_LEN, sizeof(keys)-DIGEST_LEN,
- 1, 0)<0)
- goto err;
- memcpy(cpath->rend_circ_nonce, keys, DIGEST_LEN);
-
- goto done;
-
- log_error:
- if (!err_msg) {
- if (stage_descr) {
- tor_asprintf(&err_msg,
- "unknown %s error for INTRODUCE2", stage_descr);
- } else {
- err_msg = tor_strdup("unknown error for INTRODUCE2");
- }
- }
-
- log_fn(err_msg_severity, LD_REND, "%s on circ %u", err_msg,
- (unsigned)circuit->base_.n_circ_id);
- err:
- status = -1;
- if (dh) crypto_dh_free(dh);
- if (launched) {
- circuit_mark_for_close(TO_CIRCUIT(launched), reason);
- }
- tor_free(err_msg);
-
- done:
- memwipe(keys, 0, sizeof(keys));
- memwipe(buf, 0, sizeof(buf));
- memwipe(serviceid, 0, sizeof(serviceid));
- memwipe(hexcookie, 0, sizeof(hexcookie));
-
- /* Free the parsed cell */
- rend_service_free_intro(parsed_req);
-
- /* Free rp */
- extend_info_free(rp);
-
- return status;
-}
-
-/** Given a parsed and decrypted INTRODUCE2, find the rendezvous point or
- * return NULL and an error string if we can't. Return a newly allocated
- * extend_info_t* for the rendezvous point. */
-static extend_info_t *
-find_rp_for_intro(const rend_intro_cell_t *intro,
- char **err_msg_out)
-{
- extend_info_t *rp = NULL;
- char *err_msg = NULL;
- const char *rp_nickname = NULL;
- const node_t *node = NULL;
-
- if (!intro) {
- if (err_msg_out)
- err_msg = tor_strdup("Bad parameters to find_rp_for_intro()");
-
- goto err;
- }
-
- if (intro->version == 0 || intro->version == 1) {
- rp_nickname = (const char *)(intro->u.v0_v1.rp);
-
- node = node_get_by_nickname(rp_nickname, NNF_NO_WARN_UNNAMED);
- if (!node) {
- if (err_msg_out) {
- tor_asprintf(&err_msg,
- "Couldn't find router %s named in INTRODUCE2 cell",
- escaped_safe_str_client(rp_nickname));
- }
-
- goto err;
- }
-
- /* Are we in single onion mode? */
- const int allow_direct = rend_service_allow_non_anonymous_connection(
- get_options());
- rp = extend_info_from_node(node, allow_direct);
- if (!rp) {
- if (err_msg_out) {
- tor_asprintf(&err_msg,
- "Couldn't build extend_info_t for router %s named "
- "in INTRODUCE2 cell",
- escaped_safe_str_client(rp_nickname));
- }
-
- goto err;
- }
- } else if (intro->version == 2) {
- rp = extend_info_dup(intro->u.v2.extend_info);
- } else if (intro->version == 3) {
- rp = extend_info_dup(intro->u.v3.extend_info);
- } else {
- if (err_msg_out) {
- tor_asprintf(&err_msg,
- "Unknown version %d in INTRODUCE2 cell",
- (int)(intro->version));
- }
-
- goto err;
- }
-
- /* rp is always set here: extend_info_dup guarantees a non-NULL result, and
- * the other cases goto err. */
- tor_assert(rp);
-
- /* Make sure the RP we are being asked to connect to is _not_ a private
- * address unless it's allowed. Let's avoid to build a circuit to our
- * second middle node and fail right after when extending to the RP. */
- const tor_addr_port_t *orport = extend_info_get_orport(rp, AF_INET);
- if (! orport || !extend_info_addr_is_allowed(&orport->addr)) {
- if (err_msg_out) {
- tor_asprintf(&err_msg,
- "Relay IP in INTRODUCE2 cell is private address.");
- }
- extend_info_free(rp);
- rp = NULL;
- goto err;
- }
- goto done;
-
- err:
- if (err_msg_out)
- *err_msg_out = err_msg;
- else
- tor_free(err_msg);
-
- done:
- return rp;
-}
-
-/** Free a parsed INTRODUCE1 or INTRODUCE2 cell that was allocated by
- * rend_service_parse_intro().
- */
-void
-rend_service_free_intro_(rend_intro_cell_t *request)
-{
- if (!request) {
- return;
- }
-
- /* Free ciphertext */
- tor_free(request->ciphertext);
- request->ciphertext_len = 0;
-
- /* Have plaintext? */
- if (request->plaintext) {
- /* Zero it out just to be safe */
- memwipe(request->plaintext, 0, request->plaintext_len);
- tor_free(request->plaintext);
- request->plaintext_len = 0;
- }
-
- /* Have parsed plaintext? */
- if (request->parsed) {
- switch (request->version) {
- case 0:
- case 1:
- /*
- * Nothing more to do; these formats have no further pointers
- * in them.
- */
- break;
- case 2:
- extend_info_free(request->u.v2.extend_info);
- request->u.v2.extend_info = NULL;
- break;
- case 3:
- if (request->u.v3.auth_data) {
- memwipe(request->u.v3.auth_data, 0, request->u.v3.auth_len);
- tor_free(request->u.v3.auth_data);
- }
-
- extend_info_free(request->u.v3.extend_info);
- request->u.v3.extend_info = NULL;
- break;
- default:
- log_info(LD_BUG,
- "rend_service_free_intro() saw unknown protocol "
- "version %d.",
- request->version);
- }
- }
-
- /* Zero it out to make sure sensitive stuff doesn't hang around in memory */
- memwipe(request, 0, sizeof(*request));
-
- tor_free(request);
-}
-
-/** Parse an INTRODUCE1 or INTRODUCE2 cell into a newly allocated
- * rend_intro_cell_t structure. Free it with rend_service_free_intro()
- * when finished. The type parameter should be 1 or 2 to indicate whether
- * this is INTRODUCE1 or INTRODUCE2. This parses only the non-encrypted
- * parts; after this, call rend_service_decrypt_intro() with a key, then
- * rend_service_parse_intro_plaintext() to finish parsing. The optional
- * err_msg_out parameter is set to a string suitable for log output
- * if parsing fails. This function does some validation, but only
- * that which depends solely on the contents of the cell and the
- * key; it can be unit-tested. Further validation is done in
- * rend_service_validate_intro().
- */
-
-rend_intro_cell_t *
-rend_service_begin_parse_intro(const uint8_t *request,
- size_t request_len,
- uint8_t type,
- char **err_msg_out)
-{
- rend_intro_cell_t *rv = NULL;
- char *err_msg = NULL;
-
- if (!request || request_len <= 0) goto err;
- if (!(type == 1 || type == 2)) goto err;
-
- /* First, check that the cell is long enough to be a sensible INTRODUCE */
-
- /* min key length plus digest length plus nickname length */
- if (request_len <
- (DIGEST_LEN + REND_COOKIE_LEN + (MAX_NICKNAME_LEN + 1) +
- DH1024_KEY_LEN + 42)) {
- if (err_msg_out) {
- tor_asprintf(&err_msg,
- "got a truncated INTRODUCE%d cell",
- (int)type);
- }
- goto err;
- }
-
- /* Allocate a new parsed cell structure */
- rv = tor_malloc_zero(sizeof(*rv));
-
- /* Set the type */
- rv->type = type;
-
- /* Copy in the ID */
- memcpy(rv->pk, request, DIGEST_LEN);
-
- /* Copy in the ciphertext */
- rv->ciphertext = tor_malloc(request_len - DIGEST_LEN);
- memcpy(rv->ciphertext, request + DIGEST_LEN, request_len - DIGEST_LEN);
- rv->ciphertext_len = request_len - DIGEST_LEN;
-
- goto done;
-
- err:
- rend_service_free_intro(rv);
- rv = NULL;
-
- if (err_msg_out && !err_msg) {
- tor_asprintf(&err_msg,
- "unknown INTRODUCE%d error",
- (int)type);
- }
-
- done:
- if (err_msg_out) *err_msg_out = err_msg;
- else tor_free(err_msg);
-
- return rv;
-}
-
-/** Parse the version-specific parts of a v0 or v1 INTRODUCE1 or INTRODUCE2
- * cell
- */
-
-static ssize_t
-rend_service_parse_intro_for_v0_or_v1(
- rend_intro_cell_t *intro,
- const uint8_t *buf,
- size_t plaintext_len,
- char **err_msg_out)
-{
- const char *rp_nickname, *endptr;
- size_t nickname_field_len, ver_specific_len;
-
- if (intro->version == 1) {
- ver_specific_len = MAX_HEX_NICKNAME_LEN + 2;
- rp_nickname = ((const char *)buf) + 1;
- nickname_field_len = MAX_HEX_NICKNAME_LEN + 1;
- } else if (intro->version == 0) {
- ver_specific_len = MAX_NICKNAME_LEN + 1;
- rp_nickname = (const char *)buf;
- nickname_field_len = MAX_NICKNAME_LEN + 1;
- } else {
- if (err_msg_out)
- tor_asprintf(err_msg_out,
- "rend_service_parse_intro_for_v0_or_v1() called with "
- "bad version %d on INTRODUCE%d cell (this is a bug)",
- intro->version,
- (int)(intro->type));
- goto err;
- }
-
- if (plaintext_len < ver_specific_len) {
- if (err_msg_out)
- tor_asprintf(err_msg_out,
- "short plaintext of encrypted part in v1 INTRODUCE%d "
- "cell (%lu bytes, needed %lu)",
- (int)(intro->type),
- (unsigned long)plaintext_len,
- (unsigned long)ver_specific_len);
- goto err;
- }
-
- endptr = memchr(rp_nickname, 0, nickname_field_len);
- if (!endptr || endptr == rp_nickname) {
- if (err_msg_out) {
- tor_asprintf(err_msg_out,
- "couldn't find a nul-padded nickname in "
- "INTRODUCE%d cell",
- (int)(intro->type));
- }
- goto err;
- }
-
- if ((intro->version == 0 &&
- !is_legal_nickname(rp_nickname)) ||
- (intro->version == 1 &&
- !is_legal_nickname_or_hexdigest(rp_nickname))) {
- if (err_msg_out) {
- tor_asprintf(err_msg_out,
- "bad nickname in INTRODUCE%d cell",
- (int)(intro->type));
- }
- goto err;
- }
-
- memcpy(intro->u.v0_v1.rp, rp_nickname, endptr - rp_nickname + 1);
-
- return ver_specific_len;
-
- err:
- return -1;
-}
-
-/** Parse the version-specific parts of a v2 INTRODUCE1 or INTRODUCE2 cell
- */
-
-static ssize_t
-rend_service_parse_intro_for_v2(
- rend_intro_cell_t *intro,
- const uint8_t *buf,
- size_t plaintext_len,
- char **err_msg_out)
-{
- unsigned int klen;
- extend_info_t *extend_info = NULL;
- ssize_t ver_specific_len;
-
- /*
- * We accept version 3 too so that the v3 parser can call this with
- * an adjusted buffer for the latter part of a v3 cell, which is
- * identical to a v2 cell.
- */
- if (!(intro->version == 2 ||
- intro->version == 3)) {
- if (err_msg_out)
- tor_asprintf(err_msg_out,
- "rend_service_parse_intro_for_v2() called with "
- "bad version %d on INTRODUCE%d cell (this is a bug)",
- intro->version,
- (int)(intro->type));
- goto err;
- }
-
- /* 7 == version, IP and port, DIGEST_LEN == id, 2 == key length */
- if (plaintext_len < 7 + DIGEST_LEN + 2) {
- if (err_msg_out) {
- tor_asprintf(err_msg_out,
- "truncated plaintext of encrypted parted of "
- "version %d INTRODUCE%d cell",
- intro->version,
- (int)(intro->type));
- }
-
- goto err;
- }
-
- extend_info = extend_info_new(NULL, NULL, NULL, NULL, NULL, NULL, 0);
- tor_addr_t addr;
- tor_addr_from_ipv4n(&addr, get_uint32(buf + 1));
- uint16_t port = ntohs(get_uint16(buf + 5));
- extend_info_add_orport(extend_info, &addr, port);
- memcpy(extend_info->identity_digest, buf + 7, DIGEST_LEN);
- extend_info->nickname[0] = '$';
- base16_encode(extend_info->nickname + 1, sizeof(extend_info->nickname) - 1,
- extend_info->identity_digest, DIGEST_LEN);
- klen = ntohs(get_uint16(buf + 7 + DIGEST_LEN));
-
- /* 7 == version, IP and port, DIGEST_LEN == id, 2 == key length */
- if (plaintext_len < 7 + DIGEST_LEN + 2 + klen) {
- if (err_msg_out) {
- tor_asprintf(err_msg_out,
- "truncated plaintext of encrypted parted of "
- "version %d INTRODUCE%d cell",
- intro->version,
- (int)(intro->type));
- }
-
- goto err;
- }
-
- extend_info->onion_key =
- crypto_pk_asn1_decode((const char *)(buf + 7 + DIGEST_LEN + 2), klen);
- if (!extend_info->onion_key) {
- if (err_msg_out) {
- tor_asprintf(err_msg_out,
- "error decoding onion key in version %d "
- "INTRODUCE%d cell",
- intro->version,
- (intro->type));
- }
-
- goto err;
- }
- if (128 != crypto_pk_keysize(extend_info->onion_key)) {
- if (err_msg_out) {
- tor_asprintf(err_msg_out,
- "invalid onion key size in version %d INTRODUCE%d cell",
- intro->version,
- (intro->type));
- }
-
- goto err;
- }
-
- ver_specific_len = 7+DIGEST_LEN+2+klen;
-
- if (intro->version == 2) intro->u.v2.extend_info = extend_info;
- else intro->u.v3.extend_info = extend_info;
-
- return ver_specific_len;
-
- err:
- extend_info_free(extend_info);
-
- return -1;
-}
-
-/** Parse the version-specific parts of a v3 INTRODUCE1 or INTRODUCE2 cell
- */
-
-static ssize_t
-rend_service_parse_intro_for_v3(
- rend_intro_cell_t *intro,
- const uint8_t *buf,
- size_t plaintext_len,
- char **err_msg_out)
-{
- ssize_t adjust, v2_ver_specific_len, ts_offset;
-
- /* This should only be called on v3 cells */
- if (intro->version != 3) {
- if (err_msg_out)
- tor_asprintf(err_msg_out,
- "rend_service_parse_intro_for_v3() called with "
- "bad version %d on INTRODUCE%d cell (this is a bug)",
- intro->version,
- (int)(intro->type));
- goto err;
- }
-
- /*
- * Check that we have at least enough to get auth_len:
- *
- * 1 octet for version, 1 for auth_type, 2 for auth_len
- */
- if (plaintext_len < 4) {
- if (err_msg_out) {
- tor_asprintf(err_msg_out,
- "truncated plaintext of encrypted parted of "
- "version %d INTRODUCE%d cell",
- intro->version,
- (int)(intro->type));
- }
-
- goto err;
- }
-
- /*
- * The rend_client_send_introduction() function over in rendclient.c is
- * broken (i.e., fails to match the spec) in such a way that we can't
- * change it without breaking the protocol. Specifically, it doesn't
- * emit auth_len when auth-type is REND_NO_AUTH, so everything is off
- * by two bytes after that. Calculate ts_offset and do everything from
- * the timestamp on relative to that to handle this dain bramage.
- */
-
- intro->u.v3.auth_type = buf[1];
- if (intro->u.v3.auth_type != REND_NO_AUTH) {
- intro->u.v3.auth_len = ntohs(get_uint16(buf + 2));
- ts_offset = 4 + intro->u.v3.auth_len;
- } else {
- intro->u.v3.auth_len = 0;
- ts_offset = 2;
- }
-
- /* Check that auth len makes sense for this auth type */
- if (intro->u.v3.auth_type == REND_BASIC_AUTH ||
- intro->u.v3.auth_type == REND_STEALTH_AUTH) {
- if (intro->u.v3.auth_len != REND_DESC_COOKIE_LEN) {
- if (err_msg_out) {
- tor_asprintf(err_msg_out,
- "wrong auth data size %d for INTRODUCE%d cell, "
- "should be %d",
- (int)(intro->u.v3.auth_len),
- (int)(intro->type),
- REND_DESC_COOKIE_LEN);
- }
-
- goto err;
- }
- }
-
- /* Check that we actually have everything up through the timestamp */
- if (plaintext_len < (size_t)(ts_offset)+4) {
- if (err_msg_out) {
- tor_asprintf(err_msg_out,
- "truncated plaintext of encrypted parted of "
- "version %d INTRODUCE%d cell",
- intro->version,
- (int)(intro->type));
- }
-
- goto err;
- }
-
- if (intro->u.v3.auth_type != REND_NO_AUTH &&
- intro->u.v3.auth_len > 0) {
- /* Okay, we can go ahead and copy auth_data */
- intro->u.v3.auth_data = tor_malloc(intro->u.v3.auth_len);
- /*
- * We know we had an auth_len field in this case, so 4 is
- * always right.
- */
- memcpy(intro->u.v3.auth_data, buf + 4, intro->u.v3.auth_len);
- }
-
- /*
- * From here on, the format is as in v2, so we call the v2 parser with
- * adjusted buffer and length. We are 4 + ts_offset octets in, but the
- * v2 parser expects to skip over a version byte at the start, so we
- * adjust by 3 + ts_offset.
- */
- adjust = 3 + ts_offset;
-
- v2_ver_specific_len =
- rend_service_parse_intro_for_v2(intro,
- buf + adjust, plaintext_len - adjust,
- err_msg_out);
-
- /* Success in v2 parser */
- if (v2_ver_specific_len >= 0) return v2_ver_specific_len + adjust;
- /* Failure in v2 parser; it will have provided an err_msg */
- else return v2_ver_specific_len;
-
- err:
- return -1;
-}
-
-/** Table of parser functions for version-specific parts of an INTRODUCE2
- * cell.
- */
-
-static ssize_t
- (*intro_version_handlers[])(
- rend_intro_cell_t *,
- const uint8_t *,
- size_t,
- char **) =
-{ rend_service_parse_intro_for_v0_or_v1,
- rend_service_parse_intro_for_v0_or_v1,
- rend_service_parse_intro_for_v2,
- rend_service_parse_intro_for_v3 };
-
-/** Decrypt the encrypted part of an INTRODUCE1 or INTRODUCE2 cell,
- * return 0 if successful, or < 0 and write an error message to
- * *err_msg_out if provided.
- */
-
-int
-rend_service_decrypt_intro(
- rend_intro_cell_t *intro,
- crypto_pk_t *key,
- char **err_msg_out)
-{
- char *err_msg = NULL;
- uint8_t key_digest[DIGEST_LEN];
- char service_id[REND_SERVICE_ID_LEN_BASE32+1];
- ssize_t key_len;
- uint8_t buf[RELAY_PAYLOAD_SIZE];
- int result, status = -1;
-
- if (!intro || !key) {
- if (err_msg_out) {
- err_msg =
- tor_strdup("rend_service_decrypt_intro() called with bad "
- "parameters");
- }
-
- status = -2;
- goto err;
- }
-
- /* Make sure we have ciphertext */
- if (!(intro->ciphertext) || intro->ciphertext_len <= 0) {
- if (err_msg_out) {
- tor_asprintf(&err_msg,
- "rend_intro_cell_t was missing ciphertext for "
- "INTRODUCE%d cell",
- (int)(intro->type));
- }
- status = -3;
- goto err;
- }
-
- /* Check that this cell actually matches this service key */
-
- /* first DIGEST_LEN bytes of request is intro or service pk digest */
- if (crypto_pk_get_digest(key, (char *)key_digest) < 0) {
- if (err_msg_out)
- *err_msg_out = tor_strdup("Couldn't compute RSA digest.");
- log_warn(LD_BUG, "Couldn't compute key digest.");
- status = -7;
- goto err;
- }
-
- if (tor_memneq(key_digest, intro->pk, DIGEST_LEN)) {
- if (err_msg_out) {
- base32_encode(service_id, REND_SERVICE_ID_LEN_BASE32 + 1,
- (char*)(intro->pk), REND_SERVICE_ID_LEN);
- tor_asprintf(&err_msg,
- "got an INTRODUCE%d cell for the wrong service (%s)",
- (int)(intro->type),
- escaped(service_id));
- }
-
- status = -4;
- goto err;
- }
-
- /* Make sure the encrypted part is long enough to decrypt */
-
- key_len = crypto_pk_keysize(key);
- if (intro->ciphertext_len < key_len) {
- if (err_msg_out) {
- tor_asprintf(&err_msg,
- "got an INTRODUCE%d cell with a truncated PK-encrypted "
- "part",
- (int)(intro->type));
- }
-
- status = -5;
- goto err;
- }
-
- /* Decrypt the encrypted part */
- result =
- crypto_pk_obsolete_private_hybrid_decrypt(
- key, (char *)buf, sizeof(buf),
- (const char *)(intro->ciphertext), intro->ciphertext_len,
- PK_PKCS1_OAEP_PADDING, 1);
- if (result < 0) {
- if (err_msg_out) {
- tor_asprintf(&err_msg,
- "couldn't decrypt INTRODUCE%d cell",
- (int)(intro->type));
- }
- status = -6;
- goto err;
- }
- intro->plaintext_len = result;
- intro->plaintext = tor_malloc(intro->plaintext_len);
- memcpy(intro->plaintext, buf, intro->plaintext_len);
-
- status = 0;
-
- goto done;
-
- err:
- if (err_msg_out && !err_msg) {
- tor_asprintf(&err_msg,
- "unknown INTRODUCE%d error decrypting encrypted part",
- intro ? (int)(intro->type) : -1);
- }
-
- done:
- if (err_msg_out) *err_msg_out = err_msg;
- else tor_free(err_msg);
-
- /* clean up potentially sensitive material */
- memwipe(buf, 0, sizeof(buf));
- memwipe(key_digest, 0, sizeof(key_digest));
- memwipe(service_id, 0, sizeof(service_id));
-
- return status;
-}
-
-/** Parse the plaintext of the encrypted part of an INTRODUCE1 or
- * INTRODUCE2 cell, return 0 if successful, or < 0 and write an error
- * message to *err_msg_out if provided.
- */
-
-int
-rend_service_parse_intro_plaintext(
- rend_intro_cell_t *intro,
- char **err_msg_out)
-{
- char *err_msg = NULL;
- ssize_t ver_specific_len, ver_invariant_len;
- uint8_t version;
- int status = -1;
-
- if (!intro) {
- if (err_msg_out) {
- err_msg =
- tor_strdup("rend_service_parse_intro_plaintext() called with NULL "
- "rend_intro_cell_t");
- }
-
- status = -2;
- goto err;
- }
-
- /* Check that we have plaintext */
- if (!(intro->plaintext) || intro->plaintext_len <= 0) {
- if (err_msg_out) {
- err_msg = tor_strdup("rend_intro_cell_t was missing plaintext");
- }
- status = -3;
- goto err;
- }
-
- /* In all formats except v0, the first byte is a version number */
- version = intro->plaintext[0];
-
- /* v0 has no version byte (stupid...), so handle it as a fallback */
- if (version > 3) version = 0;
-
- /* Copy the version into the parsed cell structure */
- intro->version = version;
-
- /* Call the version-specific parser from the table */
- ver_specific_len =
- intro_version_handlers[version](intro,
- intro->plaintext, intro->plaintext_len,
- &err_msg);
- if (ver_specific_len < 0) {
- status = -4;
- goto err;
- }
-
- /** The rendezvous cookie and Diffie-Hellman stuff are version-invariant
- * and at the end of the plaintext of the encrypted part of the cell.
- */
-
- ver_invariant_len = intro->plaintext_len - ver_specific_len;
- if (ver_invariant_len < REND_COOKIE_LEN + DH1024_KEY_LEN) {
- tor_asprintf(&err_msg,
- "decrypted plaintext of INTRODUCE%d cell was truncated (%ld bytes)",
- (int)(intro->type),
- (long)(intro->plaintext_len));
- status = -5;
- goto err;
- } else if (ver_invariant_len > REND_COOKIE_LEN + DH1024_KEY_LEN) {
- tor_asprintf(&err_msg,
- "decrypted plaintext of INTRODUCE%d cell was too long (%ld bytes)",
- (int)(intro->type),
- (long)(intro->plaintext_len));
- status = -6;
- goto err;
- } else {
- memcpy(intro->rc,
- intro->plaintext + ver_specific_len,
- REND_COOKIE_LEN);
- memcpy(intro->dh,
- intro->plaintext + ver_specific_len + REND_COOKIE_LEN,
- DH1024_KEY_LEN);
- }
-
- /* Flag it as being fully parsed */
- intro->parsed = 1;
-
- status = 0;
- goto done;
-
- err:
- if (err_msg_out && !err_msg) {
- tor_asprintf(&err_msg,
- "unknown INTRODUCE%d error parsing encrypted part",
- intro ? (int)(intro->type) : -1);
- }
-
- done:
- if (err_msg_out) *err_msg_out = err_msg;
- else tor_free(err_msg);
-
- return status;
-}
-
-/** Do validity checks on a parsed intro cell after decryption; some of
- * these are not done in rend_service_parse_intro_plaintext() itself because
- * they depend on a lot of other state and would make it hard to unit test.
- * Returns >= 0 if successful or < 0 if the intro cell is invalid, and
- * optionally writes out an error message for logging. If an err_msg
- * pointer is provided, it is the caller's responsibility to free any
- * provided message.
- */
-
-int
-rend_service_validate_intro_late(const rend_intro_cell_t *intro,
- char **err_msg_out)
-{
- int status = 0;
-
- if (!intro) {
- if (err_msg_out)
- *err_msg_out =
- tor_strdup("NULL intro cell passed to "
- "rend_service_validate_intro_late()");
-
- status = -1;
- goto err;
- }
-
- if (intro->version == 3 && intro->parsed) {
- if (!(intro->u.v3.auth_type == REND_NO_AUTH ||
- intro->u.v3.auth_type == REND_BASIC_AUTH ||
- intro->u.v3.auth_type == REND_STEALTH_AUTH)) {
- /* This is an informative message, not an error, as in the old code */
- if (err_msg_out)
- tor_asprintf(err_msg_out,
- "unknown authorization type %d",
- intro->u.v3.auth_type);
- }
- }
-
- err:
- return status;
-}
-
-/** Called when we fail building a rendezvous circuit at some point other
- * than the last hop: launches a new circuit to the same rendezvous point.
- */
-void
-rend_service_relaunch_rendezvous(origin_circuit_t *oldcirc)
-{
- origin_circuit_t *newcirc;
- cpath_build_state_t *newstate, *oldstate;
- const char *rend_pk_digest;
- rend_service_t *service = NULL;
-
- int flags = CIRCLAUNCH_NEED_CAPACITY | CIRCLAUNCH_IS_INTERNAL;
-
- tor_assert(oldcirc->base_.purpose == CIRCUIT_PURPOSE_S_CONNECT_REND);
- oldstate = oldcirc->build_state;
- tor_assert(oldstate);
-
- if (oldstate->service_pending_final_cpath_ref == NULL) {
- log_info(LD_REND,"Skipping relaunch of circ that failed on its first hop. "
- "Initiator will retry.");
- return;
- }
-
- log_info(LD_REND,"Reattempting rendezvous circuit to '%s'",
- safe_str(extend_info_describe(oldstate->chosen_exit)));
-
- /* Look up the service. */
- rend_pk_digest = (char *) rend_data_get_pk_digest(oldcirc->rend_data, NULL);
- service = rend_service_get_by_pk_digest(rend_pk_digest);
-
- if (!service) {
- char serviceid[REND_SERVICE_ID_LEN_BASE32+1];
- base32_encode(serviceid, REND_SERVICE_ID_LEN_BASE32+1,
- rend_pk_digest, REND_SERVICE_ID_LEN);
-
- log_warn(LD_BUG, "Internal error: Trying to relaunch a rendezvous circ "
- "for an unrecognized service %s.",
- safe_str_client(serviceid));
- return;
- }
-
- if (hs_service_requires_uptime_circ(service->ports)) {
- flags |= CIRCLAUNCH_NEED_UPTIME;
- }
-
- /* You'd think Single Onion Services would want to retry the rendezvous
- * using a direct connection. But if it's blocked by a firewall, or the
- * service is IPv6-only, or the rend point avoiding becoming a one-hop
- * proxy, we need a 3-hop connection. */
- newcirc = circuit_launch_by_extend_info(CIRCUIT_PURPOSE_S_CONNECT_REND,
- oldstate->chosen_exit, flags);
-
- if (!newcirc) {
- log_warn(LD_REND,"Couldn't relaunch rendezvous circuit to '%s'.",
- safe_str(extend_info_describe(oldstate->chosen_exit)));
- return;
- }
- newstate = newcirc->build_state;
- tor_assert(newstate);
- newstate->failure_count = oldstate->failure_count+1;
- newstate->expiry_time = oldstate->expiry_time;
- newstate->service_pending_final_cpath_ref =
- oldstate->service_pending_final_cpath_ref;
- ++(newstate->service_pending_final_cpath_ref->refcount);
-
- newcirc->rend_data = rend_data_dup(oldcirc->rend_data);
-}
-
-/** Launch a circuit to serve as an introduction point for the service
- * <b>service</b> at the introduction point <b>nickname</b>
- */
-static int
-rend_service_launch_establish_intro(rend_service_t *service,
- rend_intro_point_t *intro)
-{
- origin_circuit_t *launched;
- int flags = CIRCLAUNCH_NEED_UPTIME|CIRCLAUNCH_IS_INTERNAL;
- const or_options_t *options = get_options();
- extend_info_t *launch_ei = intro->extend_info;
- extend_info_t *direct_ei = NULL;
-
- /* Are we in single onion mode?
- *
- * We only use a one-hop path on the first attempt. If the first attempt
- * fails, we use a 3-hop path for reachability / reliability.
- * (Unlike v3, retries is incremented by the caller after it calls this
- * function.)
- */
- if (rend_service_allow_non_anonymous_connection(options) &&
- intro->circuit_retries == 0) {
- /* Do we have a descriptor for the node?
- * We've either just chosen it from the consensus, or we've just reviewed
- * our intro points to see which ones are still valid, and deleted the ones
- * that aren't in the consensus any more. */
- const node_t *node = node_get_by_id(launch_ei->identity_digest);
- if (BUG(!node)) {
- /* The service has kept an intro point after it went missing from the
- * consensus. If we did anything else here, it would be a consensus
- * distinguisher. Which are less of an issue for single onion services,
- * but still a bug. */
- return -1;
- }
- /* Can we connect to the node directly? If so, replace launch_ei
- * (a multi-hop extend_info) with one suitable for direct connection. */
- if (rend_service_use_direct_connection_node(options, node)) {
- direct_ei = extend_info_from_node(node, 1);
- if (BUG(!direct_ei)) {
- /* rend_service_use_direct_connection_node and extend_info_from_node
- * disagree about which addresses on this node are permitted. This
- * should never happen. Avoiding the connection is a safe response. */
- return -1;
- }
- flags = flags | CIRCLAUNCH_ONEHOP_TUNNEL;
- launch_ei = direct_ei;
- }
- }
- /* launch_ei is either intro->extend_info, or has been replaced with a valid
- * extend_info for single onion service direct connection. */
- tor_assert(launch_ei);
- /* We must have the same intro when making a direct connection. */
- tor_assert(tor_memeq(intro->extend_info->identity_digest,
- launch_ei->identity_digest,
- DIGEST_LEN));
-
- log_info(LD_REND,
- "Launching circuit to introduction point %s%s%s for service %s",
- safe_str_client(extend_info_describe(intro->extend_info)),
- direct_ei ? " via direct address " : "",
- direct_ei ? safe_str_client(extend_info_describe(direct_ei)) : "",
- service->service_id);
-
- rep_hist_note_used_internal(time(NULL), 1, 0);
-
- ++service->n_intro_circuits_launched;
- launched = circuit_launch_by_extend_info(CIRCUIT_PURPOSE_S_ESTABLISH_INTRO,
- launch_ei, flags);
-
- if (!launched) {
- log_info(LD_REND,
- "Can't launch circuit to establish introduction at %s%s%s.",
- safe_str_client(extend_info_describe(intro->extend_info)),
- direct_ei ? " via direct address " : "",
- direct_ei ? safe_str_client(extend_info_describe(direct_ei)) : ""
- );
- extend_info_free(direct_ei);
- return -1;
- }
- /* We must have the same exit node even if cannibalized or direct connection.
- */
- tor_assert(tor_memeq(intro->extend_info->identity_digest,
- launched->build_state->chosen_exit->identity_digest,
- DIGEST_LEN));
-
- launched->rend_data = rend_data_service_create(service->service_id,
- service->pk_digest, NULL,
- service->auth_type);
- launched->intro_key = crypto_pk_dup_key(intro->intro_key);
- if (launched->base_.state == CIRCUIT_STATE_OPEN)
- rend_service_intro_has_opened(launched);
- extend_info_free(direct_ei);
- return 0;
-}
-
-/** Return the number of introduction points that are established for the
- * given service. */
-static unsigned int
-count_established_intro_points(const rend_service_t *service)
-{
- unsigned int num = 0;
-
- SMARTLIST_FOREACH(service->intro_nodes, rend_intro_point_t *, intro,
- num += intro->circuit_established
- );
- return num;
-}
-
-/** Return the number of introduction points that are or are being
- * established for the given service. This function iterates over all
- * circuit and count those that are linked to the service and are waiting
- * for the intro point to respond. */
-static unsigned int
-count_intro_point_circuits(const rend_service_t *service)
-{
- unsigned int num_ipos = 0;
- SMARTLIST_FOREACH_BEGIN(circuit_get_global_list(), circuit_t *, circ) {
- if (!circ->marked_for_close &&
- circ->state == CIRCUIT_STATE_OPEN &&
- (circ->purpose == CIRCUIT_PURPOSE_S_ESTABLISH_INTRO ||
- circ->purpose == CIRCUIT_PURPOSE_S_INTRO)) {
- origin_circuit_t *oc = TO_ORIGIN_CIRCUIT(circ);
- if (oc->rend_data &&
- rend_circuit_pk_digest_eq(oc, (uint8_t *) service->pk_digest)) {
- num_ipos++;
- }
- }
- }
- SMARTLIST_FOREACH_END(circ);
- return num_ipos;
-}
-
-/* Given a buffer of at least RELAY_PAYLOAD_SIZE bytes in <b>cell_body_out</b>,
- write the body of a legacy ESTABLISH_INTRO cell in it. Use <b>intro_key</b>
- as the intro point auth key, and <b>rend_circ_nonce</b> as the circuit
- crypto material. On success, fill <b>cell_body_out</b> and return the number
- of bytes written. On fail, return -1.
- */
-ssize_t
-rend_service_encode_establish_intro_cell(char *cell_body_out,
- size_t cell_body_out_len,
- crypto_pk_t *intro_key,
- const char *rend_circ_nonce)
-{
- int retval = -1;
- int r;
- int len = 0;
- char auth[DIGEST_LEN + 9];
-
- tor_assert(intro_key);
- tor_assert(rend_circ_nonce);
-
- /* Build the payload for a RELAY_ESTABLISH_INTRO cell. */
- r = crypto_pk_asn1_encode(intro_key, cell_body_out+2,
- RELAY_PAYLOAD_SIZE-2);
- if (r < 0) {
- log_warn(LD_BUG, "Internal error; failed to establish intro point.");
- goto err;
- }
- len = r;
- set_uint16(cell_body_out, htons((uint16_t)len));
- len += 2;
- memcpy(auth, rend_circ_nonce, DIGEST_LEN);
- memcpy(auth+DIGEST_LEN, "INTRODUCE", 9);
- if (crypto_digest(cell_body_out+len, auth, DIGEST_LEN+9))
- goto err;
- len += 20;
- r = crypto_pk_private_sign_digest(intro_key, cell_body_out+len,
- cell_body_out_len - len,
- cell_body_out, len);
- if (r<0) {
- log_warn(LD_BUG, "Internal error: couldn't sign introduction request.");
- goto err;
- }
- len += r;
-
- retval = len;
-
- err:
- memwipe(auth, 0, sizeof(auth));
-
- return retval;
-}
-
-/** Called when we're done building a circuit to an introduction point:
- * sends a RELAY_ESTABLISH_INTRO cell.
- */
-void
-rend_service_intro_has_opened(origin_circuit_t *circuit)
-{
- rend_service_t *service;
- char buf[RELAY_PAYLOAD_SIZE];
- char serviceid[REND_SERVICE_ID_LEN_BASE32+1];
- unsigned int expiring_nodes_len, num_ip_circuits, valid_ip_circuits = 0;
- int reason = END_CIRC_REASON_TORPROTOCOL;
- const char *rend_pk_digest;
-
- tor_assert(circuit->base_.purpose == CIRCUIT_PURPOSE_S_ESTABLISH_INTRO);
- assert_circ_anonymity_ok(circuit, get_options());
- tor_assert(circuit->cpath);
- tor_assert(circuit->rend_data);
- /* XXX: This is version 2 specific (only on supported). */
- rend_pk_digest = (char *) rend_data_get_pk_digest(circuit->rend_data, NULL);
-
- base32_encode(serviceid, REND_SERVICE_ID_LEN_BASE32+1,
- rend_pk_digest, REND_SERVICE_ID_LEN);
-
- service = rend_service_get_by_pk_digest(rend_pk_digest);
- if (!service) {
- log_warn(LD_REND, "Unrecognized service ID %s on introduction circuit %u.",
- safe_str_client(serviceid), (unsigned)circuit->base_.n_circ_id);
- reason = END_CIRC_REASON_NOSUCHSERVICE;
- goto err;
- }
-
- /* Take the current amount of expiring nodes and the current amount of IP
- * circuits and compute how many valid IP circuits we have. */
- expiring_nodes_len = (unsigned int) smartlist_len(service->expiring_nodes);
- num_ip_circuits = count_intro_point_circuits(service);
- /* Let's avoid an underflow. The valid_ip_circuits is initialized to 0 in
- * case this condition turns out false because it means that all circuits
- * are expiring so we need to keep this circuit. */
- if (num_ip_circuits > expiring_nodes_len) {
- valid_ip_circuits = num_ip_circuits - expiring_nodes_len;
- }
-
- /* If we already have enough introduction circuits for this service,
- * redefine this one as a general circuit or close it, depending.
- * Subtract the amount of expiring nodes here because the circuits are
- * still opened. */
- if (valid_ip_circuits > service->n_intro_points_wanted) {
- const or_options_t *options = get_options();
- /* Remove the intro point associated with this circuit, it's being
- * repurposed or closed thus cleanup memory. */
- rend_intro_point_t *intro = find_intro_point(circuit);
- if (intro != NULL) {
- smartlist_remove(service->intro_nodes, intro);
- rend_intro_point_free(intro);
- }
-
- if (options->ExcludeNodes) {
- /* XXXX in some future version, we can test whether the transition is
- allowed or not given the actual nodes in the circuit. But for now,
- this case, we might as well close the thing. */
- log_info(LD_CIRC|LD_REND, "We have just finished an introduction "
- "circuit, but we already have enough. Closing it.");
- reason = END_CIRC_REASON_NONE;
- goto err;
- } else {
- tor_assert(circuit->build_state->is_internal);
- log_info(LD_CIRC|LD_REND, "We have just finished an introduction "
- "circuit, but we already have enough. Redefining purpose to "
- "general; leaving as internal.");
-
- if (circuit_should_use_vanguards(TO_CIRCUIT(circuit)->purpose)) {
- circuit_change_purpose(TO_CIRCUIT(circuit),
- CIRCUIT_PURPOSE_HS_VANGUARDS);
- } else {
- circuit_change_purpose(TO_CIRCUIT(circuit), CIRCUIT_PURPOSE_C_GENERAL);
- }
-
- {
- rend_data_free(circuit->rend_data);
- circuit->rend_data = NULL;
- }
- {
- crypto_pk_t *intro_key = circuit->intro_key;
- circuit->intro_key = NULL;
- crypto_pk_free(intro_key);
- }
-
- circuit_has_opened(circuit);
- goto done;
- }
- }
-
- log_info(LD_REND,
- "Established circuit %u as introduction point for service %s",
- (unsigned)circuit->base_.n_circ_id, serviceid);
- circuit_log_path(LOG_INFO, LD_REND, circuit);
-
- /* Send the ESTABLISH_INTRO cell */
- {
- ssize_t len;
- len = rend_service_encode_establish_intro_cell(buf, sizeof(buf),
- circuit->intro_key,
- circuit->cpath->prev->rend_circ_nonce);
- if (len < 0) {
- reason = END_CIRC_REASON_INTERNAL;
- goto err;
- }
-
- if (relay_send_command_from_edge(0, TO_CIRCUIT(circuit),
- RELAY_COMMAND_ESTABLISH_INTRO,
- buf, len, circuit->cpath->prev)<0) {
- log_info(LD_GENERAL,
- "Couldn't send introduction request for service %s on circuit %u",
- serviceid, (unsigned)circuit->base_.n_circ_id);
- goto done;
- }
- }
-
- /* We've attempted to use this circuit */
- pathbias_count_use_attempt(circuit);
-
- goto done;
-
- err:
- circuit_mark_for_close(TO_CIRCUIT(circuit), reason);
- done:
- memwipe(buf, 0, sizeof(buf));
- memwipe(serviceid, 0, sizeof(serviceid));
-
- return;
-}
-
-/** Called when we get an INTRO_ESTABLISHED cell; mark the circuit as a
- * live introduction point, and note that the service descriptor is
- * now out-of-date. */
-int
-rend_service_intro_established(origin_circuit_t *circuit,
- const uint8_t *request,
- size_t request_len)
-{
- rend_service_t *service;
- rend_intro_point_t *intro;
- char serviceid[REND_SERVICE_ID_LEN_BASE32+1];
- (void) request;
- (void) request_len;
- tor_assert(circuit->rend_data);
- /* XXX: This is version 2 specific (only supported one for now). */
- const char *rend_pk_digest =
- (char *) rend_data_get_pk_digest(circuit->rend_data, NULL);
-
- if (circuit->base_.purpose != CIRCUIT_PURPOSE_S_ESTABLISH_INTRO) {
- log_warn(LD_PROTOCOL,
- "received INTRO_ESTABLISHED cell on non-intro circuit.");
- goto err;
- }
- service = rend_service_get_by_pk_digest(rend_pk_digest);
- if (!service) {
- log_warn(LD_REND, "Unknown service on introduction circuit %u.",
- (unsigned)circuit->base_.n_circ_id);
- goto err;
- }
- base32_encode(serviceid, REND_SERVICE_ID_LEN_BASE32 + 1,
- rend_pk_digest, REND_SERVICE_ID_LEN);
- /* We've just successfully established a intro circuit to one of our
- * introduction point, account for it. */
- intro = find_intro_point(circuit);
- if (intro == NULL) {
- log_warn(LD_REND,
- "Introduction circuit established without a rend_intro_point_t "
- "object for service %s on circuit %u",
- safe_str_client(serviceid), (unsigned)circuit->base_.n_circ_id);
- goto err;
- }
- intro->circuit_established = 1;
- /* We might not have every introduction point ready but at this point we
- * know that the descriptor needs to be uploaded. */
- service->desc_is_dirty = time(NULL);
- circuit_change_purpose(TO_CIRCUIT(circuit), CIRCUIT_PURPOSE_S_INTRO);
-
- log_info(LD_REND,
- "Received INTRO_ESTABLISHED cell on circuit %u for service %s",
- (unsigned)circuit->base_.n_circ_id, serviceid);
-
- /* Getting a valid INTRODUCE_ESTABLISHED means we've successfully
- * used the circ */
- pathbias_mark_use_success(circuit);
-
- return 0;
- err:
- circuit_mark_for_close(TO_CIRCUIT(circuit), END_CIRC_REASON_TORPROTOCOL);
- return -1;
-}
-
-/** Called once a circuit to a rendezvous point is established: sends a
- * RELAY_COMMAND_RENDEZVOUS1 cell.
- */
-void
-rend_service_rendezvous_has_opened(origin_circuit_t *circuit)
-{
- rend_service_t *service;
- char buf[RELAY_PAYLOAD_SIZE];
- crypt_path_t *hop;
- char serviceid[REND_SERVICE_ID_LEN_BASE32+1];
- char hexcookie[9];
- int reason;
- const char *rend_cookie, *rend_pk_digest;
-
- tor_assert(circuit->base_.purpose == CIRCUIT_PURPOSE_S_CONNECT_REND);
- tor_assert(circuit->cpath);
- tor_assert(circuit->build_state);
- assert_circ_anonymity_ok(circuit, get_options());
- tor_assert(circuit->rend_data);
-
- /* XXX: This is version 2 specific (only one supported). */
- rend_pk_digest = (char *) rend_data_get_pk_digest(circuit->rend_data,
- NULL);
- rend_cookie = circuit->rend_data->rend_cookie;
-
- /* Declare the circuit dirty to avoid reuse, and for path-bias. We set the
- * timestamp regardless of its content because that circuit could have been
- * cannibalized so in any cases, we are about to use that circuit more. */
- circuit->base_.timestamp_dirty = time(NULL);
-
- /* This may be redundant */
- pathbias_count_use_attempt(circuit);
-
- hop = circuit->build_state->service_pending_final_cpath_ref->cpath;
-
- base16_encode(hexcookie,9, rend_cookie,4);
- base32_encode(serviceid, REND_SERVICE_ID_LEN_BASE32+1,
- rend_pk_digest, REND_SERVICE_ID_LEN);
-
- log_info(LD_REND,
- "Done building circuit %u to rendezvous with "
- "cookie %s for service %s",
- (unsigned)circuit->base_.n_circ_id, hexcookie, serviceid);
- circuit_log_path(LOG_INFO, LD_REND, circuit);
-
- /* Clear the 'in-progress HS circ has timed out' flag for
- * consistency with what happens on the client side; this line has
- * no effect on Tor's behaviour. */
- circuit->hs_circ_has_timed_out = 0;
-
- /* If hop is NULL, another rend circ has already connected to this
- * rend point. Close this circ. */
- if (hop == NULL) {
- log_info(LD_REND, "Another rend circ has already reached this rend point; "
- "closing this rend circ.");
- reason = END_CIRC_REASON_NONE;
- goto err;
- }
-
- /* Remove our final cpath element from the reference, so that no
- * other circuit will try to use it. Store it in
- * pending_final_cpath for now to ensure that it will be freed if
- * our rendezvous attempt fails. */
- circuit->build_state->pending_final_cpath = hop;
- circuit->build_state->service_pending_final_cpath_ref->cpath = NULL;
-
- service = rend_service_get_by_pk_digest(rend_pk_digest);
- if (!service) {
- log_warn(LD_GENERAL, "Internal error: unrecognized service ID on "
- "rendezvous circuit.");
- reason = END_CIRC_REASON_INTERNAL;
- goto err;
- }
-
- /* All we need to do is send a RELAY_RENDEZVOUS1 cell... */
- memcpy(buf, rend_cookie, REND_COOKIE_LEN);
- if (crypto_dh_get_public(hop->rend_dh_handshake_state,
- buf+REND_COOKIE_LEN, DH1024_KEY_LEN)<0) {
- log_warn(LD_GENERAL,"Couldn't get DH public key.");
- reason = END_CIRC_REASON_INTERNAL;
- goto err;
- }
- memcpy(buf+REND_COOKIE_LEN+DH1024_KEY_LEN, hop->rend_circ_nonce,
- DIGEST_LEN);
-
- /* Send the cell */
- if (relay_send_command_from_edge(0, TO_CIRCUIT(circuit),
- RELAY_COMMAND_RENDEZVOUS1,
- buf, HS_LEGACY_RENDEZVOUS_CELL_SIZE,
- circuit->cpath->prev)<0) {
- log_warn(LD_GENERAL, "Couldn't send RENDEZVOUS1 cell.");
- goto done;
- }
-
- crypto_dh_free(hop->rend_dh_handshake_state);
- hop->rend_dh_handshake_state = NULL;
-
- /* Append the cpath entry. */
- hop->state = CPATH_STATE_OPEN;
- /* set the windows to default. these are the windows
- * that the service thinks the client has.
- */
- hop->package_window = circuit_initial_package_window();
- hop->deliver_window = CIRCWINDOW_START;
-
- cpath_extend_linked_list(&circuit->cpath, hop);
- circuit->build_state->pending_final_cpath = NULL; /* prevent double-free */
-
- /* Change the circuit purpose. */
- circuit_change_purpose(TO_CIRCUIT(circuit), CIRCUIT_PURPOSE_S_REND_JOINED);
-
- goto done;
-
- err:
- circuit_mark_for_close(TO_CIRCUIT(circuit), reason);
- done:
- memwipe(buf, 0, sizeof(buf));
- memwipe(serviceid, 0, sizeof(serviceid));
- memwipe(hexcookie, 0, sizeof(hexcookie));
-
- return;
-}
-
-/*
- * Manage introduction points
- */
-
-/** Return the (possibly non-open) introduction circuit ending at
- * <b>intro</b> for the service whose public key is <b>pk_digest</b>.
- * (<b>desc_version</b> is ignored). Return NULL if no such service is
- * found.
- */
-static origin_circuit_t *
-find_intro_circuit(rend_intro_point_t *intro, const char *pk_digest)
-{
- origin_circuit_t *circ = NULL;
-
- tor_assert(intro);
- while ((circ = circuit_get_next_by_pk_and_purpose(circ,
- (uint8_t *) pk_digest, CIRCUIT_PURPOSE_S_INTRO))) {
- if (tor_memeq(circ->build_state->chosen_exit->identity_digest,
- intro->extend_info->identity_digest, DIGEST_LEN) &&
- circ->rend_data) {
- return circ;
- }
- }
-
- circ = NULL;
- while ((circ = circuit_get_next_by_pk_and_purpose(circ,
- (uint8_t *) pk_digest,
- CIRCUIT_PURPOSE_S_ESTABLISH_INTRO))) {
- if (tor_memeq(circ->build_state->chosen_exit->identity_digest,
- intro->extend_info->identity_digest, DIGEST_LEN) &&
- circ->rend_data) {
- return circ;
- }
- }
- return NULL;
-}
-
-/** Return the corresponding introdution point using the circuit <b>circ</b>
- * found in the <b>service</b>. NULL is returned if not found. */
-static rend_intro_point_t *
-find_expiring_intro_point(rend_service_t *service, origin_circuit_t *circ)
-{
- tor_assert(service);
- tor_assert(TO_CIRCUIT(circ)->purpose == CIRCUIT_PURPOSE_S_ESTABLISH_INTRO ||
- TO_CIRCUIT(circ)->purpose == CIRCUIT_PURPOSE_S_INTRO);
-
- SMARTLIST_FOREACH(service->expiring_nodes, rend_intro_point_t *,
- intro_point,
- if (crypto_pk_eq_keys(intro_point->intro_key, circ->intro_key)) {
- return intro_point;
- });
-
- return NULL;
-}
-
-/** Return a pointer to the rend_intro_point_t corresponding to the
- * service-side introduction circuit <b>circ</b>. */
-static rend_intro_point_t *
-find_intro_point(origin_circuit_t *circ)
-{
- const char *serviceid;
- rend_service_t *service = NULL;
-
- tor_assert(TO_CIRCUIT(circ)->purpose == CIRCUIT_PURPOSE_S_ESTABLISH_INTRO ||
- TO_CIRCUIT(circ)->purpose == CIRCUIT_PURPOSE_S_INTRO);
- tor_assert(circ->rend_data);
- serviceid = rend_data_get_address(circ->rend_data);
-
- SMARTLIST_FOREACH(rend_service_list, rend_service_t *, s,
- if (tor_memeq(s->service_id, serviceid, REND_SERVICE_ID_LEN_BASE32)) {
- service = s;
- break;
- });
-
- if (service == NULL) return NULL;
-
- SMARTLIST_FOREACH(service->intro_nodes, rend_intro_point_t *, intro_point,
- if (crypto_pk_eq_keys(intro_point->intro_key, circ->intro_key)) {
- return intro_point;
- });
-
- return NULL;
-}
-
-/** Upload the rend_encoded_v2_service_descriptor_t's in <b>descs</b>
- * associated with the rend_service_descriptor_t <b>renddesc</b> to
- * the responsible hidden service directories OR the hidden service
- * directories specified by <b>hs_dirs</b>; <b>service_id</b> and
- * <b>seconds_valid</b> are only passed for logging purposes.
- */
-void
-directory_post_to_hs_dir(rend_service_descriptor_t *renddesc,
- smartlist_t *descs, smartlist_t *hs_dirs,
- const char *service_id, int seconds_valid)
-{
- int i, j, failed_upload = 0;
- smartlist_t *responsible_dirs = smartlist_new();
- smartlist_t *successful_uploads = smartlist_new();
- routerstatus_t *hs_dir;
- for (i = 0; i < smartlist_len(descs); i++) {
- rend_encoded_v2_service_descriptor_t *desc = smartlist_get(descs, i);
- /** If any HSDirs are specified, they should be used instead of
- * the responsible directories */
- if (hs_dirs && smartlist_len(hs_dirs) > 0) {
- smartlist_add_all(responsible_dirs, hs_dirs);
- } else {
- /* Determine responsible dirs. */
- if (hid_serv_get_responsible_directories(responsible_dirs,
- desc->desc_id) < 0) {
- log_warn(LD_REND, "Could not determine the responsible hidden service "
- "directories to post descriptors to.");
- control_event_hs_descriptor_upload(service_id,
- "UNKNOWN",
- "UNKNOWN", NULL);
- goto done;
- }
- }
- for (j = 0; j < smartlist_len(responsible_dirs); j++) {
- char desc_id_base32[REND_DESC_ID_V2_LEN_BASE32 + 1];
- char *hs_dir_ip;
- const node_t *node;
- rend_data_t *rend_data;
- hs_dir = smartlist_get(responsible_dirs, j);
- if (smartlist_contains_digest(renddesc->successful_uploads,
- hs_dir->identity_digest))
- /* Don't upload descriptor if we succeeded in doing so last time. */
- continue;
- node = node_get_by_id(hs_dir->identity_digest);
- if (!node || !node_has_preferred_descriptor(node,0)) {
- log_info(LD_REND, "Not launching upload for for v2 descriptor to "
- "hidden service directory %s; we don't have its "
- "router descriptor. Queuing for later upload.",
- safe_str_client(routerstatus_describe(hs_dir)));
- failed_upload = -1;
- continue;
- }
- /* Send publish request. */
-
- /* We need the service ID to identify which service did the upload
- * request. Lookup is made in rend_service_desc_has_uploaded(). */
- rend_data = rend_data_client_create(service_id, desc->desc_id, NULL,
- REND_NO_AUTH);
- directory_request_t *req =
- directory_request_new(DIR_PURPOSE_UPLOAD_RENDDESC_V2);
- directory_request_set_routerstatus(req, hs_dir);
- directory_request_set_indirection(req, DIRIND_ANONYMOUS);
- directory_request_set_payload(req,
- desc->desc_str, strlen(desc->desc_str));
- directory_request_set_rend_query(req, rend_data);
- directory_initiate_request(req);
- directory_request_free(req);
-
- rend_data_free(rend_data);
- base32_encode(desc_id_base32, sizeof(desc_id_base32),
- desc->desc_id, DIGEST_LEN);
- hs_dir_ip = tor_addr_to_str_dup(&hs_dir->ipv4_addr);
- if (hs_dir_ip) {
- log_info(LD_REND, "Launching upload for v2 descriptor for "
- "service '%s' with descriptor ID '%s' with validity "
- "of %d seconds to hidden service directory '%s' on "
- "%s:%d.",
- safe_str_client(service_id),
- safe_str_client(desc_id_base32),
- seconds_valid,
- hs_dir->nickname,
- hs_dir_ip,
- hs_dir->ipv4_orport);
- tor_free(hs_dir_ip);
- }
-
- control_event_hs_descriptor_upload(service_id,
- hs_dir->identity_digest,
- desc_id_base32, NULL);
- /* Remember successful upload to this router for next time. */
- if (!smartlist_contains_digest(successful_uploads,
- hs_dir->identity_digest))
- smartlist_add(successful_uploads, hs_dir->identity_digest);
- }
- smartlist_clear(responsible_dirs);
- }
- if (!failed_upload) {
- if (renddesc->successful_uploads) {
- SMARTLIST_FOREACH(renddesc->successful_uploads, char *, c, tor_free(c););
- smartlist_free(renddesc->successful_uploads);
- renddesc->successful_uploads = NULL;
- }
- renddesc->all_uploads_performed = 1;
- } else {
- /* Remember which routers worked this time, so that we don't upload the
- * descriptor to them again. */
- if (!renddesc->successful_uploads)
- renddesc->successful_uploads = smartlist_new();
- SMARTLIST_FOREACH(successful_uploads, const char *, c, {
- if (!smartlist_contains_digest(renddesc->successful_uploads, c)) {
- char *hsdir_id = tor_memdup(c, DIGEST_LEN);
- smartlist_add(renddesc->successful_uploads, hsdir_id);
- }
- });
- }
- done:
- smartlist_free(responsible_dirs);
- smartlist_free(successful_uploads);
-}
-
-/** Encode and sign an up-to-date service descriptor for <b>service</b>,
- * and upload it/them to the responsible hidden service directories.
- */
-static void
-upload_service_descriptor(rend_service_t *service)
-{
- time_t now = time(NULL);
- int rendpostperiod;
- char serviceid[REND_SERVICE_ID_LEN_BASE32+1];
- int uploaded = 0;
-
- rendpostperiod = get_options()->RendPostPeriod;
-
- networkstatus_t *c = networkstatus_get_latest_consensus();
- if (c && smartlist_len(c->routerstatus_list) > 0) {
- int seconds_valid, i, j, num_descs;
- smartlist_t *descs = smartlist_new();
- smartlist_t *client_cookies = smartlist_new();
- /* Either upload a single descriptor (including replicas) or one
- * descriptor for each authorized client in case of authorization
- * type 'stealth'. */
- num_descs = service->auth_type == REND_STEALTH_AUTH ?
- smartlist_len(service->clients) : 1;
- for (j = 0; j < num_descs; j++) {
- crypto_pk_t *client_key = NULL;
- rend_authorized_client_t *client = NULL;
- smartlist_clear(client_cookies);
- switch (service->auth_type) {
- case REND_NO_AUTH:
- /* Do nothing here. */
- break;
- case REND_BASIC_AUTH:
- SMARTLIST_FOREACH(service->clients, rend_authorized_client_t *,
- cl, smartlist_add(client_cookies, cl->descriptor_cookie));
- break;
- case REND_STEALTH_AUTH:
- client = smartlist_get(service->clients, j);
- client_key = client->client_key;
- smartlist_add(client_cookies, client->descriptor_cookie);
- break;
- }
- /* Encode the current descriptor. */
- seconds_valid = rend_encode_v2_descriptors(descs, service->desc,
- now, 0,
- service->auth_type,
- client_key,
- client_cookies);
- if (seconds_valid < 0) {
- log_warn(LD_BUG, "Internal error: couldn't encode service "
- "descriptor; not uploading.");
- smartlist_free(descs);
- smartlist_free(client_cookies);
- return;
- }
- rend_get_service_id(service->desc->pk, serviceid);
- if (get_options()->PublishHidServDescriptors) {
- /* Post the current descriptors to the hidden service directories. */
- /* This log message is used by Chutney as part of its bootstrap
- * detection mechanism. Please don't change without first checking
- * Chutney. */
- log_info(LD_REND, "Launching upload for hidden service %s",
- serviceid);
- directory_post_to_hs_dir(service->desc, descs, NULL, serviceid,
- seconds_valid);
- }
- /* Free memory for descriptors. */
- for (i = 0; i < smartlist_len(descs); i++)
- rend_encoded_v2_service_descriptor_free_(smartlist_get(descs, i));
- smartlist_clear(descs);
- /* Update next upload time. */
- if (seconds_valid - REND_TIME_PERIOD_OVERLAPPING_V2_DESCS
- > rendpostperiod)
- service->next_upload_time = now + rendpostperiod;
- else if (seconds_valid < REND_TIME_PERIOD_OVERLAPPING_V2_DESCS)
- service->next_upload_time = now + seconds_valid + 1;
- else
- service->next_upload_time = now + seconds_valid -
- REND_TIME_PERIOD_OVERLAPPING_V2_DESCS + 1;
- /* Post also the next descriptors, if necessary. */
- if (seconds_valid < REND_TIME_PERIOD_OVERLAPPING_V2_DESCS) {
- seconds_valid = rend_encode_v2_descriptors(descs, service->desc,
- now, 1,
- service->auth_type,
- client_key,
- client_cookies);
- if (seconds_valid < 0) {
- log_warn(LD_BUG, "Internal error: couldn't encode service "
- "descriptor; not uploading.");
- smartlist_free(descs);
- smartlist_free(client_cookies);
- return;
- }
- if (get_options()->PublishHidServDescriptors) {
- directory_post_to_hs_dir(service->desc, descs, NULL, serviceid,
- seconds_valid);
- }
- /* Free memory for descriptors. */
- for (i = 0; i < smartlist_len(descs); i++)
- rend_encoded_v2_service_descriptor_free_(smartlist_get(descs, i));
- smartlist_clear(descs);
- }
- }
- smartlist_free(descs);
- smartlist_free(client_cookies);
- uploaded = 1;
- if (get_options()->PublishHidServDescriptors) {
- log_info(LD_REND, "Successfully uploaded v2 rend descriptors!");
- } else {
- log_info(LD_REND, "Successfully stored created v2 rend descriptors!");
- }
- }
-
- /* If not uploaded, try again in one minute. */
- if (!uploaded)
- service->next_upload_time = now + 60;
-
- /* Unmark dirty flag of this service. */
- service->desc_is_dirty = 0;
-}
-
-/** Return the number of INTRODUCE2 cells this hidden service has received
- * from this intro point. */
-static int
-intro_point_accepted_intro_count(rend_intro_point_t *intro)
-{
- return intro->accepted_introduce2_count;
-}
-
-/** Return non-zero iff <b>intro</b> should 'expire' now (i.e. we
- * should stop publishing it in new descriptors and eventually close
- * it). */
-static int
-intro_point_should_expire_now(rend_intro_point_t *intro,
- time_t now)
-{
- tor_assert(intro != NULL);
-
- if (intro->time_published == -1) {
- /* Don't expire an intro point if we haven't even published it yet. */
- return 0;
- }
-
- if (intro_point_accepted_intro_count(intro) >=
- intro->max_introductions) {
- /* This intro point has been used too many times. Expire it now. */
- return 1;
- }
-
- if (intro->time_to_expire == -1) {
- /* This intro point has been published, but we haven't picked an
- * expiration time for it. Pick one now. */
- int intro_point_lifetime_seconds =
- crypto_rand_int_range(INTRO_POINT_LIFETIME_MIN_SECONDS,
- INTRO_POINT_LIFETIME_MAX_SECONDS);
-
- /* Start the expiration timer now, rather than when the intro
- * point was first published. There shouldn't be much of a time
- * difference. */
- intro->time_to_expire = now + intro_point_lifetime_seconds;
-
- return 0;
- }
-
- /* This intro point has a time to expire set already. Use it. */
- return (now >= intro->time_to_expire);
-}
-
-/** Iterate over intro points in the given service and remove the invalid
- * ones. For an intro point object to be considered invalid, the circuit
- * _and_ node need to have disappeared.
- *
- * If the intro point should expire, it's placed into the expiring_nodes
- * list of the service and removed from the active intro nodes list.
- *
- * If <b>exclude_nodes</b> is not NULL, add the valid nodes to it.
- *
- * If <b>retry_nodes</b> is not NULL, add the valid node to it if the
- * circuit disappeared but the node is still in the consensus. */
-static void
-remove_invalid_intro_points(rend_service_t *service,
- smartlist_t *exclude_nodes,
- smartlist_t *retry_nodes, time_t now)
-{
- tor_assert(service);
-
- /* Remove any expired nodes that doesn't have a circuit. */
- SMARTLIST_FOREACH_BEGIN(service->expiring_nodes, rend_intro_point_t *,
- intro) {
- origin_circuit_t *intro_circ =
- find_intro_circuit(intro, service->pk_digest);
- if (intro_circ) {
- continue;
- }
- /* No more circuit, cleanup the into point object. */
- SMARTLIST_DEL_CURRENT(service->expiring_nodes, intro);
- rend_intro_point_free(intro);
- } SMARTLIST_FOREACH_END(intro);
-
- SMARTLIST_FOREACH_BEGIN(service->intro_nodes, rend_intro_point_t *,
- intro) {
- /* Find the introduction point node object. */
- const node_t *node =
- node_get_by_id(intro->extend_info->identity_digest);
- /* Find the intro circuit, this might be NULL. */
- origin_circuit_t *intro_circ =
- find_intro_circuit(intro, service->pk_digest);
-
- /* Add the valid node to the exclusion list so we don't try to establish
- * an introduction point to it again. */
- if (node && exclude_nodes) {
- smartlist_add(exclude_nodes, (void*) node);
- }
-
- /* First, make sure we still have a valid circuit for this intro point.
- * If we dont, we'll give up on it and make a new one. */
- if (intro_circ == NULL) {
- log_info(LD_REND, "Attempting to retry on %s as intro point for %s"
- " (circuit disappeared).",
- safe_str_client(extend_info_describe(intro->extend_info)),
- safe_str_client(service->service_id));
- /* We've lost the circuit for this intro point, flag it so it can be
- * accounted for when considiring uploading a descriptor. */
- intro->circuit_established = 0;
-
- /* Node is gone or we've reached our maximum circuit creation retry
- * count, clean up everything, we'll find a new one. */
- if (node == NULL ||
- intro->circuit_retries >= MAX_INTRO_POINT_CIRCUIT_RETRIES) {
- rend_intro_point_free(intro);
- SMARTLIST_DEL_CURRENT(service->intro_nodes, intro);
- /* We've just killed the intro point, nothing left to do. */
- continue;
- }
-
- /* The intro point is still alive so let's try to use it again because
- * we have a published descriptor containing it. Keep the intro point
- * in the intro_nodes list because it's still valid, we are rebuilding
- * a circuit to it. */
- if (retry_nodes) {
- smartlist_add(retry_nodes, intro);
- }
- }
- /* else, the circuit is valid so in both cases, node being alive or not,
- * we leave the circuit and intro point object as is. Closing the
- * circuit here would leak new consensus timing and freeing the intro
- * point object would make the intro circuit unusable. */
-
- /* Now, check if intro point should expire. If it does, queue it so
- * it can be cleaned up once it has been replaced properly. */
- if (intro_point_should_expire_now(intro, now)) {
- log_info(LD_REND, "Expiring %s as intro point for %s.",
- safe_str_client(extend_info_describe(intro->extend_info)),
- safe_str_client(service->service_id));
- /* We might have put it in the retry list if so, undo. */
- if (retry_nodes) {
- smartlist_remove(retry_nodes, intro);
- }
- smartlist_add(service->expiring_nodes, intro);
- SMARTLIST_DEL_CURRENT(service->intro_nodes, intro);
- /* Intro point is expired, we need a new one thus don't consider it
- * anymore has a valid established intro point. */
- intro->circuit_established = 0;
- }
- } SMARTLIST_FOREACH_END(intro);
-}
-
-/** A new descriptor has been successfully uploaded for the given
- * <b>rend_data</b>. Remove and free the expiring nodes from the associated
- * service. */
-void
-rend_service_desc_has_uploaded(const rend_data_t *rend_data)
-{
- rend_service_t *service;
- const char *onion_address;
-
- tor_assert(rend_data);
-
- onion_address = rend_data_get_address(rend_data);
-
- service = rend_service_get_by_service_id(onion_address);
- if (service == NULL) {
- return;
- }
-
- SMARTLIST_FOREACH_BEGIN(service->expiring_nodes, rend_intro_point_t *,
- intro) {
- origin_circuit_t *intro_circ =
- find_intro_circuit(intro, service->pk_digest);
- if (intro_circ != NULL) {
- circuit_mark_for_close(TO_CIRCUIT(intro_circ),
- END_CIRC_REASON_FINISHED);
- }
- SMARTLIST_DEL_CURRENT(service->expiring_nodes, intro);
- rend_intro_point_free(intro);
- } SMARTLIST_FOREACH_END(intro);
-}
-
-/** Don't try to build more than this many circuits before giving up
- * for a while. Dynamically calculated based on the configured number of
- * introduction points for the service, n_intro_points_wanted. */
-static int
-rend_max_intro_circs_per_period(unsigned int n_intro_points_wanted)
-{
- /* Allow all but one of the initial connections to fail and be
- * retried. (If all fail, we *want* to wait, because something is broken.) */
- tor_assert(n_intro_points_wanted <= NUM_INTRO_POINTS_MAX);
-
- /* For the normal use case, 3 intro points plus 2 extra for performance and
- * allow that twice because once every 24h or so, we can do it twice for two
- * descriptors that is the current one and the next one. So (3 + 2) * 2 ==
- * 12 allowed attempts for one period. */
- return ((n_intro_points_wanted + NUM_INTRO_POINTS_EXTRA) * 2);
-}
-
-/** For every service, check how many intro points it currently has, and:
- * - Invalidate introdution points based on specific criteria, see
- * remove_invalid_intro_points comments.
- * - Pick new intro points as necessary.
- * - Launch circuits to any new intro points.
- *
- * This is called once a second by the main loop.
- */
-void
-rend_consider_services_intro_points(time_t now)
-{
- int i;
- const or_options_t *options = get_options();
- /* Are we in single onion mode? */
- const int allow_direct = rend_service_allow_non_anonymous_connection(
- get_options());
- /* List of nodes we need to _exclude_ when choosing a new node to
- * establish an intro point to. */
- smartlist_t *exclude_nodes;
- /* List of nodes we need to retry to build a circuit on them because the
- * node is valid but circuit died. */
- smartlist_t *retry_nodes;
-
- if (!have_completed_a_circuit())
- return;
-
- exclude_nodes = smartlist_new();
- retry_nodes = smartlist_new();
-
- SMARTLIST_FOREACH_BEGIN(rend_service_list, rend_service_t *, service) {
- int r;
- /* Number of intro points we want to open and add to the intro nodes
- * list of the service. */
- unsigned int n_intro_points_to_open;
- /* Have an unsigned len so we can use it to compare values else gcc is
- * not happy with unmatching signed comparison. */
- unsigned int intro_nodes_len;
- /* Different service are allowed to have the same introduction point as
- * long as they are on different circuit thus why we clear this list. */
- smartlist_clear(exclude_nodes);
- smartlist_clear(retry_nodes);
-
- /* Cleanup the invalid intro points and save the node objects, if any,
- * in the exclude_nodes and retry_nodes lists. */
- remove_invalid_intro_points(service, exclude_nodes, retry_nodes, now);
-
- /* This retry period is important here so we don't stress circuit
- * creation. */
-
- if (now > service->intro_period_started + INTRO_CIRC_RETRY_PERIOD) {
- /* One period has elapsed:
- * - if we stopped, we can try building circuits again,
- * - if we haven't, we reset the circuit creation counts. */
- rend_log_intro_limit(service, LOG_INFO);
- service->intro_period_started = now;
- service->n_intro_circuits_launched = 0;
- } else if (service->n_intro_circuits_launched >=
- rend_max_intro_circs_per_period(
- service->n_intro_points_wanted)) {
- /* We have failed too many times in this period; wait for the next
- * one before we try to initiate any more connections. */
- rend_log_intro_limit(service, LOG_WARN);
- continue;
- }
-
- /* Let's try to rebuild circuit on the nodes we want to retry on. */
- SMARTLIST_FOREACH_BEGIN(retry_nodes, rend_intro_point_t *, intro) {
- r = rend_service_launch_establish_intro(service, intro);
- if (r < 0) {
- log_warn(LD_REND, "Error launching circuit to node %s for service %s.",
- safe_str_client(extend_info_describe(intro->extend_info)),
- safe_str_client(service->service_id));
- /* Unable to launch a circuit to that intro point, remove it from
- * the valid list so we can create a new one. */
- smartlist_remove(service->intro_nodes, intro);
- rend_intro_point_free(intro);
- continue;
- }
- intro->circuit_retries++;
- } SMARTLIST_FOREACH_END(intro);
-
- /* Avoid mismatched signed comparison below. */
- intro_nodes_len = (unsigned int) smartlist_len(service->intro_nodes);
-
- /* Quiescent state, we have more or the equal amount of wanted node for
- * this service. Proceed to the next service. We can have more nodes
- * because we launch extra preemptive circuits if our intro nodes list was
- * originally empty for performance reasons. */
- if (intro_nodes_len >= service->n_intro_points_wanted) {
- continue;
- }
-
- /* Number of intro points we want to open which is the wanted amount minus
- * the current amount of valid nodes. We know that this won't underflow
- * because of the check above. */
- n_intro_points_to_open = service->n_intro_points_wanted - intro_nodes_len;
- if (intro_nodes_len == 0) {
- /* We want to end up with n_intro_points_wanted intro points, but if
- * we have no intro points at all (chances are they all cycled or we
- * are starting up), we launch NUM_INTRO_POINTS_EXTRA extra circuits
- * and use the first n_intro_points_wanted that complete. See proposal
- * #155, section 4 for the rationale of this which is purely for
- * performance.
- *
- * The ones after the first n_intro_points_to_open will be converted
- * to 'general' internal circuits in rend_service_intro_has_opened(),
- * and then we'll drop them from the list of intro points. */
- n_intro_points_to_open += NUM_INTRO_POINTS_EXTRA;
- }
-
- for (i = 0; i < (int) n_intro_points_to_open; i++) {
- const node_t *node;
- rend_intro_point_t *intro;
- router_crn_flags_t flags = CRN_NEED_UPTIME|CRN_NEED_DESC;
- router_crn_flags_t direct_flags = flags;
- direct_flags |= CRN_PREF_ADDR;
- direct_flags |= CRN_DIRECT_CONN;
-
- node = router_choose_random_node(exclude_nodes,
- options->ExcludeNodes,
- allow_direct ? direct_flags : flags);
- /* If we are in single onion mode, retry node selection for a 3-hop
- * path */
- if (allow_direct && !node) {
- log_info(LD_REND,
- "Unable to find an intro point that we can connect to "
- "directly for %s, falling back to a 3-hop path.",
- safe_str_client(service->service_id));
- node = router_choose_random_node(exclude_nodes,
- options->ExcludeNodes, flags);
- }
-
- if (!node) {
- log_warn(LD_REND,
- "We only have %d introduction points established for %s; "
- "wanted %u.",
- smartlist_len(service->intro_nodes),
- safe_str_client(service->service_id),
- n_intro_points_to_open);
- break;
- }
- /* Add the chosen node to the exclusion list in order to avoid picking
- * it again in the next iteration. */
- smartlist_add(exclude_nodes, (void*)node);
- intro = tor_malloc_zero(sizeof(rend_intro_point_t));
- /* extend_info is for clients, so we want the multi-hop primary ORPort,
- * even if we are a single onion service and intend to connect to it
- * directly ourselves. */
- intro->extend_info = extend_info_from_node(node, 0);
- if (BUG(intro->extend_info == NULL)) {
- tor_free(intro);
- break;
- }
- intro->intro_key = crypto_pk_new();
- const int fail = crypto_pk_generate_key(intro->intro_key);
- tor_assert(!fail);
- intro->time_published = -1;
- intro->time_to_expire = -1;
- intro->max_introductions =
- crypto_rand_int_range(INTRO_POINT_MIN_LIFETIME_INTRODUCTIONS,
- INTRO_POINT_MAX_LIFETIME_INTRODUCTIONS);
- smartlist_add(service->intro_nodes, intro);
- log_info(LD_REND, "Picked router %s as an intro point for %s.",
- safe_str_client(node_describe(node)),
- safe_str_client(service->service_id));
- /* Establish new introduction circuit to our chosen intro point. */
- r = rend_service_launch_establish_intro(service, intro);
- if (r < 0) {
- log_warn(LD_REND, "Error launching circuit to node %s for service %s.",
- safe_str_client(extend_info_describe(intro->extend_info)),
- safe_str_client(service->service_id));
- /* This function will be called again by the main loop so this intro
- * point without a intro circuit will be retried on or removed after
- * a maximum number of attempts. */
- }
- }
- } SMARTLIST_FOREACH_END(service);
- smartlist_free(exclude_nodes);
- smartlist_free(retry_nodes);
-}
-
-#define MIN_REND_INITIAL_POST_DELAY (30)
-#define MIN_REND_INITIAL_POST_DELAY_TESTING (5)
-
-/** Regenerate and upload rendezvous service descriptors for all
- * services, if necessary. If the descriptor has been dirty enough
- * for long enough, definitely upload; else only upload when the
- * periodic timeout has expired.
- *
- * For the first upload, pick a random time between now and two periods
- * from now, and pick it independently for each service.
- */
-void
-rend_consider_services_upload(time_t now)
-{
- int i;
- rend_service_t *service;
- const or_options_t *options = get_options();
- int rendpostperiod = options->RendPostPeriod;
- int rendinitialpostdelay = (options->TestingTorNetwork ?
- MIN_REND_INITIAL_POST_DELAY_TESTING :
- MIN_REND_INITIAL_POST_DELAY);
-
- for (i=0; i < smartlist_len(rend_service_list); ++i) {
- service = smartlist_get(rend_service_list, i);
- if (!service->next_upload_time) { /* never been uploaded yet */
- /* The fixed lower bound of rendinitialpostdelay seconds ensures that
- * the descriptor is stable before being published. See comment below. */
- service->next_upload_time =
- now + rendinitialpostdelay + crypto_rand_int(2*rendpostperiod);
- /* Single Onion Services prioritise availability over hiding their
- * startup time, as their IP address is publicly discoverable anyway.
- */
- if (rend_service_reveal_startup_time(options)) {
- service->next_upload_time = now + rendinitialpostdelay;
- }
- }
- /* Does every introduction points have been established? */
- unsigned int intro_points_ready =
- count_established_intro_points(service) >=
- service->n_intro_points_wanted;
- if (intro_points_ready &&
- (service->next_upload_time < now ||
- (service->desc_is_dirty &&
- service->desc_is_dirty < now-rendinitialpostdelay))) {
- /* if it's time, or if the directory servers have a wrong service
- * descriptor and ours has been stable for rendinitialpostdelay seconds,
- * upload a new one of each format. */
- rend_service_update_descriptor(service);
- upload_service_descriptor(service);
- }
- }
-}
-
-/** True if the list of available router descriptors might have changed so
- * that we should have a look whether we can republish previously failed
- * rendezvous service descriptors. */
-static int consider_republishing_rend_descriptors = 1;
-
-/** Called when our internal view of the directory has changed, so that we
- * might have router descriptors of hidden service directories available that
- * we did not have before. */
-void
-rend_hsdir_routers_changed(void)
-{
- consider_republishing_rend_descriptors = 1;
-}
-
-/** Consider republication of v2 rendezvous service descriptors that failed
- * previously, but without regenerating descriptor contents.
- */
-void
-rend_consider_descriptor_republication(void)
-{
- int i;
- rend_service_t *service;
-
- if (!consider_republishing_rend_descriptors)
- return;
- consider_republishing_rend_descriptors = 0;
-
- if (!get_options()->PublishHidServDescriptors)
- return;
-
- for (i=0; i < smartlist_len(rend_service_list); ++i) {
- service = smartlist_get(rend_service_list, i);
- if (service->desc && !service->desc->all_uploads_performed) {
- /* If we failed in uploading a descriptor last time, try again *without*
- * updating the descriptor's contents. */
- upload_service_descriptor(service);
- }
- }
-}
-
-/** Log the status of introduction points for all rendezvous services
- * at log severity <b>severity</b>.
- */
-void
-rend_service_dump_stats(int severity)
-{
- rend_service_t *service;
- rend_intro_point_t *intro;
- const char *safe_name;
- origin_circuit_t *circ;
-
- for (int i = 0; i < smartlist_len(rend_service_list); ++i) {
- service = smartlist_get(rend_service_list, i);
- tor_log(severity, LD_GENERAL, "Service configured in %s:",
- rend_service_escaped_dir(service));
- for (int j = 0; j < smartlist_len(service->intro_nodes); ++j) {
- intro = smartlist_get(service->intro_nodes, j);
- safe_name = safe_str_client(intro->extend_info->nickname);
-
- circ = find_intro_circuit(intro, service->pk_digest);
- if (!circ) {
- tor_log(severity, LD_GENERAL, " Intro point %d at %s: no circuit",
- j, safe_name);
- continue;
- }
- tor_log(severity, LD_GENERAL, " Intro point %d at %s: circuit is %s",
- j, safe_name, circuit_state_to_string(circ->base_.state));
- }
- }
-}
-
-/** Given <b>conn</b>, a rendezvous exit stream, look up the hidden service for
- * <b>circ</b>, and look up the port and address based on conn-\>port.
- * Assign the actual conn-\>addr and conn-\>port. Return -2 on failure
- * for which the circuit should be closed, -1 on other failure,
- * or 0 for success.
- */
-int
-rend_service_set_connection_addr_port(edge_connection_t *conn,
- origin_circuit_t *circ)
-{
- rend_service_t *service;
- char serviceid[REND_SERVICE_ID_LEN_BASE32+1];
- const char *rend_pk_digest;
-
- tor_assert(circ->base_.purpose == CIRCUIT_PURPOSE_S_REND_JOINED);
- tor_assert(circ->rend_data);
- log_debug(LD_REND,"beginning to hunt for addr/port");
- rend_pk_digest = (char *) rend_data_get_pk_digest(circ->rend_data, NULL);
- base32_encode(serviceid, REND_SERVICE_ID_LEN_BASE32+1,
- rend_pk_digest, REND_SERVICE_ID_LEN);
- service = rend_service_get_by_pk_digest(rend_pk_digest);
- if (!service) {
- log_warn(LD_REND, "Couldn't find any service associated with pk %s on "
- "rendezvous circuit %u; closing.",
- serviceid, (unsigned)circ->base_.n_circ_id);
- return -2;
- }
- if (service->max_streams_per_circuit > 0) {
- /* Enforce the streams-per-circuit limit, and refuse to provide a
- * mapping if this circuit will exceed the limit. */
-#define MAX_STREAM_WARN_INTERVAL 600
- static struct ratelim_t stream_ratelim =
- RATELIM_INIT(MAX_STREAM_WARN_INTERVAL);
- if (circ->rend_data->nr_streams >= service->max_streams_per_circuit) {
- log_fn_ratelim(&stream_ratelim, LOG_WARN, LD_REND,
- "Maximum streams per circuit limit reached on rendezvous "
- "circuit %u; %s. Circuit has %d out of %d streams.",
- (unsigned)circ->base_.n_circ_id,
- service->max_streams_close_circuit ?
- "closing circuit" :
- "ignoring open stream request",
- circ->rend_data->nr_streams,
- service->max_streams_per_circuit);
- return service->max_streams_close_circuit ? -2 : -1;
- }
- }
-
- if (hs_set_conn_addr_port(service->ports, conn) == 0) {
- /* Successfully set the port to the connection. We are done. */
- return 0;
- }
-
- log_info(LD_REND,
- "No virtual port mapping exists for port %d on service %s",
- conn->base_.port, serviceid);
-
- if (service->allow_unknown_ports)
- return -1;
- else
- return -2;
-}
-
-/* Are HiddenServiceSingleHopMode and HiddenServiceNonAnonymousMode consistent?
- */
-static int
-rend_service_non_anonymous_mode_consistent(const or_options_t *options)
-{
- /* !! is used to make these options boolean */
- return (!! options->HiddenServiceSingleHopMode ==
- !! options->HiddenServiceNonAnonymousMode);
-}
-
-/* Do the options allow onion services to make direct (non-anonymous)
- * connections to introduction or rendezvous points?
- * Must only be called after options_validate_single_onion() has successfully
- * checked onion service option consistency.
- * Returns true if tor is in HiddenServiceSingleHopMode. */
-int
-rend_service_allow_non_anonymous_connection(const or_options_t *options)
-{
- tor_assert(rend_service_non_anonymous_mode_consistent(options));
- return options->HiddenServiceSingleHopMode ? 1 : 0;
-}
-
-/* Do the options allow us to reveal the exact startup time of the onion
- * service?
- * Single Onion Services prioritise availability over hiding their
- * startup time, as their IP address is publicly discoverable anyway.
- * Must only be called after options_validate_single_onion() has successfully
- * checked onion service option consistency.
- * Returns true if tor is in non-anonymous hidden service mode. */
-int
-rend_service_reveal_startup_time(const or_options_t *options)
-{
- tor_assert(rend_service_non_anonymous_mode_consistent(options));
- return rend_service_non_anonymous_mode_enabled(options);
-}
-
-/* Is non-anonymous mode enabled using the HiddenServiceNonAnonymousMode
- * config option?
- * Must only be called after options_validate_single_onion() has successfully
- * checked onion service option consistency.
- */
-int
-rend_service_non_anonymous_mode_enabled(const or_options_t *options)
-{
- tor_assert(rend_service_non_anonymous_mode_consistent(options));
- return options->HiddenServiceNonAnonymousMode ? 1 : 0;
-}
-
-#ifdef TOR_UNIT_TESTS
-
-STATIC void
-set_rend_service_list(smartlist_t *new_list)
-{
- rend_service_list = new_list;
-}
-
-STATIC void
-set_rend_rend_service_staging_list(smartlist_t *new_list)
-{
- rend_service_staging_list = new_list;
-}
-
-#endif /* defined(TOR_UNIT_TESTS) */
diff --git a/src/feature/rend/rendservice.h b/src/feature/rend/rendservice.h
deleted file mode 100644
index 012afc0f9f..0000000000
--- a/src/feature/rend/rendservice.h
+++ /dev/null
@@ -1,223 +0,0 @@
-/* Copyright (c) 2001 Matej Pfajfar.
- * Copyright (c) 2001-2004, Roger Dingledine.
- * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
-/* See LICENSE for licensing information */
-
-/**
- * \file rendservice.h
- * \brief Header file for rendservice.c.
- **/
-
-#ifndef TOR_RENDSERVICE_H
-#define TOR_RENDSERVICE_H
-
-#include "core/or/or.h"
-#include "feature/hs/hs_service.h"
-
-typedef struct rend_intro_cell_t rend_intro_cell_t;
-struct config_line_t;
-
-/* This can be used for both INTRODUCE1 and INTRODUCE2 */
-
-struct rend_intro_cell_t {
- /* Is this an INTRODUCE1 or INTRODUCE2? (set to 1 or 2) */
- uint8_t type;
- /* Public key digest */
- uint8_t pk[DIGEST_LEN];
- /* Optionally, store ciphertext here */
- uint8_t *ciphertext;
- ssize_t ciphertext_len;
- /* Optionally, store plaintext */
- uint8_t *plaintext;
- ssize_t plaintext_len;
- /* Have we parsed the plaintext? */
- uint8_t parsed;
- /* intro protocol version (0, 1, 2 or 3) */
- uint8_t version;
- /* Version-specific parts */
- union {
- struct {
- /* Rendezvous point nickname or hex-encoded key digest */
- uint8_t rp[42];
- } v0_v1;
- struct {
- /* The extend_info_t struct has everything v2 uses */
- extend_info_t *extend_info;
- } v2;
- struct {
- /* Auth type used */
- uint8_t auth_type;
- /* Length of auth data */
- uint16_t auth_len;
- /* Auth data */
- uint8_t *auth_data;
- /* Rendezvous point's IP address/port, identity digest and onion key */
- extend_info_t *extend_info;
- } v3;
- } u;
- /* Rendezvous cookie */
- uint8_t rc[REND_COOKIE_LEN];
- /* Diffie-Hellman data */
- uint8_t dh[DH1024_KEY_LEN];
-};
-
-#ifdef RENDSERVICE_PRIVATE
-
-/** Represents a single hidden service running at this OP. */
-typedef struct rend_service_t {
- /* Fields specified in config file */
- char *directory; /**< where in the filesystem it stores it. Will be NULL if
- * this service is ephemeral. */
- int dir_group_readable; /**< if 1, allow group read
- permissions on directory */
- smartlist_t *ports; /**< List of rend_service_port_config_t */
- rend_auth_type_t auth_type; /**< Client authorization type or 0 if no client
- * authorization is performed. */
- smartlist_t *clients; /**< List of rend_authorized_client_t's of
- * clients that may access our service. Can be NULL
- * if no client authorization is performed. */
- /* Other fields */
- crypto_pk_t *private_key; /**< Permanent hidden-service key. */
- char service_id[REND_SERVICE_ID_LEN_BASE32+1]; /**< Onion address without
- * '.onion' */
- char pk_digest[DIGEST_LEN]; /**< Hash of permanent hidden-service key. */
- smartlist_t *intro_nodes; /**< List of rend_intro_point_t's we have,
- * or are trying to establish. */
- /** List of rend_intro_point_t that are expiring. They are removed once
- * the new descriptor is successfully uploaded. A node in this list CAN
- * NOT appear in the intro_nodes list. */
- smartlist_t *expiring_nodes;
- time_t intro_period_started; /**< Start of the current period to build
- * introduction points. */
- int n_intro_circuits_launched; /**< Count of intro circuits we have
- * established in this period. */
- unsigned int n_intro_points_wanted; /**< Number of intro points this
- * service wants to have open. */
- rend_service_descriptor_t *desc; /**< Current hidden service descriptor. */
- time_t desc_is_dirty; /**< Time at which changes to the hidden service
- * descriptor content occurred, or 0 if it's
- * up-to-date. */
- time_t next_upload_time; /**< Scheduled next hidden service descriptor
- * upload time. */
- /** Replay cache for Diffie-Hellman values of INTRODUCE2 cells, to
- * detect repeats. Clients may send INTRODUCE1 cells for the same
- * rendezvous point through two or more different introduction points;
- * when they do, this keeps us from launching multiple simultaneous attempts
- * to connect to the same rend point. */
- replaycache_t *accepted_intro_dh_parts;
- /** If true, we don't close circuits for making requests to unsupported
- * ports. */
- int allow_unknown_ports;
- /** The maximum number of simultaneous streams-per-circuit that are allowed
- * to be established, or 0 if no limit is set.
- */
- int max_streams_per_circuit;
- /** If true, we close circuits that exceed the max_streams_per_circuit
- * limit. */
- int max_streams_close_circuit;
-} rend_service_t;
-
-STATIC void rend_service_free_(rend_service_t *service);
-#define rend_service_free(s) \
- FREE_AND_NULL(rend_service_t, rend_service_free_, (s))
-STATIC char *rend_service_sos_poison_path(const rend_service_t *service);
-STATIC int rend_service_verify_single_onion_poison(
- const rend_service_t *s,
- const or_options_t *options);
-STATIC int rend_service_poison_new_single_onion_dir(
- const rend_service_t *s,
- const or_options_t* options);
-#ifdef TOR_UNIT_TESTS
-
-STATIC void set_rend_service_list(smartlist_t *new_list);
-STATIC void set_rend_rend_service_staging_list(smartlist_t *new_list);
-STATIC void rend_service_prune_list_impl_(void);
-
-#endif /* defined(TOR_UNIT_TESTS) */
-
-#endif /* defined(RENDSERVICE_PRIVATE) */
-
-int rend_num_services(void);
-struct hs_opts_t;
-int rend_config_service(const struct hs_opts_t *hs_opts,
- const or_options_t *options,
- hs_service_config_t *config);
-void rend_service_prune_list(void);
-void rend_service_free_staging_list(void);
-int rend_service_load_all_keys(const smartlist_t *service_list);
-int rend_service_key_on_disk(const char *directory_path);
-void rend_services_add_filenames_to_lists(smartlist_t *open_lst,
- smartlist_t *stat_lst);
-void rend_consider_services_intro_points(time_t now);
-void rend_consider_services_upload(time_t now);
-void rend_hsdir_routers_changed(void);
-void rend_consider_descriptor_republication(void);
-
-void rend_service_intro_has_opened(origin_circuit_t *circuit);
-int rend_service_intro_established(origin_circuit_t *circuit,
- const uint8_t *request,
- size_t request_len);
-void rend_service_rendezvous_has_opened(origin_circuit_t *circuit);
-int rend_service_receive_introduction(origin_circuit_t *circuit,
- const uint8_t *request,
- size_t request_len);
-int rend_service_decrypt_intro(rend_intro_cell_t *request,
- crypto_pk_t *key,
- char **err_msg_out);
-void rend_service_free_intro_(rend_intro_cell_t *request);
-#define rend_service_free_intro(req) do { \
- rend_service_free_intro_(req); \
- (req) = NULL; \
- } while (0)
-rend_intro_cell_t * rend_service_begin_parse_intro(const uint8_t *request,
- size_t request_len,
- uint8_t type,
- char **err_msg_out);
-int rend_service_parse_intro_plaintext(rend_intro_cell_t *intro,
- char **err_msg_out);
-ssize_t rend_service_encode_establish_intro_cell(char *cell_body_out,
- size_t cell_body_out_len,
- crypto_pk_t *intro_key,
- const char *rend_circ_nonce);
-int rend_service_validate_intro_late(const rend_intro_cell_t *intro,
- char **err_msg_out);
-void rend_service_relaunch_rendezvous(origin_circuit_t *oldcirc);
-int rend_service_set_connection_addr_port(edge_connection_t *conn,
- origin_circuit_t *circ);
-void rend_service_dump_stats(int severity);
-void rend_service_free_all(void);
-void rend_service_init(void);
-
-rend_service_port_config_t *rend_service_parse_port_config(const char *string,
- const char *sep,
- char **err_msg_out);
-void rend_service_port_config_free_(rend_service_port_config_t *p);
-#define rend_service_port_config_free(p) \
- FREE_AND_NULL(rend_service_port_config_t, rend_service_port_config_free_, \
- (p))
-
-void rend_authorized_client_free_(rend_authorized_client_t *client);
-#define rend_authorized_client_free(client) \
- FREE_AND_NULL(rend_authorized_client_t, rend_authorized_client_free_, \
- (client))
-
-hs_service_add_ephemeral_status_t rend_service_add_ephemeral(crypto_pk_t *pk,
- smartlist_t *ports,
- int max_streams_per_circuit,
- int max_streams_close_circuit,
- rend_auth_type_t auth_type,
- smartlist_t *auth_clients,
- char **service_id_out);
-int rend_service_del_ephemeral(const char *service_id);
-
-void directory_post_to_hs_dir(rend_service_descriptor_t *renddesc,
- smartlist_t *descs, smartlist_t *hs_dirs,
- const char *service_id, int seconds_valid);
-void rend_service_desc_has_uploaded(const rend_data_t *rend_data);
-
-int rend_service_allow_non_anonymous_connection(const or_options_t *options);
-int rend_service_reveal_startup_time(const or_options_t *options);
-int rend_service_non_anonymous_mode_enabled(const or_options_t *options);
-
-#endif /* !defined(TOR_RENDSERVICE_H) */
diff --git a/src/feature/stats/bw_array_st.h b/src/feature/stats/bw_array_st.h
index 2d05ff0f77..caf4ae1793 100644
--- a/src/feature/stats/bw_array_st.h
+++ b/src/feature/stats/bw_array_st.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/stats/bwhist.c b/src/feature/stats/bwhist.c
index 06ad48e5c3..552dc7ad74 100644
--- a/src/feature/stats/bwhist.c
+++ b/src/feature/stats/bwhist.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/stats/bwhist.h b/src/feature/stats/bwhist.h
index 01055df720..d61c442e5d 100644
--- a/src/feature/stats/bwhist.h
+++ b/src/feature/stats/bwhist.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -38,7 +38,7 @@ STATIC void add_obs(bw_array_t *b, time_t when, uint64_t n);
STATIC void bw_array_free_(bw_array_t *b);
STATIC size_t bwhist_fill_bandwidth_history(char *buf, size_t len,
const bw_array_t *b);
-#endif /* defined(REPHIST_PRIVATE) */
+#endif /* defined(BWHIST_PRIVATE) */
#ifdef TOR_UNIT_TESTS
extern struct bw_array_t *write_array;
diff --git a/src/feature/stats/connstats.c b/src/feature/stats/connstats.c
index 827a332be1..8e52bdb0e9 100644
--- a/src/feature/stats/connstats.c
+++ b/src/feature/stats/connstats.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/stats/connstats.h b/src/feature/stats/connstats.h
index 1a03d0748b..7994c220ac 100644
--- a/src/feature/stats/connstats.h
+++ b/src/feature/stats/connstats.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/stats/geoip_stats.c b/src/feature/stats/geoip_stats.c
index a733653dde..a0fe8597c1 100644
--- a/src/feature/stats/geoip_stats.c
+++ b/src/feature/stats/geoip_stats.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2007-2020, The Tor Project, Inc. */
+/* Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -196,6 +196,8 @@ clientmap_entry_new(geoip_client_action_t action, const tor_addr_t *addr,
if (transport_name) {
entry->transport_name = tor_strdup(transport_name);
}
+ /* Initialize the DoS object. */
+ dos_geoip_entry_init(entry);
/* Allocated and initialized, note down its size for the OOM handler. */
geoip_increment_client_history_cache_size(clientmap_entry_size(entry));
@@ -1204,11 +1206,11 @@ format_bridge_stats_controller(time_t now)
char *
format_client_stats_heartbeat(time_t now)
{
- const int n_hours = 6;
+ const int n_seconds = get_options()->HeartbeatPeriod;
char *out = NULL;
int n_clients = 0;
clientmap_entry_t **ent;
- unsigned cutoff = (unsigned)( (now-n_hours*3600)/60 );
+ unsigned cutoff = (unsigned)( (now-n_seconds)/60 );
if (!start_of_bridge_stats_interval)
return NULL; /* Not initialized. */
@@ -1224,8 +1226,7 @@ format_client_stats_heartbeat(time_t now)
}
tor_asprintf(&out, "Heartbeat: "
- "In the last %d hours, I have seen %d unique clients.",
- n_hours,
+ "Since last heartbeat message, I have seen %d unique clients.",
n_clients);
return out;
diff --git a/src/feature/stats/geoip_stats.h b/src/feature/stats/geoip_stats.h
index fcfe7a31f0..b54304337a 100644
--- a/src/feature/stats/geoip_stats.h
+++ b/src/feature/stats/geoip_stats.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/stats/predict_ports.c b/src/feature/stats/predict_ports.c
index 57463952e7..f182d0f71b 100644
--- a/src/feature/stats/predict_ports.c
+++ b/src/feature/stats/predict_ports.c
@@ -1,5 +1,5 @@
/* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -273,8 +273,6 @@ rep_hist_circbuilding_dormant(time_t now)
(!router_all_orports_seem_reachable(options) ||
!circuit_enough_testing_circs()))
return 0;
- if (!router_dirport_seems_reachable(options))
- return 0;
return 1;
}
diff --git a/src/feature/stats/predict_ports.h b/src/feature/stats/predict_ports.h
index ed067b6ced..82e7fa739b 100644
--- a/src/feature/stats/predict_ports.h
+++ b/src/feature/stats/predict_ports.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/stats/rephist.c b/src/feature/stats/rephist.c
index 3c22fda3b8..d1ccc5edf5 100644
--- a/src/feature/stats/rephist.c
+++ b/src/feature/stats/rephist.c
@@ -1,5 +1,5 @@
/* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -69,6 +69,7 @@
#define REPHIST_PRIVATE
#include "core/or/or.h"
#include "app/config/config.h"
+#include "core/mainloop/connection.h"
#include "core/or/circuitlist.h"
#include "core/or/connection_or.h"
#include "feature/dirauth/authmode.h"
@@ -84,6 +85,8 @@
#include "feature/nodelist/networkstatus_st.h"
#include "core/or/or_circuit_st.h"
+#include <event2/dns.h>
+
#ifdef HAVE_FCNTL_H
#include <fcntl.h>
#endif
@@ -183,6 +186,405 @@ static time_t started_tracking_stability = 0;
/** Map from hex OR identity digest to or_history_t. */
static digestmap_t *history_map = NULL;
+/** Represents a state of overload stats.
+ *
+ * All the timestamps in this structure have already been rounded down to the
+ * nearest hour. */
+typedef struct {
+ /* When did we last experience a general overload? */
+ time_t overload_general_time;
+
+ /* When did we last experience a bandwidth-related overload? */
+ time_t overload_ratelimits_time;
+ /* How many times have we gone off the our read limits? */
+ uint64_t overload_read_count;
+ /* How many times have we gone off the our write limits? */
+ uint64_t overload_write_count;
+
+ /* When did we last experience a file descriptor exhaustion? */
+ time_t overload_fd_exhausted_time;
+ /* How many times have we experienced a file descriptor exhaustion? */
+ uint64_t overload_fd_exhausted;
+} overload_stats_t;
+
+/** Current state of overload stats */
+static overload_stats_t overload_stats;
+
+/** Counters to count the number of times we've reached an overload for the
+ * global connection read/write limit. Reported on the MetricsPort. */
+static uint64_t stats_n_read_limit_reached = 0;
+static uint64_t stats_n_write_limit_reached = 0;
+
+/** Total number of times we've reached TCP port exhaustion. */
+static uint64_t stats_n_tcp_exhaustion = 0;
+
+/***** DNS statistics *****/
+
+/** Overload DNS statistics. The information in this object is used to assess
+ * if, due to DNS errors, we should emit a general overload signal or not.
+ *
+ * NOTE: This structure is _not_ per DNS query type like the statistics below
+ * because of a libevent bug
+ * (https://github.com/libevent/libevent/issues/1219), on error, the type is
+ * not propagated up back to the user and so we need to keep our own stats for
+ * the overload signal. */
+typedef struct {
+ /** Total number of DNS request seen at an Exit. They might not all end
+ * successfully or might even be lost by tor. This counter is incremented
+ * right before the DNS request is initiated. */
+ uint64_t stats_n_request;
+
+ /** When is the next assessment time of the general overload for DNS errors.
+ * Once this time is reached, all stats are reset and this time is set to the
+ * next assessment time. */
+ time_t next_assessment_time;
+} overload_dns_stats_t;
+
+/** Keep track of the DNS requests for the general overload state. */
+static overload_dns_stats_t overload_dns_stats;
+
+/** Represents the statistics of DNS queries seen if it is an Exit. */
+typedef struct {
+ /* Total number of DNS errors found in RFC 1035 (from 0 to 5 code). */
+ uint64_t stats_n_error_none; /* 0 */
+ uint64_t stats_n_error_format; /* 1 */
+ uint64_t stats_n_error_serverfailed; /* 2 */
+ uint64_t stats_n_error_notexist; /* 3 */
+ uint64_t stats_n_error_notimpl; /* 4 */
+ uint64_t stats_n_error_refused; /* 5 */
+
+ /* Total number of DNS errors specific to libevent. */
+ uint64_t stats_n_error_truncated; /* 65 */
+ uint64_t stats_n_error_unknown; /* 66 */
+ uint64_t stats_n_error_tor_timeout; /* 67 */
+ uint64_t stats_n_error_shutdown; /* 68 */
+ uint64_t stats_n_error_cancel; /* 69 */
+ uint64_t stats_n_error_nodata; /* 70 */
+
+ /* Total number of DNS request seen at an Exit. They might not all end
+ * successfully or might even be lost by tor. This counter is incremented
+ * right before the DNS request is initiated. */
+ uint64_t stats_n_request;
+} dns_stats_t;
+
+/* This is disabled because of the libevent bug where on error we don't get the
+ * DNS query type back. Once it is fixed, we can re-enable this. */
+#if 0
+/** DNS statistics store for each DNS record type for which tor supports only
+ * three at the moment: A, PTR and AAAA. */
+static dns_stats_t dns_A_stats;
+static dns_stats_t dns_PTR_stats;
+static dns_stats_t dns_AAAA_stats;
+#endif
+
+/** DNS query statistics store. It covers all type of queries. */
+static dns_stats_t dns_all_stats;
+
+/** Return the point to the DNS statistics store. Ignore the type for now
+ * because of a libevent problem. */
+static inline dns_stats_t *
+get_dns_stats_by_type(const int type)
+{
+ (void) type;
+ return &dns_all_stats;
+}
+
+#if 0
+/** From a libevent record type, return a pointer to the corresponding DNS
+ * statistics store. NULL is returned if the type is unhandled. */
+static inline dns_stats_t *
+get_dns_stats_by_type(const int type)
+{
+ switch (type) {
+ case DNS_IPv4_A:
+ return &dns_A_stats;
+ case DNS_PTR:
+ return &dns_PTR_stats;
+ case DNS_IPv6_AAAA:
+ return &dns_AAAA_stats;
+ default:
+ return NULL;
+ }
+}
+#endif
+
+/** Return the DNS error count for the given libevent DNS type and error code.
+ * The possible types are: DNS_IPv4_A, DNS_PTR, DNS_IPv6_AAAA. */
+uint64_t
+rep_hist_get_n_dns_error(int type, uint8_t error)
+{
+ dns_stats_t *dns_stats = get_dns_stats_by_type(type);
+ if (BUG(!dns_stats)) {
+ return 0;
+ }
+
+ switch (error) {
+ case DNS_ERR_NONE:
+ return dns_stats->stats_n_error_none;
+ case DNS_ERR_FORMAT:
+ return dns_stats->stats_n_error_format;
+ case DNS_ERR_SERVERFAILED:
+ return dns_stats->stats_n_error_serverfailed;
+ case DNS_ERR_NOTEXIST:
+ return dns_stats->stats_n_error_notexist;
+ case DNS_ERR_NOTIMPL:
+ return dns_stats->stats_n_error_notimpl;
+ case DNS_ERR_REFUSED:
+ return dns_stats->stats_n_error_refused;
+ case DNS_ERR_TRUNCATED:
+ return dns_stats->stats_n_error_truncated;
+ case DNS_ERR_UNKNOWN:
+ return dns_stats->stats_n_error_unknown;
+ case DNS_ERR_TIMEOUT:
+ return dns_stats->stats_n_error_tor_timeout;
+ case DNS_ERR_SHUTDOWN:
+ return dns_stats->stats_n_error_shutdown;
+ case DNS_ERR_CANCEL:
+ return dns_stats->stats_n_error_cancel;
+ case DNS_ERR_NODATA:
+ return dns_stats->stats_n_error_nodata;
+ default:
+ /* Unhandled code sent back by libevent. */
+ return 0;
+ }
+}
+
+/** Return the total number of DNS request seen for the given libevent DNS
+ * record type. Possible types are: DNS_IPv4_A, DNS_PTR, DNS_IPv6_AAAA. */
+uint64_t
+rep_hist_get_n_dns_request(int type)
+{
+ dns_stats_t *dns_stats = get_dns_stats_by_type(type);
+ if (BUG(!dns_stats)) {
+ return 0;
+ }
+ return dns_stats->stats_n_request;
+}
+
+/** Note a DNS error for the given given libevent DNS record type and error
+ * code. Possible types are: DNS_IPv4_A, DNS_PTR, DNS_IPv6_AAAA.
+ *
+ * NOTE: Libevent is _not_ returning the type in case of an error and so if
+ * error is anything but DNS_ERR_NONE, the type is not usable and set to 0.
+ *
+ * See: https://gitlab.torproject.org/tpo/core/tor/-/issues/40490 */
+void
+rep_hist_note_dns_error(int type, uint8_t error)
+{
+ overload_dns_stats.stats_n_request++;
+
+ /* Again, the libevent bug (see function comment), for an error that is
+ * anything but DNS_ERR_NONE, the type is always 0 which means that we don't
+ * have a DNS stat object for it so this code will do nothing until libevent
+ * is fixed. */
+ dns_stats_t *dns_stats = get_dns_stats_by_type(type);
+ /* Unsupported DNS query type. */
+ if (!dns_stats) {
+ return;
+ }
+
+ switch (error) {
+ case DNS_ERR_NONE:
+ dns_stats->stats_n_error_none++;
+ break;
+ case DNS_ERR_FORMAT:
+ dns_stats->stats_n_error_format++;
+ break;
+ case DNS_ERR_SERVERFAILED:
+ dns_stats->stats_n_error_serverfailed++;
+ break;
+ case DNS_ERR_NOTEXIST:
+ dns_stats->stats_n_error_notexist++;
+ break;
+ case DNS_ERR_NOTIMPL:
+ dns_stats->stats_n_error_notimpl++;
+ break;
+ case DNS_ERR_REFUSED:
+ dns_stats->stats_n_error_refused++;
+ break;
+ case DNS_ERR_TRUNCATED:
+ dns_stats->stats_n_error_truncated++;
+ break;
+ case DNS_ERR_UNKNOWN:
+ dns_stats->stats_n_error_unknown++;
+ break;
+ case DNS_ERR_TIMEOUT:
+ dns_stats->stats_n_error_tor_timeout++;
+ break;
+ case DNS_ERR_SHUTDOWN:
+ dns_stats->stats_n_error_shutdown++;
+ break;
+ case DNS_ERR_CANCEL:
+ dns_stats->stats_n_error_cancel++;
+ break;
+ case DNS_ERR_NODATA:
+ dns_stats->stats_n_error_nodata++;
+ break;
+ default:
+ /* Unhandled code sent back by libevent. */
+ break;
+ }
+}
+
+/** Note a DNS request for the given given libevent DNS record type. */
+void
+rep_hist_note_dns_request(int type)
+{
+ dns_stats_t *dns_stats = get_dns_stats_by_type(type);
+ if (BUG(!dns_stats)) {
+ return;
+ }
+ dns_stats->stats_n_request++;
+}
+
+/***** END of DNS statistics *****/
+
+/** Return true if this overload happened within the last `n_hours`. */
+static bool
+overload_happened_recently(time_t overload_time, int n_hours)
+{
+ /* An overload is relevant if it happened in the last 72 hours */
+ if (overload_time > approx_time() - 3600 * n_hours) {
+ return true;
+ }
+ return false;
+}
+
+/* The current version of the overload stats version */
+#define OVERLOAD_STATS_VERSION 1
+
+/** Return the stats_n_read_limit_reached counter. */
+uint64_t
+rep_hist_get_n_read_limit_reached(void)
+{
+ return stats_n_read_limit_reached;
+}
+
+/** Return the stats_n_write_limit_reached counter. */
+uint64_t
+rep_hist_get_n_write_limit_reached(void)
+{
+ return stats_n_write_limit_reached;
+}
+
+/** Returns an allocated string for server descriptor for publising information
+ * on whether we are overloaded or not. */
+char *
+rep_hist_get_overload_general_line(void)
+{
+ char *result = NULL;
+ char tbuf[ISO_TIME_LEN+1];
+
+ /* Encode the general overload */
+ if (overload_happened_recently(overload_stats.overload_general_time, 72)) {
+ format_iso_time(tbuf, overload_stats.overload_general_time);
+ tor_asprintf(&result, "overload-general %d %s\n",
+ OVERLOAD_STATS_VERSION, tbuf);
+ }
+
+ return result;
+}
+
+/** Returns an allocated string for extra-info documents for publishing
+ * overload statistics. */
+char *
+rep_hist_get_overload_stats_lines(void)
+{
+ char *result = NULL;
+ smartlist_t *chunks = smartlist_new();
+ char tbuf[ISO_TIME_LEN+1];
+
+ /* Add bandwidth-related overloads */
+ if (overload_happened_recently(overload_stats.overload_ratelimits_time,24)) {
+ const or_options_t *options = get_options();
+ format_iso_time(tbuf, overload_stats.overload_ratelimits_time);
+ smartlist_add_asprintf(chunks,
+ "overload-ratelimits %d %s %" PRIu64 " %" PRIu64
+ " %" PRIu64 " %" PRIu64 "\n",
+ OVERLOAD_STATS_VERSION, tbuf,
+ options->BandwidthRate, options->BandwidthBurst,
+ overload_stats.overload_read_count,
+ overload_stats.overload_write_count);
+ }
+
+ /* Finally file descriptor overloads */
+ if (overload_happened_recently(
+ overload_stats.overload_fd_exhausted_time, 72)) {
+ format_iso_time(tbuf, overload_stats.overload_fd_exhausted_time);
+ smartlist_add_asprintf(chunks, "overload-fd-exhausted %d %s\n",
+ OVERLOAD_STATS_VERSION, tbuf);
+ }
+
+ /* Bail early if we had nothing to write */
+ if (smartlist_len(chunks) == 0) {
+ goto done;
+ }
+
+ result = smartlist_join_strings(chunks, "", 0, NULL);
+
+ done:
+ SMARTLIST_FOREACH(chunks, char *, cp, tor_free(cp));
+ smartlist_free(chunks);
+ return result;
+}
+
+/** Round down the time in `a` to the beginning of the current hour */
+#define SET_TO_START_OF_HOUR(a) STMT_BEGIN \
+ (a) = approx_time() - (approx_time() % 3600); \
+STMT_END
+
+/** Note down an overload event of type `overload`. */
+void
+rep_hist_note_overload(overload_type_t overload)
+{
+ static time_t last_read_counted = 0;
+ static time_t last_write_counted = 0;
+
+ switch (overload) {
+ case OVERLOAD_GENERAL:
+ SET_TO_START_OF_HOUR(overload_stats.overload_general_time);
+ break;
+ case OVERLOAD_READ: {
+ stats_n_read_limit_reached++;
+ SET_TO_START_OF_HOUR(overload_stats.overload_ratelimits_time);
+ if (approx_time() >= last_read_counted + 60) { /* Count once a minute */
+ overload_stats.overload_read_count++;
+ last_read_counted = approx_time();
+ }
+ break;
+ }
+ case OVERLOAD_WRITE: {
+ stats_n_write_limit_reached++;
+ SET_TO_START_OF_HOUR(overload_stats.overload_ratelimits_time);
+ if (approx_time() >= last_write_counted + 60) { /* Count once a minute */
+ overload_stats.overload_write_count++;
+ last_write_counted = approx_time();
+ }
+ break;
+ }
+ case OVERLOAD_FD_EXHAUSTED:
+ SET_TO_START_OF_HOUR(overload_stats.overload_fd_exhausted_time);
+ overload_stats.overload_fd_exhausted++;
+ break;
+ }
+}
+
+/** Note down that we've reached a TCP port exhaustion. This triggers an
+ * overload general event. */
+void
+rep_hist_note_tcp_exhaustion(void)
+{
+ stats_n_tcp_exhaustion++;
+ rep_hist_note_overload(OVERLOAD_GENERAL);
+}
+
+/** Return the total number of TCP exhaustion times we've reached. */
+uint64_t
+rep_hist_get_n_tcp_exhaustion(void)
+{
+ return stats_n_tcp_exhaustion;
+}
+
/** Return the or_history_t for the OR with identity digest <b>id</b>,
* creating it if necessary. */
static or_history_t *
@@ -382,7 +784,7 @@ rep_hist_downrate_old_runs(time_t now)
return stability_last_downrated + STABILITY_INTERVAL;
/* Okay, we should downrate the data. By how much? */
- while (stability_last_downrated + STABILITY_INTERVAL < now) {
+ while (stability_last_downrated + STABILITY_INTERVAL <= now) {
stability_last_downrated += STABILITY_INTERVAL;
alpha *= STABILITY_ALPHA;
}
@@ -1237,6 +1639,183 @@ rep_hist_note_exit_stream_opened(uint16_t port)
log_debug(LD_HIST, "Opened exit stream to port %d", port);
}
+/*** Exit streams statistics ***/
+
+/** Number of BEGIN streams seen. */
+static uint64_t streams_begin_seen;
+/** Number of BEGIN_DIR streams seen. */
+static uint64_t streams_begindir_seen;
+/** Number of RESOLVE streams seen. */
+static uint64_t streams_resolve_seen;
+
+/** Note a stream as seen for the given relay command. */
+void
+rep_hist_note_exit_stream(unsigned int cmd)
+{
+ switch (cmd) {
+ case RELAY_COMMAND_BEGIN:
+ streams_begin_seen++;
+ break;
+ case RELAY_COMMAND_BEGIN_DIR:
+ streams_begindir_seen++;
+ break;
+ case RELAY_COMMAND_RESOLVE:
+ streams_resolve_seen++;
+ break;
+ default:
+ tor_assert_nonfatal_unreached_once();
+ break;
+ }
+}
+
+/** Return number of stream seen for the given command. */
+uint64_t
+rep_hist_get_exit_stream_seen(unsigned int cmd)
+{
+ switch (cmd) {
+ case RELAY_COMMAND_BEGIN:
+ return streams_begin_seen;
+ case RELAY_COMMAND_BEGIN_DIR:
+ return streams_begindir_seen;
+ case RELAY_COMMAND_RESOLVE:
+ return streams_resolve_seen;
+ default:
+ return 0;
+ }
+}
+
+/******* Connections statistics *******/
+
+#define CONN_DIRECTION_INITIATED 0
+#define CONN_DIRECTION_RECEIVED 1
+
+#define CONN_DIRECTION(from_listener) \
+ (from_listener) ? CONN_DIRECTION_RECEIVED : CONN_DIRECTION_INITIATED
+
+/** Number of connections created as in seen per direction per type. */
+static uint64_t conn_num_created_v4[2][CONN_TYPE_MAX_];
+static uint64_t conn_num_created_v6[2][CONN_TYPE_MAX_];
+/** Number of connections opened per direction per type. */
+static uint64_t conn_num_opened_v4[2][CONN_TYPE_MAX_];
+static uint64_t conn_num_opened_v6[2][CONN_TYPE_MAX_];
+/** Number of connections rejected per type. Always inbound. */
+static uint64_t conn_num_rejected_v4[CONN_TYPE_MAX_];
+static uint64_t conn_num_rejected_v6[CONN_TYPE_MAX_];
+
+/** Note that a connection has opened of the given type. */
+void
+rep_hist_note_conn_opened(bool from_listener, unsigned int type, int af)
+{
+ tor_assert(type <= CONN_TYPE_MAX_);
+
+ unsigned int dir = CONN_DIRECTION(from_listener);
+
+ switch (af) {
+ case AF_INET:
+ conn_num_created_v4[dir][type]++;
+ conn_num_opened_v4[dir][type]++;
+ break;
+ case AF_INET6:
+ conn_num_created_v6[dir][type]++;
+ conn_num_opened_v6[dir][type]++;
+ break;
+ default:
+ /* Ignore non IP connections at this point in time. */
+ break;
+ }
+}
+
+/** Note that a connection has closed of the given type. */
+void
+rep_hist_note_conn_closed(bool from_listener, unsigned int type, int af)
+{
+ tor_assert(type <= CONN_TYPE_MAX_);
+
+ unsigned int dir = CONN_DIRECTION(from_listener);
+
+ switch (af) {
+ case AF_INET:
+ if (conn_num_opened_v4[dir][type] > 0) {
+ conn_num_opened_v4[dir][type]--;
+ }
+ break;
+ case AF_INET6:
+ if (conn_num_opened_v6[dir][type] > 0) {
+ conn_num_opened_v6[dir][type]--;
+ }
+ break;
+ default:
+ /* Ignore non IP connections at this point in time. */
+ break;
+ }
+}
+
+/** Note that a connection has rejected of the given type. */
+void
+rep_hist_note_conn_rejected(unsigned int type, int af)
+{
+ tor_assert(type <= CONN_TYPE_MAX_);
+
+ switch (af) {
+ case AF_INET:
+ conn_num_rejected_v4[type]++;
+ break;
+ case AF_INET6:
+ conn_num_rejected_v6[type]++;
+ break;
+ default:
+ /* Ignore non IP connections at this point in time. */
+ break;
+ }
+}
+
+/** Return number of created connections of the given type. */
+uint64_t
+rep_hist_get_conn_created(bool from_listener, unsigned int type, int af)
+{
+ tor_assert(type <= CONN_TYPE_MAX_);
+ unsigned int dir = CONN_DIRECTION(from_listener);
+ switch (af) {
+ case AF_INET:
+ return conn_num_created_v4[dir][type];
+ case AF_INET6:
+ return conn_num_created_v6[dir][type];
+ default:
+ return 0;
+ }
+}
+
+/** Return number of opened connections of the given type. */
+uint64_t
+rep_hist_get_conn_opened(bool from_listener, unsigned int type, int af)
+{
+ tor_assert(type <= CONN_TYPE_MAX_);
+ unsigned int dir = CONN_DIRECTION(from_listener);
+ switch (af) {
+ case AF_INET:
+ return conn_num_opened_v4[dir][type];
+ case AF_INET6:
+ return conn_num_opened_v6[dir][type];
+ default:
+ return 0;
+ }
+}
+
+/** Return number of opened connections of the given type. */
+uint64_t
+rep_hist_get_conn_rejected(unsigned int type, int af)
+{
+ tor_assert(type <= CONN_TYPE_MAX_);
+ switch (af) {
+ case AF_INET:
+ return conn_num_rejected_v4[type];
+ case AF_INET6:
+ return conn_num_rejected_v6[type];
+ default:
+ return 0;
+ }
+}
+
/*** cell statistics ***/
/** Start of the current buffer stats interval or 0 if we're not
@@ -1649,17 +2228,155 @@ rep_hist_note_desc_served(const char * desc)
/** Internal statistics to track how many requests of each type of
* handshake we've received, and how many we've assigned to cpuworkers.
* Useful for seeing trends in cpu load.
+ *
+ * They are reset at every heartbeat.
* @{ */
-STATIC int onion_handshakes_requested[MAX_ONION_HANDSHAKE_TYPE+1] = {0};
-STATIC int onion_handshakes_assigned[MAX_ONION_HANDSHAKE_TYPE+1] = {0};
+STATIC int onion_handshakes_requested[MAX_ONION_STAT_TYPE+1] = {0};
+STATIC int onion_handshakes_assigned[MAX_ONION_STAT_TYPE+1] = {0};
/**@}*/
+/** Counters keeping the same stats as above but for the entire duration of the
+ * process (not reset). */
+static uint64_t stats_n_onionskin_assigned[MAX_ONION_STAT_TYPE+1] = {0};
+static uint64_t stats_n_onionskin_dropped[MAX_ONION_STAT_TYPE+1] = {0};
+
+/* We use a scale here so we can represent percentages with decimal points by
+ * scaling the value by this factor and so 0.5% becomes a value of 500.
+ * Default is 1% and thus min and max range is 0 to 100%. */
+#define OVERLOAD_ONIONSKIN_NTOR_PERCENT_SCALE 1000.0
+#define OVERLOAD_ONIONSKIN_NTOR_PERCENT_DEFAULT 1000
+#define OVERLOAD_ONIONSKIN_NTOR_PERCENT_MIN 0
+#define OVERLOAD_ONIONSKIN_NTOR_PERCENT_MAX 100000
+
+/** Consensus parameter: indicate what fraction of ntor onionskin drop over the
+ * total number of requests must be reached before we trigger a general
+ * overload signal.*/
+static double overload_onionskin_ntor_fraction =
+ OVERLOAD_ONIONSKIN_NTOR_PERCENT_DEFAULT /
+ OVERLOAD_ONIONSKIN_NTOR_PERCENT_SCALE / 100.0;
+
+/* Number of seconds for the assessment period. Default is 6 hours (21600) and
+ * the min max range is within a 32bit value. We align this period to the
+ * Heartbeat so the logs would match this period more or less. */
+#define OVERLOAD_ONIONSKIN_NTOR_PERIOD_SECS_DEFAULT (60 * 60 * 6)
+#define OVERLOAD_ONIONSKIN_NTOR_PERIOD_SECS_MIN 0
+#define OVERLOAD_ONIONSKIN_NTOR_PERIOD_SECS_MAX INT32_MAX
+
+/** Consensus parameter: Period, in seconds, over which we count the number of
+ * ntor onionskins requests and how many were dropped. After that period, we
+ * assess if we trigger an overload or not. */
+static int32_t overload_onionskin_ntor_period_secs =
+ OVERLOAD_ONIONSKIN_NTOR_PERIOD_SECS_DEFAULT;
+
+/** Structure containing information for an assessment period of the onionskin
+ * drop overload general signal.
+ *
+ * It is used to track, within a time period, how many requests we've gotten
+ * and how many were dropped. The overload general signal is decided from these
+ * depending on some consensus parameters. */
+typedef struct {
+ /** Total number of ntor onionskin requested for an assessment period. */
+ uint64_t n_ntor_requested;
+
+ /** Total number of dropped ntor onionskins for an assessment period. */
+ uint64_t n_ntor_dropped;
+
+ /** When is the next assessment time of the general overload for ntor
+ * onionskin drop. Once this time is reached, all stats are reset and this
+ * time is set to the next assessment time. */
+ time_t next_assessment_time;
+} overload_onionskin_assessment_t;
+
+/** Keep track of the onionskin requests for an assessment period. */
+static overload_onionskin_assessment_t overload_onionskin_assessment;
+
+/**
+ * We combine ntorv3 and ntor into the same stat, so we must
+ * use this function to covert the cell type to a stat index.
+ */
+static inline uint16_t
+onionskin_type_to_stat(uint16_t type)
+{
+ if (type == ONION_HANDSHAKE_TYPE_NTOR_V3) {
+ return ONION_HANDSHAKE_TYPE_NTOR;
+ }
+
+ if (BUG(type > MAX_ONION_STAT_TYPE)) {
+ return MAX_ONION_STAT_TYPE; // use ntor if out of range
+ }
+
+ return type;
+}
+
+/** Assess our ntor handshake statistics and decide if we need to emit a
+ * general overload signal.
+ *
+ * Regardless of overloaded or not, if the assessment time period has passed,
+ * 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
+ * then a drop happens leading to the drop counter being incremented while the
+ * requested counter is 0. */
+static void
+overload_general_onionskin_assessment(void)
+{
+ /* Initialize the time. Should be done once. */
+ if (overload_onionskin_assessment.next_assessment_time == 0) {
+ goto reset;
+ }
+
+ /* Not the time yet. */
+ if (overload_onionskin_assessment.next_assessment_time > approx_time()) {
+ goto done;
+ }
+
+ /* Make sure we have enough requests to be able to make a proper assessment.
+ * We want to avoid 1 single request/drop to trigger an overload as we want
+ * at least the number of requests to be above the scale of our fraction. */
+ if (overload_onionskin_assessment.n_ntor_requested <
+ OVERLOAD_ONIONSKIN_NTOR_PERCENT_SCALE) {
+ goto done;
+ }
+
+ /* Lets see if we can signal a general overload. */
+ double fraction = (double) overload_onionskin_assessment.n_ntor_dropped /
+ (double) overload_onionskin_assessment.n_ntor_requested;
+ if (fraction >= overload_onionskin_ntor_fraction) {
+ log_notice(LD_HIST, "General overload -> Ntor dropped (%" PRIu64 ") "
+ "fraction %.4f%% is above threshold of %.4f%%",
+ overload_onionskin_assessment.n_ntor_dropped,
+ fraction * 100.0,
+ overload_onionskin_ntor_fraction * 100.0);
+ rep_hist_note_overload(OVERLOAD_GENERAL);
+ }
+
+ reset:
+ /* Reset counters for the next period. */
+ overload_onionskin_assessment.n_ntor_dropped = 0;
+ overload_onionskin_assessment.n_ntor_requested = 0;
+ overload_onionskin_assessment.next_assessment_time =
+ approx_time() + overload_onionskin_ntor_period_secs;
+
+ done:
+ return;
+}
+
/** A new onionskin (using the <b>type</b> handshake) has arrived. */
void
rep_hist_note_circuit_handshake_requested(uint16_t type)
{
- if (type <= MAX_ONION_HANDSHAKE_TYPE)
- onion_handshakes_requested[type]++;
+ uint16_t stat = onionskin_type_to_stat(type);
+
+ onion_handshakes_requested[stat]++;
+
+ /* Only relays get to record requested onionskins. */
+ if (stat == ONION_HANDSHAKE_TYPE_NTOR) {
+ /* Assess if we've reached the overload general signal. */
+ overload_general_onionskin_assessment();
+
+ overload_onionskin_assessment.n_ntor_requested++;
+ }
}
/** We've sent an onionskin (using the <b>type</b> handshake) to a
@@ -1667,28 +2384,52 @@ rep_hist_note_circuit_handshake_requested(uint16_t type)
void
rep_hist_note_circuit_handshake_assigned(uint16_t type)
{
- if (type <= MAX_ONION_HANDSHAKE_TYPE)
- onion_handshakes_assigned[type]++;
+ onion_handshakes_assigned[onionskin_type_to_stat(type)]++;
+ stats_n_onionskin_assigned[onionskin_type_to_stat(type)]++;
+}
+
+/** We've just drop an onionskin (using the <b>type</b> handshake) due to being
+ * overloaded. */
+void
+rep_hist_note_circuit_handshake_dropped(uint16_t type)
+{
+ uint16_t stat = onionskin_type_to_stat(type);
+
+ stats_n_onionskin_dropped[stat]++;
+
+ /* Only relays get to record requested onionskins. */
+ if (stat == ONION_HANDSHAKE_TYPE_NTOR) {
+ /* Note the dropped ntor in the overload assessment object. */
+ overload_onionskin_assessment.n_ntor_dropped++;
+ }
}
/** Get the circuit handshake value that is requested. */
MOCK_IMPL(int,
rep_hist_get_circuit_handshake_requested, (uint16_t type))
{
- if (BUG(type > MAX_ONION_HANDSHAKE_TYPE)) {
- return 0;
- }
- return onion_handshakes_requested[type];
+ return onion_handshakes_requested[onionskin_type_to_stat(type)];
}
/** Get the circuit handshake value that is assigned. */
MOCK_IMPL(int,
rep_hist_get_circuit_handshake_assigned, (uint16_t type))
{
- if (BUG(type > MAX_ONION_HANDSHAKE_TYPE)) {
- return 0;
- }
- return onion_handshakes_assigned[type];
+ return onion_handshakes_assigned[onionskin_type_to_stat(type)];
+}
+
+/** Get the total number of circuit handshake value that is assigned. */
+MOCK_IMPL(uint64_t,
+rep_hist_get_circuit_n_handshake_assigned, (uint16_t type))
+{
+ return stats_n_onionskin_assigned[onionskin_type_to_stat(type)];
+}
+
+/** Get the total number of circuit handshake value that is dropped. */
+MOCK_IMPL(uint64_t,
+rep_hist_get_circuit_n_handshake_dropped, (uint16_t type))
+{
+ return stats_n_onionskin_dropped[onionskin_type_to_stat(type)];
}
/** Log our onionskin statistics since the last time we were called. */
@@ -1710,123 +2451,214 @@ rep_hist_log_circuit_handshake_stats(time_t now)
/** Start of the current hidden service stats interval or 0 if we're
* not collecting hidden service statistics. */
-static time_t start_of_hs_stats_interval;
+static time_t start_of_hs_v2_stats_interval;
-/** Carries the various hidden service statistics, and any other
- * information needed. */
-typedef struct hs_stats_t {
- /** How many relay cells have we seen as rendezvous points? */
- uint64_t rp_relay_cells_seen;
+/** Our v2 statistics structure singleton. */
+static hs_v2_stats_t *hs_v2_stats = NULL;
- /** Set of unique public key digests we've seen this stat period
- * (could also be implemented as sorted smartlist). */
- digestmap_t *onions_seen_this_period;
-} hs_stats_t;
+/** HSv2 stats */
-/** Our statistics structure singleton. */
-static hs_stats_t *hs_stats = NULL;
-
-/** Allocate, initialize and return an hs_stats_t structure. */
-static hs_stats_t *
-hs_stats_new(void)
+/** Allocate, initialize and return an hs_v2_stats_t structure. */
+static hs_v2_stats_t *
+hs_v2_stats_new(void)
{
- hs_stats_t *new_hs_stats = tor_malloc_zero(sizeof(hs_stats_t));
- new_hs_stats->onions_seen_this_period = digestmap_new();
+ hs_v2_stats_t *new_hs_v2_stats = tor_malloc_zero(sizeof(hs_v2_stats_t));
- return new_hs_stats;
+ return new_hs_v2_stats;
}
-#define hs_stats_free(val) \
- FREE_AND_NULL(hs_stats_t, hs_stats_free_, (val))
+#define hs_v2_stats_free(val) \
+ FREE_AND_NULL(hs_v2_stats_t, hs_v2_stats_free_, (val))
-/** Free an hs_stats_t structure. */
+/** Free an hs_v2_stats_t structure. */
static void
-hs_stats_free_(hs_stats_t *victim_hs_stats)
+hs_v2_stats_free_(hs_v2_stats_t *victim_hs_v2_stats)
{
- if (!victim_hs_stats) {
+ if (!victim_hs_v2_stats) {
return;
}
+ tor_free(victim_hs_v2_stats);
+}
- digestmap_free(victim_hs_stats->onions_seen_this_period, NULL);
- tor_free(victim_hs_stats);
+/** Clear history of hidden service statistics and set the measurement
+ * interval start to <b>now</b>. */
+static void
+rep_hist_reset_hs_v2_stats(time_t now)
+{
+ if (!hs_v2_stats) {
+ hs_v2_stats = hs_v2_stats_new();
+ }
+
+ hs_v2_stats->rp_v2_relay_cells_seen = 0;
+
+ start_of_hs_v2_stats_interval = now;
}
-/** Initialize hidden service statistics. */
-void
-rep_hist_hs_stats_init(time_t now)
+/*** HSv3 stats ******/
+
+/** Start of the current hidden service stats interval or 0 if we're not
+ * collecting hidden service statistics.
+ *
+ * This is particularly important for v3 statistics since this variable
+ * controls the start time of initial v3 stats collection. It's initialized by
+ * rep_hist_hs_stats_init() to the next time period start (i.e. 12:00UTC), and
+ * should_collect_v3_stats() ensures that functions that collect v3 stats do
+ * not do so sooner than that.
+ *
+ * Collecting stats from 12:00UTC to 12:00UTC is extremely important for v3
+ * stats because rep_hist_hsdir_stored_maybe_new_v3_onion() uses the blinded
+ * key of each onion service as its double-counting index. Onion services
+ * rotate their descriptor at around 00:00UTC which means that their blinded
+ * key also changes around that time. However the precise time that onion
+ * services rotate their descriptors is actually when they fetch a new
+ * 00:00UTC consensus and that happens at a random time (e.g. it can even
+ * happen at 02:00UTC). This means that if we started keeping v3 stats at
+ * around 00:00UTC we wouldn't be able to tell when onion services change
+ * their blinded key and hence we would double count an unpredictable amount
+ * of them (for example, if an onion service fetches the 00:00UTC consensus at
+ * 01:00UTC it would upload to its old HSDir at 00:45UTC, and then to a
+ * different HSDir at 01:50UTC).
+ *
+ * For this reason, we start collecting statistics at 12:00UTC. This way we
+ * know that by the time we stop collecting statistics for that time period 24
+ * hours later, all the onion services have switched to their new blinded
+ * key. This way we can predict much better how much double counting has been
+ * performed.
+ */
+static time_t start_of_hs_v3_stats_interval;
+
+/** Our v3 statistics structure singleton. */
+static hs_v3_stats_t *hs_v3_stats = NULL;
+
+/** Allocate, initialize and return an hs_v3_stats_t structure. */
+static hs_v3_stats_t *
+hs_v3_stats_new(void)
+{
+ hs_v3_stats_t *new_hs_v3_stats = tor_malloc_zero(sizeof(hs_v3_stats_t));
+ new_hs_v3_stats->v3_onions_seen_this_period = digest256map_new();
+
+ return new_hs_v3_stats;
+}
+
+#define hs_v3_stats_free(val) \
+ FREE_AND_NULL(hs_v3_stats_t, hs_v3_stats_free_, (val))
+
+/** Free an hs_v3_stats_t structure. */
+static void
+hs_v3_stats_free_(hs_v3_stats_t *victim_hs_v3_stats)
{
- if (!hs_stats) {
- hs_stats = hs_stats_new();
+ if (!victim_hs_v3_stats) {
+ return;
}
- start_of_hs_stats_interval = now;
+ digest256map_free(victim_hs_v3_stats->v3_onions_seen_this_period, NULL);
+ tor_free(victim_hs_v3_stats);
}
/** Clear history of hidden service statistics and set the measurement
* interval start to <b>now</b>. */
static void
-rep_hist_reset_hs_stats(time_t now)
+rep_hist_reset_hs_v3_stats(time_t now)
{
- if (!hs_stats) {
- hs_stats = hs_stats_new();
+ if (!hs_v3_stats) {
+ hs_v3_stats = hs_v3_stats_new();
}
- hs_stats->rp_relay_cells_seen = 0;
+ digest256map_free(hs_v3_stats->v3_onions_seen_this_period, NULL);
+ hs_v3_stats->v3_onions_seen_this_period = digest256map_new();
- digestmap_free(hs_stats->onions_seen_this_period, NULL);
- hs_stats->onions_seen_this_period = digestmap_new();
+ hs_v3_stats->rp_v3_relay_cells_seen = 0;
- start_of_hs_stats_interval = now;
+ start_of_hs_v3_stats_interval = now;
}
-/** Stop collecting hidden service stats in a way that we can re-start
- * doing so in rep_hist_buffer_stats_init(). */
-void
-rep_hist_hs_stats_term(void)
+/** Return true if it's a good time to collect v3 stats.
+ *
+ * v3 stats have a strict stats collection period (from 12:00UTC to 12:00UTC
+ * on the real network). We don't want to collect statistics if (for example)
+ * we just booted and it's 03:00UTC; we will wait until 12:00UTC before we
+ * start collecting statistics to make sure that the final result represents
+ * the whole collection period. This behavior is controlled by
+ * rep_hist_hs_stats_init().
+ */
+MOCK_IMPL(STATIC bool,
+should_collect_v3_stats,(void))
{
- rep_hist_reset_hs_stats(0);
+ return start_of_hs_v3_stats_interval <= approx_time();
}
-/** We saw a new HS relay cell, Count it! */
+/** We just received a new descriptor with <b>blinded_key</b>. See if we've
+ * seen this blinded key before, and if not add it to the stats. */
void
-rep_hist_seen_new_rp_cell(void)
+rep_hist_hsdir_stored_maybe_new_v3_onion(const uint8_t *blinded_key)
{
- if (!hs_stats) {
- return; // We're not collecting stats
+ /* Return early if we don't collect HSv3 stats, or if it's not yet the time
+ * to collect them. */
+ if (!hs_v3_stats || !should_collect_v3_stats()) {
+ return;
}
- hs_stats->rp_relay_cells_seen++;
+ bool seen_before =
+ !!digest256map_get(hs_v3_stats->v3_onions_seen_this_period,
+ blinded_key);
+
+ log_info(LD_GENERAL, "Considering v3 descriptor with %s (%sseen before)",
+ safe_str(hex_str((char*)blinded_key, 32)),
+ seen_before ? "" : "not ");
+
+ /* Count it if we haven't seen it before. */
+ if (!seen_before) {
+ digest256map_set(hs_v3_stats->v3_onions_seen_this_period,
+ blinded_key, (void*)(uintptr_t)1);
+ }
}
-/** As HSDirs, we saw another hidden service with public key
- * <b>pubkey</b>. Check whether we have counted it before, if not
- * count it now! */
+/** We saw a new HS relay cell: count it!
+ * If <b>is_v2</b> is set then it's a v2 RP cell, otherwise it's a v3. */
void
-rep_hist_stored_maybe_new_hs(const crypto_pk_t *pubkey)
+rep_hist_seen_new_rp_cell(bool is_v2)
{
- char pubkey_hash[DIGEST_LEN];
+ log_debug(LD_GENERAL, "New RP cell (%d)", is_v2);
- if (!hs_stats) {
- return; // We're not collecting stats
+ if (is_v2 && hs_v2_stats) {
+ hs_v2_stats->rp_v2_relay_cells_seen++;
+ } else if (!is_v2 && hs_v3_stats && should_collect_v3_stats()) {
+ hs_v3_stats->rp_v3_relay_cells_seen++;
}
+}
- /* Get the digest of the pubkey which will be used to detect whether
- we've seen this hidden service before or not. */
- if (crypto_pk_get_digest(pubkey, pubkey_hash) < 0) {
- /* This fail should not happen; key has been validated by
- descriptor parsing code first. */
- return;
+/** Generic HS stats code */
+
+/** Initialize v2 and v3 hidden service statistics. */
+void
+rep_hist_hs_stats_init(time_t now)
+{
+ if (!hs_v2_stats) {
+ hs_v2_stats = hs_v2_stats_new();
}
- /* Check if this is the first time we've seen this hidden
- service. If it is, count it as new. */
- if (!digestmap_get(hs_stats->onions_seen_this_period,
- pubkey_hash)) {
- digestmap_set(hs_stats->onions_seen_this_period,
- pubkey_hash, (void*)(uintptr_t)1);
+ /* Start collecting v2 stats straight away */
+ start_of_hs_v2_stats_interval = now;
+
+ if (!hs_v3_stats) {
+ hs_v3_stats = hs_v3_stats_new();
}
+
+ /* Start collecting v3 stats at the next 12:00 UTC */
+ start_of_hs_v3_stats_interval = hs_get_start_time_of_next_time_period(now);
}
+/** Stop collecting hidden service stats in a way that we can re-start
+ * doing so in rep_hist_buffer_stats_init(). */
+void
+rep_hist_hs_stats_term(void)
+{
+ rep_hist_reset_hs_v2_stats(0);
+ rep_hist_reset_hs_v3_stats(0);
+}
+
+/** Stats reporting code */
+
/* The number of cells that are supposed to be hidden from the adversary
* by adding noise from the Laplace distribution. This value, divided by
* EPSILON, is Laplace parameter b. It must be greater than 0. */
@@ -1851,58 +2683,68 @@ rep_hist_stored_maybe_new_hs(const crypto_pk_t *pubkey)
#define ONIONS_SEEN_BIN_SIZE 8
/** Allocate and return a string containing hidden service stats that
- * are meant to be placed in the extra-info descriptor. */
-static char *
-rep_hist_format_hs_stats(time_t now)
+ * are meant to be placed in the extra-info descriptor.
+ *
+ * Function works for both v2 and v3 stats depending on <b>is_v3</b>. */
+STATIC char *
+rep_hist_format_hs_stats(time_t now, bool is_v3)
{
char t[ISO_TIME_LEN+1];
char *hs_stats_string;
- int64_t obfuscated_cells_seen;
- int64_t obfuscated_onions_seen;
+ int64_t obfuscated_onions_seen, obfuscated_cells_seen;
+
+ uint64_t rp_cells_seen = is_v3 ?
+ hs_v3_stats->rp_v3_relay_cells_seen : hs_v2_stats->rp_v2_relay_cells_seen;
+ size_t onions_seen = is_v3 ?
+ digest256map_size(hs_v3_stats->v3_onions_seen_this_period) : 0;
+ time_t start_of_hs_stats_interval = is_v3 ?
+ start_of_hs_v3_stats_interval : start_of_hs_v2_stats_interval;
uint64_t rounded_cells_seen
- = round_uint64_to_next_multiple_of(hs_stats->rp_relay_cells_seen,
- REND_CELLS_BIN_SIZE);
+ = round_uint64_to_next_multiple_of(rp_cells_seen, REND_CELLS_BIN_SIZE);
rounded_cells_seen = MIN(rounded_cells_seen, INT64_MAX);
obfuscated_cells_seen = add_laplace_noise((int64_t)rounded_cells_seen,
crypto_rand_double(),
REND_CELLS_DELTA_F, REND_CELLS_EPSILON);
uint64_t rounded_onions_seen =
- round_uint64_to_next_multiple_of((size_t)digestmap_size(
- hs_stats->onions_seen_this_period),
- ONIONS_SEEN_BIN_SIZE);
+ round_uint64_to_next_multiple_of(onions_seen, ONIONS_SEEN_BIN_SIZE);
rounded_onions_seen = MIN(rounded_onions_seen, INT64_MAX);
obfuscated_onions_seen = add_laplace_noise((int64_t)rounded_onions_seen,
crypto_rand_double(), ONIONS_SEEN_DELTA_F,
ONIONS_SEEN_EPSILON);
format_iso_time(t, now);
- tor_asprintf(&hs_stats_string, "hidserv-stats-end %s (%d s)\n"
- "hidserv-rend-relayed-cells %"PRId64" delta_f=%d "
- "epsilon=%.2f bin_size=%d\n"
- "hidserv-dir-onions-seen %"PRId64" delta_f=%d "
- "epsilon=%.2f bin_size=%d\n",
+ tor_asprintf(&hs_stats_string, "%s %s (%u s)\n"
+ "%s %"PRId64" delta_f=%d epsilon=%.2f bin_size=%d\n"
+ "%s %"PRId64" delta_f=%d epsilon=%.2f bin_size=%d\n",
+ is_v3 ? "hidserv-v3-stats-end" : "hidserv-stats-end",
t, (unsigned) (now - start_of_hs_stats_interval),
- (obfuscated_cells_seen), REND_CELLS_DELTA_F,
+ is_v3 ?
+ "hidserv-rend-v3-relayed-cells" : "hidserv-rend-relayed-cells",
+ obfuscated_cells_seen, REND_CELLS_DELTA_F,
REND_CELLS_EPSILON, REND_CELLS_BIN_SIZE,
- (obfuscated_onions_seen),
- ONIONS_SEEN_DELTA_F,
+ is_v3 ? "hidserv-dir-v3-onions-seen" :"hidserv-dir-onions-seen",
+ obfuscated_onions_seen, ONIONS_SEEN_DELTA_F,
ONIONS_SEEN_EPSILON, ONIONS_SEEN_BIN_SIZE);
return hs_stats_string;
}
/** If 24 hours have passed since the beginning of the current HS
- * stats period, write buffer stats to $DATADIR/stats/hidserv-stats
+ * stats period, write buffer stats to $DATADIR/stats/hidserv-v3-stats
* (possibly overwriting an existing file) and reset counters. Return
* when we would next want to write buffer stats or 0 if we never want to
- * write. */
+ * write. Function works for both v2 and v3 stats depending on <b>is_v3</b>.
+ */
time_t
-rep_hist_hs_stats_write(time_t now)
+rep_hist_hs_stats_write(time_t now, bool is_v3)
{
char *str = NULL;
+ time_t start_of_hs_stats_interval = is_v3 ?
+ start_of_hs_v3_stats_interval : start_of_hs_v2_stats_interval;
+
if (!start_of_hs_stats_interval) {
return 0; /* Not initialized. */
}
@@ -1912,15 +2754,20 @@ rep_hist_hs_stats_write(time_t now)
}
/* Generate history string. */
- str = rep_hist_format_hs_stats(now);
+ str = rep_hist_format_hs_stats(now, is_v3);
/* Reset HS history. */
- rep_hist_reset_hs_stats(now);
+ if (is_v3) {
+ rep_hist_reset_hs_v3_stats(now);
+ } else {
+ rep_hist_reset_hs_v2_stats(now);
+ }
/* Try to write to disk. */
if (!check_or_create_data_subdir("stats")) {
- write_to_data_subdir("stats", "hidserv-stats", str,
- "hidden service stats");
+ write_to_data_subdir("stats",
+ is_v3 ? "hidserv-v3-stats" : "hidserv-stats",
+ str, "hidden service stats");
}
done:
@@ -2134,7 +2981,8 @@ rep_hist_log_link_protocol_counts(void)
void
rep_hist_free_all(void)
{
- hs_stats_free(hs_stats);
+ hs_v2_stats_free(hs_v2_stats);
+ hs_v3_stats_free(hs_v3_stats);
digestmap_free(history_map, free_or_history);
tor_free(exit_bytes_read);
@@ -2155,3 +3003,38 @@ rep_hist_free_all(void)
tor_assert_nonfatal(rephist_total_alloc == 0);
tor_assert_nonfatal_once(rephist_total_num == 0);
}
+
+/** Called just before the consensus will be replaced. Update the consensus
+ * parameters in case they changed. */
+void
+rep_hist_consensus_has_changed(const networkstatus_t *ns)
+{
+ overload_onionskin_ntor_fraction =
+ networkstatus_get_param(ns, "overload_onionskin_ntor_scale_percent",
+ OVERLOAD_ONIONSKIN_NTOR_PERCENT_DEFAULT,
+ OVERLOAD_ONIONSKIN_NTOR_PERCENT_MIN,
+ OVERLOAD_ONIONSKIN_NTOR_PERCENT_MAX) /
+ OVERLOAD_ONIONSKIN_NTOR_PERCENT_SCALE / 100.0;
+
+ overload_onionskin_ntor_period_secs =
+ networkstatus_get_param(ns, "overload_onionskin_ntor_period_secs",
+ OVERLOAD_ONIONSKIN_NTOR_PERIOD_SECS_DEFAULT,
+ OVERLOAD_ONIONSKIN_NTOR_PERIOD_SECS_MIN,
+ OVERLOAD_ONIONSKIN_NTOR_PERIOD_SECS_MAX);
+}
+
+#ifdef TOR_UNIT_TESTS
+/* only exists for unit tests: get HSv2 stats object */
+const hs_v2_stats_t *
+rep_hist_get_hs_v2_stats(void)
+{
+ return hs_v2_stats;
+}
+
+/* only exists for unit tests: get HSv2 stats object */
+const hs_v3_stats_t *
+rep_hist_get_hs_v3_stats(void)
+{
+ return hs_v3_stats;
+}
+#endif /* defined(TOR_UNIT_TESTS) */
diff --git a/src/feature/stats/rephist.h b/src/feature/stats/rephist.h
index c9ebc5c328..fbfab4c451 100644
--- a/src/feature/stats/rephist.h
+++ b/src/feature/stats/rephist.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -41,6 +41,16 @@ void rep_hist_note_exit_bytes(uint16_t port, size_t num_written,
size_t num_read);
void rep_hist_note_exit_stream_opened(uint16_t port);
+void rep_hist_note_conn_opened(bool initiated, unsigned int type, int af);
+void rep_hist_note_conn_closed(bool initiated, unsigned int type, int af);
+void rep_hist_note_conn_rejected(unsigned int type, int af);
+uint64_t rep_hist_get_conn_created(bool initiated, unsigned int type, int af);
+uint64_t rep_hist_get_conn_opened(bool initiated, unsigned int type, int af);
+uint64_t rep_hist_get_conn_rejected(unsigned int type, int af);
+
+void rep_hist_note_exit_stream(unsigned int cmd);
+uint64_t rep_hist_get_exit_stream_seen(unsigned int cmd);
+
void rep_hist_buffer_stats_init(time_t now);
void rep_hist_buffer_stats_add_circ(circuit_t *circ,
time_t end_of_interval);
@@ -58,17 +68,25 @@ time_t rep_hist_desc_stats_write(time_t now);
void rep_hist_note_circuit_handshake_requested(uint16_t type);
void rep_hist_note_circuit_handshake_assigned(uint16_t type);
+void rep_hist_note_circuit_handshake_dropped(uint16_t type);
void rep_hist_log_circuit_handshake_stats(time_t now);
MOCK_DECL(int, rep_hist_get_circuit_handshake_requested, (uint16_t type));
MOCK_DECL(int, rep_hist_get_circuit_handshake_assigned, (uint16_t type));
+MOCK_DECL(uint64_t, rep_hist_get_circuit_n_handshake_assigned,
+ (uint16_t type));
+MOCK_DECL(uint64_t, rep_hist_get_circuit_n_handshake_dropped,
+ (uint16_t type));
+
void rep_hist_hs_stats_init(time_t now);
void rep_hist_hs_stats_term(void);
-time_t rep_hist_hs_stats_write(time_t now);
-char *rep_hist_get_hs_stats_string(void);
-void rep_hist_seen_new_rp_cell(void);
-void rep_hist_stored_maybe_new_hs(const crypto_pk_t *pubkey);
+time_t rep_hist_hs_stats_write(time_t now, bool is_v3);
+
+void rep_hist_seen_new_rp_cell(bool is_v2);
+
+char *rep_hist_get_hs_v3_stats_string(void);
+void rep_hist_hsdir_stored_maybe_new_v3_onion(const uint8_t *blinded_key);
void rep_hist_free_all(void);
@@ -76,13 +94,54 @@ void rep_hist_note_negotiated_link_proto(unsigned link_proto,
int started_here);
void rep_hist_log_link_protocol_counts(void);
+uint64_t rep_hist_get_n_dns_error(int type, uint8_t error);
+uint64_t rep_hist_get_n_dns_request(int type);
+void rep_hist_note_dns_request(int type);
+void rep_hist_note_dns_error(int type, uint8_t error);
+
+void rep_hist_consensus_has_changed(const networkstatus_t *ns);
+
+/** We combine ntor and ntorv3 stats, so we have 3 stat types:
+ * tap, fast, and ntor. The max type is ntor (2) */
+#define MAX_ONION_STAT_TYPE ONION_HANDSHAKE_TYPE_NTOR
+
extern uint64_t rephist_total_alloc;
extern uint32_t rephist_total_num;
#ifdef TOR_UNIT_TESTS
-extern int onion_handshakes_requested[MAX_ONION_HANDSHAKE_TYPE+1];
-extern int onion_handshakes_assigned[MAX_ONION_HANDSHAKE_TYPE+1];
+extern int onion_handshakes_requested[MAX_ONION_STAT_TYPE+1];
+extern int onion_handshakes_assigned[MAX_ONION_STAT_TYPE+1];
#endif
+#ifdef REPHIST_PRIVATE
+/** Carries the various hidden service statistics, and any other
+ * information needed. */
+typedef struct hs_v2_stats_t {
+ /** How many v2 relay cells have we seen as rendezvous points? */
+ uint64_t rp_v2_relay_cells_seen;
+} hs_v2_stats_t;
+
+/** Structure that contains the various statistics we keep about v3
+ * services.
+ *
+ * Because of the time period logic of v3 services, v3 statistics are more
+ * sensitive to time than v2 stats. For this reason, we collect v3
+ * statistics strictly from 12:00UTC to 12:00UTC as dictated by
+ * 'start_of_hs_v3_stats_interval'.
+ **/
+typedef struct hs_v3_stats_t {
+ /** How many v3 relay cells have we seen as a rendezvous point? */
+ uint64_t rp_v3_relay_cells_seen;
+
+ /* The number of unique v3 onion descriptors (actually, unique v3 blind keys)
+ * we've seen during the measurement period */
+ digest256map_t *v3_onions_seen_this_period;
+} hs_v3_stats_t;
+
+MOCK_DECL(STATIC bool, should_collect_v3_stats,(void));
+
+STATIC char *rep_hist_format_hs_stats(time_t now, bool is_v3);
+#endif /* defined(REPHIST_PRIVATE) */
+
/**
* Represents the type of a cell for padding accounting
*/
@@ -108,4 +167,36 @@ void rep_hist_reset_padding_counts(void);
void rep_hist_prep_published_padding_counts(time_t now);
void rep_hist_padding_count_timers(uint64_t num_timers);
+/**
+ * Represents the various types of overload we keep track of and expose in our
+ * extra-info descriptor.
+*/
+typedef enum {
+ /* A general overload -- can have many different causes. */
+ OVERLOAD_GENERAL,
+ /* We went over our configured read rate/burst bandwidth limit */
+ OVERLOAD_READ,
+ /* We went over our configured write rate/burst bandwidth limit */
+ OVERLOAD_WRITE,
+ /* We exhausted the file descriptors in this system */
+ OVERLOAD_FD_EXHAUSTED,
+} overload_type_t;
+
+void rep_hist_note_overload(overload_type_t overload);
+char *rep_hist_get_overload_general_line(void);
+char *rep_hist_get_overload_stats_lines(void);
+
+void rep_hist_note_tcp_exhaustion(void);
+uint64_t rep_hist_get_n_tcp_exhaustion(void);
+
+uint64_t rep_hist_get_n_read_limit_reached(void);
+uint64_t rep_hist_get_n_write_limit_reached(void);
+
+#ifdef TOR_UNIT_TESTS
+struct hs_v2_stats_t;
+const struct hs_v2_stats_t *rep_hist_get_hs_v2_stats(void);
+struct hs_v3_stats_t;
+const struct hs_v3_stats_t *rep_hist_get_hs_v3_stats(void);
+#endif /* defined(TOR_UNIT_TESTS) */
+
#endif /* !defined(TOR_REPHIST_H) */
diff --git a/src/include.am b/src/include.am
index 0826da7548..36d323e6eb 100644
--- a/src/include.am
+++ b/src/include.am
@@ -85,7 +85,6 @@ include src/app/main/include.am
include src/core/include.am
include src/app/include.am
-include src/rust/include.am
include src/test/include.am
include src/tools/include.am
include src/win32/include.am
diff --git a/src/lib/arch/bytes.h b/src/lib/arch/bytes.h
index c72ac3eb8e..5c3c0b30ba 100644
--- a/src/lib/arch/bytes.h
+++ b/src/lib/arch/bytes.h
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#ifndef TOR_BYTES_H
diff --git a/src/lib/buf/buffers.c b/src/lib/buf/buffers.c
index e9d5f7f031..e0faa84099 100644
--- a/src/lib/buf/buffers.c
+++ b/src/lib/buf/buffers.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/buf/buffers.h b/src/lib/buf/buffers.h
index 1361a02eba..01cb2346b6 100644
--- a/src/lib/buf/buffers.h
+++ b/src/lib/buf/buffers.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/cc/compat_compiler.h b/src/lib/cc/compat_compiler.h
index 96aa912652..991b33d9e7 100644
--- a/src/lib/cc/compat_compiler.h
+++ b/src/lib/cc/compat_compiler.h
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -15,6 +15,15 @@
#include "orconfig.h"
#include <inttypes.h>
+#if defined(__MINGW32__) || defined(__MINGW64__)
+#define MINGW_ANY
+#endif
+
+#ifdef MINGW_ANY
+/* We need this for __MINGW_PRINTF_FORMAT, alas. */
+#include <stdio.h>
+#endif
+
#if defined(__has_feature)
# if __has_feature(address_sanitizer)
/* Some of the fancy glibc strcmp() macros include references to memory that
@@ -36,16 +45,30 @@
#error "It seems that you encode characters in something other than ASCII."
#endif
+/* Use the right magic attribute on mingw, which might be printf, gnu_printf,
+ * or ms_printf, depending on how we're set up to build.
+ */
+#ifdef __MINGW_PRINTF_FORMAT
+#define PRINTF_FORMAT_ATTR __MINGW_PRINTF_FORMAT
+#else
+#define PRINTF_FORMAT_ATTR printf
+#endif
+#ifdef __MINGW_SCANF_FORMAT
+#define SCANF_FORMAT_ATTR __MINGW_SCANF_FORMAT
+#else
+#define SCANF_FORMAT_ATTR scanf
+#endif
+
/* GCC can check printf and scanf types on arbitrary functions. */
#ifdef __GNUC__
#define CHECK_PRINTF(formatIdx, firstArg) \
- __attribute__ ((format(printf, formatIdx, firstArg)))
+ __attribute__ ((format(PRINTF_FORMAT_ATTR, formatIdx, firstArg)))
#else
#define CHECK_PRINTF(formatIdx, firstArg)
#endif /* defined(__GNUC__) */
#ifdef __GNUC__
#define CHECK_SCANF(formatIdx, firstArg) \
- __attribute__ ((format(scanf, formatIdx, firstArg)))
+ __attribute__ ((format(SCANF_FORMAT_ATTR, formatIdx, firstArg)))
#else
#define CHECK_SCANF(formatIdx, firstArg)
#endif /* defined(__GNUC__) */
@@ -191,10 +214,6 @@
#define OP_EQ ==
#define OP_NE !=
-#if defined(__MINGW32__) || defined(__MINGW64__)
-#define MINGW_ANY
-#endif
-
/** Macro: yield a pointer to the field at position <b>off</b> within the
* structure <b>st</b>. Example:
* <pre>
diff --git a/src/lib/cc/tokpaste.h b/src/lib/cc/tokpaste.h
index 068621b5bd..e64f2757e9 100644
--- a/src/lib/cc/tokpaste.h
+++ b/src/lib/cc/tokpaste.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/cc/torint.h b/src/lib/cc/torint.h
index af7a90431c..f551c01454 100644
--- a/src/lib/cc/torint.h
+++ b/src/lib/cc/torint.h
@@ -1,6 +1,6 @@
/* Copyright (c) 2003, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/compress/compress.c b/src/lib/compress/compress.c
index 7ce3910d84..83e63905cc 100644
--- a/src/lib/compress/compress.c
+++ b/src/lib/compress/compress.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/compress/compress.h b/src/lib/compress/compress.h
index f36cdb82aa..c15434a1ae 100644
--- a/src/lib/compress/compress.h
+++ b/src/lib/compress/compress.h
@@ -1,6 +1,6 @@
/* Copyright (c) 2003, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/compress/compress_buf.c b/src/lib/compress/compress_buf.c
index d1941c9da6..51cca0e7ae 100644
--- a/src/lib/compress/compress_buf.c
+++ b/src/lib/compress/compress_buf.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2003, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/compress/compress_lzma.c b/src/lib/compress/compress_lzma.c
index 0cb1ece761..6ae8fd8109 100644
--- a/src/lib/compress/compress_lzma.c
+++ b/src/lib/compress/compress_lzma.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/compress/compress_lzma.h b/src/lib/compress/compress_lzma.h
index de03cda91c..c615968378 100644
--- a/src/lib/compress/compress_lzma.h
+++ b/src/lib/compress/compress_lzma.h
@@ -1,6 +1,6 @@
/* Copyright (c) 2003, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/compress/compress_none.c b/src/lib/compress/compress_none.c
index 43c021c788..f7d065e5c8 100644
--- a/src/lib/compress/compress_none.c
+++ b/src/lib/compress/compress_none.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/compress/compress_none.h b/src/lib/compress/compress_none.h
index df696a11aa..90b27ff58f 100644
--- a/src/lib/compress/compress_none.h
+++ b/src/lib/compress/compress_none.h
@@ -1,6 +1,6 @@
/* Copyright (c) 2003, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/compress/compress_sys.h b/src/lib/compress/compress_sys.h
index dce0549924..8d149133af 100644
--- a/src/lib/compress/compress_sys.h
+++ b/src/lib/compress/compress_sys.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2018-2020, The Tor Project, Inc. */
+/* Copyright (c) 2018-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/compress/compress_zlib.c b/src/lib/compress/compress_zlib.c
index 3711e46222..52f95090fe 100644
--- a/src/lib/compress/compress_zlib.c
+++ b/src/lib/compress/compress_zlib.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/compress/compress_zlib.h b/src/lib/compress/compress_zlib.h
index 7328ce899b..f683c496c6 100644
--- a/src/lib/compress/compress_zlib.h
+++ b/src/lib/compress/compress_zlib.h
@@ -1,6 +1,6 @@
/* Copyright (c) 2003, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/compress/compress_zstd.c b/src/lib/compress/compress_zstd.c
index 61c684068e..34a2e806f6 100644
--- a/src/lib/compress/compress_zstd.c
+++ b/src/lib/compress/compress_zstd.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/compress/compress_zstd.h b/src/lib/compress/compress_zstd.h
index 0fc71db749..46a8be0e45 100644
--- a/src/lib/compress/compress_zstd.h
+++ b/src/lib/compress/compress_zstd.h
@@ -1,6 +1,6 @@
/* Copyright (c) 2003, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/conf/confdecl.h b/src/lib/conf/confdecl.h
index c2d3fb335d..f7ab788636 100644
--- a/src/lib/conf/confdecl.h
+++ b/src/lib/conf/confdecl.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/conf/confmacros.h b/src/lib/conf/confmacros.h
index 9f85d21740..71b272d212 100644
--- a/src/lib/conf/confmacros.h
+++ b/src/lib/conf/confmacros.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/conf/conftesting.h b/src/lib/conf/conftesting.h
index 4707c919d3..0b4a720ae8 100644
--- a/src/lib/conf/conftesting.h
+++ b/src/lib/conf/conftesting.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/conf/conftypes.h b/src/lib/conf/conftypes.h
index 2207508ef9..d05a0e3c8c 100644
--- a/src/lib/conf/conftypes.h
+++ b/src/lib/conf/conftypes.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/confmgt/confmgt.c b/src/lib/confmgt/confmgt.c
index bf2764160e..19f0a5e517 100644
--- a/src/lib/confmgt/confmgt.c
+++ b/src/lib/confmgt/confmgt.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/confmgt/confmgt.h b/src/lib/confmgt/confmgt.h
index 5065c13b60..ae04fab604 100644
--- a/src/lib/confmgt/confmgt.h
+++ b/src/lib/confmgt/confmgt.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/confmgt/structvar.c b/src/lib/confmgt/structvar.c
index 55deb4759c..d522456ed8 100644
--- a/src/lib/confmgt/structvar.c
+++ b/src/lib/confmgt/structvar.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/confmgt/structvar.h b/src/lib/confmgt/structvar.h
index 91334fa8c5..f04fd62eb8 100644
--- a/src/lib/confmgt/structvar.h
+++ b/src/lib/confmgt/structvar.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/confmgt/type_defs.c b/src/lib/confmgt/type_defs.c
index d9e5e1e4c2..d17e97dd86 100644
--- a/src/lib/confmgt/type_defs.c
+++ b/src/lib/confmgt/type_defs.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/confmgt/type_defs.h b/src/lib/confmgt/type_defs.h
index fec002b1d3..f913125e50 100644
--- a/src/lib/confmgt/type_defs.h
+++ b/src/lib/confmgt/type_defs.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/confmgt/typedvar.c b/src/lib/confmgt/typedvar.c
index 240c03a316..b6c247ccfe 100644
--- a/src/lib/confmgt/typedvar.c
+++ b/src/lib/confmgt/typedvar.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/confmgt/typedvar.h b/src/lib/confmgt/typedvar.h
index cc90ed10a3..21d6d16216 100644
--- a/src/lib/confmgt/typedvar.h
+++ b/src/lib/confmgt/typedvar.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/confmgt/unitparse.c b/src/lib/confmgt/unitparse.c
index 99716e8d9d..a0cfacaab2 100644
--- a/src/lib/confmgt/unitparse.c
+++ b/src/lib/confmgt/unitparse.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/confmgt/unitparse.h b/src/lib/confmgt/unitparse.h
index 047e11b424..d211c9d14d 100644
--- a/src/lib/confmgt/unitparse.h
+++ b/src/lib/confmgt/unitparse.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/confmgt/var_type_def_st.h b/src/lib/confmgt/var_type_def_st.h
index 2519b86aa0..1c8f8f5d84 100644
--- a/src/lib/confmgt/var_type_def_st.h
+++ b/src/lib/confmgt/var_type_def_st.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/container/bitarray.h b/src/lib/container/bitarray.h
index 41409e350a..7052cf38b7 100644
--- a/src/lib/container/bitarray.h
+++ b/src/lib/container/bitarray.h
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#ifndef TOR_BITARRAY_H
diff --git a/src/lib/container/bloomfilt.c b/src/lib/container/bloomfilt.c
index 34b1265d81..ace3f6786e 100644
--- a/src/lib/container/bloomfilt.c
+++ b/src/lib/container/bloomfilt.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/container/bloomfilt.h b/src/lib/container/bloomfilt.h
index 6d36056b5a..6a4f3632fe 100644
--- a/src/lib/container/bloomfilt.h
+++ b/src/lib/container/bloomfilt.h
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#ifndef TOR_BLOOMFILT_H
diff --git a/src/lib/container/handles.h b/src/lib/container/handles.h
index 6b1bbd5167..6acdbdc3b9 100644
--- a/src/lib/container/handles.h
+++ b/src/lib/container/handles.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2020, The Tor Project, Inc. */
+/* Copyright (c) 2016-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/container/map.c b/src/lib/container/map.c
index 7db84313ea..2067886286 100644
--- a/src/lib/container/map.c
+++ b/src/lib/container/map.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/container/map.h b/src/lib/container/map.h
index dbc1967247..a1b6948293 100644
--- a/src/lib/container/map.h
+++ b/src/lib/container/map.h
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#ifndef TOR_MAP_H
diff --git a/src/lib/container/namemap.c b/src/lib/container/namemap.c
index 5299c78e83..1676209e14 100644
--- a/src/lib/container/namemap.c
+++ b/src/lib/container/namemap.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/container/namemap.h b/src/lib/container/namemap.h
index b451c18c68..ad36988f70 100644
--- a/src/lib/container/namemap.h
+++ b/src/lib/container/namemap.h
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#ifndef TOR_NAMEMAP_H
diff --git a/src/lib/container/namemap_st.h b/src/lib/container/namemap_st.h
index 39aa85cc09..e9cafe8f53 100644
--- a/src/lib/container/namemap_st.h
+++ b/src/lib/container/namemap_st.h
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#ifndef NAMEMAP_ST_H
diff --git a/src/lib/container/order.c b/src/lib/container/order.c
index cac241f027..2ff166ce07 100644
--- a/src/lib/container/order.c
+++ b/src/lib/container/order.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/container/order.h b/src/lib/container/order.h
index 5bca095f35..fccee86541 100644
--- a/src/lib/container/order.h
+++ b/src/lib/container/order.h
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#ifndef TOR_ORDER_H
diff --git a/src/lib/container/smartlist.c b/src/lib/container/smartlist.c
index 7784f83957..aa85d7ddc6 100644
--- a/src/lib/container/smartlist.c
+++ b/src/lib/container/smartlist.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/container/smartlist.h b/src/lib/container/smartlist.h
index 458d564cd5..b9caa19c72 100644
--- a/src/lib/container/smartlist.h
+++ b/src/lib/container/smartlist.h
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#ifndef TOR_SMARTLIST_H
diff --git a/src/lib/crypt_ops/aes.h b/src/lib/crypt_ops/aes.h
index c25417b4e6..d712b77136 100644
--- a/src/lib/crypt_ops/aes.h
+++ b/src/lib/crypt_ops/aes.h
@@ -1,6 +1,6 @@
/* Copyright (c) 2003, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/* Implements a minimal interface to counter-mode AES. */
diff --git a/src/lib/crypt_ops/aes_nss.c b/src/lib/crypt_ops/aes_nss.c
index 71d2f01449..7e4fe5ac26 100644
--- a/src/lib/crypt_ops/aes_nss.c
+++ b/src/lib/crypt_ops/aes_nss.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001, Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/crypt_ops/aes_openssl.c b/src/lib/crypt_ops/aes_openssl.c
index 502f7703bd..ca8c5aca1a 100644
--- a/src/lib/crypt_ops/aes_openssl.c
+++ b/src/lib/crypt_ops/aes_openssl.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001, Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/crypt_ops/compat_openssl.h b/src/lib/crypt_ops/compat_openssl.h
index aa66e0c3fa..0f56f338b5 100644
--- a/src/lib/crypt_ops/compat_openssl.h
+++ b/src/lib/crypt_ops/compat_openssl.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001, Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#ifndef TOR_COMPAT_OPENSSL_H
diff --git a/src/lib/crypt_ops/crypto_cipher.c b/src/lib/crypt_ops/crypto_cipher.c
index 0a24a580ae..cfece770a1 100644
--- a/src/lib/crypt_ops/crypto_cipher.c
+++ b/src/lib/crypt_ops/crypto_cipher.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001, Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/crypt_ops/crypto_cipher.h b/src/lib/crypt_ops/crypto_cipher.h
index 1e22a7c138..107e4b83b9 100644
--- a/src/lib/crypt_ops/crypto_cipher.h
+++ b/src/lib/crypt_ops/crypto_cipher.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001, Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/crypt_ops/crypto_curve25519.c b/src/lib/crypt_ops/crypto_curve25519.c
index 2a2589f07d..a20eaf4bf7 100644
--- a/src/lib/crypt_ops/crypto_curve25519.c
+++ b/src/lib/crypt_ops/crypto_curve25519.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2020, The Tor Project, Inc. */
+/* Copyright (c) 2012-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/crypt_ops/crypto_curve25519.h b/src/lib/crypt_ops/crypto_curve25519.h
index f1e5d1265d..146945fa24 100644
--- a/src/lib/crypt_ops/crypto_curve25519.h
+++ b/src/lib/crypt_ops/crypto_curve25519.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2020, The Tor Project, Inc. */
+/* Copyright (c) 2012-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/crypt_ops/crypto_dh.c b/src/lib/crypt_ops/crypto_dh.c
index 086aceed6f..d0805d834d 100644
--- a/src/lib/crypt_ops/crypto_dh.c
+++ b/src/lib/crypt_ops/crypto_dh.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001, Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/crypt_ops/crypto_dh.h b/src/lib/crypt_ops/crypto_dh.h
index 2a0e1f6912..6083566306 100644
--- a/src/lib/crypt_ops/crypto_dh.h
+++ b/src/lib/crypt_ops/crypto_dh.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001, Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/crypt_ops/crypto_dh_nss.c b/src/lib/crypt_ops/crypto_dh_nss.c
index e5d070397d..e0bed5c7e7 100644
--- a/src/lib/crypt_ops/crypto_dh_nss.c
+++ b/src/lib/crypt_ops/crypto_dh_nss.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001, Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/crypt_ops/crypto_dh_openssl.c b/src/lib/crypt_ops/crypto_dh_openssl.c
index f05afd8497..b2bebd2655 100644
--- a/src/lib/crypt_ops/crypto_dh_openssl.c
+++ b/src/lib/crypt_ops/crypto_dh_openssl.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001, Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/crypt_ops/crypto_digest.c b/src/lib/crypt_ops/crypto_digest.c
index 7775e69410..3e165c2ce2 100644
--- a/src/lib/crypt_ops/crypto_digest.c
+++ b/src/lib/crypt_ops/crypto_digest.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001, Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/crypt_ops/crypto_digest.h b/src/lib/crypt_ops/crypto_digest.h
index eefd2e3f0a..f810961357 100644
--- a/src/lib/crypt_ops/crypto_digest.h
+++ b/src/lib/crypt_ops/crypto_digest.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001, Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/crypt_ops/crypto_digest_nss.c b/src/lib/crypt_ops/crypto_digest_nss.c
index 92c20fe9e8..5e70ebe734 100644
--- a/src/lib/crypt_ops/crypto_digest_nss.c
+++ b/src/lib/crypt_ops/crypto_digest_nss.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001, Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/crypt_ops/crypto_digest_openssl.c b/src/lib/crypt_ops/crypto_digest_openssl.c
index 11189c7fb2..f71e4d0dcd 100644
--- a/src/lib/crypt_ops/crypto_digest_openssl.c
+++ b/src/lib/crypt_ops/crypto_digest_openssl.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001, Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/crypt_ops/crypto_ed25519.c b/src/lib/crypt_ops/crypto_ed25519.c
index 5823b4e557..1f02b86880 100644
--- a/src/lib/crypt_ops/crypto_ed25519.c
+++ b/src/lib/crypt_ops/crypto_ed25519.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2020, The Tor Project, Inc. */
+/* Copyright (c) 2013-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/crypt_ops/crypto_ed25519.h b/src/lib/crypt_ops/crypto_ed25519.h
index 346de464e3..34b3584b32 100644
--- a/src/lib/crypt_ops/crypto_ed25519.h
+++ b/src/lib/crypt_ops/crypto_ed25519.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2020, The Tor Project, Inc. */
+/* Copyright (c) 2012-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/crypt_ops/crypto_format.c b/src/lib/crypt_ops/crypto_format.c
index 4483b7d2f5..73c4f25f0d 100644
--- a/src/lib/crypt_ops/crypto_format.c
+++ b/src/lib/crypt_ops/crypto_format.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001, Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/crypt_ops/crypto_format.h b/src/lib/crypt_ops/crypto_format.h
index 91da137e1c..c539905955 100644
--- a/src/lib/crypt_ops/crypto_format.h
+++ b/src/lib/crypt_ops/crypto_format.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001, Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/crypt_ops/crypto_hkdf.c b/src/lib/crypt_ops/crypto_hkdf.c
index 7b02820087..ffdf71933d 100644
--- a/src/lib/crypt_ops/crypto_hkdf.c
+++ b/src/lib/crypt_ops/crypto_hkdf.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001, Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/crypt_ops/crypto_hkdf.h b/src/lib/crypt_ops/crypto_hkdf.h
index 404f548774..6501316d80 100644
--- a/src/lib/crypt_ops/crypto_hkdf.h
+++ b/src/lib/crypt_ops/crypto_hkdf.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001, Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/crypt_ops/crypto_init.c b/src/lib/crypt_ops/crypto_init.c
index a836bd8645..ef9908c893 100644
--- a/src/lib/crypt_ops/crypto_init.c
+++ b/src/lib/crypt_ops/crypto_init.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001, Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/crypt_ops/crypto_init.h b/src/lib/crypt_ops/crypto_init.h
index b11e2e34bf..5ef63fbef2 100644
--- a/src/lib/crypt_ops/crypto_init.h
+++ b/src/lib/crypt_ops/crypto_init.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001, Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/crypt_ops/crypto_nss_mgt.c b/src/lib/crypt_ops/crypto_nss_mgt.c
index d82e51249c..73580cd883 100644
--- a/src/lib/crypt_ops/crypto_nss_mgt.c
+++ b/src/lib/crypt_ops/crypto_nss_mgt.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001, Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/crypt_ops/crypto_nss_mgt.h b/src/lib/crypt_ops/crypto_nss_mgt.h
index 8686b1b8aa..80d1c78c6a 100644
--- a/src/lib/crypt_ops/crypto_nss_mgt.h
+++ b/src/lib/crypt_ops/crypto_nss_mgt.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001, Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/crypt_ops/crypto_ope.c b/src/lib/crypt_ops/crypto_ope.c
index 4cacb3dd98..e108727c34 100644
--- a/src/lib/crypt_ops/crypto_ope.c
+++ b/src/lib/crypt_ops/crypto_ope.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2018-2020, The Tor Project, Inc. */
+/* Copyright (c) 2018-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/crypt_ops/crypto_ope.h b/src/lib/crypt_ops/crypto_ope.h
index 7498ea6a2e..f1ceaff5a5 100644
--- a/src/lib/crypt_ops/crypto_ope.h
+++ b/src/lib/crypt_ops/crypto_ope.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2018-2020, The Tor Project, Inc. */
+/* Copyright (c) 2018-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/crypt_ops/crypto_openssl_mgt.c b/src/lib/crypt_ops/crypto_openssl_mgt.c
index e763491a11..6c01cb6aa8 100644
--- a/src/lib/crypt_ops/crypto_openssl_mgt.c
+++ b/src/lib/crypt_ops/crypto_openssl_mgt.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001, Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -106,7 +106,7 @@ crypto_openssl_get_version_str(void)
#else
/* This old name was changed around OpenSSL 1.1.0 */
const int query = SSLEAY_VERSION;
-#endif
+#endif /* defined(OPENSSL_VERSION) */
if (crypto_openssl_version_str == NULL) {
const char *raw_version = OpenSSL_version(query);
diff --git a/src/lib/crypt_ops/crypto_openssl_mgt.h b/src/lib/crypt_ops/crypto_openssl_mgt.h
index 91df084a15..c6f63ffa08 100644
--- a/src/lib/crypt_ops/crypto_openssl_mgt.h
+++ b/src/lib/crypt_ops/crypto_openssl_mgt.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001, Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/crypt_ops/crypto_options_st.h b/src/lib/crypt_ops/crypto_options_st.h
index a453c451fe..6e4d9147e5 100644
--- a/src/lib/crypt_ops/crypto_options_st.h
+++ b/src/lib/crypt_ops/crypto_options_st.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/crypt_ops/crypto_pwbox.c b/src/lib/crypt_ops/crypto_pwbox.c
index bfad27d9fc..792cc11e18 100644
--- a/src/lib/crypt_ops/crypto_pwbox.c
+++ b/src/lib/crypt_ops/crypto_pwbox.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2020, The Tor Project, Inc. */
+/* Copyright (c) 2014-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/crypt_ops/crypto_pwbox.h b/src/lib/crypt_ops/crypto_pwbox.h
index 0a85b1230a..41ee4f9e18 100644
--- a/src/lib/crypt_ops/crypto_pwbox.h
+++ b/src/lib/crypt_ops/crypto_pwbox.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2020, The Tor Project, Inc. */
+/* Copyright (c) 2014-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/crypt_ops/crypto_rand.c b/src/lib/crypt_ops/crypto_rand.c
index b1e3dcb6fa..f39ee6c24f 100644
--- a/src/lib/crypt_ops/crypto_rand.c
+++ b/src/lib/crypt_ops/crypto_rand.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001, Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -568,6 +568,8 @@ crypto_random_hostname(int min_rand_len, int max_rand_len, const char *prefix,
prefixlen = strlen(prefix);
resultlen = prefixlen + strlen(suffix) + randlen + 16;
+ /* (x+(n-1))/n is an idiom for dividing x by n, rounding up to the nearest
+ * integer and thus why this construction. */
rand_bytes_len = ((randlen*5)+7)/8;
if (rand_bytes_len % 5)
rand_bytes_len += 5 - (rand_bytes_len%5);
diff --git a/src/lib/crypt_ops/crypto_rand.h b/src/lib/crypt_ops/crypto_rand.h
index 99aff5d4a9..aea1428673 100644
--- a/src/lib/crypt_ops/crypto_rand.h
+++ b/src/lib/crypt_ops/crypto_rand.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001, Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/crypt_ops/crypto_rand_fast.c b/src/lib/crypt_ops/crypto_rand_fast.c
index 172ea48bdb..d1e7380a34 100644
--- a/src/lib/crypt_ops/crypto_rand_fast.c
+++ b/src/lib/crypt_ops/crypto_rand_fast.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001, Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/crypt_ops/crypto_rsa.c b/src/lib/crypt_ops/crypto_rsa.c
index 195e4bbaf9..24258cbb65 100644
--- a/src/lib/crypt_ops/crypto_rsa.c
+++ b/src/lib/crypt_ops/crypto_rsa.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001, Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/crypt_ops/crypto_rsa.h b/src/lib/crypt_ops/crypto_rsa.h
index ab2e9db80d..07da2e1846 100644
--- a/src/lib/crypt_ops/crypto_rsa.h
+++ b/src/lib/crypt_ops/crypto_rsa.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001, Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/crypt_ops/crypto_rsa_nss.c b/src/lib/crypt_ops/crypto_rsa_nss.c
index d316910b32..bda35ec1ea 100644
--- a/src/lib/crypt_ops/crypto_rsa_nss.c
+++ b/src/lib/crypt_ops/crypto_rsa_nss.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001, Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/crypt_ops/crypto_rsa_openssl.c b/src/lib/crypt_ops/crypto_rsa_openssl.c
index c96ee81fd3..a21c4a65cf 100644
--- a/src/lib/crypt_ops/crypto_rsa_openssl.c
+++ b/src/lib/crypt_ops/crypto_rsa_openssl.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001, Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/crypt_ops/crypto_s2k.c b/src/lib/crypt_ops/crypto_s2k.c
index cdd8eb3a15..ae781f24ef 100644
--- a/src/lib/crypt_ops/crypto_s2k.c
+++ b/src/lib/crypt_ops/crypto_s2k.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001, Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/crypt_ops/crypto_s2k.h b/src/lib/crypt_ops/crypto_s2k.h
index 181a17acb1..6dce855cad 100644
--- a/src/lib/crypt_ops/crypto_s2k.h
+++ b/src/lib/crypt_ops/crypto_s2k.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001, Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/crypt_ops/crypto_sys.h b/src/lib/crypt_ops/crypto_sys.h
index 2115d4fc99..7900767058 100644
--- a/src/lib/crypt_ops/crypto_sys.h
+++ b/src/lib/crypt_ops/crypto_sys.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2018-2020, The Tor Project, Inc. */
+/* Copyright (c) 2018-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/crypt_ops/crypto_util.c b/src/lib/crypt_ops/crypto_util.c
index 7ebb860d09..37d3a75ba5 100644
--- a/src/lib/crypt_ops/crypto_util.c
+++ b/src/lib/crypt_ops/crypto_util.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001, Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/crypt_ops/crypto_util.h b/src/lib/crypt_ops/crypto_util.h
index 36ee230176..fb9b3ed6c2 100644
--- a/src/lib/crypt_ops/crypto_util.h
+++ b/src/lib/crypt_ops/crypto_util.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001, Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/crypt_ops/digestset.c b/src/lib/crypt_ops/digestset.c
index 5162d6d8bd..c5be83497b 100644
--- a/src/lib/crypt_ops/digestset.c
+++ b/src/lib/crypt_ops/digestset.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2018-2020, The Tor Project, Inc. */
+/* Copyright (c) 2018-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/crypt_ops/digestset.h b/src/lib/crypt_ops/digestset.h
index 505ac10395..76e6045c98 100644
--- a/src/lib/crypt_ops/digestset.h
+++ b/src/lib/crypt_ops/digestset.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2018-2020, The Tor Project, Inc. */
+/* Copyright (c) 2018-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/ctime/di_ops.c b/src/lib/ctime/di_ops.c
index d57d286990..a6d69d4f91 100644
--- a/src/lib/ctime/di_ops.c
+++ b/src/lib/ctime/di_ops.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2020, The Tor Project, Inc. */
+/* Copyright (c) 2011-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/ctime/di_ops.h b/src/lib/ctime/di_ops.h
index 9fe2884ecc..ac2800be57 100644
--- a/src/lib/ctime/di_ops.h
+++ b/src/lib/ctime/di_ops.h
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/defs/dh_sizes.h b/src/lib/defs/dh_sizes.h
index bc2707b36f..4fc85cf3bd 100644
--- a/src/lib/defs/dh_sizes.h
+++ b/src/lib/defs/dh_sizes.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001, Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/defs/digest_sizes.h b/src/lib/defs/digest_sizes.h
index 7eef1747db..d24369fb1f 100644
--- a/src/lib/defs/digest_sizes.h
+++ b/src/lib/defs/digest_sizes.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001, Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#ifndef TOR_DIGEST_SIZES_H
diff --git a/src/lib/defs/logging_types.h b/src/lib/defs/logging_types.h
index 33aa46186b..f7876df3b5 100644
--- a/src/lib/defs/logging_types.h
+++ b/src/lib/defs/logging_types.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001, Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/defs/time.h b/src/lib/defs/time.h
index 5707330795..c9044e440f 100644
--- a/src/lib/defs/time.h
+++ b/src/lib/defs/time.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001, Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#ifndef TOR_TIME_DEFS_H
diff --git a/src/lib/defs/x25519_sizes.h b/src/lib/defs/x25519_sizes.h
index e650f5a350..b278a5ee51 100644
--- a/src/lib/defs/x25519_sizes.h
+++ b/src/lib/defs/x25519_sizes.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001, Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/dispatch/dispatch.h b/src/lib/dispatch/dispatch.h
index 63e96bcf8d..1c041c6eeb 100644
--- a/src/lib/dispatch/dispatch.h
+++ b/src/lib/dispatch/dispatch.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001, Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#ifndef TOR_DISPATCH_H
diff --git a/src/lib/dispatch/dispatch_cfg.c b/src/lib/dispatch/dispatch_cfg.c
index a54188dcaa..15b65af9ad 100644
--- a/src/lib/dispatch/dispatch_cfg.c
+++ b/src/lib/dispatch/dispatch_cfg.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001, Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/dispatch/dispatch_cfg.h b/src/lib/dispatch/dispatch_cfg.h
index a4f1948eac..f4f585bcd4 100644
--- a/src/lib/dispatch/dispatch_cfg.h
+++ b/src/lib/dispatch/dispatch_cfg.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001, Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#ifndef TOR_DISPATCH_CFG_H
diff --git a/src/lib/dispatch/dispatch_cfg_st.h b/src/lib/dispatch/dispatch_cfg_st.h
index 3c99adf2f7..636f2e6df5 100644
--- a/src/lib/dispatch/dispatch_cfg_st.h
+++ b/src/lib/dispatch/dispatch_cfg_st.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001, Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/dispatch/dispatch_core.c b/src/lib/dispatch/dispatch_core.c
index 3d51c876a7..687ba5b73c 100644
--- a/src/lib/dispatch/dispatch_core.c
+++ b/src/lib/dispatch/dispatch_core.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001, Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/dispatch/dispatch_naming.c b/src/lib/dispatch/dispatch_naming.c
index bb49343712..9fd1e67d0a 100644
--- a/src/lib/dispatch/dispatch_naming.c
+++ b/src/lib/dispatch/dispatch_naming.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001, Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/dispatch/dispatch_naming.h b/src/lib/dispatch/dispatch_naming.h
index 72206d3ed5..ebed09b66d 100644
--- a/src/lib/dispatch/dispatch_naming.h
+++ b/src/lib/dispatch/dispatch_naming.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001, Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/dispatch/dispatch_new.c b/src/lib/dispatch/dispatch_new.c
index e1dbb1c4b8..b5ef2557ec 100644
--- a/src/lib/dispatch/dispatch_new.c
+++ b/src/lib/dispatch/dispatch_new.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001, Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/dispatch/dispatch_st.h b/src/lib/dispatch/dispatch_st.h
index ad5b4efc40..e520056622 100644
--- a/src/lib/dispatch/dispatch_st.h
+++ b/src/lib/dispatch/dispatch_st.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001, Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/dispatch/msgtypes.h b/src/lib/dispatch/msgtypes.h
index 01d969dcb5..aecb114ece 100644
--- a/src/lib/dispatch/msgtypes.h
+++ b/src/lib/dispatch/msgtypes.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001, Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/encoding/binascii.c b/src/lib/encoding/binascii.c
index 5f68da183f..1b87b4fc2b 100644
--- a/src/lib/encoding/binascii.c
+++ b/src/lib/encoding/binascii.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001, Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/encoding/binascii.h b/src/lib/encoding/binascii.h
index 9cb03bab62..d8ee39c7b2 100644
--- a/src/lib/encoding/binascii.h
+++ b/src/lib/encoding/binascii.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001, Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/encoding/confline.c b/src/lib/encoding/confline.c
index 613e4a00c6..b9dcbbe25f 100644
--- a/src/lib/encoding/confline.c
+++ b/src/lib/encoding/confline.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/encoding/confline.h b/src/lib/encoding/confline.h
index ce0d6c6e17..ce2d0c5454 100644
--- a/src/lib/encoding/confline.h
+++ b/src/lib/encoding/confline.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/encoding/cstring.c b/src/lib/encoding/cstring.c
index 54c330fca3..f922fc819c 100644
--- a/src/lib/encoding/cstring.c
+++ b/src/lib/encoding/cstring.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/encoding/cstring.h b/src/lib/encoding/cstring.h
index 2a3f6d0fc4..8f6c9e1d27 100644
--- a/src/lib/encoding/cstring.h
+++ b/src/lib/encoding/cstring.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/encoding/keyval.c b/src/lib/encoding/keyval.c
index 0eb1219d43..5dc7f96d66 100644
--- a/src/lib/encoding/keyval.c
+++ b/src/lib/encoding/keyval.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2003, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/encoding/keyval.h b/src/lib/encoding/keyval.h
index b4966b01de..a5ba14ace9 100644
--- a/src/lib/encoding/keyval.h
+++ b/src/lib/encoding/keyval.h
@@ -1,6 +1,6 @@
/* Copyright (c) 2003, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/encoding/kvline.c b/src/lib/encoding/kvline.c
index 5b220605d6..398eaa5503 100644
--- a/src/lib/encoding/kvline.c
+++ b/src/lib/encoding/kvline.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/encoding/kvline.h b/src/lib/encoding/kvline.h
index 34c52908e3..1cda49397d 100644
--- a/src/lib/encoding/kvline.h
+++ b/src/lib/encoding/kvline.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/encoding/pem.c b/src/lib/encoding/pem.c
index 6c9f10e085..9756075edb 100644
--- a/src/lib/encoding/pem.c
+++ b/src/lib/encoding/pem.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001, Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/encoding/pem.h b/src/lib/encoding/pem.h
index 027c31c315..c8ac13dd91 100644
--- a/src/lib/encoding/pem.h
+++ b/src/lib/encoding/pem.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001, Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/encoding/qstring.c b/src/lib/encoding/qstring.c
index 5a34924eab..d1a4379b1c 100644
--- a/src/lib/encoding/qstring.c
+++ b/src/lib/encoding/qstring.c
@@ -1,5 +1,5 @@
/* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/encoding/qstring.h b/src/lib/encoding/qstring.h
index f19a7dad87..1a75a7ccc1 100644
--- a/src/lib/encoding/qstring.h
+++ b/src/lib/encoding/qstring.h
@@ -1,5 +1,5 @@
/* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/encoding/time_fmt.c b/src/lib/encoding/time_fmt.c
index 5e58d36698..136158ab1b 100644
--- a/src/lib/encoding/time_fmt.c
+++ b/src/lib/encoding/time_fmt.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001, Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/encoding/time_fmt.h b/src/lib/encoding/time_fmt.h
index 4adccb5990..aaf8ba7af0 100644
--- a/src/lib/encoding/time_fmt.h
+++ b/src/lib/encoding/time_fmt.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001, Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/err/backtrace.c b/src/lib/err/backtrace.c
index afb6b9503f..9987a51f0a 100644
--- a/src/lib/err/backtrace.c
+++ b/src/lib/err/backtrace.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2020, The Tor Project, Inc. */
+/* Copyright (c) 2013-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/err/backtrace.h b/src/lib/err/backtrace.h
index d02e6960b5..ec14d1ab02 100644
--- a/src/lib/err/backtrace.h
+++ b/src/lib/err/backtrace.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2020, The Tor Project, Inc. */
+/* Copyright (c) 2013-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#ifndef TOR_BACKTRACE_H
diff --git a/src/lib/err/torerr.c b/src/lib/err/torerr.c
index 2de75c0be4..4cb0120c34 100644
--- a/src/lib/err/torerr.c
+++ b/src/lib/err/torerr.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001, Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/err/torerr.h b/src/lib/err/torerr.h
index ce1b049c47..089cff823c 100644
--- a/src/lib/err/torerr.h
+++ b/src/lib/err/torerr.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001, Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/err/torerr_sys.c b/src/lib/err/torerr_sys.c
index 8ee1521f3b..24be4a497f 100644
--- a/src/lib/err/torerr_sys.c
+++ b/src/lib/err/torerr_sys.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2018-2020, The Tor Project, Inc. */
+/* Copyright (c) 2018-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/err/torerr_sys.h b/src/lib/err/torerr_sys.h
index b86ccd2790..d6d959222b 100644
--- a/src/lib/err/torerr_sys.h
+++ b/src/lib/err/torerr_sys.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2018-2020, The Tor Project, Inc. */
+/* Copyright (c) 2018-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/evloop/compat_libevent.c b/src/lib/evloop/compat_libevent.c
index 0fd247d331..fd840f8085 100644
--- a/src/lib/evloop/compat_libevent.c
+++ b/src/lib/evloop/compat_libevent.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2009-2020, The Tor Project, Inc. */
+/* Copyright (c) 2009-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/evloop/compat_libevent.h b/src/lib/evloop/compat_libevent.h
index 277ba3add6..485f85529f 100644
--- a/src/lib/evloop/compat_libevent.h
+++ b/src/lib/evloop/compat_libevent.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2009-2020, The Tor Project, Inc. */
+/* Copyright (c) 2009-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/evloop/evloop_sys.c b/src/lib/evloop/evloop_sys.c
index b639810c23..162f18fd20 100644
--- a/src/lib/evloop/evloop_sys.c
+++ b/src/lib/evloop/evloop_sys.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/evloop/evloop_sys.h b/src/lib/evloop/evloop_sys.h
index a37440e7a6..bc4a5aa9ef 100644
--- a/src/lib/evloop/evloop_sys.h
+++ b/src/lib/evloop/evloop_sys.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/evloop/procmon.c b/src/lib/evloop/procmon.c
index 718c7d4777..47c07f9eb0 100644
--- a/src/lib/evloop/procmon.c
+++ b/src/lib/evloop/procmon.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2020, The Tor Project, Inc. */
+/* Copyright (c) 2011-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/evloop/procmon.h b/src/lib/evloop/procmon.h
index 28f443da18..db5382627d 100644
--- a/src/lib/evloop/procmon.h
+++ b/src/lib/evloop/procmon.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2020, The Tor Project, Inc. */
+/* Copyright (c) 2011-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/evloop/timers.c b/src/lib/evloop/timers.c
index 11418e93fd..a8643e01b3 100644
--- a/src/lib/evloop/timers.c
+++ b/src/lib/evloop/timers.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2020, The Tor Project, Inc. */
+/* Copyright (c) 2016-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/evloop/timers.h b/src/lib/evloop/timers.h
index dd55446121..b1fe017a0c 100644
--- a/src/lib/evloop/timers.h
+++ b/src/lib/evloop/timers.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2020, The Tor Project, Inc. */
+/* Copyright (c) 2016-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/evloop/token_bucket.c b/src/lib/evloop/token_bucket.c
index a2b330fddb..16452314e2 100644
--- a/src/lib/evloop/token_bucket.c
+++ b/src/lib/evloop/token_bucket.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2018-2020, The Tor Project, Inc. */
+/* Copyright (c) 2018-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/evloop/token_bucket.h b/src/lib/evloop/token_bucket.h
index 460dad23e4..b57d704298 100644
--- a/src/lib/evloop/token_bucket.h
+++ b/src/lib/evloop/token_bucket.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2018-2020, The Tor Project, Inc. */
+/* Copyright (c) 2018-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/evloop/workqueue.c b/src/lib/evloop/workqueue.c
index 603dddd5a3..bc929148eb 100644
--- a/src/lib/evloop/workqueue.c
+++ b/src/lib/evloop/workqueue.c
@@ -672,3 +672,11 @@ replyqueue_process(replyqueue_t *queue)
tor_mutex_release(&queue->lock);
}
+
+/** Return the number of threads configured for the given pool. */
+unsigned int
+threadpool_get_n_threads(threadpool_t *tp)
+{
+ tor_assert(tp);
+ return tp->n_threads;
+}
diff --git a/src/lib/evloop/workqueue.h b/src/lib/evloop/workqueue.h
index 43cfebf788..134fe7434f 100644
--- a/src/lib/evloop/workqueue.h
+++ b/src/lib/evloop/workqueue.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2020, The Tor Project, Inc. */
+/* Copyright (c) 2013-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -65,5 +65,6 @@ void replyqueue_process(replyqueue_t *queue);
int threadpool_register_reply_event(threadpool_t *tp,
void (*cb)(threadpool_t *tp));
+unsigned int threadpool_get_n_threads(threadpool_t *tp);
#endif /* !defined(TOR_WORKQUEUE_H) */
diff --git a/src/lib/fdio/fdio.c b/src/lib/fdio/fdio.c
index 56e3818f5c..7e27644067 100644
--- a/src/lib/fdio/fdio.c
+++ b/src/lib/fdio/fdio.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/fdio/fdio.h b/src/lib/fdio/fdio.h
index 99bc33c64b..7551dedb9e 100644
--- a/src/lib/fdio/fdio.h
+++ b/src/lib/fdio/fdio.h
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/fs/conffile.c b/src/lib/fs/conffile.c
index 0d0bdf09a6..a0908ed42e 100644
--- a/src/lib/fs/conffile.c
+++ b/src/lib/fs/conffile.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/fs/conffile.h b/src/lib/fs/conffile.h
index cbfe4ec7c9..53824b6c10 100644
--- a/src/lib/fs/conffile.h
+++ b/src/lib/fs/conffile.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#ifndef TOR_CONFFILE_H
diff --git a/src/lib/fs/dir.c b/src/lib/fs/dir.c
index 3432df0299..2626635d46 100644
--- a/src/lib/fs/dir.c
+++ b/src/lib/fs/dir.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2003, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/fs/dir.h b/src/lib/fs/dir.h
index c4ab430891..138ce67b42 100644
--- a/src/lib/fs/dir.h
+++ b/src/lib/fs/dir.h
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#ifndef TOR_DIR_H
diff --git a/src/lib/fs/files.c b/src/lib/fs/files.c
index aff78db718..55f20dd49e 100644
--- a/src/lib/fs/files.c
+++ b/src/lib/fs/files.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/fs/files.h b/src/lib/fs/files.h
index f0178e2b5b..e02365db52 100644
--- a/src/lib/fs/files.h
+++ b/src/lib/fs/files.h
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/fs/freespace.c b/src/lib/fs/freespace.c
index 511f2a0b98..0b001070f2 100644
--- a/src/lib/fs/freespace.c
+++ b/src/lib/fs/freespace.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/fs/lockfile.c b/src/lib/fs/lockfile.c
index c081f57a5d..d8b091c7ab 100644
--- a/src/lib/fs/lockfile.c
+++ b/src/lib/fs/lockfile.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/fs/lockfile.h b/src/lib/fs/lockfile.h
index 91effd701d..44e3867c6e 100644
--- a/src/lib/fs/lockfile.h
+++ b/src/lib/fs/lockfile.h
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/fs/mmap.c b/src/lib/fs/mmap.c
index cc1c40b7ab..9cc4b26d31 100644
--- a/src/lib/fs/mmap.c
+++ b/src/lib/fs/mmap.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/fs/mmap.h b/src/lib/fs/mmap.h
index e142bd78c3..6b512e399f 100644
--- a/src/lib/fs/mmap.h
+++ b/src/lib/fs/mmap.h
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/fs/path.c b/src/lib/fs/path.c
index 81960bd69a..8194d920ab 100644
--- a/src/lib/fs/path.c
+++ b/src/lib/fs/path.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2003, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -533,6 +533,7 @@ unglob_win32(const char *pattern, int prev_sep, int next_sep)
return result;
}
#elif HAVE_GLOB
+#ifdef GLOB_ALTDIRFUNC // prevent warning about unused functions
/** Same as opendir but calls sandbox_intern_string before */
static DIR *
prot_opendir(const char *name)
@@ -571,6 +572,7 @@ wrap_closedir(void *arg)
{
closedir(arg);
}
+#endif /* defined(GLOB_ALTDIRFUNC) */
/** Function passed to glob to handle processing errors. <b>epath</b> is the
* path that caused the error and <b>eerrno</b> is the errno set by the
@@ -627,11 +629,13 @@ tor_glob(const char *pattern)
return NULL;
}
- // #40141: workaround for bug in glibc < 2.19 where patterns ending in path
- // separator match files and folders instead of folders only
+ // #40141, !249: workaround for glibc bug where patterns ending in path
+ // separator match files and folders instead of folders only.
+ // this could be in #ifdef __GLIBC__ but: 1. it might affect other libcs too,
+ // and 2. it doesn't cost much to stat each match again since libc is already
+ // supposed to do it (otherwise the file may be on slow NFS or something)
size_t pattern_len = strlen(pattern);
- bool dir_only = has_glob(pattern) &&
- pattern_len > 0 && pattern[pattern_len-1] == *PATH_SEPARATOR;
+ bool dir_only = pattern_len > 0 && pattern[pattern_len-1] == *PATH_SEPARATOR;
result = smartlist_new();
size_t i;
@@ -652,7 +656,7 @@ tor_glob(const char *pattern)
#else
(void)pattern;
return result;
-#endif /* !defined(HAVE_GLOB) */
+#endif /* defined(_WIN32) || ... */
return result;
}
diff --git a/src/lib/fs/path.h b/src/lib/fs/path.h
index 425bd12516..bc17ece7e3 100644
--- a/src/lib/fs/path.h
+++ b/src/lib/fs/path.h
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/fs/storagedir.c b/src/lib/fs/storagedir.c
index 5e4f9ee257..9503c93e8a 100644
--- a/src/lib/fs/storagedir.c
+++ b/src/lib/fs/storagedir.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017-2020, The Tor Project, Inc. */
+/* Copyright (c) 2017-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/fs/storagedir.h b/src/lib/fs/storagedir.h
index 9997550b8f..3e33ed5416 100644
--- a/src/lib/fs/storagedir.h
+++ b/src/lib/fs/storagedir.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017-2020, The Tor Project, Inc. */
+/* Copyright (c) 2017-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/fs/userdb.c b/src/lib/fs/userdb.c
index 40fc4dae97..74ea8e1fb9 100644
--- a/src/lib/fs/userdb.c
+++ b/src/lib/fs/userdb.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/fs/userdb.h b/src/lib/fs/userdb.h
index 4341237c5f..ef5d9ef3e4 100644
--- a/src/lib/fs/userdb.h
+++ b/src/lib/fs/userdb.h
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/fs/winlib.c b/src/lib/fs/winlib.c
index 65ccdae40b..827bc23f9b 100644
--- a/src/lib/fs/winlib.c
+++ b/src/lib/fs/winlib.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2003, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/fs/winlib.h b/src/lib/fs/winlib.h
index 27837ac46e..8dcd01e65f 100644
--- a/src/lib/fs/winlib.h
+++ b/src/lib/fs/winlib.h
@@ -1,6 +1,6 @@
/* Copyright (c) 2003, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/geoip/country.h b/src/lib/geoip/country.h
index feab554a16..9fa1e23f89 100644
--- a/src/lib/geoip/country.h
+++ b/src/lib/geoip/country.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/geoip/geoip.c b/src/lib/geoip/geoip.c
index ee03d5baa1..686040613d 100644
--- a/src/lib/geoip/geoip.c
+++ b/src/lib/geoip/geoip.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2007-2020, The Tor Project, Inc. */
+/* Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/geoip/geoip.h b/src/lib/geoip/geoip.h
index 2fc7fae754..764ed1d5a5 100644
--- a/src/lib/geoip/geoip.h
+++ b/src/lib/geoip/geoip.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/intmath/addsub.c b/src/lib/intmath/addsub.c
index 44613417fa..cdc259b74d 100644
--- a/src/lib/intmath/addsub.c
+++ b/src/lib/intmath/addsub.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/intmath/addsub.h b/src/lib/intmath/addsub.h
index bca911103b..c06451872d 100644
--- a/src/lib/intmath/addsub.h
+++ b/src/lib/intmath/addsub.h
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/intmath/bits.c b/src/lib/intmath/bits.c
index dace9ffe18..650430a839 100644
--- a/src/lib/intmath/bits.c
+++ b/src/lib/intmath/bits.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/intmath/bits.h b/src/lib/intmath/bits.h
index 687651ba35..1a6431c254 100644
--- a/src/lib/intmath/bits.h
+++ b/src/lib/intmath/bits.h
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/intmath/cmp.h b/src/lib/intmath/cmp.h
index 4e6c2b649a..d1970513a3 100644
--- a/src/lib/intmath/cmp.h
+++ b/src/lib/intmath/cmp.h
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/intmath/logic.h b/src/lib/intmath/logic.h
index b5fb79f66e..ec6a8c783c 100644
--- a/src/lib/intmath/logic.h
+++ b/src/lib/intmath/logic.h
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/intmath/muldiv.c b/src/lib/intmath/muldiv.c
index 875cf1bbf2..7936e0e475 100644
--- a/src/lib/intmath/muldiv.c
+++ b/src/lib/intmath/muldiv.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/intmath/muldiv.h b/src/lib/intmath/muldiv.h
index 43700cf1dc..d1c7b9828d 100644
--- a/src/lib/intmath/muldiv.h
+++ b/src/lib/intmath/muldiv.h
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/intmath/weakrng.c b/src/lib/intmath/weakrng.c
index a29a6a086b..1d5ce7ecba 100644
--- a/src/lib/intmath/weakrng.c
+++ b/src/lib/intmath/weakrng.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2003, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/intmath/weakrng.h b/src/lib/intmath/weakrng.h
index 0394e05f79..424c9b2106 100644
--- a/src/lib/intmath/weakrng.h
+++ b/src/lib/intmath/weakrng.h
@@ -1,6 +1,6 @@
/* Copyright (c) 2003, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/llharden/winprocess_sys.c b/src/lib/llharden/winprocess_sys.c
index f2c88d8c75..e8680e7ab8 100644
--- a/src/lib/llharden/winprocess_sys.c
+++ b/src/lib/llharden/winprocess_sys.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2018-2020, The Tor Project, Inc. */
+/* Copyright (c) 2018-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/llharden/winprocess_sys.h b/src/lib/llharden/winprocess_sys.h
index bece1b3da9..b219b40401 100644
--- a/src/lib/llharden/winprocess_sys.h
+++ b/src/lib/llharden/winprocess_sys.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2018-2020, The Tor Project, Inc. */
+/* Copyright (c) 2018-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/lock/compat_mutex.c b/src/lib/lock/compat_mutex.c
index b0084a3484..8d52d967dd 100644
--- a/src/lib/lock/compat_mutex.c
+++ b/src/lib/lock/compat_mutex.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/lock/compat_mutex.h b/src/lib/lock/compat_mutex.h
index 5631993cc4..f8e4388b34 100644
--- a/src/lib/lock/compat_mutex.h
+++ b/src/lib/lock/compat_mutex.h
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -39,8 +39,15 @@
/** A generic lock structure for multithreaded builds. */
typedef struct tor_mutex_t {
#if defined(USE_WIN32_THREADS)
- /** Windows-only: on windows, we implement locks with CRITICAL_SECTIONS. */
- CRITICAL_SECTION mutex;
+ /** Windows-only: on windows, we implement locks with SRW locks. */
+ SRWLOCK mutex;
+ /** For recursive lock support (SRW locks are not recursive) */
+ enum mutex_type_t {
+ NON_RECURSIVE = 0,
+ RECURSIVE
+ } type;
+ LONG lock_owner; // id of the thread that owns the lock
+ int lock_count; // number of times the lock is held recursively
#elif defined(USE_PTHREADS)
/** Pthreads-only: with pthreads, we implement locks with
* pthread_mutex_t. */
diff --git a/src/lib/lock/compat_mutex_pthreads.c b/src/lib/lock/compat_mutex_pthreads.c
index ac83c42a47..ba3c123a45 100644
--- a/src/lib/lock/compat_mutex_pthreads.c
+++ b/src/lib/lock/compat_mutex_pthreads.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/lock/compat_mutex_winthreads.c b/src/lib/lock/compat_mutex_winthreads.c
index 5fe6870a93..8a101e0d25 100644
--- a/src/lib/lock/compat_mutex_winthreads.c
+++ b/src/lib/lock/compat_mutex_winthreads.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -9,6 +9,23 @@
* \brief Implement the tor_mutex API using CRITICAL_SECTION.
**/
+#include "orconfig.h"
+
+/* For SRW locks support */
+#ifndef WINVER
+#error "orconfig.h didn't define WINVER"
+#endif
+#ifndef _WIN32_WINNT
+#error "orconfig.h didn't define _WIN32_WINNT"
+#endif
+#if WINVER < 0x0600
+#error "winver too low"
+#endif
+#if _WIN32_WINNT < 0x0600
+#error "winver too low"
+#endif
+
+#include <windows.h>
#include "lib/lock/compat_mutex.h"
#include "lib/err/torerr.h"
@@ -20,27 +37,78 @@ tor_locking_init(void)
void
tor_mutex_init(tor_mutex_t *m)
{
- InitializeCriticalSection(&m->mutex);
+ m->type = RECURSIVE;
+ m->lock_owner = 0;
+ m->lock_count = 0;
+ InitializeSRWLock(&m->mutex);
}
void
tor_mutex_init_nonrecursive(tor_mutex_t *m)
{
- InitializeCriticalSection(&m->mutex);
+ m->type = NON_RECURSIVE;
+ InitializeSRWLock(&m->mutex);
}
void
tor_mutex_uninit(tor_mutex_t *m)
{
- DeleteCriticalSection(&m->mutex);
+ (void) m;
+}
+
+static void
+tor_mutex_acquire_recursive(tor_mutex_t *m)
+{
+ LONG thread_id = GetCurrentThreadId();
+ // use InterlockedCompareExchange to perform an atomic read
+ LONG lock_owner = InterlockedCompareExchange(&m->lock_owner, 0, 0);
+ if (thread_id == lock_owner) {
+ ++m->lock_count;
+ return;
+ }
+ AcquireSRWLockExclusive(&m->mutex);
+ InterlockedExchange(&m->lock_owner, thread_id);
+ m->lock_count = 1;
+}
+
+static void
+tor_mutex_acquire_nonrecursive(tor_mutex_t *m)
+{
+ AcquireSRWLockExclusive(&m->mutex);
}
+
void
tor_mutex_acquire(tor_mutex_t *m)
{
raw_assert(m);
- EnterCriticalSection(&m->mutex);
+ if (m->type == NON_RECURSIVE) {
+ tor_mutex_acquire_nonrecursive(m);
+ } else {
+ tor_mutex_acquire_recursive(m);
+ }
+}
+
+static void
+tor_mutex_release_recursive(tor_mutex_t *m)
+{
+ if (--m->lock_count) {
+ return;
+ }
+ InterlockedExchange(&m->lock_owner, 0);
+ ReleaseSRWLockExclusive(&m->mutex);
}
+
+static void
+tor_mutex_release_nonrecursive(tor_mutex_t *m)
+{
+ ReleaseSRWLockExclusive(&m->mutex);
+}
+
void
tor_mutex_release(tor_mutex_t *m)
{
- LeaveCriticalSection(&m->mutex);
+ if (m->type == NON_RECURSIVE) {
+ tor_mutex_release_nonrecursive(m);
+ } else {
+ tor_mutex_release_recursive(m);
+ }
}
diff --git a/src/lib/log/escape.c b/src/lib/log/escape.c
index 88ca52a78c..6a9e3ef646 100644
--- a/src/lib/log/escape.c
+++ b/src/lib/log/escape.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2003, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/log/escape.h b/src/lib/log/escape.h
index 0d1eaef4c1..99b8cefc66 100644
--- a/src/lib/log/escape.h
+++ b/src/lib/log/escape.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001, Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/log/log.c b/src/lib/log/log.c
index 411408966b..db57ee61a2 100644
--- a/src/lib/log/log.c
+++ b/src/lib/log/log.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001, Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/log/log.h b/src/lib/log/log.h
index fb8a5a28a6..f624309d82 100644
--- a/src/lib/log/log.h
+++ b/src/lib/log/log.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001, Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/log/log_sys.c b/src/lib/log/log_sys.c
index 021c05d3e6..33609f5288 100644
--- a/src/lib/log/log_sys.c
+++ b/src/lib/log/log_sys.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2018-2020, The Tor Project, Inc. */
+/* Copyright (c) 2018-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/log/log_sys.h b/src/lib/log/log_sys.h
index 523c2e5008..19e22d6f6e 100644
--- a/src/lib/log/log_sys.h
+++ b/src/lib/log/log_sys.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2018-2020, The Tor Project, Inc. */
+/* Copyright (c) 2018-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/log/ratelim.c b/src/lib/log/ratelim.c
index 8dfaee3384..846cac0700 100644
--- a/src/lib/log/ratelim.c
+++ b/src/lib/log/ratelim.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/log/ratelim.h b/src/lib/log/ratelim.h
index 9e202028cf..a429584ccd 100644
--- a/src/lib/log/ratelim.h
+++ b/src/lib/log/ratelim.h
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/log/util_bug.c b/src/lib/log/util_bug.c
index d698ddd8a6..34b41324af 100644
--- a/src/lib/log/util_bug.c
+++ b/src/lib/log/util_bug.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2003, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/log/util_bug.h b/src/lib/log/util_bug.h
index 684dc7c6dd..dd82981e08 100644
--- a/src/lib/log/util_bug.h
+++ b/src/lib/log/util_bug.h
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -258,7 +258,7 @@
abort()
#else
#define FALLTHROUGH_UNLESS_ALL_BUGS_ARE_FATAL FALLTHROUGH
-#endif
+#endif /* defined(ALL_BUGS_ARE_FATAL) */
/** In older code, we used tor_fragile_assert() to mark optional failure
* points. At these points, we could make some debug builds fail.
diff --git a/src/lib/log/win32err.c b/src/lib/log/win32err.c
index 8136813aab..78534f8e0b 100644
--- a/src/lib/log/win32err.c
+++ b/src/lib/log/win32err.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/log/win32err.h b/src/lib/log/win32err.h
index 5c1386a64d..3d37fcd8c2 100644
--- a/src/lib/log/win32err.h
+++ b/src/lib/log/win32err.h
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/malloc/malloc.c b/src/lib/malloc/malloc.c
index 9c9d600260..0b96dd89dd 100644
--- a/src/lib/malloc/malloc.c
+++ b/src/lib/malloc/malloc.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2003, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/malloc/malloc.h b/src/lib/malloc/malloc.h
index 80e8091adc..cc031f843a 100644
--- a/src/lib/malloc/malloc.h
+++ b/src/lib/malloc/malloc.h
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/malloc/map_anon.c b/src/lib/malloc/map_anon.c
index 628966012a..d71ea33ad1 100644
--- a/src/lib/malloc/map_anon.c
+++ b/src/lib/malloc/map_anon.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/malloc/map_anon.h b/src/lib/malloc/map_anon.h
index 0354668d65..a85596b8d6 100644
--- a/src/lib/malloc/map_anon.h
+++ b/src/lib/malloc/map_anon.h
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/math/fp.c b/src/lib/math/fp.c
index c09555209e..67b1c7f233 100644
--- a/src/lib/math/fp.c
+++ b/src/lib/math/fp.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2003, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/math/fp.h b/src/lib/math/fp.h
index 0a7a685485..33e62b5350 100644
--- a/src/lib/math/fp.h
+++ b/src/lib/math/fp.h
@@ -1,6 +1,6 @@
/* Copyright (c) 2003, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/math/include.am b/src/lib/math/include.am
index b2ca280f47..f68b265da7 100644
--- a/src/lib/math/include.am
+++ b/src/lib/math/include.am
@@ -20,4 +20,5 @@ src_lib_libtor_math_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS)
noinst_HEADERS += \
src/lib/math/fp.h \
src/lib/math/laplace.h \
- src/lib/math/prob_distr.h
+ src/lib/math/prob_distr.h \
+ src/lib/math/stats.h
diff --git a/src/lib/math/laplace.c b/src/lib/math/laplace.c
index a0e67384e6..3520a95cb7 100644
--- a/src/lib/math/laplace.c
+++ b/src/lib/math/laplace.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2003, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/math/laplace.h b/src/lib/math/laplace.h
index e0dd166bbd..94c41901d9 100644
--- a/src/lib/math/laplace.h
+++ b/src/lib/math/laplace.h
@@ -1,6 +1,6 @@
/* Copyright (c) 2003, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/math/prob_distr.c b/src/lib/math/prob_distr.c
index b322b4db5c..a57fc1020c 100644
--- a/src/lib/math/prob_distr.c
+++ b/src/lib/math/prob_distr.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2018-2020, The Tor Project, Inc. */
+/* Copyright (c) 2018-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/math/stats.h b/src/lib/math/stats.h
new file mode 100644
index 0000000000..14315a2506
--- /dev/null
+++ b/src/lib/math/stats.h
@@ -0,0 +1,42 @@
+/* Copyright (c) 2022, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file stats.h
+ *
+ * \brief Header for stats.c
+ **/
+
+#ifndef TOR_STATS_H
+#define TOR_STATS_H
+
+/**
+ * Compute an N-count EWMA, aka N-EWMA. N-EWMA is defined as:
+ * EWMA = alpha*value + (1-alpha)*EWMA_prev
+ * with alpha = 2/(N+1).
+ *
+ * This works out to:
+ * EWMA = value*2/(N+1) + EMA_prev*(N-1)/(N+1)
+ * = (value*2 + EWMA_prev*(N-1))/(N+1)
+ */
+static inline double
+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!
+ * Love it when it introduces surprising edge case bugs like
+ * this will. */
+ if (avg < 0.0000002)
+ return value;
+ else
+ return (2*value + (N-1)*avg)/(N+1);
+}
+
+/* For most stats, an N_EWMA of 100 is sufficient */
+#define DEFAULT_STATS_N_EWMA_COUNT 100
+#define stats_update_running_avg(avg, value) \
+ n_count_ewma_double(avg, value, DEFAULT_STATS_N_EWMA_COUNT)
+
+#endif /* !defined(TOR_STATS_H) */
diff --git a/src/lib/memarea/memarea.c b/src/lib/memarea/memarea.c
index 4d26c20eeb..7e984938a2 100644
--- a/src/lib/memarea/memarea.c
+++ b/src/lib/memarea/memarea.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008-2020, The Tor Project, Inc. */
+/* Copyright (c) 2008-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/memarea/memarea.h b/src/lib/memarea/memarea.h
index 8b5e63e6b3..0d9ead241c 100644
--- a/src/lib/memarea/memarea.h
+++ b/src/lib/memarea/memarea.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008-2020, The Tor Project, Inc. */
+/* Copyright (c) 2008-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/meminfo/lib_meminfo.md b/src/lib/meminfo/lib_meminfo.md
index 87f509d648..e248faab90 100644
--- a/src/lib/meminfo/lib_meminfo.md
+++ b/src/lib/meminfo/lib_meminfo.md
@@ -1,5 +1,2 @@
@dir /lib/meminfo
-@brief lib/meminfo: Inspecting malloc() usage.
-
-Only available when malloc() provides mallinfo() or something similar.
-
+@brief lib/meminfo: Inspecting system memory availability.
diff --git a/src/lib/meminfo/meminfo.c b/src/lib/meminfo/meminfo.c
index 77da579f99..96f3cfc3cc 100644
--- a/src/lib/meminfo/meminfo.c
+++ b/src/lib/meminfo/meminfo.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/meminfo/meminfo.h b/src/lib/meminfo/meminfo.h
index 36a85c133d..6336c15f78 100644
--- a/src/lib/meminfo/meminfo.h
+++ b/src/lib/meminfo/meminfo.h
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/metrics/metrics_common.c b/src/lib/metrics/metrics_common.c
index 5941a4d892..f3f7e22d88 100644
--- a/src/lib/metrics/metrics_common.c
+++ b/src/lib/metrics/metrics_common.c
@@ -11,6 +11,7 @@
#include "orconfig.h"
#include "lib/log/util_bug.h"
+#include "lib/string/printf.h"
#include "lib/metrics/metrics_common.h"
@@ -27,3 +28,15 @@ metrics_type_to_str(const metrics_type_t type)
tor_assert_unreached();
}
}
+
+/** Return a static buffer pointer that contains a formatted label on the form
+ * of key=value.
+ *
+ * Subsequent call to this function invalidates the previous buffer. */
+const char *
+metrics_format_label(const char *key, const char *value)
+{
+ static char buf[128];
+ tor_snprintf(buf, sizeof(buf), "%s=\"%s\"", key, value);
+ return buf;
+}
diff --git a/src/lib/metrics/metrics_common.h b/src/lib/metrics/metrics_common.h
index c684a3ec42..3644ad3d50 100644
--- a/src/lib/metrics/metrics_common.h
+++ b/src/lib/metrics/metrics_common.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2020, The Tor Project, Inc. */
+/* Copyright (c) 2020-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -42,4 +42,7 @@ typedef struct metrics_gauge_t {
const char *metrics_type_to_str(const metrics_type_t type);
+/* Helpers. */
+const char *metrics_format_label(const char *key, const char *value);
+
#endif /* !defined(TOR_LIB_METRICS_METRICS_COMMON_H) */
diff --git a/src/lib/metrics/metrics_store.c b/src/lib/metrics/metrics_store.c
index 57847cc37c..b017e97688 100644
--- a/src/lib/metrics/metrics_store.c
+++ b/src/lib/metrics/metrics_store.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2020, The Tor Project, Inc. */
+/* Copyright (c) 2020-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -34,7 +34,8 @@ struct metrics_store_t {
};
/** Function pointer to the format function of a specific driver. */
-typedef void (fmt_driver_fn_t)(const metrics_store_entry_t *, buf_t *);
+typedef void (fmt_driver_fn_t)(const metrics_store_entry_t *, buf_t *,
+ bool no_comment);
/** Helper: Free a single entry in a metrics_store_t taking a void pointer
* parameter. */
@@ -47,6 +48,8 @@ metrics_store_free_void(void *p)
smartlist_free(list);
}
+#include <stdio.h>
+
/** Put the given store output in the buffer data and use the format function
* given in fmt to get it for each entry. */
static void
@@ -57,8 +60,11 @@ get_output(const metrics_store_t *store, buf_t *data, fmt_driver_fn_t fmt)
tor_assert(fmt);
STRMAP_FOREACH(store->entries, key, const smartlist_t *, entries) {
+ /* Indicate that we've formatted the comment already for the entries. */
+ bool comment_formatted = false;
SMARTLIST_FOREACH_BEGIN(entries, const metrics_store_entry_t *, entry) {
- fmt(entry, data);
+ fmt(entry, data, comment_formatted);
+ comment_formatted = true;
} SMARTLIST_FOREACH_END(entry);
} STRMAP_FOREACH_END;
}
@@ -138,3 +144,14 @@ metrics_store_get_output(const metrics_format_t fmt,
// LCOV_EXCL_STOP
}
}
+
+/** Reset a store as in free its content. */
+void
+metrics_store_reset(metrics_store_t *store)
+{
+ if (store == NULL) {
+ return;
+ }
+ strmap_free(store->entries, metrics_store_free_void);
+ store->entries = strmap_new();
+}
diff --git a/src/lib/metrics/metrics_store.h b/src/lib/metrics/metrics_store.h
index 9640a5e016..d85f484bd6 100644
--- a/src/lib/metrics/metrics_store.h
+++ b/src/lib/metrics/metrics_store.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2020, The Tor Project, Inc. */
+/* Copyright (c) 2020-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -28,6 +28,7 @@ metrics_store_t *metrics_store_new(void);
metrics_store_entry_t *metrics_store_add(metrics_store_t *store,
metrics_type_t type,
const char *name, const char *help);
+void metrics_store_reset(metrics_store_t *store);
/* Accessors. */
smartlist_t *metrics_store_get_all(const metrics_store_t *store,
diff --git a/src/lib/metrics/metrics_store_entry.c b/src/lib/metrics/metrics_store_entry.c
index 44ebb5cb84..482ec8d7d9 100644
--- a/src/lib/metrics/metrics_store_entry.c
+++ b/src/lib/metrics/metrics_store_entry.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2020, The Tor Project, Inc. */
+/* Copyright (c) 2020-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/metrics/metrics_store_entry.h b/src/lib/metrics/metrics_store_entry.h
index 8e8a8f3917..e4dc7a8b9a 100644
--- a/src/lib/metrics/metrics_store_entry.h
+++ b/src/lib/metrics/metrics_store_entry.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2020, The Tor Project, Inc. */
+/* Copyright (c) 2020-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -40,7 +40,7 @@ struct metrics_store_entry_t {
} u;
};
-#endif /* METRICS_STORE_ENTRY_PRIVATE */
+#endif /* defined(METRICS_STORE_ENTRY_PRIVATE) */
typedef struct metrics_store_entry_t metrics_store_entry_t;
diff --git a/src/lib/metrics/prometheus.c b/src/lib/metrics/prometheus.c
index c2b54e436f..aac23ac92e 100644
--- a/src/lib/metrics/prometheus.c
+++ b/src/lib/metrics/prometheus.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2020, The Tor Project, Inc. */
+/* Copyright (c) 2020-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -42,14 +42,17 @@ format_labels(smartlist_t *labels)
/** Format the given entry in to the buffer data. */
void
-prometheus_format_store_entry(const metrics_store_entry_t *entry, buf_t *data)
+prometheus_format_store_entry(const metrics_store_entry_t *entry, buf_t *data,
+ bool no_comment)
{
tor_assert(entry);
tor_assert(data);
- buf_add_printf(data, "# HELP %s %s\n", entry->name, entry->help);
- buf_add_printf(data, "# TYPE %s %s\n", entry->name,
- metrics_type_to_str(entry->type));
+ if (!no_comment) {
+ buf_add_printf(data, "# HELP %s %s\n", entry->name, entry->help);
+ 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));
diff --git a/src/lib/metrics/prometheus.h b/src/lib/metrics/prometheus.h
index eea26e8ac4..faa7681daa 100644
--- a/src/lib/metrics/prometheus.h
+++ b/src/lib/metrics/prometheus.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2020, The Tor Project, Inc. */
+/* Copyright (c) 2020-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -13,6 +13,6 @@
#include "lib/metrics/metrics_store_entry.h"
void prometheus_format_store_entry(const metrics_store_entry_t *entry,
- buf_t *data);
+ buf_t *data, bool no_comment);
#endif /* !defined(TOR_LIB_METRICS_PROMETHEUS_H) */
diff --git a/src/lib/net/address.c b/src/lib/net/address.c
index 21794fb4fc..085eb8c458 100644
--- a/src/lib/net/address.c
+++ b/src/lib/net/address.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -2005,20 +2005,15 @@ parse_port_range(const char *port, uint16_t *port_min_out,
char *endptr = NULL;
port_min = (int)tor_parse_long(port, 10, 0, 65535, &ok, &endptr);
if (!ok) {
- log_warn(LD_GENERAL,
- "Malformed port %s on address range; rejecting.",
- escaped(port));
- return -1;
- } else if (endptr && *endptr == '-') {
+ goto malformed_port;
+ } else if (endptr && *endptr != '\0') {
+ if (*endptr != '-')
+ goto malformed_port;
port = endptr+1;
endptr = NULL;
port_max = (int)tor_parse_long(port, 10, 1, 65535, &ok, &endptr);
- if (!ok) {
- log_warn(LD_GENERAL,
- "Malformed port %s on address range; rejecting.",
- escaped(port));
- return -1;
- }
+ if (!ok)
+ goto malformed_port;
} else {
port_max = port_min;
}
@@ -2037,6 +2032,11 @@ parse_port_range(const char *port, uint16_t *port_min_out,
*port_max_out = (uint16_t) port_max;
return 0;
+ malformed_port:
+ log_warn(LD_GENERAL,
+ "Malformed port %s on address range; rejecting.",
+ escaped(port));
+ return -1;
}
/** Given a host-order <b>addr</b>, call tor_inet_ntop() on it
diff --git a/src/lib/net/address.h b/src/lib/net/address.h
index 4c79db69d2..6c233eece9 100644
--- a/src/lib/net/address.h
+++ b/src/lib/net/address.h
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/net/alertsock.c b/src/lib/net/alertsock.c
index 537fdcaee4..741ff8447f 100644
--- a/src/lib/net/alertsock.c
+++ b/src/lib/net/alertsock.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/net/alertsock.h b/src/lib/net/alertsock.h
index dab4273cf1..79c2dc431a 100644
--- a/src/lib/net/alertsock.h
+++ b/src/lib/net/alertsock.h
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/net/buffers_net.c b/src/lib/net/buffers_net.c
index 4a0eb3bf16..a485aa41c6 100644
--- a/src/lib/net/buffers_net.c
+++ b/src/lib/net/buffers_net.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/net/buffers_net.h b/src/lib/net/buffers_net.h
index 556575c3dc..e99b16d83d 100644
--- a/src/lib/net/buffers_net.h
+++ b/src/lib/net/buffers_net.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/net/gethostname.c b/src/lib/net/gethostname.c
index 001d95391d..4d7200135e 100644
--- a/src/lib/net/gethostname.c
+++ b/src/lib/net/gethostname.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/net/gethostname.h b/src/lib/net/gethostname.h
index 90f8056779..a456934022 100644
--- a/src/lib/net/gethostname.h
+++ b/src/lib/net/gethostname.h
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/net/inaddr.c b/src/lib/net/inaddr.c
index d50ac2440c..0ec3987006 100644
--- a/src/lib/net/inaddr.c
+++ b/src/lib/net/inaddr.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/net/inaddr.h b/src/lib/net/inaddr.h
index 8d6766eb5d..3cb21cf2fe 100644
--- a/src/lib/net/inaddr.h
+++ b/src/lib/net/inaddr.h
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/net/inaddr_st.h b/src/lib/net/inaddr_st.h
index b9ee2b86cf..fe84718d81 100644
--- a/src/lib/net/inaddr_st.h
+++ b/src/lib/net/inaddr_st.h
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/net/nettypes.h b/src/lib/net/nettypes.h
index 953673d4c3..16950c64d8 100644
--- a/src/lib/net/nettypes.h
+++ b/src/lib/net/nettypes.h
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/net/network_sys.c b/src/lib/net/network_sys.c
index e95c3ba819..ea331df593 100644
--- a/src/lib/net/network_sys.c
+++ b/src/lib/net/network_sys.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2018-2020, The Tor Project, Inc. */
+/* Copyright (c) 2018-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/net/network_sys.h b/src/lib/net/network_sys.h
index 734533c7e8..d0013589af 100644
--- a/src/lib/net/network_sys.h
+++ b/src/lib/net/network_sys.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2018-2020, The Tor Project, Inc. */
+/* Copyright (c) 2018-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/net/resolve.c b/src/lib/net/resolve.c
index 68a8c01ef4..0f5c04f480 100644
--- a/src/lib/net/resolve.c
+++ b/src/lib/net/resolve.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/net/resolve.h b/src/lib/net/resolve.h
index ef3d9fa176..4eeda230ca 100644
--- a/src/lib/net/resolve.h
+++ b/src/lib/net/resolve.h
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/net/socket.c b/src/lib/net/socket.c
index adc060a735..820a89f8b9 100644
--- a/src/lib/net/socket.c
+++ b/src/lib/net/socket.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/net/socket.h b/src/lib/net/socket.h
index 46735fdef0..bb44d49b61 100644
--- a/src/lib/net/socket.h
+++ b/src/lib/net/socket.h
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/net/socketpair.c b/src/lib/net/socketpair.c
index d4310020cb..dff51cb680 100644
--- a/src/lib/net/socketpair.c
+++ b/src/lib/net/socketpair.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/**
* @file socketpair.c
diff --git a/src/lib/net/socketpair.h b/src/lib/net/socketpair.h
index b07016ab94..84bea0a61b 100644
--- a/src/lib/net/socketpair.h
+++ b/src/lib/net/socketpair.h
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#ifndef TOR_SOCKETPAIR_H
diff --git a/src/lib/net/socks5_status.h b/src/lib/net/socks5_status.h
index 90c4305d29..c27b7254c2 100644
--- a/src/lib/net/socks5_status.h
+++ b/src/lib/net/socks5_status.h
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/osinfo/libc.c b/src/lib/osinfo/libc.c
index 32cbad0fa2..f52dea41aa 100644
--- a/src/lib/osinfo/libc.c
+++ b/src/lib/osinfo/libc.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/osinfo/libc.h b/src/lib/osinfo/libc.h
index f4303f8c9c..9c250a4097 100644
--- a/src/lib/osinfo/libc.h
+++ b/src/lib/osinfo/libc.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/osinfo/uname.c b/src/lib/osinfo/uname.c
index f7f5ede307..20c5775915 100644
--- a/src/lib/osinfo/uname.c
+++ b/src/lib/osinfo/uname.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/osinfo/uname.h b/src/lib/osinfo/uname.h
index c6b1f43235..78db399e7b 100644
--- a/src/lib/osinfo/uname.h
+++ b/src/lib/osinfo/uname.h
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/process/daemon.c b/src/lib/process/daemon.c
index b3b98a297e..abd1d36576 100644
--- a/src/lib/process/daemon.c
+++ b/src/lib/process/daemon.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2003, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/process/daemon.h b/src/lib/process/daemon.h
index 23f3117898..35b56b3988 100644
--- a/src/lib/process/daemon.h
+++ b/src/lib/process/daemon.h
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/process/env.c b/src/lib/process/env.c
index 517b655a5e..b8d5676203 100644
--- a/src/lib/process/env.c
+++ b/src/lib/process/env.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/process/env.h b/src/lib/process/env.h
index 7838dcaa90..67185c50a8 100644
--- a/src/lib/process/env.h
+++ b/src/lib/process/env.h
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/process/pidfile.c b/src/lib/process/pidfile.c
index e7d9d2c47a..53b2dccde4 100644
--- a/src/lib/process/pidfile.c
+++ b/src/lib/process/pidfile.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/process/pidfile.h b/src/lib/process/pidfile.h
index d04302df3a..04c3d454f2 100644
--- a/src/lib/process/pidfile.h
+++ b/src/lib/process/pidfile.h
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/process/process.c b/src/lib/process/process.c
index d69b0ca115..c216d0d154 100644
--- a/src/lib/process/process.c
+++ b/src/lib/process/process.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2003, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/process/process.h b/src/lib/process/process.h
index 8879ec4f21..687c5cefdb 100644
--- a/src/lib/process/process.h
+++ b/src/lib/process/process.h
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/process/process_sys.c b/src/lib/process/process_sys.c
index c8332ba91e..b54308263a 100644
--- a/src/lib/process/process_sys.c
+++ b/src/lib/process/process_sys.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2018-2020, The Tor Project, Inc. */
+/* Copyright (c) 2018-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/process/process_sys.h b/src/lib/process/process_sys.h
index 97b3aaebd0..bb2191a85c 100644
--- a/src/lib/process/process_sys.h
+++ b/src/lib/process/process_sys.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2018-2020, The Tor Project, Inc. */
+/* Copyright (c) 2018-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/process/process_unix.c b/src/lib/process/process_unix.c
index 82b2630a5d..15ae03eadf 100644
--- a/src/lib/process/process_unix.c
+++ b/src/lib/process/process_unix.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2003, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/process/process_unix.h b/src/lib/process/process_unix.h
index a6b8304d48..ab752939b0 100644
--- a/src/lib/process/process_unix.h
+++ b/src/lib/process/process_unix.h
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/process/process_win32.c b/src/lib/process/process_win32.c
index 203df136aa..dfcb17a480 100644
--- a/src/lib/process/process_win32.c
+++ b/src/lib/process/process_win32.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2003, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/process/process_win32.h b/src/lib/process/process_win32.h
index 0f264c8710..6d1b16031e 100644
--- a/src/lib/process/process_win32.h
+++ b/src/lib/process/process_win32.h
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/process/restrict.c b/src/lib/process/restrict.c
index bf5ae8e500..61ea664bc0 100644
--- a/src/lib/process/restrict.c
+++ b/src/lib/process/restrict.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/process/restrict.h b/src/lib/process/restrict.h
index 6173d5a438..c34fcb5a9c 100644
--- a/src/lib/process/restrict.h
+++ b/src/lib/process/restrict.h
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/process/setuid.c b/src/lib/process/setuid.c
index 3cfd520a4f..e802027452 100644
--- a/src/lib/process/setuid.c
+++ b/src/lib/process/setuid.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2003, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/process/setuid.h b/src/lib/process/setuid.h
index fec35a1216..40cc82dc36 100644
--- a/src/lib/process/setuid.h
+++ b/src/lib/process/setuid.h
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/process/waitpid.c b/src/lib/process/waitpid.c
index 014bcf2927..d98c71c8f2 100644
--- a/src/lib/process/waitpid.c
+++ b/src/lib/process/waitpid.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/process/waitpid.h b/src/lib/process/waitpid.h
index 171cf206fb..1af8a41506 100644
--- a/src/lib/process/waitpid.h
+++ b/src/lib/process/waitpid.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2020, The Tor Project, Inc. */
+/* Copyright (c) 2011-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/pubsub/pub_binding_st.h b/src/lib/pubsub/pub_binding_st.h
index e35f246c57..b3e418c8a3 100644
--- a/src/lib/pubsub/pub_binding_st.h
+++ b/src/lib/pubsub/pub_binding_st.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001, Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/pubsub/pubsub.h b/src/lib/pubsub/pubsub.h
index d0a4d317f3..9e39f46403 100644
--- a/src/lib/pubsub/pubsub.h
+++ b/src/lib/pubsub/pubsub.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001, Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/pubsub/pubsub_build.c b/src/lib/pubsub/pubsub_build.c
index 3c134f015c..30b9194062 100644
--- a/src/lib/pubsub/pubsub_build.c
+++ b/src/lib/pubsub/pubsub_build.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001, Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/pubsub/pubsub_build.h b/src/lib/pubsub/pubsub_build.h
index 87fcaf458e..ade58debd6 100644
--- a/src/lib/pubsub/pubsub_build.h
+++ b/src/lib/pubsub/pubsub_build.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001, Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/pubsub/pubsub_builder_st.h b/src/lib/pubsub/pubsub_builder_st.h
index 57de1240ee..3f0d7b25ea 100644
--- a/src/lib/pubsub/pubsub_builder_st.h
+++ b/src/lib/pubsub/pubsub_builder_st.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001, Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/pubsub/pubsub_check.c b/src/lib/pubsub/pubsub_check.c
index 84958e101a..99e604d715 100644
--- a/src/lib/pubsub/pubsub_check.c
+++ b/src/lib/pubsub/pubsub_check.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001, Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/pubsub/pubsub_connect.h b/src/lib/pubsub/pubsub_connect.h
index b0d6ae7e92..0019aebed0 100644
--- a/src/lib/pubsub/pubsub_connect.h
+++ b/src/lib/pubsub/pubsub_connect.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001, Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/pubsub/pubsub_flags.h b/src/lib/pubsub/pubsub_flags.h
index 9912c1ae89..d9c94e1326 100644
--- a/src/lib/pubsub/pubsub_flags.h
+++ b/src/lib/pubsub/pubsub_flags.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001, Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/pubsub/pubsub_macros.h b/src/lib/pubsub/pubsub_macros.h
index 4f5b60c19b..6be45630cf 100644
--- a/src/lib/pubsub/pubsub_macros.h
+++ b/src/lib/pubsub/pubsub_macros.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001, Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/pubsub/pubsub_publish.c b/src/lib/pubsub/pubsub_publish.c
index 84c7dae02c..5ea2988826 100644
--- a/src/lib/pubsub/pubsub_publish.c
+++ b/src/lib/pubsub/pubsub_publish.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001, Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/pubsub/pubsub_publish.h b/src/lib/pubsub/pubsub_publish.h
index d9d6fa9ba5..2c6529b05f 100644
--- a/src/lib/pubsub/pubsub_publish.h
+++ b/src/lib/pubsub/pubsub_publish.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001, Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/sandbox/sandbox.c b/src/lib/sandbox/sandbox.c
index 7a57554ace..6800fa062b 100644
--- a/src/lib/sandbox/sandbox.c
+++ b/src/lib/sandbox/sandbox.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -58,6 +58,10 @@
#include <linux/futex.h>
#include <sys/file.h>
+#ifdef ENABLE_FRAGILE_HARDENING
+#include <sys/ptrace.h>
+#endif
+
#include <stdarg.h>
#include <seccomp.h>
#include <signal.h>
@@ -148,7 +152,11 @@ static sandbox_cfg_t *filter_dynamic = NULL;
static int filter_nopar_gen[] = {
SCMP_SYS(access),
SCMP_SYS(brk),
+#ifdef __NR_clock_gettime64
+ SCMP_SYS(clock_gettime64),
+#else
SCMP_SYS(clock_gettime),
+#endif
SCMP_SYS(close),
SCMP_SYS(clone),
SCMP_SYS(dup),
@@ -194,6 +202,9 @@ static int filter_nopar_gen[] = {
SCMP_SYS(getgid32),
#endif
SCMP_SYS(getpid),
+#ifdef ENABLE_FRAGILE_HARDENING
+ SCMP_SYS(getppid),
+#endif
#ifdef __NR_getrlimit
SCMP_SYS(getrlimit),
#endif
@@ -247,6 +258,9 @@ static int filter_nopar_gen[] = {
SCMP_SYS(sigreturn),
#endif
SCMP_SYS(stat),
+#if defined(__i386__) && defined(__NR_statx)
+ SCMP_SYS(statx),
+#endif
SCMP_SYS(uname),
SCMP_SYS(wait4),
SCMP_SYS(write),
@@ -345,6 +359,7 @@ sb_rt_sigaction(scmp_filter_ctx ctx, sandbox_cfg_t *filter)
return rc;
}
+#ifdef __NR_time
/**
* Function responsible for setting up the time syscall for
* the seccomp filter sandbox.
@@ -353,13 +368,11 @@ static int
sb_time(scmp_filter_ctx ctx, sandbox_cfg_t *filter)
{
(void) filter;
-#ifdef __NR_time
+
return seccomp_rule_add_1(ctx, SCMP_ACT_ALLOW, SCMP_SYS(time),
SCMP_CMP(0, SCMP_CMP_EQ, 0));
-#else
- return 0;
-#endif /* defined(__NR_time) */
}
+#endif /* defined(__NR_time) */
/**
* Function responsible for setting up the accept4 syscall for
@@ -538,6 +551,24 @@ sb_open(scmp_filter_ctx ctx, sandbox_cfg_t *filter)
int use_openat = libc_uses_openat_for_open();
+#ifdef ENABLE_FRAGILE_HARDENING
+ /* AddressSanitizer uses the "open" syscall to access information about the
+ * running process via the filesystem, so that call must be allowed without
+ * restriction or the sanitizer will be unable to execute normally when the
+ * process terminates. */
+ rc = seccomp_rule_add_0(ctx, SCMP_ACT_ALLOW, SCMP_SYS(open));
+ if (rc != 0) {
+ log_err(LD_BUG,"(Sandbox) failed to add open syscall, received "
+ "libseccomp error %d", rc);
+ return rc;
+ }
+
+ /* If glibc also uses only the "open" syscall to open files on this system
+ * there is no need to consider any additional rules. */
+ if (!use_openat)
+ return 0;
+#endif
+
// for each dynamic parameter filters
for (elem = filter; elem != NULL; elem = elem->next) {
smp_param_t *param = elem->param;
@@ -581,6 +612,32 @@ sb_chmod(scmp_filter_ctx ctx, sandbox_cfg_t *filter)
return 0;
}
+#ifdef __i386__
+static int
+sb_chown32(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(chown32)) {
+ rc = seccomp_rule_add_1(ctx, SCMP_ACT_ALLOW, SCMP_SYS(chown32),
+ SCMP_CMP_STR(0, SCMP_CMP_EQ, param->value));
+ if (rc != 0) {
+ log_err(LD_BUG,"(Sandbox) failed to add chown32 syscall, received "
+ "libseccomp error %d", rc);
+ return rc;
+ }
+ }
+ }
+
+ return 0;
+}
+#else
static int
sb_chown(scmp_filter_ctx ctx, sandbox_cfg_t *filter)
{
@@ -605,6 +662,7 @@ sb_chown(scmp_filter_ctx ctx, sandbox_cfg_t *filter)
return 0;
}
+#endif /* defined(__i386__) */
/**
* Function responsible for setting up the rename syscall for
@@ -693,6 +751,34 @@ sb_opendir(scmp_filter_ctx ctx, sandbox_cfg_t *filter)
return 0;
}
+#ifdef ENABLE_FRAGILE_HARDENING
+/**
+ * Function responsible for setting up the ptrace syscall for
+ * the seccomp filter sandbox.
+ */
+static int
+sb_ptrace(scmp_filter_ctx ctx, sandbox_cfg_t *filter)
+{
+ int rc;
+ pid_t pid = getpid();
+ (void) filter;
+
+ rc = seccomp_rule_add_2(ctx, SCMP_ACT_ALLOW, SCMP_SYS(ptrace),
+ SCMP_CMP(0, SCMP_CMP_EQ, PTRACE_ATTACH),
+ SCMP_CMP(1, SCMP_CMP_EQ, pid));
+ if (rc)
+ return rc;
+
+ rc = seccomp_rule_add_2(ctx, SCMP_ACT_ALLOW, SCMP_SYS(ptrace),
+ SCMP_CMP(0, SCMP_CMP_EQ, PTRACE_GETREGS),
+ SCMP_CMP(1, SCMP_CMP_EQ, pid));
+ if (rc)
+ return rc;
+
+ return 0;
+}
+#endif
+
/**
* Function responsible for setting up the socket syscall for
* the seccomp filter sandbox.
@@ -740,7 +826,7 @@ sb_socket(scmp_filter_ctx ctx, sandbox_cfg_t *filter)
SCMP_CMP(2, SCMP_CMP_EQ, IPPROTO_IP));
if (rc)
return rc;
-#endif
+#endif /* defined(ENABLE_NSS) */
rc = seccomp_rule_add_3(ctx, SCMP_ACT_ALLOW, SCMP_SYS(socket),
SCMP_CMP(0, SCMP_CMP_EQ, PF_UNIX),
@@ -868,6 +954,14 @@ sb_setsockopt(scmp_filter_ctx ctx, sandbox_cfg_t *filter)
return rc;
#endif /* defined(IPV6_V6ONLY) */
+#ifdef IP_BIND_ADDRESS_NO_PORT
+ rc = seccomp_rule_add_2(ctx, SCMP_ACT_ALLOW, SCMP_SYS(setsockopt),
+ SCMP_CMP(1, SCMP_CMP_EQ, SOL_IP),
+ SCMP_CMP(2, SCMP_CMP_EQ, IP_BIND_ADDRESS_NO_PORT));
+ if (rc)
+ return rc;
+#endif
+
return 0;
}
@@ -1015,6 +1109,18 @@ sb_prctl(scmp_filter_ctx ctx, sandbox_cfg_t *filter)
int rc = 0;
(void) filter;
+#ifdef ENABLE_FRAGILE_HARDENING
+ rc = seccomp_rule_add_1(ctx, SCMP_ACT_ALLOW, SCMP_SYS(prctl),
+ SCMP_CMP(0, SCMP_CMP_EQ, PR_GET_DUMPABLE));
+ if (rc)
+ return rc;
+
+ rc = seccomp_rule_add_1(ctx, SCMP_ACT_ALLOW, SCMP_SYS(prctl),
+ SCMP_CMP(0, SCMP_CMP_EQ, PR_SET_PTRACER));
+ if (rc)
+ return rc;
+#endif
+
rc = seccomp_rule_add_1(ctx, SCMP_ACT_ALLOW, SCMP_SYS(prctl),
SCMP_CMP(0, SCMP_CMP_EQ, PR_SET_DUMPABLE));
if (rc)
@@ -1059,6 +1165,13 @@ sb_rt_sigprocmask(scmp_filter_ctx ctx, sandbox_cfg_t *filter)
int rc = 0;
(void) filter;
+#ifdef ENABLE_FRAGILE_HARDENING
+ rc = seccomp_rule_add_1(ctx, SCMP_ACT_ALLOW, SCMP_SYS(rt_sigprocmask),
+ SCMP_CMP(0, SCMP_CMP_EQ, SIG_BLOCK));
+ if (rc)
+ return rc;
+#endif
+
rc = seccomp_rule_add_1(ctx, SCMP_ACT_ALLOW, SCMP_SYS(rt_sigprocmask),
SCMP_CMP(0, SCMP_CMP_EQ, SIG_UNBLOCK));
if (rc)
@@ -1198,16 +1311,25 @@ sb_kill(scmp_filter_ctx ctx, sandbox_cfg_t *filter)
static sandbox_filter_func_t filter_func[] = {
sb_rt_sigaction,
sb_rt_sigprocmask,
+#ifdef __NR_time
sb_time,
+#endif
sb_accept4,
#ifdef __NR_mmap2
sb_mmap2,
#endif
+#ifdef __i386__
+ sb_chown32,
+#else
sb_chown,
+#endif
sb_chmod,
sb_open,
sb_openat,
sb_opendir,
+#ifdef ENABLE_FRAGILE_HARDENING
+ sb_ptrace,
+#endif
sb_rename,
#ifdef __NR_fcntl64
sb_fcntl64,
@@ -1474,6 +1596,12 @@ new_element(int syscall, char *value)
return new_element2(syscall, value, NULL);
}
+#ifdef __i386__
+#define SCMP_chown SCMP_SYS(chown32)
+#else
+#define SCMP_chown SCMP_SYS(chown)
+#endif
+
#ifdef __NR_stat64
#define SCMP_stat SCMP_SYS(stat64)
#else
@@ -1524,7 +1652,7 @@ sandbox_cfg_allow_chown_filename(sandbox_cfg_t **cfg, char *file)
{
sandbox_cfg_t *elem = NULL;
- elem = new_element(SCMP_SYS(chown), file);
+ elem = new_element(SCMP_chown, file);
elem->next = *cfg;
*cfg = elem;
@@ -1719,7 +1847,7 @@ get_syscall_from_ucontext(const ucontext_t *ctx)
{
return (int) ctx->uc_mcontext.M_SYSCALL;
}
-#else
+#else /* !defined(SYSCALL_NAME_DEBUGGING) */
static const char *
get_syscall_name(int syscall_num)
{
@@ -1732,7 +1860,7 @@ get_syscall_from_ucontext(const ucontext_t *ctx)
(void) ctx;
return -1;
}
-#endif
+#endif /* defined(SYSCALL_NAME_DEBUGGING) */
#ifdef USE_BACKTRACE
#define MAX_DEPTH 256
diff --git a/src/lib/sandbox/sandbox.h b/src/lib/sandbox/sandbox.h
index eba99afbde..17d32d16de 100644
--- a/src/lib/sandbox/sandbox.h
+++ b/src/lib/sandbox/sandbox.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/smartlist_core/smartlist_core.c b/src/lib/smartlist_core/smartlist_core.c
index 571d17aa5d..f0c1f8aae7 100644
--- a/src/lib/smartlist_core/smartlist_core.c
+++ b/src/lib/smartlist_core/smartlist_core.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/smartlist_core/smartlist_core.h b/src/lib/smartlist_core/smartlist_core.h
index de6fe69d3a..9af49269ef 100644
--- a/src/lib/smartlist_core/smartlist_core.h
+++ b/src/lib/smartlist_core/smartlist_core.h
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/smartlist_core/smartlist_foreach.h b/src/lib/smartlist_core/smartlist_foreach.h
index 03edb80f05..977865c17e 100644
--- a/src/lib/smartlist_core/smartlist_foreach.h
+++ b/src/lib/smartlist_core/smartlist_foreach.h
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/smartlist_core/smartlist_split.c b/src/lib/smartlist_core/smartlist_split.c
index b76b87406d..e275e87051 100644
--- a/src/lib/smartlist_core/smartlist_split.c
+++ b/src/lib/smartlist_core/smartlist_split.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/smartlist_core/smartlist_split.h b/src/lib/smartlist_core/smartlist_split.h
index fc964201e9..07ded4c0ab 100644
--- a/src/lib/smartlist_core/smartlist_split.h
+++ b/src/lib/smartlist_core/smartlist_split.h
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/string/compat_ctype.c b/src/lib/string/compat_ctype.c
index a7668bfbfb..87b39c3516 100644
--- a/src/lib/string/compat_ctype.c
+++ b/src/lib/string/compat_ctype.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/string/compat_ctype.h b/src/lib/string/compat_ctype.h
index 53ee6066f8..d7a939cbd1 100644
--- a/src/lib/string/compat_ctype.h
+++ b/src/lib/string/compat_ctype.h
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/string/compat_string.c b/src/lib/string/compat_string.c
index 2bd3c2f2b4..c7d809c997 100644
--- a/src/lib/string/compat_string.c
+++ b/src/lib/string/compat_string.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/string/compat_string.h b/src/lib/string/compat_string.h
index 5c9bf05ebd..57f08580bb 100644
--- a/src/lib/string/compat_string.h
+++ b/src/lib/string/compat_string.h
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/string/parse_int.c b/src/lib/string/parse_int.c
index 11ce0fa415..9beaf9462e 100644
--- a/src/lib/string/parse_int.c
+++ b/src/lib/string/parse_int.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2003, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/string/parse_int.h b/src/lib/string/parse_int.h
index 27939ade61..0bc98b1ef5 100644
--- a/src/lib/string/parse_int.h
+++ b/src/lib/string/parse_int.h
@@ -1,6 +1,6 @@
/* Copyright (c) 2003, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/string/printf.c b/src/lib/string/printf.c
index 86d860935e..bd35b76d1b 100644
--- a/src/lib/string/printf.c
+++ b/src/lib/string/printf.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -8,9 +8,9 @@
* \brief Compatibility wrappers around snprintf and its friends
**/
+#include "lib/cc/torint.h"
#include "lib/string/printf.h"
#include "lib/err/torerr.h"
-#include "lib/cc/torint.h"
#include "lib/malloc/malloc.h"
#include <stdlib.h>
@@ -45,7 +45,7 @@ tor_vsnprintf(char *str, size_t size, const char *format, va_list args)
return -1; /* no place for the NUL */
if (size > SIZE_T_CEILING)
return -1;
-#ifdef _WIN32
+#if defined(_WIN32) && !defined(HAVE_VSNPRINTF)
r = _vsnprintf(str, size, format, args);
#else
r = vsnprintf(str, size, format, args);
diff --git a/src/lib/string/printf.h b/src/lib/string/printf.h
index 5ab751b338..b1923a37a4 100644
--- a/src/lib/string/printf.h
+++ b/src/lib/string/printf.h
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/string/scanf.c b/src/lib/string/scanf.c
index 89d1683204..cfa75b5582 100644
--- a/src/lib/string/scanf.c
+++ b/src/lib/string/scanf.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/string/scanf.h b/src/lib/string/scanf.h
index 67e9c5eb78..6defbb8ea0 100644
--- a/src/lib/string/scanf.h
+++ b/src/lib/string/scanf.h
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/string/util_string.c b/src/lib/string/util_string.c
index ba5f9f2203..b1c0a11439 100644
--- a/src/lib/string/util_string.c
+++ b/src/lib/string/util_string.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/string/util_string.h b/src/lib/string/util_string.h
index 15d35415fe..cf63d53f37 100644
--- a/src/lib/string/util_string.h
+++ b/src/lib/string/util_string.h
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/subsys/subsys.h b/src/lib/subsys/subsys.h
index abfc82d56a..e9b45dc142 100644
--- a/src/lib/subsys/subsys.h
+++ b/src/lib/subsys/subsys.h
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/term/getpass.c b/src/lib/term/getpass.c
index d2d6cb2b7b..ad94bf402c 100644
--- a/src/lib/term/getpass.c
+++ b/src/lib/term/getpass.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/term/getpass.h b/src/lib/term/getpass.h
index b080ad2473..ea059b7943 100644
--- a/src/lib/term/getpass.h
+++ b/src/lib/term/getpass.h
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/testsupport/testsupport.h b/src/lib/testsupport/testsupport.h
index 165c497f71..72e76a6d96 100644
--- a/src/lib/testsupport/testsupport.h
+++ b/src/lib/testsupport/testsupport.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2020, The Tor Project, Inc. */
+/* Copyright (c) 2013-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/thread/compat_pthreads.c b/src/lib/thread/compat_pthreads.c
index d143b80252..61de020a2e 100644
--- a/src/lib/thread/compat_pthreads.c
+++ b/src/lib/thread/compat_pthreads.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/thread/compat_threads.c b/src/lib/thread/compat_threads.c
index 75ade9c9f2..dca034f9e9 100644
--- a/src/lib/thread/compat_threads.c
+++ b/src/lib/thread/compat_threads.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/thread/compat_winthreads.c b/src/lib/thread/compat_winthreads.c
index fcc9c0279b..f28cdcca00 100644
--- a/src/lib/thread/compat_winthreads.c
+++ b/src/lib/thread/compat_winthreads.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -144,13 +144,17 @@ tor_threadlocal_set(tor_threadlocal_t *threadlocal, void *value)
int
tor_cond_wait(tor_cond_t *cond, tor_mutex_t *lock_, const struct timeval *tv)
{
- CRITICAL_SECTION *lock = &lock_->mutex;
+ // recursive SRW locks are not supported because they need extra logic for
+ // acquiring and releasing but SleepConditionVariableSRW will use the OS
+ // lock release function which lacks our extra logic
+ tor_assert(lock_->type == NON_RECURSIVE);
+ SRWLOCK *lock = &lock_->mutex;
DWORD ms = INFINITE;
if (tv) {
ms = tv->tv_sec*1000 + (tv->tv_usec+999)/1000;
}
- BOOL ok = SleepConditionVariableCS(&cond->cond, lock, ms);
+ BOOL ok = SleepConditionVariableSRW(&cond->cond, lock, ms, 0);
if (!ok) {
DWORD err = GetLastError();
if (err == ERROR_TIMEOUT) {
diff --git a/src/lib/thread/numcpus.c b/src/lib/thread/numcpus.c
index 18454ce3ad..40fac7dbe4 100644
--- a/src/lib/thread/numcpus.c
+++ b/src/lib/thread/numcpus.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -53,10 +53,10 @@ compute_num_cpus_impl(void)
cpus = cpus_onln;
} else if (cpus_onln > 0 && cpus_conf > 0) {
if (cpus_onln < cpus_conf) {
- log_notice(LD_GENERAL, "I think we have %ld CPUS, but only %ld of them "
- "are available. Telling Tor to only use %ld. You can over"
- "ride this with the NumCPUs option",
- cpus_conf, cpus_onln, cpus_onln);
+ log_info(LD_GENERAL, "I think we have %ld CPUS, but only %ld of them "
+ "are available. Telling Tor to only use %ld. You can over"
+ "ride this with the NumCPUs option",
+ cpus_conf, cpus_onln, cpus_onln);
}
cpus = cpus_onln;
}
@@ -70,7 +70,11 @@ compute_num_cpus_impl(void)
#endif /* defined(_WIN32) || ... */
}
-#define MAX_DETECTABLE_CPUS 16
+/** This is an arbitrary number but at this point in time, it is not that
+ * uncommon to see servers up to that amount of CPUs. Most servers will likely
+ * be around 16 to 32 cores now. Lets take advantage of large machines! The
+ * "NumCPUs" torrc option overrides this maximum. */
+#define MAX_DETECTABLE_CPUS 128
/** Return how many CPUs we are running with. We assume that nobody is
* using hot-swappable CPUs, so we don't recompute this after the first
diff --git a/src/lib/thread/numcpus.h b/src/lib/thread/numcpus.h
index 65e6c430cf..8b7bd96968 100644
--- a/src/lib/thread/numcpus.h
+++ b/src/lib/thread/numcpus.h
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/thread/thread_sys.h b/src/lib/thread/thread_sys.h
index 6206fac9d6..f764cfdc60 100644
--- a/src/lib/thread/thread_sys.h
+++ b/src/lib/thread/thread_sys.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2018-2020, The Tor Project, Inc. */
+/* Copyright (c) 2018-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/thread/threads.h b/src/lib/thread/threads.h
index ead4dc3874..d74a7dc429 100644
--- a/src/lib/thread/threads.h
+++ b/src/lib/thread/threads.h
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/time/compat_time.c b/src/lib/time/compat_time.c
index 9a5ce062d7..eb716259c4 100644
--- a/src/lib/time/compat_time.c
+++ b/src/lib/time/compat_time.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/time/compat_time.h b/src/lib/time/compat_time.h
index 08fd0f0c25..da96023894 100644
--- a/src/lib/time/compat_time.h
+++ b/src/lib/time/compat_time.h
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/time/time_sys.c b/src/lib/time/time_sys.c
index 1c1bc4cd18..9bdf64403f 100644
--- a/src/lib/time/time_sys.c
+++ b/src/lib/time/time_sys.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2018-2020, The Tor Project, Inc. */
+/* Copyright (c) 2018-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/time/time_sys.h b/src/lib/time/time_sys.h
index f2401e1911..e4ca9909f8 100644
--- a/src/lib/time/time_sys.h
+++ b/src/lib/time/time_sys.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2018-2020, The Tor Project, Inc. */
+/* Copyright (c) 2018-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/time/tvdiff.c b/src/lib/time/tvdiff.c
index 14a89bc76e..42470d86dc 100644
--- a/src/lib/time/tvdiff.c
+++ b/src/lib/time/tvdiff.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/time/tvdiff.h b/src/lib/time/tvdiff.h
index e779e758f1..62af727063 100644
--- a/src/lib/time/tvdiff.h
+++ b/src/lib/time/tvdiff.h
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/tls/buffers_tls.c b/src/lib/tls/buffers_tls.c
index de0e9cb4ef..3b6deea7f2 100644
--- a/src/lib/tls/buffers_tls.c
+++ b/src/lib/tls/buffers_tls.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/tls/buffers_tls.h b/src/lib/tls/buffers_tls.h
index ed391cefbd..4a903843ed 100644
--- a/src/lib/tls/buffers_tls.h
+++ b/src/lib/tls/buffers_tls.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/tls/nss_countbytes.c b/src/lib/tls/nss_countbytes.c
index 4b98df80ec..4d57d0cc29 100644
--- a/src/lib/tls/nss_countbytes.c
+++ b/src/lib/tls/nss_countbytes.c
@@ -1,4 +1,4 @@
-/* Copyright 2018-2020, The Tor Project Inc. */
+/* Copyright 2018-2021, The Tor Project Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/tls/nss_countbytes.h b/src/lib/tls/nss_countbytes.h
index 36ed55e10d..47aab05d31 100644
--- a/src/lib/tls/nss_countbytes.h
+++ b/src/lib/tls/nss_countbytes.h
@@ -1,4 +1,4 @@
-/* Copyright 2018-2020, The Tor Project, Inc. */
+/* Copyright 2018-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/tls/tortls.c b/src/lib/tls/tortls.c
index 9e70e54725..80f16e1c74 100644
--- a/src/lib/tls/tortls.c
+++ b/src/lib/tls/tortls.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2003, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/tls/tortls.h b/src/lib/tls/tortls.h
index 3703ecad56..96f93e2679 100644
--- a/src/lib/tls/tortls.h
+++ b/src/lib/tls/tortls.h
@@ -1,6 +1,6 @@
/* Copyright (c) 2003, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#ifndef TOR_TORTLS_H
diff --git a/src/lib/tls/tortls_internal.h b/src/lib/tls/tortls_internal.h
index 3f56f181ee..a4c6b87cac 100644
--- a/src/lib/tls/tortls_internal.h
+++ b/src/lib/tls/tortls_internal.h
@@ -1,6 +1,6 @@
/* Copyright (c) 2003, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/tls/tortls_nss.c b/src/lib/tls/tortls_nss.c
index 25446a81af..392747e930 100644
--- a/src/lib/tls/tortls_nss.c
+++ b/src/lib/tls/tortls_nss.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2003, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -588,6 +588,10 @@ tor_tls_write(tor_tls_t *tls, const char *cp, size_t n)
tor_assert(cp || n == 0);
tor_assert(n < INT_MAX);
+ if (n == 0) {
+ return 0;
+ }
+
PRInt32 rv = PR_Write(tls->ssl, cp, (int)n);
// log_debug(LD_NET, "PR_Write(%zu) returned %d", n, (int)rv);
if (rv > 0) {
diff --git a/src/lib/tls/tortls_openssl.c b/src/lib/tls/tortls_openssl.c
index 78ecc25a35..77de2d6a11 100644
--- a/src/lib/tls/tortls_openssl.c
+++ b/src/lib/tls/tortls_openssl.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2003, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -701,6 +701,12 @@ tor_tls_context_new(crypto_pk_t *identity, unsigned int key_lifetime,
/* let us realloc bufs that we're writing from */
SSL_CTX_set_mode(result->ctx, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
+#ifdef SSL_OP_TLSEXT_PADDING
+ /* Adds a padding extension to ensure the ClientHello size is never between
+ * 256 and 511 bytes in length. */
+ SSL_CTX_set_options(result->ctx, SSL_OP_TLSEXT_PADDING);
+#endif
+
return result;
error:
diff --git a/src/lib/tls/tortls_st.h b/src/lib/tls/tortls_st.h
index 34abe52ee3..b27e73b15f 100644
--- a/src/lib/tls/tortls_st.h
+++ b/src/lib/tls/tortls_st.h
@@ -1,6 +1,6 @@
/* Copyright (c) 2003, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#ifndef TOR_TORTLS_ST_H
@@ -80,7 +80,7 @@ struct tor_tls_t {
uint64_t last_write_count;
uint64_t last_read_count;
long last_error;
-#endif
+#endif /* defined(ENABLE_NSS) */
};
#endif /* !defined(TOR_TORTLS_ST_H) */
diff --git a/src/lib/tls/tortls_sys.h b/src/lib/tls/tortls_sys.h
index 177c198f71..74efb21d7e 100644
--- a/src/lib/tls/tortls_sys.h
+++ b/src/lib/tls/tortls_sys.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2018-2020, The Tor Project, Inc. */
+/* Copyright (c) 2018-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/tls/x509.c b/src/lib/tls/x509.c
index 2515499298..819c497f1c 100644
--- a/src/lib/tls/x509.c
+++ b/src/lib/tls/x509.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2003, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/tls/x509.h b/src/lib/tls/x509.h
index 5919b9089d..deaefb969f 100644
--- a/src/lib/tls/x509.h
+++ b/src/lib/tls/x509.h
@@ -1,6 +1,6 @@
/* Copyright (c) 2003, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#ifndef TOR_X509_H
diff --git a/src/lib/tls/x509_internal.h b/src/lib/tls/x509_internal.h
index 145be7e71c..9e5b6f0d00 100644
--- a/src/lib/tls/x509_internal.h
+++ b/src/lib/tls/x509_internal.h
@@ -1,6 +1,6 @@
/* Copyright (c) 2003, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#ifndef TOR_X509_INTERNAL_H
diff --git a/src/lib/tls/x509_nss.c b/src/lib/tls/x509_nss.c
index 9ee92e9fb0..1034d1c39d 100644
--- a/src/lib/tls/x509_nss.c
+++ b/src/lib/tls/x509_nss.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2003, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/tls/x509_openssl.c b/src/lib/tls/x509_openssl.c
index 2abf02851d..249c9c6688 100644
--- a/src/lib/tls/x509_openssl.c
+++ b/src/lib/tls/x509_openssl.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2003, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/trace/debug.h b/src/lib/trace/debug.h
index 4ee14fab8d..f9d536b301 100644
--- a/src/lib/trace/debug.h
+++ b/src/lib/trace/debug.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017-2020, The Tor Project, Inc. */
+/* Copyright (c) 2017-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -28,7 +28,7 @@
log_debug(LD_GENERAL, "Tracepoint \"" XSTR(event_name) "\" from " \
"subsystem \"" XSTR(subsystem) "\" hit.")
-#else /* defined(USE_TRACING_INSTRUMENTATION_LOG_DEBUG) */
+#else /* !defined(USE_TRACING_INSTRUMENTATION_LOG_DEBUG) */
/* NOP the debug event. */
#define TOR_TRACE_LOG_DEBUG(subsystem, name, ...)
diff --git a/src/lib/trace/events.h b/src/lib/trace/events.h
index ce1604de22..165c1aebc0 100644
--- a/src/lib/trace/events.h
+++ b/src/lib/trace/events.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017-2020, The Tor Project, Inc. */
+/* Copyright (c) 2017-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/trace/trace.c b/src/lib/trace/trace.c
index 10d11c17c5..5d4e983737 100644
--- a/src/lib/trace/trace.c
+++ b/src/lib/trace/trace.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2020, The Tor Project, Inc. */
+/* Copyright (c) 2020-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/trace/trace.h b/src/lib/trace/trace.h
index 22589dbe94..b94600a383 100644
--- a/src/lib/trace/trace.h
+++ b/src/lib/trace/trace.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2020, The Tor Project, Inc. */
+/* Copyright (c) 2020-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -26,7 +26,7 @@ tracing_log_warning(void)
"purpose, your tor is NOT safe to run.");
}
-#else
+#else /* !defined(HAVE_TRACING) */
/* NOP it. */
#define tracing_log_warning()
diff --git a/src/lib/trace/trace_stub.c b/src/lib/trace/trace_stub.c
index fddf8c63f0..6db5c8ef1a 100644
--- a/src/lib/trace/trace_stub.c
+++ b/src/lib/trace/trace_stub.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2020, The Tor Project, Inc. */
+/* Copyright (c) 2020-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/trace/trace_sys.c b/src/lib/trace/trace_sys.c
index 2ba0258407..0a68e24433 100644
--- a/src/lib/trace/trace_sys.c
+++ b/src/lib/trace/trace_sys.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2018-2019, The Tor Project, Inc. */
+/* Copyright (c) 2018-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/trace/trace_sys.h b/src/lib/trace/trace_sys.h
index d4da5a9701..d5b5a2cdf2 100644
--- a/src/lib/trace/trace_sys.h
+++ b/src/lib/trace/trace_sys.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2018-2019, The Tor Project, Inc. */
+/* Copyright (c) 2018-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/version/git_revision.c b/src/lib/version/git_revision.c
index 09f11aa316..5fcd54c9fe 100644
--- a/src/lib/version/git_revision.c
+++ b/src/lib/version/git_revision.c
@@ -1,6 +1,6 @@
/* Copyright 2001-2004 Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
diff --git a/src/lib/version/git_revision.h b/src/lib/version/git_revision.h
index 80b6c4734e..cd4d3b2646 100644
--- a/src/lib/version/git_revision.h
+++ b/src/lib/version/git_revision.h
@@ -1,6 +1,6 @@
/* Copyright 2001-2004 Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#ifndef TOR_GIT_REVISION_H
diff --git a/src/lib/version/torversion.h b/src/lib/version/torversion.h
index 679df74381..352f83e129 100644
--- a/src/lib/version/torversion.h
+++ b/src/lib/version/torversion.h
@@ -1,6 +1,6 @@
/* Copyright 2001-2004 Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#ifndef TOR_VERSION_H
diff --git a/src/lib/version/version.c b/src/lib/version/version.c
index ec1d0bea2f..e0a0a78867 100644
--- a/src/lib/version/version.c
+++ b/src/lib/version/version.c
@@ -1,6 +1,6 @@
/* Copyright 2001-2004 Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
diff --git a/src/lib/wallclock/approx_time.c b/src/lib/wallclock/approx_time.c
index c815f20e51..1399b72f19 100644
--- a/src/lib/wallclock/approx_time.c
+++ b/src/lib/wallclock/approx_time.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2003, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/wallclock/approx_time.h b/src/lib/wallclock/approx_time.h
index 42040a1f52..661e2a3348 100644
--- a/src/lib/wallclock/approx_time.h
+++ b/src/lib/wallclock/approx_time.h
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/wallclock/time_to_tm.c b/src/lib/wallclock/time_to_tm.c
index 8c747b4c7b..35f3088610 100644
--- a/src/lib/wallclock/time_to_tm.c
+++ b/src/lib/wallclock/time_to_tm.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/wallclock/time_to_tm.h b/src/lib/wallclock/time_to_tm.h
index bfa8fa3689..f6d218d71c 100644
--- a/src/lib/wallclock/time_to_tm.h
+++ b/src/lib/wallclock/time_to_tm.h
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/wallclock/timeval.h b/src/lib/wallclock/timeval.h
index d7d5bda99f..a04b0c853f 100644
--- a/src/lib/wallclock/timeval.h
+++ b/src/lib/wallclock/timeval.h
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/wallclock/tor_gettimeofday.c b/src/lib/wallclock/tor_gettimeofday.c
index a07f83220d..7b768a865e 100644
--- a/src/lib/wallclock/tor_gettimeofday.c
+++ b/src/lib/wallclock/tor_gettimeofday.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/wallclock/tor_gettimeofday.h b/src/lib/wallclock/tor_gettimeofday.h
index c1a8afca3a..b8aab11aa4 100644
--- a/src/lib/wallclock/tor_gettimeofday.h
+++ b/src/lib/wallclock/tor_gettimeofday.h
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/lib/wallclock/wallclock_sys.h b/src/lib/wallclock/wallclock_sys.h
index 3997d11e7a..8bbc7a737b 100644
--- a/src/lib/wallclock/wallclock_sys.h
+++ b/src/lib/wallclock/wallclock_sys.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2018-2020, The Tor Project, Inc. */
+/* Copyright (c) 2018-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/rust/.cargo/config.in b/src/rust/.cargo/config.in
deleted file mode 100644
index 6eddc75459..0000000000
--- a/src/rust/.cargo/config.in
+++ /dev/null
@@ -1,12 +0,0 @@
-[source]
-
-@RUST_DL@ [source.crates-io]
-@RUST_DL@ registry = 'https://github.com/rust-lang/crates.io-index'
-@RUST_DL@ replace-with = 'vendored-sources'
-
-@RUST_DL@ [source.vendored-sources]
-@RUST_DL@ directory = '@TOR_RUST_DEPENDENCIES@'
-
-[build]
-@RUST_WARN@ rustflags = [ "-D", "warnings" ]
-@RUST_TARGET_PROP@
diff --git a/src/rust/.rustfmt.toml b/src/rust/.rustfmt.toml
deleted file mode 100644
index 4ff839dcf3..0000000000
--- a/src/rust/.rustfmt.toml
+++ /dev/null
@@ -1,12 +0,0 @@
-max_width = 100
-hard_tabs = false
-tab_spaces = 4
-newline_style = "Unix"
-#use_small_heuristics = "Default"
-reorder_imports = true
-reorder_modules = true
-remove_nested_parens = true
-merge_derives = true
-use_try_shorthand = false
-use_field_init_shorthand = false
-force_explicit_abi = true
diff --git a/src/rust/Cargo.lock b/src/rust/Cargo.lock
deleted file mode 100644
index e2f24b0af7..0000000000
--- a/src/rust/Cargo.lock
+++ /dev/null
@@ -1,122 +0,0 @@
-# This file is automatically @generated by Cargo.
-# It is not intended for manual editing.
-[[package]]
-name = "crypto"
-version = "0.0.1"
-dependencies = [
- "digest 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "external 0.0.1",
- "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)",
- "rand 0.5.0-pre.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "rand_core 0.2.0-pre.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "smartlist 0.0.1",
- "tor_allocate 0.0.1",
- "tor_log 0.1.0",
-]
-
-[[package]]
-name = "digest"
-version = "0.7.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "generic-array 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "external"
-version = "0.0.1"
-dependencies = [
- "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)",
- "smartlist 0.0.1",
- "tor_allocate 0.0.1",
-]
-
-[[package]]
-name = "generic-array"
-version = "0.9.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "typenum 1.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "libc"
-version = "0.2.39"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-
-[[package]]
-name = "protover"
-version = "0.0.1"
-dependencies = [
- "external 0.0.1",
- "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)",
- "smartlist 0.0.1",
- "tor_allocate 0.0.1",
- "tor_log 0.1.0",
- "tor_util 0.0.1",
-]
-
-[[package]]
-name = "rand"
-version = "0.5.0-pre.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "rand_core 0.2.0-pre.0 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "rand_core"
-version = "0.2.0-pre.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-
-[[package]]
-name = "smartlist"
-version = "0.0.1"
-dependencies = [
- "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "tor_allocate"
-version = "0.0.1"
-dependencies = [
- "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "tor_log"
-version = "0.1.0"
-dependencies = [
- "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)",
- "tor_allocate 0.0.1",
-]
-
-[[package]]
-name = "tor_rust"
-version = "0.1.0"
-dependencies = [
- "protover 0.0.1",
- "tor_util 0.0.1",
-]
-
-[[package]]
-name = "tor_util"
-version = "0.0.1"
-dependencies = [
- "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)",
- "tor_allocate 0.0.1",
- "tor_log 0.1.0",
-]
-
-[[package]]
-name = "typenum"
-version = "1.9.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-
-[metadata]
-"checksum digest 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "00a49051fef47a72c9623101b19bd71924a45cca838826caae3eaa4d00772603"
-"checksum generic-array 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ef25c5683767570c2bbd7deba372926a55eaae9982d7726ee2a1050239d45b9d"
-"checksum libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)" = "f54263ad99207254cf58b5f701ecb432c717445ea2ee8af387334bdd1a03fdff"
-"checksum rand 0.5.0-pre.2 (registry+https://github.com/rust-lang/crates.io-index)" = "3795e4701d9628a63a84d0289e66279883b40df165fca7caed7b87122447032a"
-"checksum rand_core 0.2.0-pre.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c7255ffbdb188d5be1a69b6f9f3cf187de4207430b9e79ed5b76458a6b20de9a"
-"checksum typenum 1.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "13a99dc6780ef33c78780b826cf9d2a78840b72cae9474de4bcaf9051e60ebbd"
diff --git a/src/rust/Cargo.toml b/src/rust/Cargo.toml
deleted file mode 100644
index de8693ea33..0000000000
--- a/src/rust/Cargo.toml
+++ /dev/null
@@ -1,26 +0,0 @@
-[workspace]
-members = [
- "crypto",
- "external",
- "protover",
- "smartlist",
- "tor_allocate",
- "tor_log",
- "tor_rust",
- "tor_util",
-]
-
-# Can remove panic="abort" when this issue is fixed:
-# https://github.com/rust-lang/rust/issues/52652
-[profile.dev]
-panic = "abort"
-
-[profile.release]
-debug = true
-panic = "abort"
-
-[profile.test]
-panic = "abort"
-
-[profile.bench]
-panic = "abort"
diff --git a/src/rust/build.rs b/src/rust/build.rs
deleted file mode 100644
index 5626b35f75..0000000000
--- a/src/rust/build.rs
+++ /dev/null
@@ -1,192 +0,0 @@
-//! Build script for Rust modules in Tor.
-//!
-//! We need to use this because some of our Rust tests need to use some
-//! of our C modules, which need to link some external libraries.
-//!
-//! This script works by looking at a "config.rust" file generated by our
-//! configure script, and then building a set of options for cargo to pass to
-//! the compiler.
-
-use std::collections::HashMap;
-use std::env;
-use std::fs::File;
-use std::io;
-use std::io::prelude::*;
-use std::path::PathBuf;
-
-/// Wrapper around a key-value map.
-struct Config(HashMap<String, String>);
-
-/// Locate a config.rust file generated by autoconf, starting in the OUT_DIR
-/// location provided by cargo and recursing up the directory tree. Note that
-/// we need to look in the OUT_DIR, since autoconf will place generated files
-/// in the build directory.
-fn find_cfg() -> io::Result<String> {
- let mut path = PathBuf::from(env::var("OUT_DIR").unwrap());
- loop {
- path.push("config.rust");
- if path.exists() {
- return Ok(path.to_str().unwrap().to_owned());
- }
- path.pop(); // remove config.rust
- if !path.pop() {
- // can't remove last part of directory
- return Err(io::Error::new(io::ErrorKind::NotFound, "No config.rust"));
- }
- }
-}
-
-impl Config {
- /// Find the config.rust file and try to parse it.
- ///
- /// The file format is a series of lines of the form KEY=VAL, with
- /// any blank lines and lines starting with # ignored.
- fn load() -> io::Result<Config> {
- let path = find_cfg()?;
- let f = File::open(&path)?;
- let reader = io::BufReader::new(f);
- let mut map = HashMap::new();
- for line in reader.lines() {
- let s = line?;
- if s.trim().starts_with("#") || s.trim() == "" {
- continue;
- }
- let idx = match s.find("=") {
- None => {
- return Err(io::Error::new(io::ErrorKind::InvalidData, "missing ="));
- }
- Some(x) => x,
- };
- let (var, eq_val) = s.split_at(idx);
- let val = &eq_val[1..];
- map.insert(var.to_owned(), val.to_owned());
- }
- Ok(Config(map))
- }
-
- /// Return a reference to the value whose key is 'key'.
- ///
- /// Panics if 'key' is not found in the configuration.
- fn get(&self, key: &str) -> &str {
- self.0.get(key).unwrap()
- }
-
- /// Add a dependency on a static C library that is part of Tor, by name.
- fn component(&self, s: &str) {
- println!("cargo:rustc-link-lib=static={}", s);
- }
-
- /// Add a dependency on a native library that is not part of Tor, by name.
- fn dependency(&self, s: &str) {
- println!("cargo:rustc-link-lib={}", s);
- }
-
- /// Add a link path, relative to Tor's build directory.
- fn link_relpath(&self, s: &str) {
- let builddir = self.get("BUILDDIR");
- println!("cargo:rustc-link-search=native={}/{}", builddir, s);
- }
-
- /// Add an absolute link path.
- fn link_path(&self, s: &str) {
- println!("cargo:rustc-link-search=native={}", s);
- }
-
- /// Parse the CFLAGS in s, looking for -l and -L items, and adding
- /// rust configuration as appropriate.
- fn from_cflags(&self, s: &str) {
- let mut next_is_lib = false;
- let mut next_is_path = false;
- for ent in self.get(s).split_whitespace() {
- if next_is_lib {
- self.dependency(ent);
- next_is_lib = false;
- } else if next_is_path {
- self.link_path(ent);
- next_is_path = false;
- } else if ent == "-l" {
- next_is_lib = true;
- } else if ent == "-L" {
- next_is_path = true;
- } else if ent.starts_with("-L") {
- self.link_path(&ent[2..]);
- } else if ent.starts_with("-l") {
- self.dependency(&ent[2..]);
- }
- }
- }
-}
-
-pub fn main() {
- let cfg = Config::load().unwrap();
- let package = env::var("CARGO_PKG_NAME").unwrap();
-
- match package.as_ref() {
- "crypto" => {
- // Right now, I'm having a separate configuration for each Rust
- // package, since I'm hoping we can trim them down. Once we have a
- // second Rust package that needs to use this build script, let's
- // extract some of this stuff into a module.
- //
- // This is a ridiculous amount of code to be pulling in just
- // to test our crypto library: modularity would be our
- // friend here.
- cfg.from_cflags("TOR_LDFLAGS_zlib");
- cfg.from_cflags("TOR_LDFLAGS_openssl");
- cfg.from_cflags("TOR_LDFLAGS_libevent");
-
- cfg.link_relpath("src/lib");
- cfg.link_relpath("src/ext/keccak-tiny");
- cfg.link_relpath("src/ext/ed25519/ref10");
- cfg.link_relpath("src/ext/ed25519/donna");
- cfg.link_relpath("src/trunnel");
-
- // Note that we can't pull in "libtor-testing", or else we
- // will have dependencies on all the other rust packages that
- // tor uses. We must be careful with factoring and dependencies
- // moving forward!
- cfg.component("tor-crypt-ops-testing");
- cfg.component("tor-sandbox-testing");
- cfg.component("tor-encoding-testing");
- cfg.component("tor-fs-testing");
- cfg.component("tor-net-testing");
- cfg.component("tor-buf-testing");
- cfg.component("tor-time-testing");
- cfg.component("tor-thread-testing");
- cfg.component("tor-memarea-testing");
- cfg.component("tor-log-testing");
- cfg.component("tor-lock-testing");
- cfg.component("tor-fdio-testing");
- cfg.component("tor-container-testing");
- cfg.component("tor-smartlist-core-testing");
- cfg.component("tor-string-testing");
- cfg.component("tor-malloc");
- cfg.component("tor-wallclock");
- cfg.component("tor-err-testing");
- cfg.component("tor-version-testing");
- cfg.component("tor-intmath-testing");
- cfg.component("tor-ctime-testing");
- cfg.component("curve25519_donna");
- cfg.component("keccak-tiny");
- cfg.component("ed25519_ref10");
- cfg.component("ed25519_donna");
- cfg.component("or-trunnel-testing");
-
- cfg.from_cflags("TOR_ZLIB_LIBS");
- cfg.from_cflags("TOR_LIB_MATH");
- cfg.from_cflags("NSS_LIBS");
- cfg.from_cflags("TOR_OPENSSL_LIBS");
- cfg.from_cflags("TOR_LIBEVENT_LIBS");
- cfg.from_cflags("TOR_LIB_WS32");
- cfg.from_cflags("TOR_LIB_GDI");
- cfg.from_cflags("TOR_LIB_USERENV");
- cfg.from_cflags("CURVE25519_LIBS");
- cfg.from_cflags("TOR_LZMA_LIBS");
- cfg.from_cflags("TOR_ZSTD_LIBS");
- cfg.from_cflags("LIBS");
- }
- _ => {
- panic!("No configuration in build.rs for package {}", package);
- }
- }
-}
diff --git a/src/rust/crypto/Cargo.toml b/src/rust/crypto/Cargo.toml
deleted file mode 100644
index a7ff7f78d9..0000000000
--- a/src/rust/crypto/Cargo.toml
+++ /dev/null
@@ -1,37 +0,0 @@
-[package]
-authors = ["The Tor Project",
- "Isis Lovecruft <isis@torproject.org>"]
-name = "crypto"
-version = "0.0.1"
-publish = false
-build = "../build.rs"
-
-[lib]
-name = "crypto"
-path = "lib.rs"
-
-[dependencies]
-libc = "=0.2.39"
-digest = "=0.7.2"
-rand_core = { version = "=0.2.0-pre.0", default-features = false }
-
-external = { path = "../external" }
-smartlist = { path = "../smartlist" }
-tor_allocate = { path = "../tor_allocate" }
-tor_log = { path = "../tor_log" }
-
-[dev-dependencies]
-rand = { version = "=0.5.0-pre.2", default-features = false }
-rand_core = { version = "=0.2.0-pre.0", default-features = false }
-
-[features]
-# If this feature is enabled, test code which calls Tor C code from Rust will
-# execute with `cargo test`. Due to numerous linker issues (#25386), this is
-# currently disabled by default.
-test-c-from-rust = []
-
-# We have to define a feature here because doctests don't get cfg(test),
-# and we need to disable some C dependencies when running the doctests
-# because of the various linker issues. See
-# https://github.com/rust-lang/rust/issues/45599
-test_linking_hack = []
diff --git a/src/rust/crypto/digests/mod.rs b/src/rust/crypto/digests/mod.rs
deleted file mode 100644
index 58343b9ca7..0000000000
--- a/src/rust/crypto/digests/mod.rs
+++ /dev/null
@@ -1,7 +0,0 @@
-// Copyright (c) 2018-2019, The Tor Project, Inc.
-// Copyright (c) 2018, isis agora lovecruft
-// See LICENSE for licensing information
-
-//! Hash Digests and eXtendible Output Functions (XOFs)
-
-pub mod sha2;
diff --git a/src/rust/crypto/digests/sha2.rs b/src/rust/crypto/digests/sha2.rs
deleted file mode 100644
index 91e8b2b3c9..0000000000
--- a/src/rust/crypto/digests/sha2.rs
+++ /dev/null
@@ -1,234 +0,0 @@
-// Copyright (c) 2018-2019, The Tor Project, Inc.
-// Copyright (c) 2018, isis agora lovecruft
-// See LICENSE for licensing information
-
-//! Hash Digests and eXtendible Output Functions (XOFs)
-
-pub use digest::Digest;
-
-use digest::generic_array::typenum::U32;
-use digest::generic_array::typenum::U64;
-use digest::generic_array::GenericArray;
-use digest::BlockInput;
-use digest::FixedOutput;
-use digest::Input;
-
-use external::crypto_digest::get_256_bit_digest;
-use external::crypto_digest::get_512_bit_digest;
-use external::crypto_digest::CryptoDigest;
-use external::crypto_digest::DigestAlgorithm;
-
-pub use external::crypto_digest::DIGEST256_LEN;
-pub use external::crypto_digest::DIGEST512_LEN;
-
-/// The block size for both SHA-256 and SHA-512 digests is 512 bits/64 bytes.
-///
-/// Unfortunately, we have to use the generic_array crate currently to express
-/// this at compile time. Later, in the future, when Rust implements const
-/// generics, we'll be able to remove this dependency (actually, it will get
-/// removed from the digest crate, which is currently `pub use`ing it).
-type BlockSize = U64;
-
-/// A SHA2-256 digest.
-///
-/// # C_RUST_COUPLED
-///
-/// * `crypto_digest_dup`
-#[derive(Clone)]
-pub struct Sha256 {
- engine: CryptoDigest,
-}
-
-/// Construct a new, default instance of a `Sha256` hash digest function.
-///
-/// # Examples
-///
-/// ```rust,no_run
-/// use crypto::digests::sha2::{Sha256, Digest};
-///
-/// let mut hasher: Sha256 = Sha256::default();
-/// ```
-///
-/// # Returns
-///
-/// A new `Sha256` digest.
-impl Default for Sha256 {
- fn default() -> Sha256 {
- Sha256 {
- engine: CryptoDigest::new(Some(DigestAlgorithm::SHA2_256)),
- }
- }
-}
-
-impl BlockInput for Sha256 {
- type BlockSize = BlockSize;
-}
-
-/// Input `msg` into the digest.
-///
-/// # Examples
-///
-/// ```rust,no_run
-/// use crypto::digests::sha2::{Sha256, Digest};
-///
-/// let mut hasher: Sha256 = Sha256::default();
-///
-/// hasher.input(b"foo");
-/// hasher.input(b"bar");
-/// ```
-impl Input for Sha256 {
- fn process(&mut self, msg: &[u8]) {
- self.engine.add_bytes(&msg);
- }
-}
-
-/// Retrieve the output hash from everything which has been fed into this
-/// `Sha256` digest thus far.
-///
-//
-// FIXME: Once const generics land in Rust, we should genericise calling
-// crypto_digest_get_digest in external::crypto_digest.
-impl FixedOutput for Sha256 {
- type OutputSize = U32;
-
- fn fixed_result(self) -> GenericArray<u8, Self::OutputSize> {
- let buffer: [u8; DIGEST256_LEN] = get_256_bit_digest(self.engine);
-
- GenericArray::from(buffer)
- }
-}
-
-/// A SHA2-512 digest.
-///
-/// # C_RUST_COUPLED
-///
-/// * `crypto_digest_dup`
-#[derive(Clone)]
-pub struct Sha512 {
- engine: CryptoDigest,
-}
-
-/// Construct a new, default instance of a `Sha512` hash digest function.
-///
-/// # Examples
-///
-/// ```rust,no_run
-/// use crypto::digests::sha2::{Sha512, Digest};
-///
-/// let mut hasher: Sha512 = Sha512::default();
-/// ```
-///
-/// # Returns
-///
-/// A new `Sha512` digest.
-impl Default for Sha512 {
- fn default() -> Sha512 {
- Sha512 {
- engine: CryptoDigest::new(Some(DigestAlgorithm::SHA2_512)),
- }
- }
-}
-
-impl BlockInput for Sha512 {
- type BlockSize = BlockSize;
-}
-
-/// Input `msg` into the digest.
-///
-/// # Examples
-///
-/// ```rust,no_run
-/// use crypto::digests::sha2::{Sha512, Digest};
-///
-/// let mut hasher: Sha512 = Sha512::default();
-///
-/// hasher.input(b"foo");
-/// hasher.input(b"bar");
-/// ```
-impl Input for Sha512 {
- fn process(&mut self, msg: &[u8]) {
- self.engine.add_bytes(&msg);
- }
-}
-
-/// Retrieve the output hash from everything which has been fed into this
-/// `Sha512` digest thus far.
-///
-//
-// FIXME: Once const generics land in Rust, we should genericise calling
-// crypto_digest_get_digest in external::crypto_digest.
-impl FixedOutput for Sha512 {
- type OutputSize = U64;
-
- fn fixed_result(self) -> GenericArray<u8, Self::OutputSize> {
- let buffer: [u8; DIGEST512_LEN] = get_512_bit_digest(self.engine);
-
- GenericArray::clone_from_slice(&buffer)
- }
-}
-
-#[cfg(test)]
-mod test {
- #[cfg(feature = "test-c-from-rust")]
- use digest::Digest;
-
- #[cfg(feature = "test-c-from-rust")]
- use super::*;
-
- #[cfg(feature = "test-c-from-rust")]
- #[test]
- fn sha256_default() {
- let _: Sha256 = Sha256::default();
- }
-
- #[cfg(feature = "test-c-from-rust")]
- #[test]
- fn sha256_digest() {
- let mut h: Sha256 = Sha256::new();
- let mut result: [u8; DIGEST256_LEN] = [0u8; DIGEST256_LEN];
- let expected = [
- 151, 223, 53, 136, 181, 163, 242, 75, 171, 195, 133, 27, 55, 47, 11, 167, 26, 157, 205,
- 222, 212, 59, 20, 185, 208, 105, 97, 191, 193, 112, 125, 157,
- ];
-
- h.input(b"foo");
- h.input(b"bar");
- h.input(b"baz");
-
- result.copy_from_slice(h.fixed_result().as_slice());
-
- println!("{:?}", &result[..]);
-
- assert_eq!(result, expected);
- }
-
- #[cfg(feature = "test-c-from-rust")]
- #[test]
- fn sha512_default() {
- let _: Sha512 = Sha512::default();
- }
-
- #[cfg(feature = "test-c-from-rust")]
- #[test]
- fn sha512_digest() {
- let mut h: Sha512 = Sha512::new();
- let mut result: [u8; DIGEST512_LEN] = [0u8; DIGEST512_LEN];
-
- let expected = [
- 203, 55, 124, 16, 176, 245, 166, 44, 128, 54, 37, 167, 153, 217, 233, 8, 190, 69, 231,
- 103, 245, 209, 71, 212, 116, 73, 7, 203, 5, 89, 122, 164, 237, 211, 41, 160, 175, 20,
- 122, 221, 12, 244, 24, 30, 211, 40, 250, 30, 121, 148, 38, 88, 38, 179, 237, 61, 126,
- 246, 240, 103, 202, 153, 24, 90,
- ];
-
- h.input(b"foo");
- h.input(b"bar");
- h.input(b"baz");
-
- result.copy_from_slice(h.fixed_result().as_slice());
-
- println!("{:?}", &result[..]);
-
- assert_eq!(&result[..], &expected[..]);
- }
-}
diff --git a/src/rust/crypto/lib.rs b/src/rust/crypto/lib.rs
deleted file mode 100644
index 866ea93547..0000000000
--- a/src/rust/crypto/lib.rs
+++ /dev/null
@@ -1,46 +0,0 @@
-// Copyright (c) 2018-2019, The Tor Project, Inc.
-// Copyright (c) 2018, isis agora lovecruft
-// See LICENSE for licensing information
-
-//! Common cryptographic functions and utilities.
-//!
-//! # Hash Digests and eXtendable Output Functions (XOFs)
-//!
-//! The `digests` module contains submodules for specific hash digests
-//! and extendable output functions.
-//!
-//! ```rust,no_run
-//! use crypto::digests::sha2::*;
-//!
-//! let mut hasher: Sha256 = Sha256::default();
-//! let mut result: [u8; 32] = [0u8; 32];
-//!
-//! hasher.input(b"foo");
-//! hasher.input(b"bar");
-//! hasher.input(b"baz");
-//!
-//! result.copy_from_slice(hasher.result().as_slice());
-//!
-//! assert!(result == [b'X'; DIGEST256_LEN]);
-//! ```
-
-// XXX: add missing docs
-//#![deny(missing_docs)]
-
-// External crates from cargo or TOR_RUST_DEPENDENCIES.
-extern crate digest;
-extern crate libc;
-extern crate rand_core;
-
-// External dependencies for tests.
-#[cfg(test)]
-extern crate rand as rand_crate;
-
-// Our local crates.
-extern crate external;
-#[cfg(not(test))]
-#[macro_use]
-extern crate tor_log;
-
-pub mod digests; // Unfortunately named "digests" plural to avoid name conflict with the digest crate
-pub mod rand;
diff --git a/src/rust/crypto/rand/mod.rs b/src/rust/crypto/rand/mod.rs
deleted file mode 100644
index da8b3bd8a5..0000000000
--- a/src/rust/crypto/rand/mod.rs
+++ /dev/null
@@ -1,6 +0,0 @@
-// Copyright (c) 2018-2019, The Tor Project, Inc.
-// Copyright (c) 2018, isis agora lovecruft
-// See LICENSE for licensing information
-
-// Internal dependencies
-pub mod rng;
diff --git a/src/rust/crypto/rand/rng.rs b/src/rust/crypto/rand/rng.rs
deleted file mode 100644
index 644a5c20b1..0000000000
--- a/src/rust/crypto/rand/rng.rs
+++ /dev/null
@@ -1,145 +0,0 @@
-// Copyright (c) 2018-2019, The Tor Project, Inc.
-// Copyright (c) 2018, isis agora lovecruft
-// See LICENSE for licensing information
-
-//! Wrappers for Tor's random number generators to provide implementations of
-//! `rand_core` traits.
-
-// This is the real implementation, in use in production, which calls into our C
-// wrappers in /src/common/crypto_rand.c, which call into OpenSSL, system
-// libraries, and make syscalls.
-#[cfg(not(test))]
-mod internal {
- use std::u64;
-
- use rand_core::impls::next_u32_via_fill;
- use rand_core::impls::next_u64_via_fill;
- use rand_core::CryptoRng;
- use rand_core::Error;
- use rand_core::RngCore;
-
- use external::c_tor_crypto_rand;
- use external::c_tor_crypto_seed_rng;
- use external::c_tor_crypto_strongest_rand;
-
- use tor_log::LogDomain;
- use tor_log::LogSeverity;
-
- /// Largest strong entropy request permitted.
- //
- // C_RUST_COUPLED: `MAX_STRONGEST_RAND_SIZE` /src/common/crypto_rand.c
- const MAX_STRONGEST_RAND_SIZE: usize = 256;
-
- /// A wrapper around OpenSSL's RNG.
- pub struct TorRng {
- // This private, zero-length field forces the struct to be treated the
- // same as its opaque C counterpart.
- _unused: [u8; 0],
- }
-
- /// Mark `TorRng` as being suitable for cryptographic purposes.
- impl CryptoRng for TorRng {}
-
- impl TorRng {
- // C_RUST_COUPLED: `crypto_seed_rng()` /src/common/crypto_rand.c
- #[allow(dead_code)]
- pub fn new() -> Self {
- if !c_tor_crypto_seed_rng() {
- tor_log_msg!(
- LogSeverity::Warn,
- LogDomain::General,
- "TorRng::from_seed()",
- "The RNG could not be seeded!"
- );
- }
- // XXX also log success at info level —isis
- TorRng { _unused: [0u8; 0] }
- }
- }
-
- impl RngCore for TorRng {
- // C_RUST_COUPLED: `crypto_strongest_rand()` /src/common/crypto_rand.c
- fn next_u32(&mut self) -> u32 {
- next_u32_via_fill(self)
- }
-
- // C_RUST_COUPLED: `crypto_strongest_rand()` /src/common/crypto_rand.c
- fn next_u64(&mut self) -> u64 {
- next_u64_via_fill(self)
- }
-
- // C_RUST_COUPLED: `crypto_strongest_rand()` /src/common/crypto_rand.c
- fn fill_bytes(&mut self, dest: &mut [u8]) {
- c_tor_crypto_rand(dest);
- }
-
- // C_RUST_COUPLED: `crypto_strongest_rand()` /src/common/crypto_rand.c
- fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
- Ok(self.fill_bytes(dest))
- }
- }
-
- /// A CSPRNG which hashes together randomness from OpenSSL's RNG and entropy
- /// obtained from the operating system.
- pub struct TorStrongestRng {
- // This private, zero-length field forces the struct to be treated the
- // same as its opaque C counterpart.
- _unused: [u8; 0],
- }
-
- /// Mark `TorRng` as being suitable for cryptographic purposes.
- impl CryptoRng for TorStrongestRng {}
-
- impl TorStrongestRng {
- // C_RUST_COUPLED: `crypto_seed_rng()` /src/common/crypto_rand.c
- #[allow(dead_code)]
- pub fn new() -> Self {
- if !c_tor_crypto_seed_rng() {
- tor_log_msg!(
- LogSeverity::Warn,
- LogDomain::General,
- "TorStrongestRng::from_seed()",
- "The RNG could not be seeded!"
- );
- }
- // XXX also log success at info level —isis
- TorStrongestRng { _unused: [0u8; 0] }
- }
- }
-
- impl RngCore for TorStrongestRng {
- // C_RUST_COUPLED: `crypto_strongest_rand()` /src/common/crypto_rand.c
- fn next_u32(&mut self) -> u32 {
- next_u32_via_fill(self)
- }
-
- // C_RUST_COUPLED: `crypto_strongest_rand()` /src/common/crypto_rand.c
- fn next_u64(&mut self) -> u64 {
- next_u64_via_fill(self)
- }
-
- // C_RUST_COUPLED: `crypto_strongest_rand()` /src/common/crypto_rand.c
- fn fill_bytes(&mut self, dest: &mut [u8]) {
- debug_assert!(dest.len() <= MAX_STRONGEST_RAND_SIZE);
-
- c_tor_crypto_strongest_rand(dest);
- }
-
- // C_RUST_COUPLED: `crypto_strongest_rand()` /src/common/crypto_rand.c
- fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
- Ok(self.fill_bytes(dest))
- }
- }
-}
-
-// For testing, we expose a pure-Rust implementation.
-#[cfg(test)]
-mod internal {
- // It doesn't matter if we pretend ChaCha is a CSPRNG in tests.
- pub use rand_crate::ChaChaRng as TorRng;
- pub use rand_crate::ChaChaRng as TorStrongestRng;
-}
-
-// Finally, expose the public functionality of whichever appropriate internal
-// module.
-pub use self::internal::*;
diff --git a/src/rust/external/Cargo.toml b/src/rust/external/Cargo.toml
deleted file mode 100644
index 5f443645bb..0000000000
--- a/src/rust/external/Cargo.toml
+++ /dev/null
@@ -1,20 +0,0 @@
-[package]
-authors = ["The Tor Project"]
-version = "0.0.1"
-name = "external"
-
-[dependencies]
-libc = "=0.2.39"
-smartlist = { path = "../smartlist" }
-tor_allocate = { path = "../tor_allocate" }
-
-[lib]
-name = "external"
-path = "lib.rs"
-
-[features]
-# We have to define a feature here because doctests don't get cfg(test),
-# and we need to disable some C dependencies when running the doctests
-# because of the various linker issues. See
-# https://github.com/rust-lang/rust/issues/45599
-test_linking_hack = []
diff --git a/src/rust/external/crypto_digest.rs b/src/rust/external/crypto_digest.rs
deleted file mode 100644
index 873f75e7a3..0000000000
--- a/src/rust/external/crypto_digest.rs
+++ /dev/null
@@ -1,454 +0,0 @@
-// Copyright (c) 2018-2019, The Tor Project, Inc.
-// Copyright (c) 2018, isis agora lovecruft
-// See LICENSE for licensing information
-
-//! Bindings to external digest and XOF functions which live within
-//! src/common/crypto_digest.[ch].
-//!
-//! We wrap our C implementations in src/common/crypto_digest.[ch] with more
-//! Rusty types and interfaces in src/rust/crypto/digest/.
-
-use std::process::abort;
-
-use libc::c_char;
-use libc::c_int;
-use libc::size_t;
-use libc::uint8_t;
-
-use smartlist::Stringlist;
-
-/// Length of the output of our message digest.
-pub const DIGEST_LEN: usize = 20;
-
-/// Length of the output of our second (improved) message digests. (For now
-/// this is just sha256, but it could be any other 256-bit digest.)
-pub const DIGEST256_LEN: usize = 32;
-
-/// Length of the output of our 64-bit optimized message digests (SHA512).
-pub const DIGEST512_LEN: usize = 64;
-
-/// Length of a sha1 message digest when encoded in base32 with trailing = signs
-/// removed.
-pub const BASE32_DIGEST_LEN: usize = 32;
-
-/// Length of a sha1 message digest when encoded in base64 with trailing = signs
-/// removed.
-pub const BASE64_DIGEST_LEN: usize = 27;
-
-/// Length of a sha256 message digest when encoded in base64 with trailing =
-/// signs removed.
-pub const BASE64_DIGEST256_LEN: usize = 43;
-
-/// Length of a sha512 message digest when encoded in base64 with trailing =
-/// signs removed.
-pub const BASE64_DIGEST512_LEN: usize = 86;
-
-/// Length of hex encoding of SHA1 digest, not including final NUL.
-pub const HEX_DIGEST_LEN: usize = 40;
-
-/// Length of hex encoding of SHA256 digest, not including final NUL.
-pub const HEX_DIGEST256_LEN: usize = 64;
-
-/// Length of hex encoding of SHA512 digest, not including final NUL.
-pub const HEX_DIGEST512_LEN: usize = 128;
-
-/// Our C code uses an enum to declare the digest algorithm types which we know
-/// about. However, because enums are implementation-defined in C, we can
-/// neither work with them directly nor translate them into Rust enums.
-/// Instead, we represent them as a u8 (under the assumption that we'll never
-/// support more than 256 hash functions).
-#[allow(non_camel_case_types)]
-type digest_algorithm_t = u8;
-
-const DIGEST_SHA1: digest_algorithm_t = 0;
-const DIGEST_SHA256: digest_algorithm_t = 1;
-const DIGEST_SHA512: digest_algorithm_t = 2;
-const DIGEST_SHA3_256: digest_algorithm_t = 3;
-const DIGEST_SHA3_512: digest_algorithm_t = 4;
-
-/// The number of hash digests we produce for a `common_digests_t`.
-///
-/// We can't access these from Rust, because their definitions in C require
-/// introspecting the `digest_algorithm_t` typedef, which is an enum, so we have
-/// to redefine them here.
-const N_COMMON_DIGEST_ALGORITHMS: usize = DIGEST_SHA256 as usize + 1;
-
-/// A digest function.
-#[repr(C)]
-#[derive(Debug, Copy, Clone)]
-#[allow(non_camel_case_types)]
-struct crypto_digest_t {
- // This private, zero-length field forces the struct to be treated the same
- // as its opaque C counterpart.
- _unused: [u8; 0],
-}
-
-/// An eXtendible Output Function (XOF).
-#[repr(C)]
-#[derive(Debug, Copy, Clone)]
-#[allow(non_camel_case_types)]
-struct crypto_xof_t {
- // This private, zero-length field forces the struct to be treated the same
- // as its opaque C counterpart.
- _unused: [u8; 0],
-}
-
-/// A set of all the digests we commonly compute, taken on a single
-/// string. Any digests that are shorter than 512 bits are right-padded
-/// with 0 bits.
-///
-/// Note that this representation wastes 44 bytes for the SHA1 case, so
-/// don't use it for anything where we need to allocate a whole bunch at
-/// once.
-#[repr(C)]
-#[derive(Debug, Copy, Clone)]
-#[allow(non_camel_case_types)]
-struct common_digests_t {
- pub d: [[c_char; N_COMMON_DIGEST_ALGORITHMS]; DIGEST256_LEN],
-}
-
-/// A `smartlist_t` is just an alias for the `#[repr(C)]` type `Stringlist`, to
-/// make it more clear that we're working with a smartlist which is owned by C.
-#[allow(non_camel_case_types)]
-// BINDGEN_GENERATED: This type isn't actually bindgen generated, but the code
-// below it which uses it is. As such, this comes up as "dead code" as well.
-#[allow(dead_code)]
-type smartlist_t = Stringlist;
-
-/// All of the external functions from `src/common/crypto_digest.h`.
-///
-/// These are kept private because they should be wrapped with Rust to make their usage safer.
-//
-// BINDGEN_GENERATED: These definitions were generated with bindgen and cleaned
-// up manually. As such, there are more bindings than are likely necessary or
-// which are in use.
-#[allow(dead_code)]
-extern "C" {
- fn crypto_digest(digest: *mut c_char, m: *const c_char, len: size_t) -> c_int;
- fn crypto_digest256(
- digest: *mut c_char,
- m: *const c_char,
- len: size_t,
- algorithm: digest_algorithm_t,
- ) -> c_int;
- fn crypto_digest512(
- digest: *mut c_char,
- m: *const c_char,
- len: size_t,
- algorithm: digest_algorithm_t,
- ) -> c_int;
- fn crypto_common_digests(ds_out: *mut common_digests_t, m: *const c_char, len: size_t)
- -> c_int;
- fn crypto_digest_smartlist_prefix(
- digest_out: *mut c_char,
- len_out: size_t,
- prepend: *const c_char,
- lst: *const smartlist_t,
- append: *const c_char,
- alg: digest_algorithm_t,
- );
- fn crypto_digest_smartlist(
- digest_out: *mut c_char,
- len_out: size_t,
- lst: *const smartlist_t,
- append: *const c_char,
- alg: digest_algorithm_t,
- );
- fn crypto_digest_algorithm_get_name(alg: digest_algorithm_t) -> *const c_char;
- fn crypto_digest_algorithm_get_length(alg: digest_algorithm_t) -> size_t;
- fn crypto_digest_algorithm_parse_name(name: *const c_char) -> c_int;
- fn crypto_digest_new() -> *mut crypto_digest_t;
- fn crypto_digest256_new(algorithm: digest_algorithm_t) -> *mut crypto_digest_t;
- fn crypto_digest512_new(algorithm: digest_algorithm_t) -> *mut crypto_digest_t;
- fn crypto_digest_free_(digest: *mut crypto_digest_t);
- fn crypto_digest_add_bytes(digest: *mut crypto_digest_t, data: *const c_char, len: size_t);
- fn crypto_digest_get_digest(digest: *mut crypto_digest_t, out: *mut c_char, out_len: size_t);
- fn crypto_digest_dup(digest: *const crypto_digest_t) -> *mut crypto_digest_t;
- fn crypto_digest_assign(into: *mut crypto_digest_t, from: *const crypto_digest_t);
- fn crypto_hmac_sha256(
- hmac_out: *mut c_char,
- key: *const c_char,
- key_len: size_t,
- msg: *const c_char,
- msg_len: size_t,
- );
- fn crypto_mac_sha3_256(
- mac_out: *mut uint8_t,
- len_out: size_t,
- key: *const uint8_t,
- key_len: size_t,
- msg: *const uint8_t,
- msg_len: size_t,
- );
- fn crypto_xof_new() -> *mut crypto_xof_t;
- fn crypto_xof_add_bytes(xof: *mut crypto_xof_t, data: *const uint8_t, len: size_t);
- fn crypto_xof_squeeze_bytes(xof: *mut crypto_xof_t, out: *mut uint8_t, len: size_t);
- fn crypto_xof_free(xof: *mut crypto_xof_t);
-}
-
-/// A wrapper around a `digest_algorithm_t`.
-pub enum DigestAlgorithm {
- SHA2_256,
- SHA2_512,
- SHA3_256,
- SHA3_512,
-}
-
-impl From<DigestAlgorithm> for digest_algorithm_t {
- fn from(digest: DigestAlgorithm) -> digest_algorithm_t {
- match digest {
- DigestAlgorithm::SHA2_256 => DIGEST_SHA256,
- DigestAlgorithm::SHA2_512 => DIGEST_SHA512,
- DigestAlgorithm::SHA3_256 => DIGEST_SHA3_256,
- DigestAlgorithm::SHA3_512 => DIGEST_SHA3_512,
- }
- }
-}
-
-/// A wrapper around a mutable pointer to a `crypto_digest_t`.
-pub struct CryptoDigest(*mut crypto_digest_t);
-
-/// Explicitly copy the state of a `CryptoDigest` hash digest context.
-///
-/// # C_RUST_COUPLED
-///
-/// * `crypto_digest_dup`
-impl Clone for CryptoDigest {
- fn clone(&self) -> CryptoDigest {
- let digest: *mut crypto_digest_t;
-
- unsafe {
- digest = crypto_digest_dup(self.0 as *const crypto_digest_t);
- }
-
- // See the note in the implementation of CryptoDigest for the
- // reasoning for `abort()` here.
- if digest.is_null() {
- abort();
- }
-
- CryptoDigest(digest)
- }
-}
-
-impl CryptoDigest {
- /// A wrapper to call one of the C functions `crypto_digest_new`,
- /// `crypto_digest256_new`, or `crypto_digest512_new`.
- ///
- /// # Warnings
- ///
- /// This function will `abort()` the entire process in an "abnormal" fashion,
- /// i.e. not unwinding this or any other thread's stack, running any
- /// destructors, or calling any panic/exit hooks) if `tor_malloc()` (called in
- /// `crypto_digest256_new()`) is unable to allocate memory.
- ///
- /// # Returns
- ///
- /// A new `CryptoDigest`, which is a wrapper around a opaque representation
- /// of a `crypto_digest_t`. The underlying `crypto_digest_t` _MUST_ only
- /// ever be handled via a raw pointer, and never introspected.
- ///
- /// # C_RUST_COUPLED
- ///
- /// * `crypto_digest_new`
- /// * `crypto_digest256_new`
- /// * `crypto_digest512_new`
- /// * `tor_malloc` (called by `crypto_digest256_new`, but we make
- /// assumptions about its behaviour and return values here)
- pub fn new(algorithm: Option<DigestAlgorithm>) -> CryptoDigest {
- let digest: *mut crypto_digest_t;
-
- if algorithm.is_none() {
- unsafe {
- digest = crypto_digest_new();
- }
- } else {
- let algo: digest_algorithm_t = algorithm.unwrap().into(); // can't fail because it's Some
-
- unsafe {
- // XXX This is a pretty awkward API to use from Rust...
- digest = match algo {
- DIGEST_SHA1 => crypto_digest_new(),
- DIGEST_SHA256 => crypto_digest256_new(DIGEST_SHA256),
- DIGEST_SHA3_256 => crypto_digest256_new(DIGEST_SHA3_256),
- DIGEST_SHA512 => crypto_digest512_new(DIGEST_SHA512),
- DIGEST_SHA3_512 => crypto_digest512_new(DIGEST_SHA3_512),
- _ => abort(),
- }
- }
- }
-
- // In our C code, `crypto_digest*_new()` allocates memory with
- // `tor_malloc()`. In `tor_malloc()`, if the underlying malloc
- // implementation fails to allocate the requested memory and returns a
- // NULL pointer, we call `exit(1)`. In the case that this `exit(1)` is
- // called within a worker, be that a process or a thread, the inline
- // comments within `tor_malloc()` mention "that's ok, since the parent
- // will run out of memory soon anyway". However, if it takes long
- // enough for the worker to die, and it manages to return a NULL pointer
- // to our Rust code, our Rust is now in an irreparably broken state and
- // may exhibit undefined behaviour. An even worse scenario, if/when we
- // have parent/child processes/threads controlled by Rust, would be that
- // the UB contagion in Rust manages to spread to other children before
- // the entire process (hopefully terminates).
- //
- // However, following the assumptions made in `tor_malloc()` that
- // calling `exit(1)` in a child is okay because the parent will
- // eventually run into the same errors, and also to stymie any UB
- // contagion in the meantime, we call abort!() here to terminate the
- // entire program immediately.
- if digest.is_null() {
- abort();
- }
-
- CryptoDigest(digest)
- }
-
- /// A wrapper to call the C function `crypto_digest_add_bytes`.
- ///
- /// # Inputs
- ///
- /// * `bytes`: a byte slice of bytes to be added into this digest.
- ///
- /// # C_RUST_COUPLED
- ///
- /// * `crypto_digest_add_bytes`
- pub fn add_bytes(&self, bytes: &[u8]) {
- unsafe {
- crypto_digest_add_bytes(
- self.0 as *mut crypto_digest_t,
- bytes.as_ptr() as *const c_char,
- bytes.len() as size_t,
- )
- }
- }
-}
-
-impl Drop for CryptoDigest {
- fn drop(&mut self) {
- unsafe {
- crypto_digest_free_(self.0 as *mut crypto_digest_t);
- }
- }
-}
-
-/// Get the 256-bit digest output of a `crypto_digest_t`.
-///
-/// # Inputs
-///
-/// * `digest`: A `CryptoDigest` which wraps either a `DIGEST_SHA256` or a
-/// `DIGEST_SHA3_256`.
-///
-/// # Warning
-///
-/// Calling this function with a `CryptoDigest` which is neither SHA2-256 or
-/// SHA3-256 is a programming error. Since we cannot introspect the opaque
-/// struct from Rust, however, there is no way for us to check that the correct
-/// one is being passed in. That is up to you, dear programmer. If you mess
-/// up, you will get a incorrectly-sized hash digest in return, and it will be
-/// your fault. Don't do that.
-///
-/// # Returns
-///
-/// A 256-bit hash digest, as a `[u8; 32]`.
-///
-/// # C_RUST_COUPLED
-///
-/// * `crypto_digest_get_digest`
-/// * `DIGEST256_LEN`
-//
-// FIXME: Once const generics land in Rust, we should genericise calling
-// crypto_digest_get_digest w.r.t. output array size.
-pub fn get_256_bit_digest(digest: CryptoDigest) -> [u8; DIGEST256_LEN] {
- let mut buffer: [u8; DIGEST256_LEN] = [0u8; DIGEST256_LEN];
-
- unsafe {
- crypto_digest_get_digest(
- digest.0,
- buffer.as_mut_ptr() as *mut c_char,
- DIGEST256_LEN as size_t,
- );
-
- if buffer.as_ptr().is_null() {
- abort();
- }
- }
- buffer
-}
-
-/// Get the 512-bit digest output of a `crypto_digest_t`.
-///
-/// # Inputs
-///
-/// * `digest`: A `CryptoDigest` which wraps either a `DIGEST_SHA512` or a
-/// `DIGEST_SHA3_512`.
-///
-/// # Warning
-///
-/// Calling this function with a `CryptoDigest` which is neither SHA2-512 or
-/// SHA3-512 is a programming error. Since we cannot introspect the opaque
-/// struct from Rust, however, there is no way for us to check that the correct
-/// one is being passed in. That is up to you, dear programmer. If you mess
-/// up, you will get a incorrectly-sized hash digest in return, and it will be
-/// your fault. Don't do that.
-///
-/// # Returns
-///
-/// A 512-bit hash digest, as a `[u8; 64]`.
-///
-/// # C_RUST_COUPLED
-///
-/// * `crypto_digest_get_digest`
-/// * `DIGEST512_LEN`
-//
-// FIXME: Once const generics land in Rust, we should genericise calling
-// crypto_digest_get_digest w.r.t. output array size.
-pub fn get_512_bit_digest(digest: CryptoDigest) -> [u8; DIGEST512_LEN] {
- let mut buffer: [u8; DIGEST512_LEN] = [0u8; DIGEST512_LEN];
-
- unsafe {
- crypto_digest_get_digest(
- digest.0,
- buffer.as_mut_ptr() as *mut c_char,
- DIGEST512_LEN as size_t,
- );
-
- if buffer.as_ptr().is_null() {
- abort();
- }
- }
- buffer
-}
-
-#[cfg(test)]
-mod test {
- use super::*;
-
- #[test]
- fn test_layout_common_digests_t() {
- assert_eq!(
- ::std::mem::size_of::<common_digests_t>(),
- 64usize,
- concat!("Size of: ", stringify!(common_digests_t))
- );
- assert_eq!(
- ::std::mem::align_of::<common_digests_t>(),
- 1usize,
- concat!("Alignment of ", stringify!(common_digests_t))
- );
- }
-
- #[test]
- fn test_layout_crypto_digest_t() {
- assert_eq!(
- ::std::mem::size_of::<crypto_digest_t>(),
- 0usize,
- concat!("Size of: ", stringify!(crypto_digest_t))
- );
- assert_eq!(
- ::std::mem::align_of::<crypto_digest_t>(),
- 1usize,
- concat!("Alignment of ", stringify!(crypto_digest_t))
- );
- }
-}
diff --git a/src/rust/external/crypto_rand.rs b/src/rust/external/crypto_rand.rs
deleted file mode 100644
index 703382093c..0000000000
--- a/src/rust/external/crypto_rand.rs
+++ /dev/null
@@ -1,84 +0,0 @@
-// Copyright (c) 2018-2019, The Tor Project, Inc.
-// Copyright (c) 2018, isis agora lovecruft
-// See LICENSE for licensing information
-
-//! Bindings to external (P)RNG interfaces and utilities in
-//! src/common/crypto_rand.[ch].
-//!
-//! We wrap our C implementations in src/common/crypto_rand.[ch] here in order
-//! to provide wrappers with native Rust types, and then provide more Rusty
-//! types and and trait implementations in src/rust/crypto/rand/.
-
-use std::time::Duration;
-
-use libc::c_double;
-use libc::c_int;
-use libc::size_t;
-use libc::time_t;
-use libc::uint8_t;
-
-extern "C" {
- fn crypto_seed_rng() -> c_int;
- fn crypto_rand(out: *mut uint8_t, out_len: size_t);
- fn crypto_strongest_rand(out: *mut uint8_t, out_len: size_t);
- fn crypto_rand_time_range(min: time_t, max: time_t) -> time_t;
- fn crypto_rand_double() -> c_double;
-}
-
-/// Seed OpenSSL's random number generator with bytes from the operating
-/// system.
-///
-/// # Returns
-///
-/// `true` on success; `false` on failure.
-pub fn c_tor_crypto_seed_rng() -> bool {
- let ret: c_int;
-
- unsafe {
- ret = crypto_seed_rng();
- }
- match ret {
- 0 => return true,
- _ => return false,
- }
-}
-
-/// Fill the bytes of `dest` with random data.
-pub fn c_tor_crypto_rand(dest: &mut [u8]) {
- unsafe {
- crypto_rand(dest.as_mut_ptr(), dest.len() as size_t);
- }
-}
-
-/// Fill the bytes of `dest` with "strong" random data by hashing
-/// together randomness obtained from OpenSSL's RNG and the operating
-/// system.
-pub fn c_tor_crypto_strongest_rand(dest: &mut [u8]) {
- // We'll let the C side panic if the len is larger than
- // MAX_STRONGEST_RAND_SIZE, rather than potentially panicking here. A
- // paranoid caller should assert on the length of dest *before* calling this
- // function.
- unsafe {
- crypto_strongest_rand(dest.as_mut_ptr(), dest.len() as size_t);
- }
-}
-
-/// Get a random time, in seconds since the Unix Epoch.
-///
-/// # Returns
-///
-/// A `std::time::Duration` of seconds since the Unix Epoch.
-pub fn c_tor_crypto_rand_time_range(min: &Duration, max: &Duration) -> Duration {
- let ret: time_t;
-
- unsafe {
- ret = crypto_rand_time_range(min.as_secs() as time_t, max.as_secs() as time_t);
- }
-
- Duration::from_secs(ret as u64)
-}
-
-/// Return a pseudorandom 64-bit float, chosen uniformly from the range [0.0, 1.0).
-pub fn c_tor_crypto_rand_double() -> f64 {
- unsafe { crypto_rand_double() }
-}
diff --git a/src/rust/external/external.rs b/src/rust/external/external.rs
deleted file mode 100644
index 0d324c8820..0000000000
--- a/src/rust/external/external.rs
+++ /dev/null
@@ -1,37 +0,0 @@
-// Copyright (c) 2016-2019, The Tor Project, Inc. */
-// See LICENSE for licensing information */
-
-use libc::{c_char, c_int};
-use std::ffi::CString;
-
-extern "C" {
- fn tor_version_as_new_as(platform: *const c_char, cutoff: *const c_char) -> c_int;
-}
-
-/// Wrap calls to tor_version_as_new_as, defined in routerparse.c
-pub fn c_tor_version_as_new_as(platform: &str, cutoff: &str) -> bool {
- // CHK: These functions should log a warning if an error occurs. This
- // can be added when integration with tor's logger is added to rust
- let c_platform = match CString::new(platform) {
- Ok(n) => n,
- Err(_) => return false,
- };
-
- let c_cutoff = match CString::new(cutoff) {
- Ok(n) => n,
- Err(_) => return false,
- };
-
- let result: c_int = unsafe { tor_version_as_new_as(c_platform.as_ptr(), c_cutoff.as_ptr()) };
-
- result == 1
-}
-
-extern "C" {
- fn tor_is_using_nss() -> c_int;
-}
-
-/// Return true if Tor was built to use NSS.
-pub fn c_tor_is_using_nss() -> bool {
- 0 != unsafe { tor_is_using_nss() }
-}
diff --git a/src/rust/external/lib.rs b/src/rust/external/lib.rs
deleted file mode 100644
index 2f50610a4d..0000000000
--- a/src/rust/external/lib.rs
+++ /dev/null
@@ -1,19 +0,0 @@
-//! Copyright (c) 2016-2019, The Tor Project, Inc. */
-//! See LICENSE for licensing information */
-
-//! Interface for external calls to tor C ABI
-//!
-//! The purpose of this module is to provide a clean interface for when Rust
-//! modules need to interact with functionality in tor C code rather than each
-//! module implementing this functionality repeatedly.
-
-extern crate libc;
-extern crate tor_allocate;
-extern crate smartlist;
-
-pub mod crypto_digest;
-mod crypto_rand;
-mod external;
-
-pub use crypto_rand::*;
-pub use external::*;
diff --git a/src/rust/include.am b/src/rust/include.am
deleted file mode 100644
index 5e5b0b3faf..0000000000
--- a/src/rust/include.am
+++ /dev/null
@@ -1,41 +0,0 @@
-include src/rust/tor_rust/include.am
-
-EXTRA_DIST +=\
- src/rust/build.rs \
- src/rust/Cargo.toml \
- src/rust/Cargo.lock \
- src/rust/.cargo/config.in \
- src/rust/crypto/Cargo.toml \
- src/rust/crypto/lib.rs \
- src/rust/crypto/digests/mod.rs \
- src/rust/crypto/digests/sha2.rs \
- src/rust/crypto/rand/mod.rs \
- src/rust/crypto/rand/rng.rs \
- src/rust/external/Cargo.toml \
- src/rust/external/crypto_digest.rs \
- src/rust/external/crypto_rand.rs \
- src/rust/external/external.rs \
- src/rust/external/lib.rs \
- src/rust/protover/Cargo.toml \
- src/rust/protover/errors.rs \
- src/rust/protover/protoset.rs \
- src/rust/protover/ffi.rs \
- src/rust/protover/lib.rs \
- src/rust/protover/protover.rs \
- src/rust/protover/tests/protover.rs \
- src/rust/smartlist/Cargo.toml \
- src/rust/smartlist/lib.rs \
- src/rust/smartlist/smartlist.rs \
- src/rust/tor_allocate/Cargo.toml \
- src/rust/tor_allocate/lib.rs \
- src/rust/tor_allocate/tor_allocate.rs \
- src/rust/tor_log/Cargo.toml \
- src/rust/tor_log/lib.rs \
- src/rust/tor_log/tor_log.rs \
- src/rust/tor_rust/Cargo.toml \
- src/rust/tor_rust/include.am \
- src/rust/tor_rust/lib.rs \
- src/rust/tor_util/Cargo.toml \
- src/rust/tor_util/ffi.rs \
- src/rust/tor_util/lib.rs \
- src/rust/tor_util/strings.rs
diff --git a/src/rust/protover/Cargo.toml b/src/rust/protover/Cargo.toml
deleted file mode 100644
index 84a7c71c1a..0000000000
--- a/src/rust/protover/Cargo.toml
+++ /dev/null
@@ -1,33 +0,0 @@
-[package]
-authors = ["The Tor Project"]
-version = "0.0.1"
-name = "protover"
-
-[features]
-# We have to define a feature here because doctests don't get cfg(test),
-# and we need to disable some C dependencies when running the doctests
-# because of the various linker issues. See
-# https://github.com/rust-lang/rust/issues/45599
-test_linking_hack = []
-
-[dependencies]
-libc = "=0.2.39"
-
-[dependencies.smartlist]
-path = "../smartlist"
-
-[dependencies.external]
-path = "../external"
-
-[dependencies.tor_util]
-path = "../tor_util"
-
-[dependencies.tor_allocate]
-path = "../tor_allocate"
-
-[dependencies.tor_log]
-path = "../tor_log"
-
-[lib]
-name = "protover"
-path = "lib.rs"
diff --git a/src/rust/protover/errors.rs b/src/rust/protover/errors.rs
deleted file mode 100644
index 04397ac4fe..0000000000
--- a/src/rust/protover/errors.rs
+++ /dev/null
@@ -1,57 +0,0 @@
-// Copyright (c) 2018-2019, The Tor Project, Inc.
-// Copyright (c) 2018, isis agora lovecruft
-// See LICENSE for licensing information
-
-//! Various errors which may occur during protocol version parsing.
-
-use std::fmt;
-use std::fmt::Display;
-
-/// All errors which may occur during protover parsing routines.
-#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
-#[allow(missing_docs)] // See Display impl for error descriptions
-pub enum ProtoverError {
- Overlap,
- LowGreaterThanHigh,
- Unparseable,
- ExceedsMax,
- ExceedsExpansionLimit,
- UnknownProtocol,
- ExceedsNameLimit,
- InvalidProtocol,
-}
-
-/// Descriptive error messages for `ProtoverError` variants.
-impl Display for ProtoverError {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- match *self {
- ProtoverError::Overlap => write!(
- f,
- "Two or more (low, high) protover ranges would overlap once expanded."
- ),
- ProtoverError::LowGreaterThanHigh => write!(
- f,
- "The low in a (low, high) protover range was greater than high."
- ),
- ProtoverError::Unparseable => write!(f, "The protover string was unparseable."),
- ProtoverError::ExceedsMax => write!(
- f,
- "The high in a (low, high) protover range exceeds 63."
- ),
- ProtoverError::ExceedsExpansionLimit => write!(
- f,
- "The protover string would exceed the maximum expansion limit."
- ),
- ProtoverError::UnknownProtocol => write!(
- f,
- "A protocol in the protover string we attempted to parse is unknown."
- ),
- ProtoverError::ExceedsNameLimit => {
- write!(f, "An unrecognised protocol name was too long.")
- }
- ProtoverError::InvalidProtocol => {
- write!(f, "A protocol name includes invalid characters.")
- }
- }
- }
-}
diff --git a/src/rust/protover/ffi.rs b/src/rust/protover/ffi.rs
deleted file mode 100644
index 2bf8d3a987..0000000000
--- a/src/rust/protover/ffi.rs
+++ /dev/null
@@ -1,247 +0,0 @@
-// Copyright (c) 2016-2019, The Tor Project, Inc. */
-// See LICENSE for licensing information */
-
-//! FFI functions, only to be called from C.
-//!
-//! Equivalent C versions of this api are in `protover.c`
-
-use libc::{c_char, c_int, uint32_t};
-use std::ffi::CStr;
-
-use smartlist::*;
-use tor_allocate::allocate_and_copy_string;
-
-use errors::ProtoverError;
-use protover::*;
-
-/// Translate C enums to Rust Proto enums, using the integer value of the C
-/// enum to map to its associated Rust enum.
-///
-/// C_RUST_COUPLED: protover.h `protocol_type_t`
-fn translate_to_rust(c_proto: uint32_t) -> Result<Protocol, ProtoverError> {
- match c_proto {
- 0 => Ok(Protocol::Link),
- 1 => Ok(Protocol::LinkAuth),
- 2 => Ok(Protocol::Relay),
- 3 => Ok(Protocol::DirCache),
- 4 => Ok(Protocol::HSDir),
- 5 => Ok(Protocol::HSIntro),
- 6 => Ok(Protocol::HSRend),
- 7 => Ok(Protocol::Desc),
- 8 => Ok(Protocol::Microdesc),
- 9 => Ok(Protocol::Cons),
- 10 => Ok(Protocol::Padding),
- 11 => Ok(Protocol::FlowCtrl),
- _ => Err(ProtoverError::UnknownProtocol),
- }
-}
-
-/// Provide an interface for C to translate arguments and return types for
-/// protover::all_supported
-#[no_mangle]
-pub extern "C" fn protover_all_supported(
- c_relay_version: *const c_char,
- missing_out: *mut *mut c_char,
-) -> c_int {
- if c_relay_version.is_null() {
- return 1;
- }
-
- // Require an unsafe block to read the version from a C string. The pointer
- // is checked above to ensure it is not null.
- let c_str: &CStr = unsafe { CStr::from_ptr(c_relay_version) };
-
- let relay_version = match c_str.to_str() {
- Ok(n) => n,
- Err(_) => return 1,
- };
-
- let relay_proto_entry: UnvalidatedProtoEntry =
- match UnvalidatedProtoEntry::from_str_any_len(relay_version) {
- Ok(n) => n,
- Err(_) => return 1,
- };
-
- if let Some(unsupported) = relay_proto_entry.all_supported() {
- if missing_out.is_null() {
- return 0;
- }
- let ptr = allocate_and_copy_string(&unsupported.to_string());
- unsafe { *missing_out = ptr };
-
- return 0;
- }
-
- 1
-}
-
-/// Provide an interface for C to translate arguments and return types for
-/// protover::list_supports_protocol
-#[no_mangle]
-pub extern "C" fn protocol_list_supports_protocol(
- c_protocol_list: *const c_char,
- c_protocol: uint32_t,
- version: uint32_t,
-) -> c_int {
- if c_protocol_list.is_null() {
- return 0;
- }
-
- // Require an unsafe block to read the version from a C string. The pointer
- // is checked above to ensure it is not null.
- let c_str: &CStr = unsafe { CStr::from_ptr(c_protocol_list) };
-
- let protocol_list = match c_str.to_str() {
- Ok(n) => n,
- Err(_) => return 0,
- };
- let proto_entry: UnvalidatedProtoEntry = match protocol_list.parse() {
- Ok(n) => n,
- Err(_) => return 0,
- };
- let protocol: UnknownProtocol = match translate_to_rust(c_protocol) {
- Ok(n) => n.into(),
- Err(_) => return 0,
- };
- if proto_entry.supports_protocol(&protocol, &version) {
- 1
- } else {
- 0
- }
-}
-
-#[no_mangle]
-pub extern "C" fn protover_contains_long_protocol_names_(c_protocol_list: *const c_char) -> c_int {
- if c_protocol_list.is_null() {
- return 1;
- }
-
- // Require an unsafe block to read the version from a C string. The pointer
- // is checked above to ensure it is not null.
- let c_str: &CStr = unsafe { CStr::from_ptr(c_protocol_list) };
-
- let protocol_list = match c_str.to_str() {
- Ok(n) => n,
- Err(_) => return 1,
- };
-
- match protocol_list.parse::<UnvalidatedProtoEntry>() {
- Ok(_) => 0,
- Err(_) => 1,
- }
-}
-
-/// Provide an interface for C to translate arguments and return types for
-/// protover::list_supports_protocol_or_later
-#[no_mangle]
-pub extern "C" fn protocol_list_supports_protocol_or_later(
- c_protocol_list: *const c_char,
- c_protocol: uint32_t,
- version: uint32_t,
-) -> c_int {
- if c_protocol_list.is_null() {
- return 0;
- }
-
- // Require an unsafe block to read the version from a C string. The pointer
- // is checked above to ensure it is not null.
- let c_str: &CStr = unsafe { CStr::from_ptr(c_protocol_list) };
-
- let protocol_list = match c_str.to_str() {
- Ok(n) => n,
- Err(_) => return 0,
- };
-
- let protocol = match translate_to_rust(c_protocol) {
- Ok(n) => n,
- Err(_) => return 0,
- };
-
- let proto_entry: UnvalidatedProtoEntry = match protocol_list.parse() {
- Ok(n) => n,
- Err(_) => return 0,
- };
-
- if proto_entry.supports_protocol_or_later(&protocol.into(), &version) {
- return 1;
- }
- 0
-}
-
-/// Provide an interface for C to translate arguments and return types for
-/// protover::get_supported_protocols
-#[no_mangle]
-pub extern "C" fn protover_get_supported_protocols() -> *const c_char {
- let supported: &'static CStr;
-
- supported = get_supported_protocols_cstr();
- supported.as_ptr()
-}
-
-/// Provide an interface for C to translate arguments and return types for
-/// protover::compute_vote
-//
-// Why is the threshold a signed integer? —isis
-#[no_mangle]
-pub extern "C" fn protover_compute_vote(list: *const Stringlist, threshold: c_int) -> *mut c_char {
- if list.is_null() {
- return allocate_and_copy_string("");
- }
-
- // Dereference of raw pointer requires an unsafe block. The pointer is
- // checked above to ensure it is not null.
- let data: Vec<String> = unsafe { (*list).get_list() };
- let hold: usize = threshold as usize;
- let mut proto_entries: Vec<UnvalidatedProtoEntry> = Vec::new();
-
- for datum in data {
- let entry: UnvalidatedProtoEntry = match datum.parse() {
- Ok(n) => n,
- Err(_) => continue,
- };
- proto_entries.push(entry);
- }
- let vote: UnvalidatedProtoEntry = ProtoverVote::compute(&proto_entries, &hold);
-
- allocate_and_copy_string(&vote.to_string())
-}
-
-/// Provide an interface for C to translate arguments and return types for
-/// protover::is_supported_here
-#[no_mangle]
-pub extern "C" fn protover_is_supported_here(c_protocol: uint32_t, version: uint32_t) -> c_int {
- let protocol = match translate_to_rust(c_protocol) {
- Ok(n) => n,
- Err(_) => return 0,
- };
-
- let is_supported = is_supported_here(&protocol, &version);
-
- return if is_supported { 1 } else { 0 };
-}
-
-/// Provide an interface for C to translate arguments and return types for
-/// protover::compute_for_old_tor
-#[no_mangle]
-pub extern "C" fn protover_compute_for_old_tor(version: *const c_char) -> *const c_char {
- let supported: &'static CStr;
- let empty: &'static CStr;
-
- empty = cstr!("");
-
- if version.is_null() {
- return empty.as_ptr();
- }
-
- // Require an unsafe block to read the version from a C string. The pointer
- // is checked above to ensure it is not null.
- let c_str: &CStr = unsafe { CStr::from_ptr(version) };
-
- let version = match c_str.to_str() {
- Ok(n) => n,
- Err(_) => return empty.as_ptr(),
- };
-
- supported = compute_for_old_tor_cstr(&version);
- supported.as_ptr()
-}
diff --git a/src/rust/protover/lib.rs b/src/rust/protover/lib.rs
deleted file mode 100644
index 35c4106ae5..0000000000
--- a/src/rust/protover/lib.rs
+++ /dev/null
@@ -1,40 +0,0 @@
-//! Copyright (c) 2016-2019, The Tor Project, Inc. */
-//! See LICENSE for licensing information */
-
-//! Versioning information for different pieces of the Tor protocol.
-//!
-//! The below description is taken from src/rust/protover.c, which is currently
-//! enabled by default. We are in the process of experimenting with Rust in
-//! tor, and this protover module is implemented to help achieve this goal.
-//!
-//! Starting in version 0.2.9.3-alpha, Tor places separate version numbers on
-//! each of the different components of its protocol. Relays use these numbers
-//! to advertise what versions of the protocols they can support, and clients
-//! use them to find what they can ask a given relay to do. Authorities vote
-//! on the supported protocol versions for each relay, and also vote on the
-//! which protocols you should have to support in order to be on the Tor
-//! network. All Tor instances use these required/recommended protocol versions
-//! to tell what level of support for recent protocols each relay has, and
-//! to decide whether they should be running given their current protocols.
-//!
-//! The main advantage of these protocol versions numbers over using Tor
-//! version numbers is that they allow different implementations of the Tor
-//! protocols to develop independently, without having to claim compatibility
-//! with specific versions of Tor.
-
-// XXX: add missing docs
-//#![deny(missing_docs)]
-
-extern crate external;
-extern crate libc;
-extern crate smartlist;
-extern crate tor_allocate;
-#[macro_use]
-extern crate tor_util;
-
-pub mod errors;
-pub mod ffi;
-pub mod protoset;
-mod protover;
-
-pub use protover::*;
diff --git a/src/rust/protover/protoset.rs b/src/rust/protover/protoset.rs
deleted file mode 100644
index 0ab94457c5..0000000000
--- a/src/rust/protover/protoset.rs
+++ /dev/null
@@ -1,697 +0,0 @@
-// Copyright (c) 2018-2019, The Tor Project, Inc.
-// Copyright (c) 2018, isis agora lovecruft
-// See LICENSE for licensing information
-
-//! Sets for lazily storing ordered, non-overlapping ranges of integers.
-
-use std::cmp;
-use std::iter;
-use std::slice;
-use std::str::FromStr;
-use std::u32;
-
-use errors::ProtoverError;
-
-/// A single version number.
-pub type Version = u32;
-
-/// A `ProtoSet` stores an ordered `Vec<T>` of `(low, high)` pairs of ranges of
-/// non-overlapping protocol versions.
-///
-/// # Examples
-///
-/// ```
-/// use std::str::FromStr;
-///
-/// use protover::errors::ProtoverError;
-/// use protover::protoset::ProtoSet;
-/// use protover::protoset::Version;
-///
-/// # fn do_test() -> Result<ProtoSet, ProtoverError> {
-/// let protoset: ProtoSet = ProtoSet::from_str("3-5,8")?;
-///
-/// // We could also equivalently call:
-/// let protoset: ProtoSet = "3-5,8".parse()?;
-///
-/// assert!(protoset.contains(&4));
-/// assert!(!protoset.contains(&7));
-///
-/// let expanded: Vec<Version> = protoset.clone().into();
-///
-/// assert_eq!(&expanded[..], &[3, 4, 5, 8]);
-///
-/// let contracted: String = protoset.clone().to_string();
-///
-/// assert_eq!(contracted, "3-5,8".to_string());
-/// # Ok(protoset)
-/// # }
-/// # fn main() { do_test(); } // wrap the test so we can use the ? operator
-#[derive(Clone, Debug, Eq, PartialEq, Hash)]
-pub struct ProtoSet {
- pub(crate) pairs: Vec<(Version, Version)>,
-}
-
-impl Default for ProtoSet {
- fn default() -> Self {
- let pairs: Vec<(Version, Version)> = Vec::new();
-
- ProtoSet { pairs }
- }
-}
-
-impl<'a> ProtoSet {
- /// Create a new `ProtoSet` from a slice of `(low, high)` pairs.
- ///
- /// # Inputs
- ///
- /// We do not assume the input pairs are deduplicated or ordered.
- pub fn from_slice(low_high_pairs: &'a [(Version, Version)]) -> Result<Self, ProtoverError> {
- let mut pairs: Vec<(Version, Version)> = Vec::with_capacity(low_high_pairs.len());
-
- for &(low, high) in low_high_pairs {
- pairs.push((low, high));
- }
- // Sort the pairs without reallocation and remove all duplicate pairs.
- pairs.sort_unstable();
- pairs.dedup();
-
- ProtoSet { pairs }.is_ok()
- }
-}
-
-/// Expand this `ProtoSet` to a `Vec` of all its `Version`s.
-///
-/// # Examples
-///
-/// ```
-/// use std::str::FromStr;
-/// use protover::protoset::ProtoSet;
-/// use protover::protoset::Version;
-/// # use protover::errors::ProtoverError;
-///
-/// # fn do_test() -> Result<Vec<Version>, ProtoverError> {
-/// let protoset: ProtoSet = ProtoSet::from_str("3-5,21")?;
-/// let versions: Vec<Version> = protoset.into();
-///
-/// assert_eq!(&versions[..], &[3, 4, 5, 21]);
-/// #
-/// # Ok(versions)
-/// # }
-/// # fn main() { do_test(); } // wrap the test so we can use the ? operator
-/// ```
-impl Into<Vec<Version>> for ProtoSet {
- fn into(self) -> Vec<Version> {
- let mut versions: Vec<Version> = Vec::new();
-
- for &(low, high) in self.iter() {
- versions.extend(low..high + 1);
- }
- versions
- }
-}
-
-impl ProtoSet {
- /// Get an iterator over the `(low, high)` `pairs` in this `ProtoSet`.
- pub fn iter(&self) -> slice::Iter<(Version, Version)> {
- self.pairs.iter()
- }
-
- /// Expand this `ProtoSet` into a `Vec` of all its `Version`s.
- ///
- /// # Examples
- ///
- /// ```
- /// # use protover::errors::ProtoverError;
- /// use protover::protoset::ProtoSet;
- ///
- /// # fn do_test() -> Result<bool, ProtoverError> {
- /// let protoset: ProtoSet = "3-5,9".parse()?;
- ///
- /// assert_eq!(protoset.expand(), vec![3, 4, 5, 9]);
- ///
- /// let protoset: ProtoSet = "1,3,5-7".parse()?;
- ///
- /// assert_eq!(protoset.expand(), vec![1, 3, 5, 6, 7]);
- /// #
- /// # Ok(true)
- /// # }
- /// # fn main() { do_test(); } // wrap the test so we can use the ? operator
- /// ```
- pub fn expand(self) -> Vec<Version> {
- self.into()
- }
-
- pub fn len(&self) -> usize {
- let mut length: usize = 0;
-
- for &(low, high) in self.iter() {
- length += (high as usize - low as usize) + 1;
- }
-
- length
- }
-
- /// Check that this `ProtoSet` is well-formed.
- ///
- /// This is automatically called in `ProtoSet::from_str()`.
- ///
- /// # Errors
- ///
- /// * `ProtoverError::LowGreaterThanHigh`: if its `pairs` were not
- /// well-formed, i.e. a `low` in a `(low, high)` was higher than the
- /// previous `high`,
- /// * `ProtoverError::Overlap`: if one or more of the `pairs` are
- /// overlapping,
- /// * `ProtoverError::ExceedsMax`: if the number of versions when expanded
- /// would exceed `MAX_PROTOCOLS_TO_EXPAND`, and
- ///
- /// # Returns
- ///
- /// A `Result` whose `Ok` is this `Protoset`, and whose `Err` is one of the
- /// errors enumerated in the Errors section above.
- fn is_ok(self) -> Result<ProtoSet, ProtoverError> {
- let mut last_high: Version = 0;
-
- for &(low, high) in self.iter() {
- if low == u32::MAX || high == u32::MAX {
- return Err(ProtoverError::ExceedsMax);
- }
- if low <= last_high {
- return Err(ProtoverError::Overlap);
- } else if low > high {
- return Err(ProtoverError::LowGreaterThanHigh);
- }
- last_high = high;
- }
-
- Ok(self)
- }
-
- /// Determine if this `ProtoSet` contains no `Version`s.
- ///
- /// # Returns
- ///
- /// * `true` if this `ProtoSet`'s length is zero, and
- /// * `false` otherwise.
- ///
- /// # Examples
- ///
- /// ```
- /// use protover::protoset::ProtoSet;
- ///
- /// let protoset: ProtoSet = ProtoSet::default();
- ///
- /// assert!(protoset.is_empty());
- /// ```
- pub fn is_empty(&self) -> bool {
- self.pairs.len() == 0
- }
-
- /// Determine if `version` is included within this `ProtoSet`.
- ///
- /// # Inputs
- ///
- /// * `version`: a `Version`.
- ///
- /// # Returns
- ///
- /// `true` if the `version` is contained within this set; `false` otherwise.
- ///
- /// # Examples
- ///
- /// ```
- /// # use protover::errors::ProtoverError;
- /// use protover::protoset::ProtoSet;
- ///
- /// # fn do_test() -> Result<ProtoSet, ProtoverError> {
- /// let protoset: ProtoSet = ProtoSet::from_slice(&[(0, 5), (7, 9), (13, 14)])?;
- ///
- /// assert!(protoset.contains(&5));
- /// assert!(!protoset.contains(&10));
- /// #
- /// # Ok(protoset)
- /// # }
- /// # fn main() { do_test(); } // wrap the test so we can use the ? operator
- /// ```
- pub fn contains(&self, version: &Version) -> bool {
- for &(low, high) in self.iter() {
- if low <= *version && *version <= high {
- return true;
- }
- }
- false
- }
-
- /// Returns all the `Version`s in `self` which are not also in the `other`
- /// `ProtoSet`.
- ///
- /// # Examples
- ///
- /// ```
- /// # use protover::errors::ProtoverError;
- /// use protover::protoset::ProtoSet;
- ///
- /// # fn do_test() -> Result<bool, ProtoverError> {
- /// let protoset: ProtoSet = "1,3-6,10-12,15-16".parse()?;
- /// let other: ProtoSet = "2,5-7,9-11,14-20".parse()?;
- ///
- /// let subset: ProtoSet = protoset.and_not_in(&other);
- ///
- /// assert_eq!(subset.expand(), vec![1, 3, 4, 12]);
- /// #
- /// # Ok(true)
- /// # }
- /// # fn main() { do_test(); } // wrap the test so we can use the ? operator
- /// ```
- pub fn and_not_in(&self, other: &Self) -> Self {
- if self.is_empty() || other.is_empty() {
- return self.clone();
- }
-
- let pairs = self.iter().flat_map(|&(lo, hi)| {
- let the_end = (hi + 1, hi + 1); // special case to mark the end of the range.
- let excluded_ranges = other
- .iter()
- .cloned() // have to be owned tuples, to match iter::once(the_end).
- .skip_while(move|&(_, hi2)| hi2 < lo) // skip the non-overlapping ranges.
- .take_while(move|&(lo2, _)| lo2 <= hi) // take all the overlapping ones.
- .chain(iter::once(the_end));
-
- let mut nextlo = lo;
- excluded_ranges.filter_map(move |(excluded_lo, excluded_hi)| {
- let pair = if nextlo < excluded_lo {
- Some((nextlo, excluded_lo - 1))
- } else {
- None
- };
- nextlo = cmp::min(excluded_hi, u32::MAX - 1) + 1;
- pair
- })
- });
-
- let pairs = pairs.collect();
- ProtoSet::is_ok(ProtoSet { pairs }).expect("should be already sorted")
- }
-}
-
-/// Largest allowed protocol version.
-/// C_RUST_COUPLED: protover.c `MAX_PROTOCOL_VERSION`
-const MAX_PROTOCOL_VERSION: Version = 63;
-
-impl FromStr for ProtoSet {
- type Err = ProtoverError;
-
- /// Parse the unique version numbers supported by a subprotocol from a string.
- ///
- /// # Inputs
- ///
- /// * `version_string`, a string comprised of "[0-9,-]"
- ///
- /// # Returns
- ///
- /// A `Result` whose `Ok` value is a `ProtoSet` holding all of the unique
- /// version numbers.
- ///
- /// The returned `Result`'s `Err` value is an `ProtoverError` appropriate to
- /// the error.
- ///
- /// # Errors
- ///
- /// This function will error if:
- ///
- /// * the `version_string` is an equals (`"="`) sign,
- /// * the expansion of a version range produces an error (see
- /// `expand_version_range`),
- /// * any single version number is not parseable as an `u32` in radix 10, or
- /// * there are greater than 2^16 version numbers to expand.
- ///
- /// # Examples
- ///
- /// ```
- /// use std::str::FromStr;
- ///
- /// use protover::errors::ProtoverError;
- /// use protover::protoset::ProtoSet;
- ///
- /// # fn do_test() -> Result<ProtoSet, ProtoverError> {
- /// let protoset: ProtoSet = ProtoSet::from_str("2-5,8")?;
- ///
- /// assert!(protoset.contains(&5));
- /// assert!(!protoset.contains(&10));
- ///
- /// // We can also equivalently call `ProtoSet::from_str` by doing (all
- /// // implementations of `FromStr` can be called this way, this one isn't
- /// // special):
- /// let protoset: ProtoSet = "4-6,12".parse()?;
- ///
- /// // Calling it (either way) can take really large ranges (up to `u32::MAX`):
- /// let protoset: ProtoSet = "1-70000".parse()?;
- /// let protoset: ProtoSet = "1-4294967296".parse()?;
- ///
- /// // There are lots of ways to get an `Err` from this function. Here are
- /// // a few:
- /// assert_eq!(Err(ProtoverError::Unparseable), ProtoSet::from_str("="));
- /// assert_eq!(Err(ProtoverError::Unparseable), ProtoSet::from_str("-"));
- /// assert_eq!(Err(ProtoverError::Unparseable), ProtoSet::from_str("not_an_int"));
- /// assert_eq!(Err(ProtoverError::Unparseable), ProtoSet::from_str("3-"));
- /// assert_eq!(Err(ProtoverError::Unparseable), ProtoSet::from_str("1-,4"));
- ///
- /// // An empty string is, however, legal, and results in an
- /// // empty `ProtoSet`:
- /// assert_eq!(Ok(ProtoSet::default()), ProtoSet::from_str(""));
- /// #
- /// # Ok(protoset)
- /// # }
- /// # fn main() { do_test(); } // wrap the test so we can use the ? operator
- /// ```
- fn from_str(version_string: &str) -> Result<Self, Self::Err> {
- // If we were passed in an empty string, then return an empty ProtoSet.
- if version_string.is_empty() {
- return Ok(Self::default());
- }
-
- let mut pairs: Vec<(Version, Version)> = Vec::new();
- let pieces: ::std::str::Split<char> = version_string.split(',');
-
- for p in pieces {
- let (lo,hi) = if p.contains('-') {
- let mut pair = p.splitn(2, '-');
-
- let low = pair.next().ok_or(ProtoverError::Unparseable)?;
- let high = pair.next().ok_or(ProtoverError::Unparseable)?;
-
- let lo: Version = low.parse().or(Err(ProtoverError::Unparseable))?;
- let hi: Version = high.parse().or(Err(ProtoverError::Unparseable))?;
-
- (lo,hi)
- } else {
- let v: u32 = p.parse().or(Err(ProtoverError::Unparseable))?;
-
- (v, v)
- };
-
- if lo > MAX_PROTOCOL_VERSION || hi > MAX_PROTOCOL_VERSION {
- return Err(ProtoverError::ExceedsMax);
- }
- pairs.push((lo, hi));
- }
-
- ProtoSet::from_slice(&pairs[..])
- }
-}
-
-impl ToString for ProtoSet {
- /// Contracts a `ProtoSet` of versions into a string.
- ///
- /// # Returns
- ///
- /// A `String` representation of this `ProtoSet` in ascending order.
- fn to_string(&self) -> String {
- let mut final_output: Vec<String> = Vec::new();
-
- for &(lo, hi) in self.iter() {
- if lo != hi {
- debug_assert!(lo < hi);
- final_output.push(format!("{}-{}", lo, hi));
- } else {
- final_output.push(format!("{}", lo));
- }
- }
- final_output.join(",")
- }
-}
-
-/// Checks to see if there is a continuous range of integers, starting at the
-/// first in the list. Returns the last integer in the range if a range exists.
-///
-/// # Inputs
-///
-/// `list`, an ordered vector of `u32` integers of "[0-9,-]" representing the
-/// supported versions for a single protocol.
-///
-/// # Returns
-///
-/// A `bool` indicating whether the list contains a range, starting at the first
-/// in the list, a`Version` of the last integer in the range, and a `usize` of
-/// the index of that version.
-///
-/// For example, if given vec![1, 2, 3, 5], find_range will return true,
-/// as there is a continuous range, and 3, which is the last number in the
-/// continuous range, and 2 which is the index of 3.
-fn find_range(list: &Vec<Version>) -> (bool, Version, usize) {
- if list.len() == 0 {
- return (false, 0, 0);
- }
-
- let mut index: usize = 0;
- let mut iterable = list.iter().peekable();
- let mut range_end = match iterable.next() {
- Some(n) => *n,
- None => return (false, 0, 0),
- };
-
- let mut has_range = false;
-
- while iterable.peek().is_some() {
- let n = *iterable.next().unwrap();
- if n != range_end + 1 {
- break;
- }
-
- has_range = true;
- range_end = n;
- index += 1;
- }
-
- (has_range, range_end, index)
-}
-
-impl From<Vec<Version>> for ProtoSet {
- fn from(mut v: Vec<Version>) -> ProtoSet {
- let mut version_pairs: Vec<(Version, Version)> = Vec::new();
-
- v.sort_unstable();
- v.dedup();
-
- 'vector: while !v.is_empty() {
- let (has_range, end, index): (bool, Version, usize) = find_range(&v);
-
- if has_range {
- let first: Version = match v.first() {
- Some(x) => *x,
- None => continue,
- };
- let last: Version = match v.get(index) {
- Some(x) => *x,
- None => continue,
- };
- debug_assert!(last == end, format!("last = {}, end = {}", last, end));
-
- version_pairs.push((first, last));
- v = v.split_off(index + 1);
-
- if v.len() == 0 {
- break 'vector;
- }
- } else {
- let last: Version = match v.get(index) {
- Some(x) => *x,
- None => continue,
- };
- version_pairs.push((last, last));
- v.remove(index);
- }
- }
- ProtoSet::from_slice(&version_pairs[..]).unwrap_or(ProtoSet::default())
- }
-}
-
-#[cfg(test)]
-mod test {
- use super::*;
-
- #[test]
- fn test_find_range() {
- assert_eq!((false, 0, 0), find_range(&vec![]));
- assert_eq!((false, 1, 0), find_range(&vec![1]));
- assert_eq!((true, 2, 1), find_range(&vec![1, 2]));
- assert_eq!((true, 3, 2), find_range(&vec![1, 2, 3]));
- assert_eq!((true, 3, 2), find_range(&vec![1, 2, 3, 5]));
- }
-
- macro_rules! assert_contains_each {
- ($protoset:expr, $versions:expr) => {
- for version in $versions {
- assert!($protoset.contains(version));
- }
- };
- }
-
- macro_rules! test_protoset_contains_versions {
- ($list:expr, $str:expr) => {
- let versions: &[Version] = $list;
- let protoset: Result<ProtoSet, ProtoverError> = ProtoSet::from_str($str);
-
- assert!(protoset.is_ok());
- let p = protoset.unwrap();
- assert_contains_each!(p, versions);
- };
- }
-
- #[test]
- fn test_versions_from_str() {
- test_protoset_contains_versions!(&[], "");
- test_protoset_contains_versions!(&[1], "1");
- test_protoset_contains_versions!(&[1, 2], "1,2");
- test_protoset_contains_versions!(&[1, 2, 3], "1-3");
- test_protoset_contains_versions!(&[1, 2, 5], "1-2,5");
- test_protoset_contains_versions!(&[1, 3, 4, 5], "1,3-5");
- test_protoset_contains_versions!(&[42, 55, 56, 57, 58], "42,55-58");
- }
-
- #[test]
- fn test_versions_from_str_ab() {
- assert_eq!(Err(ProtoverError::Unparseable), ProtoSet::from_str("a,b"));
- }
-
- #[test]
- fn test_versions_from_str_negative_1() {
- assert_eq!(Err(ProtoverError::Unparseable), ProtoSet::from_str("-1"));
- }
-
- #[test]
- fn test_versions_from_str_commas() {
- assert_eq!(Err(ProtoverError::Unparseable), ProtoSet::from_str(","));
- assert_eq!(Err(ProtoverError::Unparseable), ProtoSet::from_str("1,,2"));
- assert_eq!(Err(ProtoverError::Unparseable), ProtoSet::from_str("1,2,"));
- }
-
- #[test]
- fn test_versions_from_str_hyphens() {
- assert_eq!(Err(ProtoverError::Unparseable), ProtoSet::from_str("--1"));
- assert_eq!(Err(ProtoverError::Unparseable), ProtoSet::from_str("-1-2"));
- assert_eq!(Err(ProtoverError::Unparseable), ProtoSet::from_str("1--2"));
- }
-
- #[test]
- fn test_versions_from_str_triple() {
- assert_eq!(Err(ProtoverError::Unparseable), ProtoSet::from_str("1-2-3"));
- }
-
- #[test]
- fn test_versions_from_str_1exclam() {
- assert_eq!(Err(ProtoverError::Unparseable), ProtoSet::from_str("1,!"));
- }
-
- #[test]
- fn test_versions_from_str_percent_equal() {
- assert_eq!(Err(ProtoverError::Unparseable), ProtoSet::from_str("%="));
- }
-
- #[test]
- fn test_versions_from_str_whitespace() {
- assert_eq!(Err(ProtoverError::Unparseable), ProtoSet::from_str("1,2\n"));
- assert_eq!(Err(ProtoverError::Unparseable), ProtoSet::from_str("1\r,2"));
- assert_eq!(Err(ProtoverError::Unparseable), ProtoSet::from_str("1,\t2"));
- }
-
- #[test]
- fn test_versions_from_str_overlap() {
- assert_eq!(Err(ProtoverError::Overlap), ProtoSet::from_str("1-3,2-4"));
- }
-
- #[test]
- fn test_versions_from_slice_overlap() {
- assert_eq!(
- Err(ProtoverError::Overlap),
- ProtoSet::from_slice(&[(1, 3), (2, 4)])
- );
- }
-
- #[test]
- fn test_versions_from_str_max() {
- assert_eq!(
- Err(ProtoverError::ExceedsMax),
- ProtoSet::from_str("4294967295")
- );
- }
-
- #[test]
- fn test_versions_from_slice_max() {
- assert_eq!(
- Err(ProtoverError::ExceedsMax),
- ProtoSet::from_slice(&[(4294967295, 4294967295)])
- );
- }
-
- #[test]
- fn test_protoset_contains() {
- let protoset: ProtoSet = ProtoSet::from_slice(&[(1, 5), (7, 9), (13, 14)]).unwrap();
-
- for x in 1..6 {
- assert!(protoset.contains(&x), format!("should contain {}", x));
- }
- for x in 7..10 {
- assert!(protoset.contains(&x), format!("should contain {}", x));
- }
- for x in 13..15 {
- assert!(protoset.contains(&x), format!("should contain {}", x));
- }
-
- for x in [6, 10, 11, 12, 15, 42, 43, 44, 45, 1234584].iter() {
- assert!(!protoset.contains(&x), format!("should not contain {}", x));
- }
- }
-
- #[test]
- fn test_protoset_contains_1_3() {
- let protoset: ProtoSet = ProtoSet::from_slice(&[(1, 3)]).unwrap();
-
- for x in 1..4 {
- assert!(protoset.contains(&x), format!("should contain {}", x));
- }
- }
-
- macro_rules! assert_protoset_from_vec_contains_all {
- ($($x:expr),*) => (
- let vec: Vec<Version> = vec!($($x),*);
- let protoset: ProtoSet = vec.clone().into();
-
- for x in vec.iter() {
- assert!(protoset.contains(&x));
- }
- )
- }
-
- #[test]
- fn test_protoset_from_vec_123() {
- assert_protoset_from_vec_contains_all!(1, 2, 3);
- }
-
- #[test]
- fn test_protoset_from_vec_1_315() {
- assert_protoset_from_vec_contains_all!(1, 2, 3, 15);
- }
-
- #[test]
- fn test_protoset_from_vec_unordered() {
- let v: Vec<Version> = vec![2, 3, 8, 4, 3, 9, 7, 2];
- let ps: ProtoSet = v.into();
-
- assert_eq!(ps.to_string(), "2-4,7-9");
- }
-
- #[test]
- fn test_protoset_into_vec() {
- let ps: ProtoSet = "1-13,42".parse().unwrap();
- let v: Vec<Version> = ps.into();
-
- assert!(v.contains(&7));
- assert!(v.contains(&42));
- }
-}
-
-#[cfg(all(test, feature = "bench"))]
-mod bench {
- use super::*;
-}
diff --git a/src/rust/protover/protover.rs b/src/rust/protover/protover.rs
deleted file mode 100644
index da87509ffa..0000000000
--- a/src/rust/protover/protover.rs
+++ /dev/null
@@ -1,984 +0,0 @@
-// Copyright (c) 2016-2019, The Tor Project, Inc. */
-// See LICENSE for licensing information */
-
-use std::collections::hash_map;
-use std::collections::HashMap;
-use std::ffi::CStr;
-use std::fmt;
-use std::str;
-use std::str::FromStr;
-use std::string::String;
-
-use external::c_tor_version_as_new_as;
-
-use errors::ProtoverError;
-use protoset::ProtoSet;
-use protoset::Version;
-
-/// The first version of Tor that included "proto" entries in its descriptors.
-/// Authorities should use this to decide whether to guess proto lines.
-///
-/// C_RUST_COUPLED:
-/// protover.h `FIRST_TOR_VERSION_TO_ADVERTISE_PROTOCOLS`
-const FIRST_TOR_VERSION_TO_ADVERTISE_PROTOCOLS: &'static str = "0.2.9.3-alpha";
-
-/// The maximum number of subprotocol version numbers we will attempt to expand
-/// before concluding that someone is trying to DoS us
-///
-/// C_RUST_COUPLED: protover.c `MAX_PROTOCOLS_TO_EXPAND`
-const MAX_PROTOCOLS_TO_EXPAND: usize = 1 << 16;
-
-/// The maximum size an `UnknownProtocol`'s name may be.
-pub(crate) const MAX_PROTOCOL_NAME_LENGTH: usize = 100;
-
-/// Known subprotocols in Tor. Indicates which subprotocol a relay supports.
-///
-/// C_RUST_COUPLED: protover.h `protocol_type_t`
-#[derive(Clone, Hash, Eq, PartialEq, Debug)]
-pub enum Protocol {
- Cons,
- Desc,
- DirCache,
- HSDir,
- HSIntro,
- HSRend,
- Link,
- LinkAuth,
- Microdesc,
- Relay,
- Padding,
- FlowCtrl,
-}
-
-impl fmt::Display for Protocol {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- write!(f, "{:?}", self)
- }
-}
-
-/// Translates a string representation of a protocol into a Proto type.
-/// Error if the string is an unrecognized protocol name.
-///
-/// C_RUST_COUPLED: protover.c `PROTOCOL_NAMES`
-impl FromStr for Protocol {
- type Err = ProtoverError;
-
- fn from_str(s: &str) -> Result<Self, Self::Err> {
- match s {
- "Cons" => Ok(Protocol::Cons),
- "Desc" => Ok(Protocol::Desc),
- "DirCache" => Ok(Protocol::DirCache),
- "HSDir" => Ok(Protocol::HSDir),
- "HSIntro" => Ok(Protocol::HSIntro),
- "HSRend" => Ok(Protocol::HSRend),
- "Link" => Ok(Protocol::Link),
- "LinkAuth" => Ok(Protocol::LinkAuth),
- "Microdesc" => Ok(Protocol::Microdesc),
- "Relay" => Ok(Protocol::Relay),
- "Padding" => Ok(Protocol::Padding),
- "FlowCtrl" => Ok(Protocol::FlowCtrl),
- _ => Err(ProtoverError::UnknownProtocol),
- }
- }
-}
-
-/// A protocol string which is not one of the `Protocols` we currently know
-/// about.
-#[derive(Clone, Debug, Hash, Eq, PartialEq)]
-pub struct UnknownProtocol(String);
-
-impl fmt::Display for UnknownProtocol {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- write!(f, "{}", self.0)
- }
-}
-
-fn is_valid_proto(s: &str) -> bool {
- s.chars().all(|c| c.is_ascii_alphanumeric() || c == '-')
-}
-
-impl FromStr for UnknownProtocol {
- type Err = ProtoverError;
-
- fn from_str(s: &str) -> Result<Self, Self::Err> {
- if !is_valid_proto(s) {
- Err(ProtoverError::InvalidProtocol)
- } else if s.len() <= MAX_PROTOCOL_NAME_LENGTH {
- Ok(UnknownProtocol(s.to_string()))
- } else {
- Err(ProtoverError::ExceedsNameLimit)
- }
- }
-}
-
-impl UnknownProtocol {
- /// Create an `UnknownProtocol`, ignoring whether or not it
- /// exceeds MAX_PROTOCOL_NAME_LENGTH.
- fn from_str_any_len(s: &str) -> Result<Self, ProtoverError> {
- if !is_valid_proto(s) {
- return Err(ProtoverError::InvalidProtocol);
- }
- Ok(UnknownProtocol(s.to_string()))
- }
-}
-
-impl From<Protocol> for UnknownProtocol {
- fn from(p: Protocol) -> UnknownProtocol {
- UnknownProtocol(p.to_string())
- }
-}
-
-#[cfg(feature = "test_linking_hack")]
-fn have_linkauth_v1() -> bool {
- true
-}
-
-#[cfg(not(feature = "test_linking_hack"))]
-fn have_linkauth_v1() -> bool {
- use external::c_tor_is_using_nss;
- !c_tor_is_using_nss()
-}
-
-/// Get a CStr representation of current supported protocols, for
-/// passing to C, or for converting to a `&str` for Rust.
-///
-/// # Returns
-///
-/// An `&'static CStr` whose value is the existing protocols supported by tor.
-/// Returned data is in the format as follows:
-///
-/// "HSDir=1-1 LinkAuth=1"
-///
-/// # Note
-///
-/// Rust code can use the `&'static CStr` as a normal `&'a str` by
-/// calling `protover::get_supported_protocols`.
-///
-// C_RUST_COUPLED: protover.c `protover_get_supported_protocols`
-pub(crate) fn get_supported_protocols_cstr() -> &'static CStr {
- if !have_linkauth_v1() {
- cstr!(
- "Cons=1-2 \
- Desc=1-2 \
- DirCache=2 \
- FlowCtrl=1 \
- HSDir=1-2 \
- HSIntro=3-5 \
- HSRend=1-2 \
- Link=1-5 \
- LinkAuth=3 \
- Microdesc=1-2 \
- Padding=2 \
- Relay=1-3"
- )
- } else {
- cstr!(
- "Cons=1-2 \
- Desc=1-2 \
- DirCache=2 \
- FlowCtrl=1 \
- HSDir=1-2 \
- HSIntro=3-5 \
- HSRend=1-2 \
- Link=1-5 \
- LinkAuth=1,3 \
- Microdesc=1-2 \
- Padding=2 \
- Relay=1-3"
- )
- }
-}
-
-/// A map of protocol names to the versions of them which are supported.
-#[derive(Clone, Debug, PartialEq, Eq)]
-pub struct ProtoEntry(HashMap<Protocol, ProtoSet>);
-
-impl Default for ProtoEntry {
- fn default() -> ProtoEntry {
- ProtoEntry(HashMap::new())
- }
-}
-
-impl ProtoEntry {
- /// Get an iterator over the `Protocol`s and their `ProtoSet`s in this `ProtoEntry`.
- pub fn iter(&self) -> hash_map::Iter<Protocol, ProtoSet> {
- self.0.iter()
- }
-
- /// Translate the supported tor versions from a string into a
- /// ProtoEntry, which is useful when looking up a specific
- /// subprotocol.
- pub fn supported() -> Result<Self, ProtoverError> {
- let supported_cstr: &'static CStr = get_supported_protocols_cstr();
- let supported: &str = supported_cstr.to_str().unwrap_or("");
-
- supported.parse()
- }
-
- pub fn len(&self) -> usize {
- self.0.len()
- }
-
- pub fn get(&self, protocol: &Protocol) -> Option<&ProtoSet> {
- self.0.get(protocol)
- }
-
- pub fn insert(&mut self, key: Protocol, value: ProtoSet) {
- self.0.insert(key, value);
- }
-
- pub fn remove(&mut self, key: &Protocol) -> Option<ProtoSet> {
- self.0.remove(key)
- }
-
- pub fn is_empty(&self) -> bool {
- self.0.is_empty()
- }
-}
-
-impl FromStr for ProtoEntry {
- type Err = ProtoverError;
-
- /// Parse a string of subprotocol types and their version numbers.
- ///
- /// # Inputs
- ///
- /// * A `protocol_entry` string, comprised of a keywords, an "=" sign, and
- /// one or more version numbers, each separated by a space. For example,
- /// `"Cons=3-4 HSDir=1"`.
- ///
- /// # Returns
- ///
- /// A `Result` whose `Ok` value is a `ProtoEntry`.
- /// Otherwise, the `Err` value of this `Result` is a `ProtoverError`.
- fn from_str(protocol_entry: &str) -> Result<ProtoEntry, ProtoverError> {
- let mut proto_entry: ProtoEntry = ProtoEntry::default();
-
- if protocol_entry.is_empty() {
- return Ok(proto_entry);
- }
-
- let entries = protocol_entry.split(' ');
-
- for entry in entries {
- let mut parts = entry.splitn(2, '=');
-
- let proto = match parts.next() {
- Some(n) => n,
- None => return Err(ProtoverError::Unparseable),
- };
-
- let vers = match parts.next() {
- Some(n) => n,
- None => return Err(ProtoverError::Unparseable),
- };
- let versions: ProtoSet = vers.parse()?;
- let proto_name: Protocol = proto.parse()?;
-
- proto_entry.insert(proto_name, versions);
-
- if proto_entry.len() > MAX_PROTOCOLS_TO_EXPAND {
- return Err(ProtoverError::ExceedsMax);
- }
- }
- Ok(proto_entry)
- }
-}
-
-/// Generate an implementation of `ToString` for either a `ProtoEntry` or an
-/// `UnvalidatedProtoEntry`.
-macro_rules! impl_to_string_for_proto_entry {
- ($t:ty) => {
- impl ToString for $t {
- fn to_string(&self) -> String {
- let mut parts: Vec<String> = Vec::new();
-
- for (protocol, versions) in self.iter() {
- parts.push(format!("{}={}", protocol.to_string(), versions.to_string()));
- }
- parts.sort_unstable();
- parts.join(" ")
- }
- }
- };
-}
-
-impl_to_string_for_proto_entry!(ProtoEntry);
-impl_to_string_for_proto_entry!(UnvalidatedProtoEntry);
-
-/// A `ProtoEntry`, but whose `Protocols` can be any `UnknownProtocol`, not just
-/// the supported ones enumerated in `Protocols`. The protocol versions are
-/// validated, however.
-#[derive(Clone, Debug, PartialEq, Eq)]
-pub struct UnvalidatedProtoEntry(HashMap<UnknownProtocol, ProtoSet>);
-
-impl Default for UnvalidatedProtoEntry {
- fn default() -> UnvalidatedProtoEntry {
- UnvalidatedProtoEntry(HashMap::new())
- }
-}
-
-impl UnvalidatedProtoEntry {
- /// Get an iterator over the `Protocol`s and their `ProtoSet`s in this `ProtoEntry`.
- pub fn iter(&self) -> hash_map::Iter<UnknownProtocol, ProtoSet> {
- self.0.iter()
- }
-
- pub fn get(&self, protocol: &UnknownProtocol) -> Option<&ProtoSet> {
- self.0.get(protocol)
- }
-
- pub fn insert(&mut self, key: UnknownProtocol, value: ProtoSet) {
- self.0.insert(key, value);
- }
-
- pub fn remove(&mut self, key: &UnknownProtocol) -> Option<ProtoSet> {
- self.0.remove(key)
- }
-
- pub fn is_empty(&self) -> bool {
- self.0.is_empty()
- }
-
- pub fn len(&self) -> usize {
- let mut total: usize = 0;
-
- for (_, versions) in self.iter() {
- total += versions.len();
- }
- total
- }
-
- /// Determine if we support every protocol a client supports, and if not,
- /// determine which protocols we do not have support for.
- ///
- /// # Returns
- ///
- /// Optionally, return parameters which the client supports but which we do not.
- ///
- /// # Examples
- /// ```
- /// use protover::UnvalidatedProtoEntry;
- ///
- /// let protocols: UnvalidatedProtoEntry = "LinkAuth=1 Microdesc=1-2 Relay=2".parse().unwrap();
- /// let unsupported: Option<UnvalidatedProtoEntry> = protocols.all_supported();
- /// assert_eq!(true, unsupported.is_none());
- ///
- /// let protocols: UnvalidatedProtoEntry = "Link=1-2 Wombat=9".parse().unwrap();
- /// let unsupported: Option<UnvalidatedProtoEntry> = protocols.all_supported();
- /// assert_eq!(true, unsupported.is_some());
- /// assert_eq!("Wombat=9", &unsupported.unwrap().to_string());
- /// ```
- pub fn all_supported(&self) -> Option<UnvalidatedProtoEntry> {
- let mut unsupported: UnvalidatedProtoEntry = UnvalidatedProtoEntry::default();
- let supported: ProtoEntry = match ProtoEntry::supported() {
- Ok(x) => x,
- Err(_) => return None,
- };
-
- for (protocol, versions) in self.iter() {
- let is_supported: Result<Protocol, ProtoverError> = protocol.0.parse();
- let supported_protocol: Protocol;
-
- // If the protocol wasn't even in the enum, then we definitely don't
- // know about it and don't support any of its versions.
- if is_supported.is_err() {
- if !versions.is_empty() {
- unsupported.insert(protocol.clone(), versions.clone());
- }
- continue;
- } else {
- supported_protocol = is_supported.unwrap();
- }
-
- let maybe_supported_versions: Option<&ProtoSet> = supported.get(&supported_protocol);
- let supported_versions: &ProtoSet;
-
- // If the protocol wasn't in the map, then we don't know about it
- // and don't support any of its versions. Add its versions to the
- // map (if it has versions).
- if maybe_supported_versions.is_none() {
- if !versions.is_empty() {
- unsupported.insert(protocol.clone(), versions.clone());
- }
- continue;
- } else {
- supported_versions = maybe_supported_versions.unwrap();
- }
- let unsupported_versions = versions.and_not_in(supported_versions);
-
- if !unsupported_versions.is_empty() {
- unsupported.insert(protocol.clone(), unsupported_versions);
- }
- }
-
- if unsupported.is_empty() {
- return None;
- }
- Some(unsupported)
- }
-
- /// Determine if we have support for some protocol and version.
- ///
- /// # Inputs
- ///
- /// * `proto`, an `UnknownProtocol` to test support for
- /// * `vers`, a `Version` which we will go on to determine whether the
- /// specified protocol supports.
- ///
- /// # Return
- ///
- /// Returns `true` iff this `UnvalidatedProtoEntry` includes support for the
- /// indicated protocol and version, and `false` otherwise.
- ///
- /// # Examples
- ///
- /// ```
- /// # use std::str::FromStr;
- /// use protover::*;
- /// # use protover::errors::ProtoverError;
- ///
- /// # fn do_test () -> Result<UnvalidatedProtoEntry, ProtoverError> {
- /// let proto: UnvalidatedProtoEntry = "Link=3-4 Cons=1 Doggo=3-5".parse()?;
- /// assert_eq!(true, proto.supports_protocol(&Protocol::Cons.into(), &1));
- /// assert_eq!(false, proto.supports_protocol(&Protocol::Cons.into(), &5));
- /// assert_eq!(true, proto.supports_protocol(&UnknownProtocol::from_str("Doggo")?, &4));
- /// # Ok(proto)
- /// # } fn main () { do_test(); }
- /// ```
- pub fn supports_protocol(&self, proto: &UnknownProtocol, vers: &Version) -> bool {
- let supported_versions: &ProtoSet = match self.get(proto) {
- Some(n) => n,
- None => return false,
- };
- supported_versions.contains(&vers)
- }
-
- /// As `UnvalidatedProtoEntry::supports_protocol()`, but also returns `true`
- /// if any later version of the protocol is supported.
- ///
- /// # Examples
- /// ```
- /// use protover::*;
- /// # use protover::errors::ProtoverError;
- ///
- /// # fn do_test () -> Result<UnvalidatedProtoEntry, ProtoverError> {
- /// let proto: UnvalidatedProtoEntry = "Link=3-4 Cons=5".parse()?;
- ///
- /// assert_eq!(true, proto.supports_protocol_or_later(&Protocol::Cons.into(), &5));
- /// assert_eq!(true, proto.supports_protocol_or_later(&Protocol::Cons.into(), &4));
- /// assert_eq!(false, proto.supports_protocol_or_later(&Protocol::Cons.into(), &6));
- /// # Ok(proto)
- /// # } fn main () { do_test(); }
- /// ```
- pub fn supports_protocol_or_later(&self, proto: &UnknownProtocol, vers: &Version) -> bool {
- let supported_versions: &ProtoSet = match self.get(&proto) {
- Some(n) => n,
- None => return false,
- };
- supported_versions.iter().any(|v| v.1 >= *vers)
- }
-
- /// Split a string containing (potentially) several protocols and their
- /// versions into a `Vec` of tuples of string in `(protocol, versions)`
- /// form.
- ///
- /// # Inputs
- ///
- /// A &str in the form `"Link=3-4 Cons=5"`.
- ///
- /// # Returns
- ///
- /// A `Result` whose `Ok` variant is a `Vec<(&str, &str)>` of `(protocol,
- /// versions)`, or whose `Err` variant is a `ProtoverError`.
- ///
- /// # Errors
- ///
- /// This will error with a `ProtoverError::Unparseable` if any of the
- /// following are true:
- ///
- /// * If a protocol name is an empty string, e.g. `"Cons=1,3 =3-5"`.
- /// * If an entry has no equals sign, e.g. `"Cons=1,3 Desc"`.
- /// * If there is leading or trailing whitespace, e.g. `" Cons=1,3 Link=3"`.
- /// * If there is any other extra whitespice, e.g. `"Cons=1,3 Link=3"`.
- fn parse_protocol_and_version_str<'a>(
- protocol_string: &'a str,
- ) -> Result<Vec<(&'a str, &'a str)>, ProtoverError> {
- let mut protovers: Vec<(&str, &str)> = Vec::new();
-
- if protocol_string.is_empty() {
- return Ok(protovers);
- }
-
- for subproto in protocol_string.split(' ') {
- let mut parts = subproto.splitn(2, '=');
-
- let name = match parts.next() {
- Some("") => return Err(ProtoverError::Unparseable),
- Some(n) => n,
- None => return Err(ProtoverError::Unparseable),
- };
- let vers = match parts.next() {
- Some(n) => n,
- None => return Err(ProtoverError::Unparseable),
- };
- protovers.push((name, vers));
- }
- Ok(protovers)
- }
-}
-
-impl FromStr for UnvalidatedProtoEntry {
- type Err = ProtoverError;
-
- /// Parses a protocol list without validating the protocol names.
- ///
- /// # Inputs
- ///
- /// * `protocol_string`, a string comprised of keys and values, both which are
- /// strings. The keys are the protocol names while values are a string
- /// representation of the supported versions.
- ///
- /// The input is _not_ expected to be a subset of the Protocol types
- ///
- /// # Returns
- ///
- /// A `Result` whose `Ok` value is an `UnvalidatedProtoEntry`.
- ///
- /// The returned `Result`'s `Err` value is an `ProtoverError`.
- ///
- /// # Errors
- ///
- /// This function will error if:
- ///
- /// * The protocol string does not follow the "protocol_name=version_list"
- /// expected format, or
- /// * If the version string is malformed. See `impl FromStr for ProtoSet`.
- fn from_str(protocol_string: &str) -> Result<UnvalidatedProtoEntry, ProtoverError> {
- let mut parsed: UnvalidatedProtoEntry = UnvalidatedProtoEntry::default();
- let parts: Vec<(&str, &str)> =
- UnvalidatedProtoEntry::parse_protocol_and_version_str(protocol_string)?;
-
- for &(name, vers) in parts.iter() {
- let versions = ProtoSet::from_str(vers)?;
- let protocol = UnknownProtocol::from_str(name)?;
-
- parsed.insert(protocol, versions);
- }
- Ok(parsed)
- }
-}
-
-impl UnvalidatedProtoEntry {
- /// Create an `UnknownProtocol`, ignoring whether or not it
- /// exceeds MAX_PROTOCOL_NAME_LENGTH.
- pub(crate) fn from_str_any_len(
- protocol_string: &str,
- ) -> Result<UnvalidatedProtoEntry, ProtoverError> {
- let mut parsed: UnvalidatedProtoEntry = UnvalidatedProtoEntry::default();
- let parts: Vec<(&str, &str)> =
- UnvalidatedProtoEntry::parse_protocol_and_version_str(protocol_string)?;
-
- for &(name, vers) in parts.iter() {
- let versions = ProtoSet::from_str(vers)?;
- let protocol = UnknownProtocol::from_str_any_len(name)?;
-
- parsed.insert(protocol, versions);
- }
- Ok(parsed)
- }
-}
-
-/// Pretend a `ProtoEntry` is actually an `UnvalidatedProtoEntry`.
-impl From<ProtoEntry> for UnvalidatedProtoEntry {
- fn from(proto_entry: ProtoEntry) -> UnvalidatedProtoEntry {
- let mut unvalidated: UnvalidatedProtoEntry = UnvalidatedProtoEntry::default();
-
- for (protocol, versions) in proto_entry.iter() {
- unvalidated.insert(UnknownProtocol::from(protocol.clone()), versions.clone());
- }
- unvalidated
- }
-}
-
-/// A mapping of protocols to a count of how many times each of their `Version`s
-/// were voted for or supported.
-///
-/// # Warning
-///
-/// The "protocols" are *not* guaranteed to be known/supported `Protocol`s, in
-/// order to allow new subprotocols to be introduced even if Directory
-/// Authorities don't yet know of them.
-pub struct ProtoverVote(HashMap<UnknownProtocol, HashMap<Version, usize>>);
-
-impl Default for ProtoverVote {
- fn default() -> ProtoverVote {
- ProtoverVote(HashMap::new())
- }
-}
-
-impl IntoIterator for ProtoverVote {
- type Item = (UnknownProtocol, HashMap<Version, usize>);
- type IntoIter = hash_map::IntoIter<UnknownProtocol, HashMap<Version, usize>>;
-
- fn into_iter(self) -> Self::IntoIter {
- self.0.into_iter()
- }
-}
-
-impl ProtoverVote {
- pub fn entry(
- &mut self,
- key: UnknownProtocol,
- ) -> hash_map::Entry<UnknownProtocol, HashMap<Version, usize>> {
- self.0.entry(key)
- }
-
- /// Protocol voting implementation.
- ///
- /// Given a slice of `UnvalidatedProtoEntry`s and a vote `threshold`, return
- /// a new `UnvalidatedProtoEntry` encoding all of the protocols that are
- /// listed by at least `threshold` of the inputs.
- ///
- /// # Examples
- ///
- /// ```
- /// use protover::ProtoverVote;
- /// use protover::UnvalidatedProtoEntry;
- ///
- /// let protos: &[UnvalidatedProtoEntry] = &["Link=3-4".parse().unwrap(),
- /// "Link=3".parse().unwrap()];
- /// let vote = ProtoverVote::compute(protos, &2);
- /// assert_eq!("Link=3", vote.to_string());
- /// ```
- // C_RUST_COUPLED: protover.c protover_compute_vote
- pub fn compute(
- proto_entries: &[UnvalidatedProtoEntry],
- threshold: &usize,
- ) -> UnvalidatedProtoEntry {
- let mut all_count: ProtoverVote = ProtoverVote::default();
- let mut final_output: UnvalidatedProtoEntry = UnvalidatedProtoEntry::default();
-
- if proto_entries.is_empty() {
- return final_output;
- }
-
- // parse and collect all of the protos and their versions and collect them
- for vote in proto_entries {
- // C_RUST_DIFFERS: This doesn't actually differ, bu this check on
- // the total is here to make it match. Because the C version calls
- // expand_protocol_list() which checks if there would be too many
- // subprotocols *or* individual version numbers, i.e. more than
- // MAX_PROTOCOLS_TO_EXPAND, and does this *per vote*, we need to
- // match it's behaviour and ensure we're not allowing more than it
- // would.
- if vote.len() > MAX_PROTOCOLS_TO_EXPAND {
- continue;
- }
-
- for (protocol, versions) in vote.iter() {
- let supported_vers: &mut HashMap<Version, usize> =
- all_count.entry(protocol.clone()).or_insert(HashMap::new());
-
- for version in versions.clone().expand() {
- let counter: &mut usize = supported_vers.entry(version).or_insert(0);
- *counter += 1;
- }
- }
- }
-
- for (protocol, mut versions) in all_count {
- // Go through and remove versions that are less than the threshold
- versions.retain(|_, count| *count as usize >= *threshold);
-
- if versions.len() > 0 {
- let voted_versions: Vec<Version> = versions.keys().cloned().collect();
- let voted_protoset: ProtoSet = ProtoSet::from(voted_versions);
-
- final_output.insert(protocol, voted_protoset);
- }
- }
- final_output
- }
-}
-
-/// Returns a boolean indicating whether the given protocol and version is
-/// supported in any of the existing Tor protocols
-///
-/// # Examples
-/// ```
-/// use protover::is_supported_here;
-/// use protover::Protocol;
-///
-/// let is_supported = is_supported_here(&Protocol::Link, &10);
-/// assert_eq!(false, is_supported);
-///
-/// let is_supported = is_supported_here(&Protocol::Link, &1);
-/// assert_eq!(true, is_supported);
-/// ```
-pub fn is_supported_here(proto: &Protocol, vers: &Version) -> bool {
- let currently_supported: ProtoEntry = match ProtoEntry::supported() {
- Ok(result) => result,
- Err(_) => return false,
- };
- let supported_versions = match currently_supported.get(proto) {
- Some(n) => n,
- None => return false,
- };
- supported_versions.contains(vers)
-}
-
-/// Since older versions of Tor cannot infer their own subprotocols,
-/// determine which subprotocols are supported by older Tor versions.
-///
-/// # Inputs
-///
-/// * `version`, a string comprised of "[0-9a-z.-]"
-///
-/// # Returns
-///
-/// A `&'static CStr` encoding a list of protocol names and supported
-/// versions. The string takes the following format:
-///
-/// "HSDir=1-1 LinkAuth=1"
-///
-/// This function returns the protocols that are supported by the version input,
-/// only for tor versions older than `FIRST_TOR_VERSION_TO_ADVERTISE_PROTOCOLS`
-/// (but not older than 0.2.4.19). For newer tors (or older than 0.2.4.19), it
-/// returns an empty string.
-///
-/// # Note
-///
-/// This function is meant to be called for/within FFI code. If you'd
-/// like to use this code in Rust, please see `compute_for_old_tor()`.
-//
-// C_RUST_COUPLED: src/rust/protover.c `compute_for_old_tor`
-pub(crate) fn compute_for_old_tor_cstr(version: &str) -> &'static CStr {
- let empty: &'static CStr = cstr!("");
-
- if c_tor_version_as_new_as(version, FIRST_TOR_VERSION_TO_ADVERTISE_PROTOCOLS) {
- return empty;
- }
- if c_tor_version_as_new_as(version, "0.2.9.1-alpha") {
- return cstr!(
- "Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 \
- Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2"
- );
- }
- if c_tor_version_as_new_as(version, "0.2.7.5") {
- return cstr!(
- "Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1 \
- Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2"
- );
- }
- if c_tor_version_as_new_as(version, "0.2.4.19") {
- return cstr!(
- "Cons=1 Desc=1 DirCache=1 HSDir=1 HSIntro=3 HSRend=1 \
- Link=1-4 LinkAuth=1 Microdesc=1 Relay=1-2"
- );
- }
- empty
-}
-
-/// Since older versions of Tor cannot infer their own subprotocols,
-/// determine which subprotocols are supported by older Tor versions.
-///
-/// # Inputs
-///
-/// * `version`, a string comprised of "[0-9a-z.-]"
-///
-/// # Returns
-///
-/// A `Result` whose `Ok` value is an `&'static str` encoding a list of protocol
-/// names and supported versions. The string takes the following format:
-///
-/// "HSDir=1-1 LinkAuth=1"
-///
-/// This function returns the protocols that are supported by the version input,
-/// only for tor versions older than `FIRST_TOR_VERSION_TO_ADVERTISE_PROTOCOLS`.
-/// (but not older than 0.2.4.19). For newer tors (or older than 0.2.4.19), its
-/// `Ok` `Result` contains an empty string.
-///
-/// Otherwise, its `Err` contains a `ProtoverError::Unparseable` if the
-/// `version` string was invalid utf-8.
-///
-/// # Note
-///
-/// This function is meant to be called for/within non-FFI Rust code.
-//
-// C_RUST_COUPLED: src/rust/protover.c `compute_for_old_tor`
-pub fn compute_for_old_tor(version: &str) -> Result<&'static str, ProtoverError> {
- // .to_str() fails with a Utf8Error if it couldn't validate the
- // utf-8, so convert that here into an Unparseable ProtoverError.
- compute_for_old_tor_cstr(version)
- .to_str()
- .or(Err(ProtoverError::Unparseable))
-}
-
-#[cfg(test)]
-mod test {
- use std::str::FromStr;
- use std::string::ToString;
-
- use super::*;
-
- macro_rules! parse_proto {
- ($e:expr) => {{
- let proto: Result<UnknownProtocol, _> = $e.parse();
- let proto2 = UnknownProtocol::from_str_any_len($e);
- assert_eq!(proto, proto2);
- proto
- }};
- }
-
- #[test]
- fn test_protocol_from_str() {
- assert!(parse_proto!("Cons").is_ok());
- assert!(parse_proto!("123").is_ok());
- assert!(parse_proto!("1-2-3").is_ok());
-
- let err = Err(ProtoverError::InvalidProtocol);
- assert_eq!(err, parse_proto!("a_b_c"));
- assert_eq!(err, parse_proto!("a b"));
- assert_eq!(err, parse_proto!("a,"));
- assert_eq!(err, parse_proto!("b."));
- assert_eq!(err, parse_proto!("é"));
- }
-
- macro_rules! assert_protoentry_is_parseable {
- ($e:expr) => {
- let protoentry: Result<ProtoEntry, ProtoverError> = $e.parse();
-
- assert!(protoentry.is_ok(), format!("{:?}", protoentry.err()));
- };
- }
-
- macro_rules! assert_protoentry_is_unparseable {
- ($e:expr) => {
- let protoentry: Result<ProtoEntry, ProtoverError> = $e.parse();
-
- assert!(protoentry.is_err());
- };
- }
-
- #[test]
- fn test_protoentry_from_str_multiple_protocols_multiple_versions() {
- assert_protoentry_is_parseable!("Cons=3-4 Link=1,3-5");
- }
-
- #[test]
- fn test_protoentry_from_str_empty() {
- assert_protoentry_is_parseable!("");
- assert!(UnvalidatedProtoEntry::from_str("").is_ok());
- }
-
- #[test]
- fn test_protoentry_from_str_single_protocol_single_version() {
- assert_protoentry_is_parseable!("HSDir=1");
- }
-
- #[test]
- fn test_protoentry_from_str_unknown_protocol() {
- assert_protoentry_is_unparseable!("Ducks=5-7,8");
- }
-
- #[test]
- fn test_protoentry_from_str_allowed_number_of_versions() {
- assert_protoentry_is_parseable!("Desc=1-63");
- }
-
- #[test]
- fn test_protoentry_from_str_too_many_versions() {
- assert_protoentry_is_unparseable!("Desc=1-64");
- }
-
- #[test]
- fn test_protoentry_all_supported_single_protocol_single_version() {
- let protocol: UnvalidatedProtoEntry = "Cons=1".parse().unwrap();
- let unsupported: Option<UnvalidatedProtoEntry> = protocol.all_supported();
- assert_eq!(true, unsupported.is_none());
- }
-
- #[test]
- fn test_protoentry_all_supported_multiple_protocol_multiple_versions() {
- let protocols: UnvalidatedProtoEntry = "Link=3-4 Desc=2".parse().unwrap();
- let unsupported: Option<UnvalidatedProtoEntry> = protocols.all_supported();
- assert_eq!(true, unsupported.is_none());
- }
-
- #[test]
- fn test_protoentry_all_supported_three_values() {
- let protocols: UnvalidatedProtoEntry = "LinkAuth=1 Microdesc=1-2 Relay=2".parse().unwrap();
- let unsupported: Option<UnvalidatedProtoEntry> = protocols.all_supported();
- assert_eq!(true, unsupported.is_none());
- }
-
- #[test]
- fn test_protoentry_all_supported_unknown_protocol() {
- let protocols: UnvalidatedProtoEntry = "Wombat=9".parse().unwrap();
- let unsupported: Option<UnvalidatedProtoEntry> = protocols.all_supported();
- assert_eq!(true, unsupported.is_some());
- assert_eq!("Wombat=9", &unsupported.unwrap().to_string());
- }
-
- #[test]
- fn test_protoentry_all_supported_unsupported_high_version() {
- let protocols: UnvalidatedProtoEntry = "HSDir=12-60".parse().unwrap();
- let unsupported: Option<UnvalidatedProtoEntry> = protocols.all_supported();
- assert_eq!(true, unsupported.is_some());
- assert_eq!("HSDir=12-60", &unsupported.unwrap().to_string());
- }
-
- #[test]
- fn test_protoentry_all_supported_unsupported_low_version() {
- let protocols: UnvalidatedProtoEntry = "HSIntro=2-3".parse().unwrap();
- let unsupported: Option<UnvalidatedProtoEntry> = protocols.all_supported();
- assert_eq!(true, unsupported.is_some());
- assert_eq!("HSIntro=2", &unsupported.unwrap().to_string());
- }
-
- #[test]
- fn test_contract_protocol_list() {
- let mut versions = "";
- assert_eq!(
- String::from(versions),
- ProtoSet::from_str(&versions).unwrap().to_string()
- );
-
- versions = "1";
- assert_eq!(
- String::from(versions),
- ProtoSet::from_str(&versions).unwrap().to_string()
- );
-
- versions = "1-2";
- assert_eq!(
- String::from(versions),
- ProtoSet::from_str(&versions).unwrap().to_string()
- );
-
- versions = "1,3";
- assert_eq!(
- String::from(versions),
- ProtoSet::from_str(&versions).unwrap().to_string()
- );
-
- versions = "1-4";
- assert_eq!(
- String::from(versions),
- ProtoSet::from_str(&versions).unwrap().to_string()
- );
-
- versions = "1,3,5-7";
- assert_eq!(
- String::from(versions),
- ProtoSet::from_str(&versions).unwrap().to_string()
- );
-
- versions = "1-3,50";
- assert_eq!(
- String::from(versions),
- ProtoSet::from_str(&versions).unwrap().to_string()
- );
- }
-}
diff --git a/src/rust/protover/tests/protover.rs b/src/rust/protover/tests/protover.rs
deleted file mode 100644
index a6305ac39a..0000000000
--- a/src/rust/protover/tests/protover.rs
+++ /dev/null
@@ -1,365 +0,0 @@
-// Copyright (c) 2016-2019, The Tor Project, Inc. */
-// See LICENSE for licensing information */
-
-extern crate protover;
-
-use protover::errors::ProtoverError;
-use protover::ProtoEntry;
-use protover::ProtoverVote;
-use protover::UnvalidatedProtoEntry;
-
-#[test]
-fn parse_protocol_with_single_proto_and_single_version() {
- let _: ProtoEntry = "Cons=1".parse().unwrap();
-}
-
-#[test]
-fn parse_protocol_with_single_protocol_and_multiple_versions() {
- let _: ProtoEntry = "Cons=1-2".parse().unwrap();
-}
-
-#[test]
-fn parse_protocol_with_different_single_protocol_and_single_version() {
- let _: ProtoEntry = "HSDir=1".parse().unwrap();
-}
-
-#[test]
-fn parse_protocol_with_single_protocol_and_supported_version() {
- let _: ProtoEntry = "Desc=2".parse().unwrap();
-}
-
-#[test]
-fn parse_protocol_with_two_protocols_and_single_version() {
- let _: ProtoEntry = "Cons=1 HSDir=1".parse().unwrap();
-}
-
-#[test]
-fn parse_protocol_with_single_protocol_and_two_sequential_versions() {
- let _: ProtoEntry = "Desc=1-2".parse().unwrap();
-}
-
-#[test]
-fn parse_protocol_with_single_protocol_and_protocol_range() {
- let _: ProtoEntry = "Link=1-4".parse().unwrap();
-}
-
-#[test]
-fn parse_protocol_with_single_protocol_and_protocol_set() {
- let _: ProtoEntry = "Link=3-4 Desc=2".parse().unwrap();
-}
-
-#[test]
-fn protocol_all_supported_with_single_protocol_and_protocol_set() {
- let protocols: UnvalidatedProtoEntry = "Link=3-4 Desc=2".parse().unwrap();
- let unsupported: Option<UnvalidatedProtoEntry> = protocols.all_supported();
- assert_eq!(true, unsupported.is_none());
-}
-
-#[test]
-fn protocol_all_supported_with_two_values() {
- let protocols: UnvalidatedProtoEntry = "Microdesc=1-2 Relay=2".parse().unwrap();
- let unsupported: Option<UnvalidatedProtoEntry> = protocols.all_supported();
- assert_eq!(true, unsupported.is_none());
-}
-
-#[test]
-fn protocol_all_supported_with_one_value() {
- let protocols: UnvalidatedProtoEntry = "Microdesc=1-2".parse().unwrap();
- let unsupported: Option<UnvalidatedProtoEntry> = protocols.all_supported();
- assert_eq!(true, unsupported.is_none());
-}
-
-#[test]
-fn protocol_all_supported_with_three_values() {
- let protocols: UnvalidatedProtoEntry = "LinkAuth=1 Microdesc=1-2 Relay=2".parse().unwrap();
- let unsupported: Option<UnvalidatedProtoEntry> = protocols.all_supported();
- assert_eq!(true, unsupported.is_none());
-}
-
-#[test]
-fn protocol_all_supported_with_unsupported_protocol() {
- let protocols: UnvalidatedProtoEntry = "Wombat=9".parse().unwrap();
- let unsupported: Option<UnvalidatedProtoEntry> = protocols.all_supported();
- assert_eq!(true, unsupported.is_some());
- assert_eq!("Wombat=9", &unsupported.unwrap().to_string());
-}
-
-#[test]
-fn protocol_all_supported_with_unsupported_versions() {
- let protocols: UnvalidatedProtoEntry = "Link=3-63".parse().unwrap();
- let unsupported: Option<UnvalidatedProtoEntry> = protocols.all_supported();
- assert_eq!(true, unsupported.is_some());
- assert_eq!("Link=6-63", &unsupported.unwrap().to_string());
-}
-
-#[test]
-fn protocol_all_supported_with_unsupported_low_version() {
- let protocols: UnvalidatedProtoEntry = "HSIntro=2-3".parse().unwrap();
- let unsupported: Option<UnvalidatedProtoEntry> = protocols.all_supported();
- assert_eq!(true, unsupported.is_some());
- assert_eq!("HSIntro=2", &unsupported.unwrap().to_string());
-}
-
-#[test]
-fn protocol_all_supported_with_unsupported_high_version() {
- let protocols: UnvalidatedProtoEntry = "Cons=1-2,60".parse().unwrap();
- let unsupported: Option<UnvalidatedProtoEntry> = protocols.all_supported();
- assert_eq!(true, unsupported.is_some());
- assert_eq!("Cons=60", &unsupported.unwrap().to_string());
-}
-
-#[test]
-fn protocol_all_supported_with_mix_of_supported_and_unsupproted() {
- let protocols: UnvalidatedProtoEntry = "Link=3-4 Wombat=9".parse().unwrap();
- let unsupported: Option<UnvalidatedProtoEntry> = protocols.all_supported();
- assert_eq!(true, unsupported.is_some());
- assert_eq!("Wombat=9", &unsupported.unwrap().to_string());
-}
-
-#[test]
-fn protover_string_supports_protocol_returns_true_for_single_supported() {
- let protocols: UnvalidatedProtoEntry = "Link=3-4 Cons=1".parse().unwrap();
- let is_supported = protocols.supports_protocol(&protover::Protocol::Cons.into(), &1);
- assert_eq!(true, is_supported);
-}
-
-#[test]
-fn protover_string_supports_protocol_returns_false_for_single_unsupported() {
- let protocols: UnvalidatedProtoEntry = "Link=3-4 Cons=1".parse().unwrap();
- let is_supported = protocols.supports_protocol(&protover::Protocol::Cons.into(), &2);
- assert_eq!(false, is_supported);
-}
-
-#[test]
-fn protover_string_supports_protocol_returns_false_for_unsupported() {
- let protocols: UnvalidatedProtoEntry = "Link=3-4".parse().unwrap();
- let is_supported = protocols.supports_protocol(&protover::Protocol::Cons.into(), &2);
- assert_eq!(false, is_supported);
-}
-
-#[test]
-#[should_panic]
-fn parse_protocol_with_unexpected_characters() {
- let _: UnvalidatedProtoEntry = "Cons=*-%".parse().unwrap();
-}
-
-#[test]
-fn protover_compute_vote_returns_empty_for_empty_string() {
- let protocols: &[UnvalidatedProtoEntry] = &["".parse().unwrap()];
- let listed = ProtoverVote::compute(protocols, &1);
- assert_eq!("", listed.to_string());
-}
-
-#[test]
-fn protover_compute_vote_returns_single_protocol_for_matching() {
- let protocols: &[UnvalidatedProtoEntry] = &["Cons=1".parse().unwrap()];
- let listed = ProtoverVote::compute(protocols, &1);
- assert_eq!("Cons=1", listed.to_string());
-}
-
-#[test]
-fn protover_compute_vote_returns_two_protocols_for_two_matching() {
- let protocols: &[UnvalidatedProtoEntry] = &["Link=1 Cons=1".parse().unwrap()];
- let listed = ProtoverVote::compute(protocols, &1);
- assert_eq!("Cons=1 Link=1", listed.to_string());
-}
-
-#[test]
-fn protover_compute_vote_returns_one_protocol_when_one_out_of_two_matches() {
- let protocols: &[UnvalidatedProtoEntry] =
- &["Cons=1 Link=2".parse().unwrap(), "Cons=1".parse().unwrap()];
- let listed = ProtoverVote::compute(protocols, &2);
- assert_eq!("Cons=1", listed.to_string());
-}
-
-#[test]
-fn protover_compute_vote_returns_protocols_that_it_doesnt_currently_support() {
- let protocols: &[UnvalidatedProtoEntry] =
- &["Foo=1 Cons=2".parse().unwrap(), "Bar=1".parse().unwrap()];
- let listed = ProtoverVote::compute(protocols, &1);
- assert_eq!("Bar=1 Cons=2 Foo=1", listed.to_string());
-}
-
-#[test]
-fn protover_compute_vote_returns_matching_for_mix() {
- let protocols: &[UnvalidatedProtoEntry] = &["Link=1-10,50 Cons=1,3-7,8".parse().unwrap()];
- let listed = ProtoverVote::compute(protocols, &1);
- assert_eq!("Cons=1,3-8 Link=1-10,50", listed.to_string());
-}
-
-#[test]
-fn protover_compute_vote_returns_matching_for_longer_mix() {
- let protocols: &[UnvalidatedProtoEntry] = &[
- "Desc=1-10,50 Cons=1,3-7,8".parse().unwrap(),
- "Link=12-45,8 Cons=2-6,8 Desc=9".parse().unwrap(),
- ];
-
- let listed = ProtoverVote::compute(protocols, &1);
- assert_eq!("Cons=1-8 Desc=1-10,50 Link=8,12-45", listed.to_string());
-}
-
-#[test]
-fn protover_compute_vote_returns_matching_for_longer_mix_with_threshold_two() {
- let protocols: &[UnvalidatedProtoEntry] = &[
- "Desc=1-10,50 Cons=1,3-7,8".parse().unwrap(),
- "Link=8,12-45 Cons=2-6,8 Desc=9".parse().unwrap(),
- ];
-
- let listed = ProtoverVote::compute(protocols, &2);
- assert_eq!("Cons=3-6,8 Desc=9", listed.to_string());
-}
-
-#[test]
-fn protover_compute_vote_handles_duplicated_versions() {
- let protocols: &[UnvalidatedProtoEntry] =
- &["Cons=1".parse().unwrap(), "Cons=1".parse().unwrap()];
- assert_eq!("Cons=1", ProtoverVote::compute(protocols, &2).to_string());
-
- let protocols: &[UnvalidatedProtoEntry] =
- &["Cons=1-2".parse().unwrap(), "Cons=1-2".parse().unwrap()];
- assert_eq!("Cons=1-2", ProtoverVote::compute(protocols, &2).to_string());
-}
-
-#[test]
-fn protover_compute_vote_handles_invalid_proto_entries() {
- let protocols: &[UnvalidatedProtoEntry] = &[
- "Cons=1".parse().unwrap(),
- "Cons=1".parse().unwrap(),
- "Dinosaur=1".parse().unwrap(),
- ];
- assert_eq!("Cons=1", ProtoverVote::compute(protocols, &2).to_string());
-}
-
-#[test]
-fn parse_protocol_with_single_protocol_and_two_nonsequential_versions() {
- let _: ProtoEntry = "Desc=1,2".parse().unwrap();
-}
-
-#[test]
-fn protover_is_supported_here_returns_true_for_supported_protocol() {
- assert_eq!(
- true,
- protover::is_supported_here(&protover::Protocol::Cons, &1)
- );
-}
-
-#[test]
-fn protover_is_supported_here_returns_false_for_unsupported_protocol() {
- assert_eq!(
- false,
- protover::is_supported_here(&protover::Protocol::Cons, &5)
- );
-}
-
-#[test]
-fn protocol_all_supported_with_single_proto_and_single_version() {
- let protocol: UnvalidatedProtoEntry = "Cons=1".parse().unwrap();
- let unsupported: Option<UnvalidatedProtoEntry> = protocol.all_supported();
- assert_eq!(true, unsupported.is_none());
-}
-
-#[test]
-fn protocol_all_supported_with_single_protocol_and_multiple_versions() {
- let protocol: UnvalidatedProtoEntry = "Cons=1-2".parse().unwrap();
- let unsupported: Option<UnvalidatedProtoEntry> = protocol.all_supported();
- assert_eq!(true, unsupported.is_none());
-}
-
-#[test]
-fn protocol_all_supported_with_different_single_protocol_and_single_version() {
- let protocol: UnvalidatedProtoEntry = "HSDir=1".parse().unwrap();
- let unsupported: Option<UnvalidatedProtoEntry> = protocol.all_supported();
- assert_eq!(true, unsupported.is_none());
-}
-
-#[test]
-fn protocol_all_supported_with_single_protocol_and_supported_version() {
- let protocol: UnvalidatedProtoEntry = "Desc=2".parse().unwrap();
- let unsupported: Option<UnvalidatedProtoEntry> = protocol.all_supported();
- assert_eq!(true, unsupported.is_none());
-}
-
-#[test]
-fn protocol_all_supported_with_two_protocols_and_single_version() {
- let protocols: UnvalidatedProtoEntry = "Cons=1 HSDir=1".parse().unwrap();
- let unsupported: Option<UnvalidatedProtoEntry> = protocols.all_supported();
- assert_eq!(true, unsupported.is_none());
-}
-
-#[test]
-fn protocol_all_supported_with_single_protocol_and_two_nonsequential_versions() {
- let protocol: UnvalidatedProtoEntry = "Desc=1,2".parse().unwrap();
- let unsupported: Option<UnvalidatedProtoEntry> = protocol.all_supported();
- assert_eq!(true, unsupported.is_none());
-}
-
-#[test]
-fn protocol_all_supported_with_single_protocol_and_two_sequential_versions() {
- let protocol: UnvalidatedProtoEntry = "Desc=1-2".parse().unwrap();
- let unsupported: Option<UnvalidatedProtoEntry> = protocol.all_supported();
- assert_eq!(true, unsupported.is_none());
-}
-
-#[test]
-fn protocol_all_supported_with_single_protocol_and_protocol_range() {
- let protocol: UnvalidatedProtoEntry = "Link=1-4".parse().unwrap();
- let unsupported: Option<UnvalidatedProtoEntry> = protocol.all_supported();
- assert_eq!(true, unsupported.is_none());
-}
-
-#[test]
-fn protover_all_supported_should_exclude_versions_we_actually_do_support() {
- let proto: UnvalidatedProtoEntry = "Link=3-63".parse().unwrap();
- let result: String = proto.all_supported().unwrap().to_string();
-
- assert_eq!(result, "Link=6-63".to_string());
-}
-
-#[test]
-fn protover_all_supported_should_exclude_versions_we_actually_do_support_complex1() {
- let proto: UnvalidatedProtoEntry = "Link=1-3,30-63".parse().unwrap();
- let result: String = proto.all_supported().unwrap().to_string();
-
- assert_eq!(result, "Link=30-63".to_string());
-}
-
-#[test]
-fn protover_all_supported_should_exclude_versions_we_actually_do_support_complex2() {
- let proto: UnvalidatedProtoEntry = "Link=1-3,5-12".parse().unwrap();
- let result: String = proto.all_supported().unwrap().to_string();
-
- assert_eq!(result, "Link=6-12".to_string());
-}
-
-#[test]
-fn protover_all_supported_should_exclude_some_versions_and_entire_protocols() {
- let proto: UnvalidatedProtoEntry = "Link=1-3,5-12 Quokka=50-51".parse().unwrap();
- let result: String = proto.all_supported().unwrap().to_string();
-
- assert_eq!(result, "Link=6-12 Quokka=50-51".to_string());
-}
-
-#[test]
-// C_RUST_DIFFERS: The C will return true (e.g. saying "yes, that's supported")
-// but set the msg to NULL (??? seems maybe potentially bad). The Rust will
-// simply return a None.
-fn protover_all_supported_should_return_empty_string_for_weird_thing() {
- let proto: UnvalidatedProtoEntry = "Fribble=".parse().unwrap();
- let result: Option<UnvalidatedProtoEntry> = proto.all_supported();
-
- assert!(result.is_none());
-}
-
-#[test]
-fn protover_unvalidatedprotoentry_should_err_entirely_unparseable_things() {
- let proto: Result<UnvalidatedProtoEntry, ProtoverError> = "Fribble".parse();
-
- assert_eq!(Err(ProtoverError::Unparseable), proto);
-}
-
-#[test]
-fn protover_all_supported_over_maximum_limit() {
- let proto: Result<UnvalidatedProtoEntry, ProtoverError> = "Sleen=1-4294967295".parse();
-
- assert_eq!(Err(ProtoverError::ExceedsMax), proto);
-}
diff --git a/src/rust/smartlist/Cargo.toml b/src/rust/smartlist/Cargo.toml
deleted file mode 100644
index a5afe7bf74..0000000000
--- a/src/rust/smartlist/Cargo.toml
+++ /dev/null
@@ -1,18 +0,0 @@
-[package]
-authors = ["The Tor Project"]
-version = "0.0.1"
-name = "smartlist"
-
-[dependencies]
-libc = "0.2.39"
-
-[lib]
-name = "smartlist"
-path = "lib.rs"
-
-[features]
-# We have to define a feature here because doctests don't get cfg(test),
-# and we need to disable some C dependencies when running the doctests
-# because of the various linker issues. See
-# https://github.com/rust-lang/rust/issues/45599
-test_linking_hack = []
diff --git a/src/rust/smartlist/lib.rs b/src/rust/smartlist/lib.rs
deleted file mode 100644
index 23301f88c3..0000000000
--- a/src/rust/smartlist/lib.rs
+++ /dev/null
@@ -1,17 +0,0 @@
-// Copyright (c) 2016-2019, The Tor Project, Inc. */
-// See LICENSE for licensing information */
-
-extern crate libc;
-
-mod smartlist;
-
-pub use smartlist::*;
-
-// When testing we may be compiled with sanitizers which are incompatible with
-// Rust's default allocator, jemalloc (unsure why at this time). Most crates
-// link to `tor_allocate` which switches by default to a non-jemalloc allocator,
-// but we don't already depend on `tor_allocate` so make sure that while testing
-// we don't use jemalloc. (but rather malloc/free)
-#[global_allocator]
-#[cfg(test)]
-static A: std::alloc::System = std::alloc::System;
diff --git a/src/rust/smartlist/smartlist.rs b/src/rust/smartlist/smartlist.rs
deleted file mode 100644
index d8f8083dff..0000000000
--- a/src/rust/smartlist/smartlist.rs
+++ /dev/null
@@ -1,115 +0,0 @@
-// Copyright (c) 2016-2019, The Tor Project, Inc. */
-// See LICENSE for licensing information */
-
-use libc::{c_char, c_int};
-use std::ffi::CStr;
-use std::slice;
-
-/// Smartlists are a type used in C code in tor to define a collection of a
-/// generic type, which has a capacity and a number used. Each Smartlist
-/// defines how to extract the list of values from the underlying C structure
-///
-/// Implementations are required to have a C representation, as this module
-/// serves purely to translate smartlists as defined in tor to vectors in Rust.
-pub trait Smartlist<T> {
- fn get_list(&self) -> Vec<T>;
-}
-
-#[repr(C)]
-pub struct Stringlist {
- pub list: *const *const c_char,
- pub num_used: c_int,
- pub capacity: c_int,
-}
-
-impl Smartlist<String> for Stringlist {
- fn get_list(&self) -> Vec<String> {
- let empty: Vec<String> = Vec::new();
- let mut rust_list: Vec<String> = Vec::new();
-
- if self.list.is_null() || self.num_used == 0 {
- return empty;
- }
-
- // unsafe, as we need to extract the smartlist list into a vector of
- // pointers, and then transform each element into a Rust string.
- let elems: &[*const c_char] =
- unsafe { slice::from_raw_parts(self.list, self.num_used as usize) };
-
- for elem in elems.iter() {
- if elem.is_null() {
- continue;
- }
-
- // unsafe, as we need to create a cstring from the referenced
- // element
- let c_string = unsafe { CStr::from_ptr(*elem) };
-
- let r_string = match c_string.to_str() {
- Ok(n) => n,
- Err(_) => return empty,
- };
-
- rust_list.push(String::from(r_string));
- }
-
- rust_list
- }
-}
-
-// TODO: CHK: this module maybe should be tested from a test in C with a
-// smartlist as defined in tor.
-#[cfg(test)]
-mod test {
- #[test]
- fn test_get_list_of_strings() {
- extern crate libc;
-
- use libc::c_char;
- use std::ffi::CString;
-
- use super::Smartlist;
- use super::Stringlist;
-
- {
- // test to verify that null pointers are gracefully handled
- use std::ptr;
-
- let sl = Stringlist {
- list: ptr::null(),
- num_used: 0,
- capacity: 0,
- };
-
- let data = sl.get_list();
- assert_eq!(0, data.len());
- }
-
- {
- let args = vec![String::from("a"), String::from("b")];
-
- // for each string, transform it into a CString
- let c_strings: Vec<_> = args
- .iter()
- .map(|arg| CString::new(arg.as_str()).unwrap())
- .collect();
-
- // then, collect a pointer for each CString
- let p_args: Vec<_> = c_strings.iter().map(|arg| arg.as_ptr()).collect();
-
- let p: *const *const c_char = p_args.as_ptr();
-
- // This is the representation that we expect when receiving a
- // smartlist at the Rust/C FFI layer.
- let sl = Stringlist {
- list: p,
- num_used: 2,
- capacity: 2,
- };
-
- let data = sl.get_list();
- assert_eq!("a", &data[0]);
- assert_eq!("b", &data[1]);
- }
- }
-}
diff --git a/src/rust/tor_allocate/Cargo.toml b/src/rust/tor_allocate/Cargo.toml
deleted file mode 100644
index 06ac605f17..0000000000
--- a/src/rust/tor_allocate/Cargo.toml
+++ /dev/null
@@ -1,18 +0,0 @@
-[package]
-authors = ["The Tor Project"]
-version = "0.0.1"
-name = "tor_allocate"
-
-[dependencies]
-libc = "=0.2.39"
-
-[lib]
-name = "tor_allocate"
-path = "lib.rs"
-
-[features]
-# We have to define a feature here because doctests don't get cfg(test),
-# and we need to disable some C dependencies when running the doctests
-# because of the various linker issues. See
-# https://github.com/rust-lang/rust/issues/45599
-test_linking_hack = []
diff --git a/src/rust/tor_allocate/lib.rs b/src/rust/tor_allocate/lib.rs
deleted file mode 100644
index fff8a08006..0000000000
--- a/src/rust/tor_allocate/lib.rs
+++ /dev/null
@@ -1,20 +0,0 @@
-// Copyright (c) 2016-2019, The Tor Project, Inc. */
-// See LICENSE for licensing information */
-
-//! Allocation helper functions that allow data to be allocated in Rust
-//! using tor's specified allocator. In doing so, this can be later freed
-//! from C.
-//!
-//! This is currently a temporary solution, we will later use tor's allocator
-//! by default for any allocation that occurs in Rust. However, as this will
-//! stabalize in 2018, we can use this as a temporary measure.
-
-extern crate libc;
-
-use std::alloc::System;
-
-mod tor_allocate;
-pub use tor_allocate::*;
-
-#[global_allocator]
-static A: System = System;
diff --git a/src/rust/tor_allocate/tor_allocate.rs b/src/rust/tor_allocate/tor_allocate.rs
deleted file mode 100644
index 7b35e2451f..0000000000
--- a/src/rust/tor_allocate/tor_allocate.rs
+++ /dev/null
@@ -1,104 +0,0 @@
-// Copyright (c) 2016-2019, The Tor Project, Inc. */
-// See LICENSE for licensing information */
-// No-op defined purely for testing at the module level
-use libc::c_char;
-
-use libc::c_void;
-#[cfg(not(feature = "testing"))]
-use std::{mem, ptr, slice};
-
-// Define a no-op implementation for testing Rust modules without linking to C
-#[cfg(feature = "testing")]
-pub fn allocate_and_copy_string(s: &str) -> *mut c_char {
- use std::ffi::CString;
- CString::new(s).unwrap().into_raw()
-}
-
-// Defined only for tests, used for testing purposes, so that we don't need
-// to link to tor C files. Uses the system allocator
-#[cfg(test)]
-unsafe extern "C" fn tor_malloc_(size: usize) -> *mut c_void {
- use libc::malloc;
- malloc(size)
-}
-
-#[cfg(all(not(test), not(feature = "testing")))]
-extern "C" {
- fn tor_malloc_(size: usize) -> *mut c_void;
-}
-
-/// Allocate memory using tor_malloc_ and copy an existing string into the
-/// allocated buffer, returning a pointer that can later be called in C.
-///
-/// # Inputs
-///
-/// * `src`, a reference to a String.
-///
-/// # Returns
-///
-/// A `*mut c_char` that should be freed by tor_free in C
-///
-#[cfg(not(feature = "testing"))]
-pub fn allocate_and_copy_string(src: &str) -> *mut c_char {
- let bytes: &[u8] = src.as_bytes();
-
- let size = mem::size_of_val::<[u8]>(bytes);
- let size_one_byte = mem::size_of::<u8>();
-
- // handle integer overflow when adding one to the calculated length
- let size_with_null_byte = match size.checked_add(size_one_byte) {
- Some(n) => n,
- None => return ptr::null_mut(),
- };
-
- let dest = unsafe { tor_malloc_(size_with_null_byte) as *mut u8 };
-
- if dest.is_null() {
- return ptr::null_mut();
- }
-
- unsafe { ptr::copy_nonoverlapping(bytes.as_ptr(), dest, size) };
-
- // set the last byte as null, using the ability to index into a slice
- // rather than doing pointer arithmetic
- let slice = unsafe { slice::from_raw_parts_mut(dest, size_with_null_byte) };
- slice[size] = 0; // add a null terminator
-
- dest as *mut c_char
-}
-
-#[cfg(test)]
-mod test {
-
- #[test]
- fn test_allocate_and_copy_string_with_empty() {
- use libc::{c_void, free};
- use std::ffi::CStr;
-
- use tor_allocate::allocate_and_copy_string;
-
- let allocated_empty = allocate_and_copy_string("");
-
- let allocated_empty_rust = unsafe { CStr::from_ptr(allocated_empty).to_str().unwrap() };
-
- assert_eq!("", allocated_empty_rust);
-
- unsafe { free(allocated_empty as *mut c_void) };
- }
-
- #[test]
- fn test_allocate_and_copy_string_with_not_empty_string() {
- use libc::{c_void, free};
- use std::ffi::CStr;
-
- use tor_allocate::allocate_and_copy_string;
-
- let allocated_empty = allocate_and_copy_string("foo bar biz");
-
- let allocated_empty_rust = unsafe { CStr::from_ptr(allocated_empty).to_str().unwrap() };
-
- assert_eq!("foo bar biz", allocated_empty_rust);
-
- unsafe { free(allocated_empty as *mut c_void) };
- }
-}
diff --git a/src/rust/tor_log/Cargo.toml b/src/rust/tor_log/Cargo.toml
deleted file mode 100644
index 14d9ae803a..0000000000
--- a/src/rust/tor_log/Cargo.toml
+++ /dev/null
@@ -1,21 +0,0 @@
-[package]
-name = "tor_log"
-version = "0.1.0"
-authors = ["The Tor Project"]
-
-[lib]
-name = "tor_log"
-path = "lib.rs"
-
-[features]
-# We have to define a feature here because doctests don't get cfg(test),
-# and we need to disable some C dependencies when running the doctests
-# because of the various linker issues. See
-# https://github.com/rust-lang/rust/issues/45599
-test_linking_hack = []
-
-[dependencies]
-libc = "0.2.39"
-
-[dependencies.tor_allocate]
-path = "../tor_allocate"
diff --git a/src/rust/tor_log/lib.rs b/src/rust/tor_log/lib.rs
deleted file mode 100644
index 4aa658e35b..0000000000
--- a/src/rust/tor_log/lib.rs
+++ /dev/null
@@ -1,16 +0,0 @@
-//! Copyright (c) 2016-2019, The Tor Project, Inc. */
-//! See LICENSE for licensing information */
-
-//! Logging wrapper for Rust to utilize Tor's logger, found at
-//! src/common/log.c and src/common/torlog.h
-//!
-//! Exposes different interfaces depending on whether we are running in test
-//! or non-test mode. When testing, we use a no-op implementation,
-//! otherwise we link directly to C.
-
-extern crate libc;
-extern crate tor_allocate;
-
-mod tor_log;
-
-pub use tor_log::*;
diff --git a/src/rust/tor_log/tor_log.rs b/src/rust/tor_log/tor_log.rs
deleted file mode 100644
index 391cb32ab3..0000000000
--- a/src/rust/tor_log/tor_log.rs
+++ /dev/null
@@ -1,265 +0,0 @@
-// Copyright (c) 2016-2019, The Tor Project, Inc. */
-// See LICENSE for licensing information */
-
-// Note that these functions are untested due to the fact that there are no
-// return variables to test and they are calling into a C API.
-
-/// The related domain which the logging message is relevant. For example,
-/// log messages relevant to networking would use LogDomain::LdNet, whereas
-/// general messages can use LdGeneral.
-#[derive(Eq, PartialEq)]
-pub enum LogDomain {
- Net,
- General,
-}
-
-/// The severity level at which to log messages.
-#[derive(Eq, PartialEq)]
-pub enum LogSeverity {
- Notice,
- Warn,
-}
-
-/// Main entry point for Rust modules to log messages.
-///
-/// # Inputs
-///
-/// * A `severity` of type LogSeverity, which defines the level of severity the
-/// message will be logged.
-/// * A `domain` of type LogDomain, which defines the domain the log message
-/// will be associated with.
-/// * A `function` of type &str, which defines the name of the function where
-/// the message is being logged. There is a current RFC for a macro that
-/// defines function names. When it is, we should use it. See
-/// https://github.com/rust-lang/rfcs/pull/1719
-/// * A `message` of type &str, which is the log message itself.
-#[macro_export]
-macro_rules! tor_log_msg {
- ($severity: path,
- $domain: path,
- $function: expr,
- $($message:tt)*) =>
- {
- {
- let msg = format!($($message)*);
- $crate::tor_log_msg_impl($severity, $domain, $function, msg)
- }
- };
-}
-
-#[inline]
-pub fn tor_log_msg_impl(severity: LogSeverity, domain: LogDomain, function: &str, message: String) {
- use std::ffi::CString;
-
- /// Default function name to log in case of errors when converting
- /// a function name to a CString
- const ERR_LOG_FUNCTION: &str = "tor_log_msg";
-
- /// Default message to log in case of errors when converting a log
- /// message to a CString
- const ERR_LOG_MSG: &str = "Unable to log message from Rust \
- module due to error when converting to CString";
-
- let func = match CString::new(function) {
- Ok(n) => n,
- Err(_) => CString::new(ERR_LOG_FUNCTION).unwrap(),
- };
-
- let msg = match CString::new(message) {
- Ok(n) => n,
- Err(_) => CString::new(ERR_LOG_MSG).unwrap(),
- };
-
- // Bind to a local variable to preserve ownership. This is essential so
- // that ownership is guaranteed until these local variables go out of scope
- let func_ptr = func.as_ptr();
- let msg_ptr = msg.as_ptr();
-
- let c_severity = unsafe { log::translate_severity(severity) };
- let c_domain = unsafe { log::translate_domain(domain) };
-
- unsafe { log::tor_log_string(c_severity, c_domain, func_ptr, msg_ptr) }
-}
-
-/// This implementation is used when compiling for actual use, as opposed to
-/// testing.
-#[cfg(not(test))]
-pub mod log {
- use super::LogDomain;
- use super::LogSeverity;
- use libc::{c_char, c_int};
-
- /// Severity log types. These mirror definitions in src/lib/log/log.h
- /// C_RUST_COUPLED: src/lib/log/log.c, log domain types
- extern "C" {
- static LOG_WARN_: c_int;
- static LOG_NOTICE_: c_int;
- }
-
- /// Domain log types. These mirror definitions in src/lib/log/log.h
- /// C_RUST_COUPLED: src/lib/log/log.c, log severity types
- extern "C" {
- static LD_NET_: u64;
- static LD_GENERAL_: u64;
- }
-
- /// Translate Rust definitions of log domain levels to C. This exposes a 1:1
- /// mapping between types.
- #[inline]
- pub unsafe fn translate_domain(domain: LogDomain) -> u64 {
- match domain {
- LogDomain::Net => LD_NET_,
- LogDomain::General => LD_GENERAL_,
- }
- }
-
- /// Translate Rust definitions of log severity levels to C. This exposes a
- /// 1:1 mapping between types.
- #[inline]
- pub unsafe fn translate_severity(severity: LogSeverity) -> c_int {
- match severity {
- LogSeverity::Warn => LOG_WARN_,
- LogSeverity::Notice => LOG_NOTICE_,
- }
- }
-
- /// The main entry point into Tor's logger. When in non-test mode, this
- /// will link directly with `tor_log_string` in torlog.c
- extern "C" {
- pub fn tor_log_string(
- severity: c_int,
- domain: u64,
- function: *const c_char,
- string: *const c_char,
- );
- }
-}
-
-/// This module exposes no-op functionality for testing other Rust modules
-/// without linking to C.
-#[cfg(test)]
-pub mod log {
- use super::LogDomain;
- use super::LogSeverity;
- use libc::{c_char, c_int};
-
- pub static mut LAST_LOGGED_FUNCTION: *mut String = 0 as *mut String;
- pub static mut LAST_LOGGED_MESSAGE: *mut String = 0 as *mut String;
-
- pub unsafe fn tor_log_string(
- _severity: c_int,
- _domain: u32,
- function: *const c_char,
- message: *const c_char,
- ) {
- use std::ffi::CStr;
-
- let f = CStr::from_ptr(function);
- let fct = match f.to_str() {
- Ok(n) => n,
- Err(_) => "",
- };
- LAST_LOGGED_FUNCTION = Box::into_raw(Box::new(String::from(fct)));
-
- let m = CStr::from_ptr(message);
- let msg = match m.to_str() {
- Ok(n) => n,
- Err(_) => "",
- };
- LAST_LOGGED_MESSAGE = Box::into_raw(Box::new(String::from(msg)));
- }
-
- pub unsafe fn translate_domain(_domain: LogDomain) -> u32 {
- 1
- }
-
- pub unsafe fn translate_severity(_severity: LogSeverity) -> c_int {
- 1
- }
-}
-
-#[cfg(test)]
-mod test {
- use tor_log::log::{LAST_LOGGED_FUNCTION, LAST_LOGGED_MESSAGE};
- use tor_log::*;
-
- #[test]
- fn test_get_log_message() {
- {
- fn test_macro() {
- tor_log_msg!(
- LogSeverity::Warn,
- LogDomain::Net,
- "test_macro",
- "test log message {}",
- "a",
- );
- }
-
- test_macro();
-
- let function = unsafe { Box::from_raw(LAST_LOGGED_FUNCTION) };
- assert_eq!("test_macro", *function);
-
- let message = unsafe { Box::from_raw(LAST_LOGGED_MESSAGE) };
- assert_eq!("test log message a", *message);
- }
-
- // test multiple inputs into the log message
- {
- fn test_macro() {
- tor_log_msg!(
- LogSeverity::Warn,
- LogDomain::Net,
- "next_test_macro",
- "test log message {} {} {} {} {}",
- 1,
- 2,
- 3,
- 4,
- 5
- );
- }
-
- test_macro();
-
- let function = unsafe { Box::from_raw(LAST_LOGGED_FUNCTION) };
- assert_eq!("next_test_macro", *function);
-
- let message = unsafe { Box::from_raw(LAST_LOGGED_MESSAGE) };
- assert_eq!("test log message 1 2 3 4 5", *message);
- }
-
- // test how a long log message will be formatted
- {
- fn test_macro() {
- tor_log_msg!(
- LogSeverity::Warn,
- LogDomain::Net,
- "test_macro",
- "{}",
- "All the world's a stage, and all the men and women \
- merely players: they have their exits and their \
- entrances; and one man in his time plays many parts, his \
- acts being seven ages."
- );
- }
-
- test_macro();
-
- let expected_string = "All the world's a \
- stage, and all the men \
- and women merely players: \
- they have their exits and \
- their entrances; and one man \
- in his time plays many parts, \
- his acts being seven ages.";
-
- let function = unsafe { Box::from_raw(LAST_LOGGED_FUNCTION) };
- assert_eq!("test_macro", *function);
-
- let message = unsafe { Box::from_raw(LAST_LOGGED_MESSAGE) };
- assert_eq!(expected_string, *message);
- }
- }
-}
diff --git a/src/rust/tor_rust/Cargo.toml b/src/rust/tor_rust/Cargo.toml
deleted file mode 100644
index 35c629882e..0000000000
--- a/src/rust/tor_rust/Cargo.toml
+++ /dev/null
@@ -1,22 +0,0 @@
-[package]
-authors = ["The Tor Project"]
-name = "tor_rust"
-version = "0.1.0"
-
-[lib]
-name = "tor_rust"
-path = "lib.rs"
-crate_type = ["staticlib"]
-
-[dependencies.tor_util]
-path = "../tor_util"
-
-[dependencies.protover]
-path = "../protover"
-
-[features]
-# We have to define a feature here because doctests don't get cfg(test),
-# and we need to disable some C dependencies when running the doctests
-# because of the various linker issues. See
-# https://github.com/rust-lang/rust/issues/45599
-test_linking_hack = []
diff --git a/src/rust/tor_rust/include.am b/src/rust/tor_rust/include.am
deleted file mode 100644
index ce673abbee..0000000000
--- a/src/rust/tor_rust/include.am
+++ /dev/null
@@ -1,28 +0,0 @@
-EXTRA_DIST +=\
- src/rust/tor_rust/Cargo.toml \
- src/rust/tor_rust/lib.rs
-
-EXTRA_CARGO_OPTIONS=
-
-@TOR_RUST_LIB_PATH@: FORCE
- ( cd "$(abs_top_builddir)/src/rust" ; \
- CARGO_TARGET_DIR="$(abs_top_builddir)/src/rust/target" \
- $(CARGO) build --release $(EXTRA_CARGO_OPTIONS) \
- $(CARGO_ONLINE) \
- --manifest-path "$(abs_top_srcdir)/src/rust/tor_rust/Cargo.toml" )
-
-distclean-rust:
- ( cd "$(abs_top_builddir)/src/rust" ; \
- CARGO_TARGET_DIR="$(abs_top_builddir)/src/rust/target" \
- $(CARGO) clean $(EXTRA_CARGO_OPTIONS) \
- $(CARGO_ONLINE) \
- --manifest-path "$(abs_top_srcdir)/src/rust/tor_rust/Cargo.toml" )
- rm -rf "$(abs_top_builddir)/src/rust/registry"
-
-if USE_RUST
-build-rust: @TOR_RUST_LIB_PATH@
-else
-build-rust:
-endif
-
-FORCE:
diff --git a/src/rust/tor_rust/lib.rs b/src/rust/tor_rust/lib.rs
deleted file mode 100644
index 18519f8497..0000000000
--- a/src/rust/tor_rust/lib.rs
+++ /dev/null
@@ -1,5 +0,0 @@
-extern crate protover;
-extern crate tor_util;
-
-pub use protover::*;
-pub use tor_util::*;
diff --git a/src/rust/tor_util/Cargo.toml b/src/rust/tor_util/Cargo.toml
deleted file mode 100644
index 9ffaeda8a6..0000000000
--- a/src/rust/tor_util/Cargo.toml
+++ /dev/null
@@ -1,24 +0,0 @@
-[package]
-authors = ["The Tor Project"]
-name = "tor_util"
-version = "0.0.1"
-
-[lib]
-name = "tor_util"
-path = "lib.rs"
-
-[dependencies.tor_allocate]
-path = "../tor_allocate"
-
-[dependencies.tor_log]
-path = "../tor_log"
-
-[dependencies]
-libc = "=0.2.39"
-
-[features]
-# We have to define a feature here because doctests don't get cfg(test),
-# and we need to disable some C dependencies when running the doctests
-# because of the various linker issues. See
-# https://github.com/rust-lang/rust/issues/45599
-test_linking_hack = []
diff --git a/src/rust/tor_util/ffi.rs b/src/rust/tor_util/ffi.rs
deleted file mode 100644
index b71b2bd093..0000000000
--- a/src/rust/tor_util/ffi.rs
+++ /dev/null
@@ -1,27 +0,0 @@
-// Copyright (c) 2016-2019, The Tor Project, Inc. */
-// See LICENSE for licensing information */
-
-//! FFI functions to announce Rust support during tor startup, only to be
-//! called from C.
-//!
-
-use tor_log::{LogDomain, LogSeverity};
-
-/// Returns a short string to announce Rust support during startup.
-///
-/// # Examples
-/// ```c
-/// char *rust_str = rust_welcome_string();
-/// printf("%s", rust_str);
-/// tor_free(rust_str);
-/// ```
-#[no_mangle]
-pub extern "C" fn rust_log_welcome_string() {
- tor_log_msg!(
- LogSeverity::Notice,
- LogDomain::General,
- "rust_log_welcome_string",
- "Tor is running with Rust integration. Please report \
- any bugs you encounter."
- );
-}
diff --git a/src/rust/tor_util/lib.rs b/src/rust/tor_util/lib.rs
deleted file mode 100644
index 8886767ede..0000000000
--- a/src/rust/tor_util/lib.rs
+++ /dev/null
@@ -1,14 +0,0 @@
-// Copyright (c) 2016-2019, The Tor Project, Inc. */
-// See LICENSE for licensing information */
-
-//! Small module to announce Rust support during startup for demonstration
-//! purposes.
-
-extern crate libc;
-extern crate tor_allocate;
-
-#[macro_use]
-extern crate tor_log;
-
-pub mod ffi;
-pub mod strings;
diff --git a/src/rust/tor_util/strings.rs b/src/rust/tor_util/strings.rs
deleted file mode 100644
index ede42c6ea8..0000000000
--- a/src/rust/tor_util/strings.rs
+++ /dev/null
@@ -1,136 +0,0 @@
-// Copyright (c) 2016-2019, The Tor Project, Inc. */
-// See LICENSE for licensing information */
-
-//! Utilities for working with static strings.
-
-/// Create a `CStr` from a literal byte slice, appending a NUL byte to it first.
-///
-/// # Warning
-///
-/// The literal byte slice which is taken as an argument *MUST NOT* have any NUL
-/// bytes (`b"\0"`) in it, anywhere, or else an empty string will be returned
-/// (`CStr::from_bytes_with_nul_unchecked(b"\0")`) so as to avoid `panic!()`ing.
-///
-/// # Examples
-///
-/// ```
-/// #[macro_use]
-/// extern crate tor_util;
-///
-/// use std::ffi::CStr;
-///
-/// # fn do_test() -> Result<&'static CStr, &'static str> {
-/// let message: &'static str = "This is a test of the tsunami warning system.";
-/// let tuesday: &'static CStr;
-/// let original: &str;
-///
-/// tuesday = cstr!("This is a test of the tsunami warning system.");
-/// original = tuesday.to_str().or(Err("Couldn't unwrap CStr!"))?;
-///
-/// assert!(original == message);
-/// #
-/// # Ok(tuesday)
-/// # }
-/// # fn main() {
-/// # do_test(); // so that we can use the ? operator in the test
-/// # }
-/// ```
-/// It is also possible to pass several string literals to this macro. They
-/// will be concatenated together in the order of the arguments, unmodified,
-/// before finally being suffixed with a NUL byte:
-///
-/// ```
-/// #[macro_use]
-/// extern crate tor_util;
-/// #
-/// # use std::ffi::CStr;
-/// #
-/// # fn do_test() -> Result<&'static CStr, &'static str> {
-///
-/// let quux: &'static CStr = cstr!("foo", "bar", "baz");
-/// let orig: &'static str = quux.to_str().or(Err("Couldn't unwrap CStr!"))?;
-///
-/// assert!(orig == "foobarbaz");
-/// # Ok(quux)
-/// # }
-/// # fn main() {
-/// # do_test(); // so that we can use the ? operator in the test
-/// # }
-/// ```
-/// This is useful for passing static strings to C from Rust FFI code. To do so
-/// so, use the `.as_ptr()` method on the resulting `&'static CStr` to convert
-/// it to the Rust equivalent of a C `const char*`:
-///
-/// ```
-/// #[macro_use]
-/// extern crate tor_util;
-///
-/// use std::ffi::CStr;
-/// use std::os::raw::c_char;
-///
-/// pub extern "C" fn give_static_borrowed_string_to_c() -> *const c_char {
-/// let hello: &'static CStr = cstr!("Hello, language my parents wrote.");
-///
-/// hello.as_ptr()
-/// }
-/// # fn main() {
-/// # let greetings = give_static_borrowed_string_to_c();
-/// # }
-/// ```
-/// Note that the C code this static borrowed string is passed to *MUST NOT*
-/// attempt to free the memory for the string.
-///
-/// # Note
-///
-/// An unfortunate limitation of the rustc compiler (as of 1.25.0-nightly), is
-/// that the first example above compiles, but if we were to change the
-/// assignment of `tuesday` as follows, it will fail to compile, because Rust
-/// macros are expanded at parse time, and at parse time there is no symbol
-/// table available.
-///
-/// ```ignore
-/// tuesday = cstr!(message);
-/// ```
-/// with the error message `error: expected a literal`.
-///
-/// # Returns
-///
-/// If the string literals passed as arguments contain no NUL bytes anywhere,
-/// then an `&'static CStr` containing the (concatenated) bytes of the string
-/// literal(s) passed as arguments, with a NUL byte appended, is returned.
-/// Otherwise, an `&'static CStr` containing a single NUL byte is returned (an
-/// "empty" string in C).
-#[macro_export]
-macro_rules! cstr {
- ($($bytes:expr),*) => (
- ::std::ffi::CStr::from_bytes_with_nul(
- concat!($($bytes),*, "\0").as_bytes()
- ).unwrap_or_default()
- )
-}
-
-#[cfg(test)]
-mod test {
- use std::ffi::CStr;
-
- #[test]
- fn cstr_macro() {
- let _: &'static CStr = cstr!("boo");
- }
-
- #[test]
- fn cstr_macro_multi_input() {
- let quux: &'static CStr = cstr!("foo", "bar", "baz");
-
- assert!(quux.to_str().unwrap() == "foobarbaz");
- }
-
- #[test]
- fn cstr_macro_bad_input() {
- let waving: &'static CStr = cstr!("waving not drowning o/");
- let drowning: &'static CStr = cstr!("\0 drowning not waving");
-
- assert!(waving.to_str().unwrap() == "waving not drowning o/");
- assert!(drowning.to_str().unwrap() == "")
- }
-}
diff --git a/src/test/bench.c b/src/test/bench.c
index 7a8c04e802..a76ea67eb8 100644
--- a/src/test/bench.c
+++ b/src/test/bench.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/test/ed25519_exts_ref.py b/src/test/ed25519_exts_ref.py
index dcc0a7c25a..abc9a1de7f 100644
--- a/src/test/ed25519_exts_ref.py
+++ b/src/test/ed25519_exts_ref.py
@@ -42,7 +42,7 @@ def blindESK(esk, param):
s_prime = (s * mult) % ell
k = esk[32:]
assert(len(k) == 32)
- k_prime = H("Derive temporary signing key hash input" + k)[:32]
+ k_prime = H(b"Derive temporary signing key hash input" + k)[:32]
return encodeint(s_prime) + k_prime
def blindPK(pk, param):
@@ -170,6 +170,8 @@ RAND_INPUTS = [
'5c8eac469bb3f1b85bc7cd893f52dc42a9ab66f1b02b5ce6a68e9b175d3bb433',
'eda433d483059b6d1ff8b7cfbd0fe406bfb23722c8f3c8252629284573b61b86',
'4377c40431c30883c5fbd9bc92ae48d1ed8a47b81d13806beac5351739b5533d',
+ 'c6bbcce615839756aed2cc78b1de13884dd3618f48367a17597a16c1cd7a290b',
+ 'c6bbcce615839756aed2cc78b1de13884dd3618f48367a17597a16c1cd7a290b',
'c6bbcce615839756aed2cc78b1de13884dd3618f48367a17597a16c1cd7a290b']
# From pprint.pprint([ binascii.b2a_hex(os.urandom(32)) for _ in xrange(8) ])
@@ -181,7 +183,9 @@ BLINDING_PARAMS = [
'b1fe79d1dec9bc108df69f6612c72812755751f21ecc5af99663b30be8b9081f',
'81f1512b63ab5fb5c1711a4ec83d379c420574aedffa8c3368e1c3989a3a0084',
'97f45142597c473a4b0e9a12d64561133ad9e1155fe5a9807fe6af8a93557818',
- '3f44f6a5a92cde816635dfc12ade70539871078d2ff097278be2a555c9859cd0']
+ '3f44f6a5a92cde816635dfc12ade70539871078d2ff097278be2a555c9859cd0',
+ '0000000000000000000000000000000000000000000000000000000000000000',
+ '1111111111111111111111111111111111111111111111111111111111111111']
PREFIX = "ED25519_"
@@ -193,9 +197,9 @@ def writeArray(name, array):
if len(h) > 70:
h1 = h[:70]
h2 = h[70:]
- print(' "{0}"\n "{1}",'.format(h1,h2))
+ print(' "{0}"\n "{1}",'.format(h1.decode('utf-8'),h2.decode('utf-8')))
else:
- print(' "{0}",'.format(h))
+ print(' "{0}",'.format(h.decode('utf-8')))
print("};\n")
def comment(text, initial="/**"):
diff --git a/src/test/ed25519_vectors.inc b/src/test/ed25519_vectors.inc
index 60c863beba..3813282e00 100644
--- a/src/test/ed25519_vectors.inc
+++ b/src/test/ed25519_vectors.inc
@@ -16,6 +16,8 @@ static const char *ED25519_SECRET_KEYS[] = {
"eda433d483059b6d1ff8b7cfbd0fe406bfb23722c8f3c8252629284573b61b86",
"4377c40431c30883c5fbd9bc92ae48d1ed8a47b81d13806beac5351739b5533d",
"c6bbcce615839756aed2cc78b1de13884dd3618f48367a17597a16c1cd7a290b",
+ "c6bbcce615839756aed2cc78b1de13884dd3618f48367a17597a16c1cd7a290b",
+ "c6bbcce615839756aed2cc78b1de13884dd3618f48367a17597a16c1cd7a290b",
};
/**
@@ -39,6 +41,10 @@ static const char *ED25519_EXPANDED_SECRET_KEYS[] = {
"e5fd7ac43794394507ad440ecfdf59c4c255f19b768a273109e06d7d8e",
"b003077c1e52a62308eef7950b2d532e1d4a7eea50ad22d8ac11b892851f1c40ffb9c9"
"ff8dcd0c6c233f665a2e176324d92416bfcfcd1f787424c0c667452d86",
+ "b003077c1e52a62308eef7950b2d532e1d4a7eea50ad22d8ac11b892851f1c40ffb9c9"
+ "ff8dcd0c6c233f665a2e176324d92416bfcfcd1f787424c0c667452d86",
+ "b003077c1e52a62308eef7950b2d532e1d4a7eea50ad22d8ac11b892851f1c40ffb9c9"
+ "ff8dcd0c6c233f665a2e176324d92416bfcfcd1f787424c0c667452d86",
};
/**
@@ -53,6 +59,8 @@ static const char *ED25519_PUBLIC_KEYS[] = {
"d21c294db0e64cb2d8976625786ede1d9754186ae8197a64d72f68c792eecc19",
"c4d58b4cf85a348ff3d410dd936fa460c4f18da962c01b1963792b9dcc8a6ea6",
"95126f14d86494020665face03f2d42ee2b312a85bc729903eb17522954a1c4a",
+ "95126f14d86494020665face03f2d42ee2b312a85bc729903eb17522954a1c4a",
+ "95126f14d86494020665face03f2d42ee2b312a85bc729903eb17522954a1c4a",
};
/**
@@ -69,6 +77,8 @@ static const char *ED25519_CURVE25519_PUBLIC_KEYS[] = {
"59e20dcb691c4a345fe86c8a79ac817e5b514d84bbf0512a842a08e43f7f087e",
"9e43b820b320eda35f66f122c155b2bf8e2192c468617b7115bf067d19e08369",
"861f33296cb57f8f01e4a5e8a7e5d5d7043a6247586ab36dea8a1a3c4403ee30",
+ "861f33296cb57f8f01e4a5e8a7e5d5d7043a6247586ab36dea8a1a3c4403ee30",
+ "861f33296cb57f8f01e4a5e8a7e5d5d7043a6247586ab36dea8a1a3c4403ee30",
};
/**
@@ -83,6 +93,8 @@ static const char *ED25519_BLINDING_PARAMS[] = {
"81f1512b63ab5fb5c1711a4ec83d379c420574aedffa8c3368e1c3989a3a0084",
"97f45142597c473a4b0e9a12d64561133ad9e1155fe5a9807fe6af8a93557818",
"3f44f6a5a92cde816635dfc12ade70539871078d2ff097278be2a555c9859cd0",
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "1111111111111111111111111111111111111111111111111111111111111111",
};
/**
@@ -107,6 +119,10 @@ static const char *ED25519_BLINDED_SECRET_KEYS[] = {
"8f8e556d78f4bdcb9a13b6f6066fe81d3134ae965dc48cd0785b3af2b8",
"288cbfd923cb286d48c084555b5bdd06c05e92fb81acdb45271367f57515380e053d9c"
"00c81e1331c06ab50087be8cfc7dc11691b132614474f1aa9c2503cccd",
+ "e5cd03eb4cc456e11bc36724b558873df0045729b22d8b748360067a7770ac02053d9c"
+ "00c81e1331c06ab50087be8cfc7dc11691b132614474f1aa9c2503cccd",
+ "2cf7ed8b163f5af960d2fc62e1883aa422a6090736b4f18a5456ddcaf78ede0c053d9c"
+ "00c81e1331c06ab50087be8cfc7dc11691b132614474f1aa9c2503cccd",
};
/**
@@ -123,6 +139,8 @@ static const char *ED25519_BLINDED_PUBLIC_KEYS[] = {
"2b946a484344eb1c17c89dd8b04196a84f3b7222c876a07a4cece85f676f87d9",
"c6b585129b135f8769df2eba987e76e089e80ba3a2a6729134d3b28008ac098e",
"0eefdc795b59cabbc194c6174e34ba9451e8355108520554ec285acabebb34ac",
+ "312404d06a0a9de489904b18d5233e83a50b225977fa8734f2c897a73c067952",
+ "952a908a4a9e0e5176a2549f8f328955aca6817a9fdc59e3acec5dec50838108",
};
/**
@@ -146,5 +164,9 @@ static const char *ED25519_SELF_SIGNATURES[] = {
"4867daa60f2a82d09ba9652d41e8dde292b624afc8d2c26441b95e3c0e",
"815213640a643d198bd056e02bba74e1c8d2d931643e84497adf3347eb485079c9afe0"
"afce9284cdc084946b561abbb214f1304ca11228ff82702185cf28f60d",
+ "815213640a643d198bd056e02bba74e1c8d2d931643e84497adf3347eb485079c9afe0"
+ "afce9284cdc084946b561abbb214f1304ca11228ff82702185cf28f60d",
+ "815213640a643d198bd056e02bba74e1c8d2d931643e84497adf3347eb485079c9afe0"
+ "afce9284cdc084946b561abbb214f1304ca11228ff82702185cf28f60d",
};
diff --git a/src/test/fakechans.h b/src/test/fakechans.h
index c3accb1637..e84e0233f6 100644
--- a/src/test/fakechans.h
+++ b/src/test/fakechans.h
@@ -1,4 +1,4 @@
- /* Copyright (c) 2014-2020, The Tor Project, Inc. */
+ /* Copyright (c) 2014-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#ifndef TOR_FAKECHANS_H
diff --git a/src/test/fakecircs.c b/src/test/fakecircs.c
index 4d5b97197e..cca3b43483 100644
--- a/src/test/fakecircs.c
+++ b/src/test/fakecircs.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2019-2020, The Tor Project, Inc. */
+/* Copyright (c) 2019-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/test/fakecircs.h b/src/test/fakecircs.h
index ed8a150a3f..61359e9bab 100644
--- a/src/test/fakecircs.h
+++ b/src/test/fakecircs.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2019-2020, The Tor Project, Inc. */
+/* Copyright (c) 2019-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/test/fuzz/fuzz_address.c b/src/test/fuzz/fuzz_address.c
new file mode 100644
index 0000000000..6dccd65e9d
--- /dev/null
+++ b/src/test/fuzz/fuzz_address.c
@@ -0,0 +1,26 @@
+#include "lib/net/address.h"
+#include "lib/malloc/malloc.h"
+
+#include "test/fuzz/fuzzing.h"
+
+int
+fuzz_init(void)
+{
+ return 0;
+}
+
+int
+fuzz_cleanup(void)
+{
+ return 0;
+}
+
+int
+fuzz_main(const uint8_t *data, size_t sz)
+{
+ tor_addr_t addr;
+ char *fuzzing_data = tor_memdup_nulterm(data, sz);
+ tor_addr_parse(&addr, fuzzing_data);
+ tor_free(fuzzing_data);
+ return 0;
+}
diff --git a/src/test/fuzz/fuzz_addressPTR.c b/src/test/fuzz/fuzz_addressPTR.c
new file mode 100644
index 0000000000..b503d53666
--- /dev/null
+++ b/src/test/fuzz/fuzz_addressPTR.c
@@ -0,0 +1,32 @@
+#include "lib/net/address.h"
+#include "lib/net/socket.h"
+#include "lib/cc/ctassert.h"
+#include "lib/container/smartlist.h"
+#include "lib/ctime/di_ops.h"
+#include "lib/log/log.h"
+#include "lib/log/escape.h"
+#include "lib/malloc/malloc.h"
+#include "lib/net/address.h"
+#include "test/fuzz/fuzzing.h"
+
+int
+fuzz_init(void)
+{
+ return 0;
+}
+
+int
+fuzz_cleanup(void)
+{
+ return 0;
+}
+
+int
+fuzz_main(const uint8_t *data, size_t sz)
+{
+ tor_addr_t addr_result;
+ char *fuzzing_data = tor_memdup_nulterm(data, sz);
+ tor_addr_parse_PTR_name(&addr_result, fuzzing_data, AF_UNSPEC, 1);
+ tor_free(fuzzing_data);
+ return 0;
+}
diff --git a/src/test/fuzz/fuzz_consensus.c b/src/test/fuzz/fuzz_consensus.c
index f2bf29ea78..bf5a2b69e3 100644
--- a/src/test/fuzz/fuzz_consensus.c
+++ b/src/test/fuzz/fuzz_consensus.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2020, The Tor Project, Inc. */
+/* Copyright (c) 2016-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define SIGCOMMON_PRIVATE
#include "core/or/or.h"
diff --git a/src/test/fuzz/fuzz_descriptor.c b/src/test/fuzz/fuzz_descriptor.c
index eb4d4d507f..db1e921995 100644
--- a/src/test/fuzz/fuzz_descriptor.c
+++ b/src/test/fuzz/fuzz_descriptor.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2020, The Tor Project, Inc. */
+/* Copyright (c) 2016-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define SIGCOMMON_PRIVATE
#include "core/or/or.h"
diff --git a/src/test/fuzz/fuzz_diff.c b/src/test/fuzz/fuzz_diff.c
index 9cd2116245..9b9b1c706f 100644
--- a/src/test/fuzz/fuzz_diff.c
+++ b/src/test/fuzz/fuzz_diff.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2020, The Tor Project, Inc. */
+/* Copyright (c) 2016-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define CONSDIFF_PRIVATE
diff --git a/src/test/fuzz/fuzz_diff_apply.c b/src/test/fuzz/fuzz_diff_apply.c
index a819c73338..f145bd2625 100644
--- a/src/test/fuzz/fuzz_diff_apply.c
+++ b/src/test/fuzz/fuzz_diff_apply.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2020, The Tor Project, Inc. */
+/* Copyright (c) 2016-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define CONSDIFF_PRIVATE
diff --git a/src/test/fuzz/fuzz_extrainfo.c b/src/test/fuzz/fuzz_extrainfo.c
index ad21254e3e..0cdc3d7ebf 100644
--- a/src/test/fuzz/fuzz_extrainfo.c
+++ b/src/test/fuzz/fuzz_extrainfo.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2020, The Tor Project, Inc. */
+/* Copyright (c) 2016-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define SIGCOMMON_PRIVATE
#include "core/or/or.h"
diff --git a/src/test/fuzz/fuzz_hsdescv2.c b/src/test/fuzz/fuzz_hsdescv2.c
deleted file mode 100644
index 81d9e5f00e..0000000000
--- a/src/test/fuzz/fuzz_hsdescv2.c
+++ /dev/null
@@ -1,52 +0,0 @@
-/* Copyright (c) 2016-2020, The Tor Project, Inc. */
-/* See LICENSE for licensing information */
-#include "core/or/or.h"
-#include "feature/dirparse/unparseable.h"
-#include "feature/rend/rendcommon.h"
-#include "feature/rend/rendparse.h"
-#include "lib/crypt_ops/crypto_ed25519.h"
-#include "test/fuzz/fuzzing.h"
-
-static void
-mock_dump_desc__nodump(const char *desc, const char *type)
-{
- (void)desc;
- (void)type;
-}
-
-int
-fuzz_init(void)
-{
- disable_signature_checking();
- MOCK(dump_desc, mock_dump_desc__nodump);
- ed25519_init();
- return 0;
-}
-
-int
-fuzz_cleanup(void)
-{
- return 0;
-}
-
-int
-fuzz_main(const uint8_t *data, size_t sz)
-{
- rend_service_descriptor_t *desc = NULL;
- char desc_id[64];
- char *ipts = NULL;
- size_t ipts_size, esize;
- const char *next;
- char *str = tor_memdup_nulterm(data, sz);
- (void) rend_parse_v2_service_descriptor(&desc, desc_id, &ipts, &ipts_size,
- &esize, &next, str, 1);
- if (desc) {
- log_debug(LD_GENERAL, "Parsing okay");
- rend_service_descriptor_free(desc);
- } else {
- log_debug(LD_GENERAL, "Parsing failed");
- }
- tor_free(ipts);
- tor_free(str);
- return 0;
-}
diff --git a/src/test/fuzz/fuzz_hsdescv3.c b/src/test/fuzz/fuzz_hsdescv3.c
index 8d7eab1a8d..73e509469a 100644
--- a/src/test/fuzz/fuzz_hsdescv3.c
+++ b/src/test/fuzz/fuzz_hsdescv3.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017-2020, The Tor Project, Inc. */
+/* Copyright (c) 2017-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define HS_DESCRIPTOR_PRIVATE
diff --git a/src/test/fuzz/fuzz_hsdescv3_inner.c b/src/test/fuzz/fuzz_hsdescv3_inner.c
new file mode 100644
index 0000000000..5aa719f5c3
--- /dev/null
+++ b/src/test/fuzz/fuzz_hsdescv3_inner.c
@@ -0,0 +1,119 @@
+/* Copyright (c) 2017-2021, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#define HS_DESCRIPTOR_PRIVATE
+
+#include "core/or/or.h"
+#include "trunnel/ed25519_cert.h" /* Trunnel interface. */
+#include "lib/crypt_ops/crypto_ed25519.h"
+#include "feature/hs/hs_descriptor.h"
+#include "feature/dirparse/unparseable.h"
+
+#include "test/fuzz/fuzzing.h"
+
+static void
+mock_dump_desc__nodump(const char *desc, const char *type)
+{
+ (void)desc;
+ (void)type;
+}
+
+static int
+mock_rsa_ed25519_crosscert_check(const uint8_t *crosscert,
+ const size_t crosscert_len,
+ const crypto_pk_t *rsa_id_key,
+ const ed25519_public_key_t *master_key,
+ const time_t reject_if_expired_before)
+{
+ (void) crosscert;
+ (void) crosscert_len;
+ (void) rsa_id_key;
+ (void) master_key;
+ (void) reject_if_expired_before;
+ return 0;
+}
+
+static size_t
+mock_decrypt_desc_layer(const hs_descriptor_t *desc,
+ const uint8_t *descriptor_cookie,
+ bool is_superencrypted_layer,
+ char **decrypted_out)
+{
+ (void)is_superencrypted_layer;
+ (void)desc;
+ (void)descriptor_cookie;
+ const size_t overhead = HS_DESC_ENCRYPTED_SALT_LEN + DIGEST256_LEN;
+ const uint8_t *encrypted_blob = (is_superencrypted_layer)
+ ? desc->plaintext_data.superencrypted_blob
+ : desc->superencrypted_data.encrypted_blob;
+ size_t encrypted_blob_size = (is_superencrypted_layer)
+ ? desc->plaintext_data.superencrypted_blob_size
+ : desc->superencrypted_data.encrypted_blob_size;
+
+ if (encrypted_blob_size < overhead)
+ return 0;
+ *decrypted_out = tor_memdup_nulterm(
+ encrypted_blob + HS_DESC_ENCRYPTED_SALT_LEN,
+ encrypted_blob_size - overhead);
+ size_t result = strlen(*decrypted_out);
+ if (result) {
+ return result;
+ } else {
+ tor_free(*decrypted_out);
+ return 0;
+ }
+}
+
+static const uint8_t *decrypted_data = NULL;
+static size_t decrypted_len = 0;
+static size_t
+mock_desc_decrypt_encrypted(const hs_descriptor_t *desc,
+ const curve25519_secret_key_t *client_auth_sk,
+ char **decrypted_out)
+{
+ (void)desc;
+ (void)client_auth_sk;
+ *decrypted_out = (char*)tor_memdup_nulterm(decrypted_data, decrypted_len);
+ return decrypted_len;
+}
+
+int
+fuzz_init(void)
+{
+ disable_signature_checking();
+ MOCK(dump_desc, mock_dump_desc__nodump);
+ MOCK(rsa_ed25519_crosscert_check, mock_rsa_ed25519_crosscert_check);
+ MOCK(decrypt_desc_layer, mock_decrypt_desc_layer);
+ MOCK(desc_decrypt_encrypted, mock_desc_decrypt_encrypted);
+ ed25519_init();
+ return 0;
+}
+
+int
+fuzz_cleanup(void)
+{
+ return 0;
+}
+
+int
+fuzz_main(const uint8_t *data, size_t sz)
+{
+ decrypted_data = data;
+ decrypted_len = sz;
+
+ hs_descriptor_t *desc = tor_malloc_zero(sizeof(hs_descriptor_t));
+ hs_desc_encrypted_data_t *output = tor_malloc_zero(sizeof(*output));
+ curve25519_secret_key_t *client_auth_sk = NULL;
+ hs_desc_decode_status_t status;
+
+ status = desc_decode_encrypted_v3(desc, client_auth_sk, output);
+ if (status == HS_DESC_DECODE_OK) {
+ log_debug(LD_GENERAL, "Decoding okay");
+ } else {
+ log_debug(LD_GENERAL, "Decoding failed");
+ }
+
+ hs_descriptor_free(desc);
+ hs_desc_encrypted_data_free(output);
+ return 0;
+}
diff --git a/src/test/fuzz/fuzz_hsdescv3_middle.c b/src/test/fuzz/fuzz_hsdescv3_middle.c
new file mode 100644
index 0000000000..66a9d52cf3
--- /dev/null
+++ b/src/test/fuzz/fuzz_hsdescv3_middle.c
@@ -0,0 +1,116 @@
+/* Copyright (c) 2017-2021, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#define HS_DESCRIPTOR_PRIVATE
+
+#include "core/or/or.h"
+#include "trunnel/ed25519_cert.h" /* Trunnel interface. */
+#include "lib/crypt_ops/crypto_ed25519.h"
+#include "feature/hs/hs_descriptor.h"
+#include "feature/dirparse/unparseable.h"
+
+#include "test/fuzz/fuzzing.h"
+
+static void
+mock_dump_desc__nodump(const char *desc, const char *type)
+{
+ (void)desc;
+ (void)type;
+}
+
+static int
+mock_rsa_ed25519_crosscert_check(const uint8_t *crosscert,
+ const size_t crosscert_len,
+ const crypto_pk_t *rsa_id_key,
+ const ed25519_public_key_t *master_key,
+ const time_t reject_if_expired_before)
+{
+ (void) crosscert;
+ (void) crosscert_len;
+ (void) rsa_id_key;
+ (void) master_key;
+ (void) reject_if_expired_before;
+ return 0;
+}
+
+static size_t
+mock_decrypt_desc_layer(const hs_descriptor_t *desc,
+ const uint8_t *descriptor_cookie,
+ bool is_superencrypted_layer,
+ char **decrypted_out)
+{
+ (void)is_superencrypted_layer;
+ (void)desc;
+ (void)descriptor_cookie;
+ const size_t overhead = HS_DESC_ENCRYPTED_SALT_LEN + DIGEST256_LEN;
+ const uint8_t *encrypted_blob = (is_superencrypted_layer)
+ ? desc->plaintext_data.superencrypted_blob
+ : desc->superencrypted_data.encrypted_blob;
+ size_t encrypted_blob_size = (is_superencrypted_layer)
+ ? desc->plaintext_data.superencrypted_blob_size
+ : desc->superencrypted_data.encrypted_blob_size;
+
+ if (encrypted_blob_size < overhead)
+ return 0;
+ *decrypted_out = tor_memdup_nulterm(
+ encrypted_blob + HS_DESC_ENCRYPTED_SALT_LEN,
+ encrypted_blob_size - overhead);
+ size_t result = strlen(*decrypted_out);
+ if (result) {
+ return result;
+ } else {
+ tor_free(*decrypted_out);
+ return 0;
+ }
+}
+
+static const uint8_t *decrypted_data = NULL;
+static size_t decrypted_len = 0;
+static size_t
+mock_desc_decrypt_superencrypted(const hs_descriptor_t *desc,
+ char **decrypted_out)
+{
+ (void)desc;
+ *decrypted_out = (char*)tor_memdup_nulterm(decrypted_data, decrypted_len);
+ return decrypted_len;
+}
+
+int
+fuzz_init(void)
+{
+ disable_signature_checking();
+ MOCK(dump_desc, mock_dump_desc__nodump);
+ MOCK(rsa_ed25519_crosscert_check, mock_rsa_ed25519_crosscert_check);
+ MOCK(decrypt_desc_layer, mock_decrypt_desc_layer);
+ MOCK(desc_decrypt_superencrypted, mock_desc_decrypt_superencrypted);
+ ed25519_init();
+ return 0;
+}
+
+int
+fuzz_cleanup(void)
+{
+ return 0;
+}
+
+int
+fuzz_main(const uint8_t *data, size_t sz)
+{
+ decrypted_data = data;
+ decrypted_len = sz;
+
+ hs_descriptor_t *desc = tor_malloc_zero(sizeof(hs_descriptor_t));
+ hs_desc_superencrypted_data_t *output = tor_malloc_zero(sizeof(*output));
+ hs_desc_decode_status_t status;
+
+ status = desc_decode_superencrypted_v3(desc, output);
+ if (status == HS_DESC_DECODE_OK) {
+ log_debug(LD_GENERAL, "Decoding okay");
+ } else {
+ log_debug(LD_GENERAL, "Decoding failed");
+ }
+
+ hs_descriptor_free(desc);
+ hs_desc_superencrypted_data_free(output);
+ return 0;
+}
diff --git a/src/test/fuzz/fuzz_http.c b/src/test/fuzz/fuzz_http.c
index a4fd182f1e..cf5e995ef3 100644
--- a/src/test/fuzz/fuzz_http.c
+++ b/src/test/fuzz/fuzz_http.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2020, The Tor Project, Inc. */
+/* Copyright (c) 2016-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
diff --git a/src/test/fuzz/fuzz_http_connect.c b/src/test/fuzz/fuzz_http_connect.c
index 9e5a48ba4d..c71ccb5c1e 100644
--- a/src/test/fuzz/fuzz_http_connect.c
+++ b/src/test/fuzz/fuzz_http_connect.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2020, The Tor Project, Inc. */
+/* Copyright (c) 2016-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
diff --git a/src/test/fuzz/fuzz_iptsv2.c b/src/test/fuzz/fuzz_iptsv2.c
index bc51ffcdb8..259be437f0 100644
--- a/src/test/fuzz/fuzz_iptsv2.c
+++ b/src/test/fuzz/fuzz_iptsv2.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2020, The Tor Project, Inc. */
+/* Copyright (c) 2016-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "core/or/or.h"
diff --git a/src/test/fuzz/fuzz_microdesc.c b/src/test/fuzz/fuzz_microdesc.c
index 3fc709183b..d77f137b2b 100644
--- a/src/test/fuzz/fuzz_microdesc.c
+++ b/src/test/fuzz/fuzz_microdesc.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2020, The Tor Project, Inc. */
+/* Copyright (c) 2016-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "core/or/or.h"
diff --git a/src/test/fuzz/fuzz_socks.c b/src/test/fuzz/fuzz_socks.c
index 4e7cb4d48d..eeb989994d 100644
--- a/src/test/fuzz/fuzz_socks.c
+++ b/src/test/fuzz/fuzz_socks.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2020, The Tor Project, Inc. */
+/* Copyright (c) 2016-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
diff --git a/src/test/fuzz/fuzz_strops.c b/src/test/fuzz/fuzz_strops.c
index 05d9101e72..02a74d1d8c 100644
--- a/src/test/fuzz/fuzz_strops.c
+++ b/src/test/fuzz/fuzz_strops.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2018-2020, The Tor Project, Inc. */
+/* Copyright (c) 2018-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/test/fuzz/fuzz_vrs.c b/src/test/fuzz/fuzz_vrs.c
index d6e88e59e7..e1bb28801a 100644
--- a/src/test/fuzz/fuzz_vrs.c
+++ b/src/test/fuzz/fuzz_vrs.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2020, The Tor Project, Inc. */
+/* Copyright (c) 2016-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define NS_PARSE_PRIVATE
#define NETWORKSTATUS_PRIVATE
diff --git a/src/test/fuzz/fuzzing.h b/src/test/fuzz/fuzzing.h
index 6cbcdc41ad..b9bec84ce4 100644
--- a/src/test/fuzz/fuzzing.h
+++ b/src/test/fuzz/fuzzing.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2020, The Tor Project, Inc. */
+/* Copyright (c) 2016-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#ifndef FUZZING_H
#define FUZZING_H
diff --git a/src/test/fuzz/fuzzing_common.c b/src/test/fuzz/fuzzing_common.c
index d9719074ad..d64d20e0ba 100644
--- a/src/test/fuzz/fuzzing_common.c
+++ b/src/test/fuzz/fuzzing_common.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2020, The Tor Project, Inc. */
+/* Copyright (c) 2016-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define CRYPTO_ED25519_PRIVATE
#define CONFIG_PRIVATE
diff --git a/src/test/fuzz/include.am b/src/test/fuzz/include.am
index ef952c3812..9fece7d004 100644
--- a/src/test/fuzz/include.am
+++ b/src/test/fuzz/include.am
@@ -8,7 +8,6 @@ FUZZING_LDFLAG = \
@TOR_LDFLAGS_zlib@ $(TOR_LDFLAGS_CRYPTLIB) @TOR_LDFLAGS_libevent@
FUZZING_LIBS = \
src/test/libtor-testing.a \
- $(rust_ldadd) \
@TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ \
@TOR_LIBEVENT_LIBS@ $(TOR_LIBS_CRYPTLIB) \
@TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_SHLWAPI@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@ @CURVE25519_LIBS@ \
@@ -23,17 +22,36 @@ oss-fuzz-prereqs: \
noinst_HEADERS += \
src/test/fuzz/fuzzing.h
-LIBFUZZER = -lFuzzer
LIBFUZZER_CPPFLAGS = $(FUZZING_CPPFLAGS) -DLLVM_FUZZ
LIBFUZZER_CFLAGS = $(FUZZING_CFLAGS)
-LIBFUZZER_LDFLAG = $(FUZZING_LDFLAG)
-LIBFUZZER_LIBS = $(FUZZING_LIBS) $(LIBFUZZER) -lstdc++
+LIBFUZZER_LDFLAG = $(FUZZING_LDFLAG) -fsanitize=fuzzer
+LIBFUZZER_LIBS = $(FUZZING_LIBS) -lstdc++
LIBOSS_FUZZ_CPPFLAGS = $(FUZZING_CPPFLAGS) -DLLVM_FUZZ
LIBOSS_FUZZ_CFLAGS = $(FUZZING_CFLAGS)
# ===== AFL fuzzers
if UNITTESTS_ENABLED
+src_test_fuzz_fuzz_address_SOURCES = \
+ src/test/fuzz/fuzzing_common.c \
+ src/test/fuzz/fuzz_address.c
+src_test_fuzz_fuzz_address_CPPFLAGS = $(FUZZING_CPPFLAGS)
+src_test_fuzz_fuzz_address_CFLAGS = $(FUZZING_CFLAGS)
+src_test_fuzz_fuzz_address_LDFLAGS = $(FUZZING_LDFLAG)
+src_test_fuzz_fuzz_address_LDADD = $(FUZZING_LIBS)
+endif
+
+if UNITTESTS_ENABLED
+src_test_fuzz_fuzz_addressPTR_SOURCES = \
+ src/test/fuzz/fuzzing_common.c \
+ src/test/fuzz/fuzz_addressPTR.c
+src_test_fuzz_fuzz_addressPTR_CPPFLAGS = $(FUZZING_CPPFLAGS)
+src_test_fuzz_fuzz_addressPTR_CFLAGS = $(FUZZING_CFLAGS)
+src_test_fuzz_fuzz_addressPTR_LDFLAGS = $(FUZZING_LDFLAG)
+src_test_fuzz_fuzz_addressPTR_LDADD = $(FUZZING_LIBS)
+endif
+
+if UNITTESTS_ENABLED
src_test_fuzz_fuzz_consensus_SOURCES = \
src/test/fuzz/fuzzing_common.c \
src/test/fuzz/fuzz_consensus.c
@@ -84,16 +102,6 @@ src_test_fuzz_fuzz_extrainfo_LDADD = $(FUZZING_LIBS)
endif
if UNITTESTS_ENABLED
-src_test_fuzz_fuzz_hsdescv2_SOURCES = \
- src/test/fuzz/fuzzing_common.c \
- src/test/fuzz/fuzz_hsdescv2.c
-src_test_fuzz_fuzz_hsdescv2_CPPFLAGS = $(FUZZING_CPPFLAGS)
-src_test_fuzz_fuzz_hsdescv2_CFLAGS = $(FUZZING_CFLAGS)
-src_test_fuzz_fuzz_hsdescv2_LDFLAGS = $(FUZZING_LDFLAG)
-src_test_fuzz_fuzz_hsdescv2_LDADD = $(FUZZING_LIBS)
-endif
-
-if UNITTESTS_ENABLED
src_test_fuzz_fuzz_hsdescv3_SOURCES = \
src/test/fuzz/fuzzing_common.c \
src/test/fuzz/fuzz_hsdescv3.c
@@ -104,6 +112,28 @@ src_test_fuzz_fuzz_hsdescv3_LDADD = $(FUZZING_LIBS)
endif
if UNITTESTS_ENABLED
+src_test_fuzz_fuzz_hsdescv3_inner_SOURCES = \
+ src/test/fuzz/fuzzing_common.c \
+ src/test/fuzz/fuzz_hsdescv3_inner.c
+src_test_fuzz_fuzz_hsdescv3_inner_CPPFLAGS = $(FUZZING_CPPFLAGS)
+src_test_fuzz_fuzz_hsdescv3_inner_CFLAGS = $(FUZZING_CFLAGS)
+src_test_fuzz_fuzz_hsdescv3_inner_LDFLAGS = $(FUZZING_LDFLAG)
+src_test_fuzz_fuzz_hsdescv3_inner_LDADD = $(FUZZING_LIBS)
+endif
+
+
+if UNITTESTS_ENABLED
+src_test_fuzz_fuzz_hsdescv3_middle_SOURCES = \
+ src/test/fuzz/fuzzing_common.c \
+ src/test/fuzz/fuzz_hsdescv3_middle.c
+src_test_fuzz_fuzz_hsdescv3_middle_CPPFLAGS = $(FUZZING_CPPFLAGS)
+src_test_fuzz_fuzz_hsdescv3_middle_CFLAGS = $(FUZZING_CFLAGS)
+src_test_fuzz_fuzz_hsdescv3_middle_LDFLAGS = $(FUZZING_LDFLAG)
+src_test_fuzz_fuzz_hsdescv3_middle_LDADD = $(FUZZING_LIBS)
+endif
+
+
+if UNITTESTS_ENABLED
src_test_fuzz_fuzz_http_SOURCES = \
src/test/fuzz/fuzzing_common.c \
src/test/fuzz/fuzz_http.c
@@ -124,16 +154,6 @@ src_test_fuzz_fuzz_http_connect_LDADD = $(FUZZING_LIBS)
endif
if UNITTESTS_ENABLED
-src_test_fuzz_fuzz_iptsv2_SOURCES = \
- src/test/fuzz/fuzzing_common.c \
- src/test/fuzz/fuzz_iptsv2.c
-src_test_fuzz_fuzz_iptsv2_CPPFLAGS = $(FUZZING_CPPFLAGS)
-src_test_fuzz_fuzz_iptsv2_CFLAGS = $(FUZZING_CFLAGS)
-src_test_fuzz_fuzz_iptsv2_LDFLAGS = $(FUZZING_LDFLAG)
-src_test_fuzz_fuzz_iptsv2_LDADD = $(FUZZING_LIBS)
-endif
-
-if UNITTESTS_ENABLED
src_test_fuzz_fuzz_microdesc_SOURCES = \
src/test/fuzz/fuzzing_common.c \
src/test/fuzz/fuzz_microdesc.c
@@ -175,16 +195,18 @@ endif
if UNITTESTS_ENABLED
FUZZERS = \
+ src/test/fuzz/fuzz-address \
+ src/test/fuzz/fuzz-addressPTR \
src/test/fuzz/fuzz-consensus \
src/test/fuzz/fuzz-descriptor \
src/test/fuzz/fuzz-diff \
src/test/fuzz/fuzz-diff-apply \
src/test/fuzz/fuzz-extrainfo \
- src/test/fuzz/fuzz-hsdescv2 \
src/test/fuzz/fuzz-hsdescv3 \
+ src/test/fuzz/fuzz-hsdescv3-inner \
+ src/test/fuzz/fuzz-hsdescv3-middle \
src/test/fuzz/fuzz-http \
src/test/fuzz/fuzz-http-connect \
- src/test/fuzz/fuzz-iptsv2 \
src/test/fuzz/fuzz-microdesc \
src/test/fuzz/fuzz-socks \
src/test/fuzz/fuzz-strops \
@@ -195,6 +217,24 @@ endif
if LIBFUZZER_ENABLED
if UNITTESTS_ENABLED
+src_test_fuzz_lf_fuzz_address_SOURCES = \
+ $(src_test_fuzz_fuzz_address_SOURCES)
+src_test_fuzz_lf_fuzz_address_CPPFLAGS = $(LIBFUZZER_CPPFLAGS)
+src_test_fuzz_lf_fuzz_address_CFLAGS = $(LIBFUZZER_CFLAGS)
+src_test_fuzz_lf_fuzz_address_LDFLAGS = $(LIBFUZZER_LDFLAG)
+src_test_fuzz_lf_fuzz_address_LDADD = $(LIBFUZZER_LIBS)
+endif
+
+if UNITTESTS_ENABLED
+src_test_fuzz_lf_fuzz_addressPTR_SOURCES = \
+ $(src_test_fuzz_fuzz_addressPTR_SOURCES)
+src_test_fuzz_lf_fuzz_addressPTR_CPPFLAGS = $(LIBFUZZER_CPPFLAGS)
+src_test_fuzz_lf_fuzz_addressPTR_CFLAGS = $(LIBFUZZER_CFLAGS)
+src_test_fuzz_lf_fuzz_addressPTR_LDFLAGS = $(LIBFUZZER_LDFLAG)
+src_test_fuzz_lf_fuzz_addressPTR_LDADD = $(LIBFUZZER_LIBS)
+endif
+
+if UNITTESTS_ENABLED
src_test_fuzz_lf_fuzz_consensus_SOURCES = \
$(src_test_fuzz_fuzz_consensus_SOURCES)
src_test_fuzz_lf_fuzz_consensus_CPPFLAGS = $(LIBFUZZER_CPPFLAGS)
@@ -240,15 +280,6 @@ src_test_fuzz_lf_fuzz_extrainfo_LDADD = $(LIBFUZZER_LIBS)
endif
if UNITTESTS_ENABLED
-src_test_fuzz_lf_fuzz_hsdescv2_SOURCES = \
- $(src_test_fuzz_fuzz_hsdescv2_SOURCES)
-src_test_fuzz_lf_fuzz_hsdescv2_CPPFLAGS = $(LIBFUZZER_CPPFLAGS)
-src_test_fuzz_lf_fuzz_hsdescv2_CFLAGS = $(LIBFUZZER_CFLAGS)
-src_test_fuzz_lf_fuzz_hsdescv2_LDFLAGS = $(LIBFUZZER_LDFLAG)
-src_test_fuzz_lf_fuzz_hsdescv2_LDADD = $(LIBFUZZER_LIBS)
-endif
-
-if UNITTESTS_ENABLED
src_test_fuzz_lf_fuzz_hsdescv3_SOURCES = \
$(src_test_fuzz_fuzz_hsdescv3_SOURCES)
src_test_fuzz_lf_fuzz_hsdescv3_CPPFLAGS = $(LIBFUZZER_CPPFLAGS)
@@ -258,6 +289,25 @@ src_test_fuzz_lf_fuzz_hsdescv3_LDADD = $(LIBFUZZER_LIBS)
endif
if UNITTESTS_ENABLED
+src_test_fuzz_lf_fuzz_hsdescv3_inner_SOURCES = \
+ $(src_test_fuzz_fuzz_hsdescv3_inner_SOURCES)
+src_test_fuzz_lf_fuzz_hsdescv3_inner_CPPFLAGS = $(LIBFUZZER_CPPFLAGS)
+src_test_fuzz_lf_fuzz_hsdescv3_inner_CFLAGS = $(LIBFUZZER_CFLAGS)
+src_test_fuzz_lf_fuzz_hsdescv3_inner_LDFLAGS = $(LIBFUZZER_LDFLAG)
+src_test_fuzz_lf_fuzz_hsdescv3_inner_LDADD = $(LIBFUZZER_LIBS)
+endif
+
+if UNITTESTS_ENABLED
+src_test_fuzz_lf_fuzz_hsdescv3_middle_SOURCES = \
+ $(src_test_fuzz_fuzz_hsdescv3_middle_SOURCES)
+src_test_fuzz_lf_fuzz_hsdescv3_middle_CPPFLAGS = $(LIBFUZZER_CPPFLAGS)
+src_test_fuzz_lf_fuzz_hsdescv3_middle_CFLAGS = $(LIBFUZZER_CFLAGS)
+src_test_fuzz_lf_fuzz_hsdescv3_middle_LDFLAGS = $(LIBFUZZER_LDFLAG)
+src_test_fuzz_lf_fuzz_hsdescv3_middle_LDADD = $(LIBFUZZER_LIBS)
+endif
+
+
+if UNITTESTS_ENABLED
src_test_fuzz_lf_fuzz_http_SOURCES = \
$(src_test_fuzz_fuzz_http_SOURCES)
src_test_fuzz_lf_fuzz_http_CPPFLAGS = $(LIBFUZZER_CPPFLAGS)
@@ -276,15 +326,6 @@ src_test_fuzz_lf_fuzz_http_connect_LDADD = $(LIBFUZZER_LIBS)
endif
if UNITTESTS_ENABLED
-src_test_fuzz_lf_fuzz_iptsv2_SOURCES = \
- $(src_test_fuzz_fuzz_iptsv2_SOURCES)
-src_test_fuzz_lf_fuzz_iptsv2_CPPFLAGS = $(LIBFUZZER_CPPFLAGS)
-src_test_fuzz_lf_fuzz_iptsv2_CFLAGS = $(LIBFUZZER_CFLAGS)
-src_test_fuzz_lf_fuzz_iptsv2_LDFLAGS = $(LIBFUZZER_LDFLAG)
-src_test_fuzz_lf_fuzz_iptsv2_LDADD = $(LIBFUZZER_LIBS)
-endif
-
-if UNITTESTS_ENABLED
src_test_fuzz_lf_fuzz_microdesc_SOURCES = \
$(src_test_fuzz_fuzz_microdesc_SOURCES)
src_test_fuzz_lf_fuzz_microdesc_CPPFLAGS = $(LIBFUZZER_CPPFLAGS)
@@ -321,16 +362,18 @@ src_test_fuzz_lf_fuzz_vrs_LDADD = $(LIBFUZZER_LIBS)
endif
LIBFUZZER_FUZZERS = \
+ src/test/fuzz/lf-fuzz-address \
+ src/test/fuzz/lf-fuzz-addressPTR \
src/test/fuzz/lf-fuzz-consensus \
src/test/fuzz/lf-fuzz-descriptor \
src/test/fuzz/lf-fuzz-diff \
src/test/fuzz/lf-fuzz-diff-apply \
src/test/fuzz/lf-fuzz-extrainfo \
- src/test/fuzz/lf-fuzz-hsdescv2 \
src/test/fuzz/lf-fuzz-hsdescv3 \
+ src/test/fuzz/lf-fuzz-hsdescv3-inner \
+ src/test/fuzz/lf-fuzz-hsdescv3-middle \
src/test/fuzz/lf-fuzz-http \
src/test/fuzz/lf-fuzz-http-connect \
- src/test/fuzz/lf-fuzz-iptsv2 \
src/test/fuzz/lf-fuzz-microdesc \
src/test/fuzz/lf-fuzz-socks \
src/test/fuzz/lf-fuzz-strops \
@@ -344,6 +387,20 @@ endif
if OSS_FUZZ_ENABLED
if UNITTESTS_ENABLED
+src_test_fuzz_liboss_fuzz_address_a_SOURCES = \
+ $(src_test_fuzz_fuzz_address_SOURCES)
+src_test_fuzz_liboss_fuzz_address_a_CPPFLAGS = $(LIBOSS_FUZZ_CPPFLAGS)
+src_test_fuzz_liboss_fuzz_address_a_CFLAGS = $(LIBOSS_FUZZ_CFLAGS)
+endif
+
+if UNITTESTS_ENABLED
+src_test_fuzz_liboss_fuzz_addressPTR_a_SOURCES = \
+ $(src_test_fuzz_fuzz_addressPTR_SOURCES)
+src_test_fuzz_liboss_fuzz_addressPTR_a_CPPFLAGS = $(LIBOSS_FUZZ_CPPFLAGS)
+src_test_fuzz_liboss_fuzz_addressPTR_a_CFLAGS = $(LIBOSS_FUZZ_CFLAGS)
+endif
+
+if UNITTESTS_ENABLED
src_test_fuzz_liboss_fuzz_consensus_a_SOURCES = \
$(src_test_fuzz_fuzz_consensus_SOURCES)
src_test_fuzz_liboss_fuzz_consensus_a_CPPFLAGS = $(LIBOSS_FUZZ_CPPFLAGS)
@@ -379,13 +436,6 @@ src_test_fuzz_liboss_fuzz_extrainfo_a_CFLAGS = $(LIBOSS_FUZZ_CFLAGS)
endif
if UNITTESTS_ENABLED
-src_test_fuzz_liboss_fuzz_hsdescv2_a_SOURCES = \
- $(src_test_fuzz_fuzz_hsdescv2_SOURCES)
-src_test_fuzz_liboss_fuzz_hsdescv2_a_CPPFLAGS = $(LIBOSS_FUZZ_CPPFLAGS)
-src_test_fuzz_liboss_fuzz_hsdescv2_a_CFLAGS = $(LIBOSS_FUZZ_CFLAGS)
-endif
-
-if UNITTESTS_ENABLED
src_test_fuzz_liboss_fuzz_hsdescv3_a_SOURCES = \
$(src_test_fuzz_fuzz_hsdescv3_SOURCES)
src_test_fuzz_liboss_fuzz_hsdescv3_a_CPPFLAGS = $(LIBOSS_FUZZ_CPPFLAGS)
@@ -393,6 +443,20 @@ src_test_fuzz_liboss_fuzz_hsdescv3_a_CFLAGS = $(LIBOSS_FUZZ_CFLAGS)
endif
if UNITTESTS_ENABLED
+src_test_fuzz_liboss_fuzz_hsdescv3_inner_a_SOURCES = \
+ $(src_test_fuzz_fuzz_hsdescv3_inner_SOURCES)
+src_test_fuzz_liboss_fuzz_hsdescv3_inner_a_CPPFLAGS = $(LIBOSS_FUZZ_CPPFLAGS)
+src_test_fuzz_liboss_fuzz_hsdescv3_inner_a_CFLAGS = $(LIBOSS_FUZZ_CFLAGS)
+endif
+
+if UNITTESTS_ENABLED
+src_test_fuzz_liboss_fuzz_hsdescv3_middle_a_SOURCES = \
+ $(src_test_fuzz_fuzz_hsdescv3_middle_SOURCES)
+src_test_fuzz_liboss_fuzz_hsdescv3_middle_a_CPPFLAGS = $(LIBOSS_FUZZ_CPPFLAGS)
+src_test_fuzz_liboss_fuzz_hsdescv3_middle_a_CFLAGS = $(LIBOSS_FUZZ_CFLAGS)
+endif
+
+if UNITTESTS_ENABLED
src_test_fuzz_liboss_fuzz_http_a_SOURCES = \
$(src_test_fuzz_fuzz_http_SOURCES)
src_test_fuzz_liboss_fuzz_http_a_CPPFLAGS = $(LIBOSS_FUZZ_CPPFLAGS)
@@ -407,13 +471,6 @@ src_test_fuzz_liboss_fuzz_http_connect_a_CFLAGS = $(LIBOSS_FUZZ_CFLAGS)
endif
if UNITTESTS_ENABLED
-src_test_fuzz_liboss_fuzz_iptsv2_a_SOURCES = \
- $(src_test_fuzz_fuzz_iptsv2_SOURCES)
-src_test_fuzz_liboss_fuzz_iptsv2_a_CPPFLAGS = $(LIBOSS_FUZZ_CPPFLAGS)
-src_test_fuzz_liboss_fuzz_iptsv2_a_CFLAGS = $(LIBOSS_FUZZ_CFLAGS)
-endif
-
-if UNITTESTS_ENABLED
src_test_fuzz_liboss_fuzz_microdesc_a_SOURCES = \
$(src_test_fuzz_fuzz_microdesc_SOURCES)
src_test_fuzz_liboss_fuzz_microdesc_a_CPPFLAGS = $(LIBOSS_FUZZ_CPPFLAGS)
@@ -442,16 +499,18 @@ src_test_fuzz_liboss_fuzz_vrs_a_CFLAGS = $(LIBOSS_FUZZ_CFLAGS)
endif
OSS_FUZZ_FUZZERS = \
+ src/test/fuzz/liboss-fuzz-address.a \
+ src/test/fuzz/liboss-fuzz-addressPTR.a \
src/test/fuzz/liboss-fuzz-consensus.a \
src/test/fuzz/liboss-fuzz-descriptor.a \
src/test/fuzz/liboss-fuzz-diff.a \
src/test/fuzz/liboss-fuzz-diff-apply.a \
src/test/fuzz/liboss-fuzz-extrainfo.a \
- src/test/fuzz/liboss-fuzz-hsdescv2.a \
src/test/fuzz/liboss-fuzz-hsdescv3.a \
+ src/test/fuzz/liboss-fuzz-hsdescv3-inner.a \
+ src/test/fuzz/liboss-fuzz-hsdescv3-middle.a \
src/test/fuzz/liboss-fuzz-http.a \
src/test/fuzz/liboss-fuzz-http-connect.a \
- src/test/fuzz/liboss-fuzz-iptsv2.a \
src/test/fuzz/liboss-fuzz-microdesc.a \
src/test/fuzz/liboss-fuzz-socks.a \
src/test/fuzz/liboss-fuzz-strops.a \
diff --git a/src/test/hs_build_address.py b/src/test/hs_build_address.py
index 91864eabcb..216b7626bf 100644
--- a/src/test/hs_build_address.py
+++ b/src/test/hs_build_address.py
@@ -10,17 +10,21 @@ import base64
# Python 3.6+, the SHA3 is available in hashlib natively. Else this requires
# the pysha3 package (pip install pysha3).
+TEST_INPUT = b"Hello World"
if sys.version_info < (3, 6):
import sha3
+ m = sha3.sha3_256(TEST_INPUT)
+else:
+ m = hashlib.sha3_256(TEST_INPUT)
# Test vector to make sure the right sha3 version will be used. pysha3 < 1.0
# used the old Keccak implementation. During the finalization of SHA3, NIST
# changed the delimiter suffix from 0x01 to 0x06. The Keccak sponge function
# stayed the same. pysha3 1.0 provides the previous Keccak hash, too.
TEST_VALUE = "e167f68d6563d75bb25f3aa49c29ef612d41352dc00606de7cbd630bb2665f51"
-if TEST_VALUE != sha3.sha3_256(b"Hello World").hexdigest():
+if TEST_VALUE != m.hexdigest():
print("pysha3 version is < 1.0. Please install from:")
- print("https://github.com/tiran/pysha3https://github.com/tiran/pysha3")
+ print("https://github.com/tiran/pysha3")
sys.exit(1)
# Checksum is built like so:
@@ -28,7 +32,11 @@ if TEST_VALUE != sha3.sha3_256(b"Hello World").hexdigest():
PREFIX = ".onion checksum".encode()
# 32 bytes ed25519 pubkey from first test vector of
# https://tools.ietf.org/html/draft-josefsson-eddsa-ed25519-02#section-6
-PUBKEY = "d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a".decode('hex')
+PUBKEY_STRING = "d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a"
+if sys.version_info < (3, 0):
+ PUBKEY = PUBKEY_STRING.decode('hex')
+else:
+ PUBKEY = bytes.fromhex(PUBKEY_STRING)
# Version 3 is proposal224
VERSION = 3
diff --git a/src/test/hs_test_helpers.c b/src/test/hs_test_helpers.c
index e9aafa4760..20b225ba4a 100644
--- a/src/test/hs_test_helpers.c
+++ b/src/test/hs_test_helpers.c
@@ -1,9 +1,10 @@
-/* Copyright (c) 2017-2020, The Tor Project, Inc. */
+/* Copyright (c) 2017-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define HS_CLIENT_PRIVATE
#include "core/or/or.h"
+#include "core/or/versions.h"
#include "lib/crypt_ops/crypto_ed25519.h"
#include "test/test.h"
#include "feature/nodelist/torcert.h"
@@ -134,7 +135,8 @@ hs_helper_build_intro_point(const ed25519_keypair_t *signing_kp, time_t now,
* points are added. */
static hs_descriptor_t *
hs_helper_build_hs_desc_impl(unsigned int no_ip,
- const ed25519_keypair_t *signing_kp)
+ const ed25519_keypair_t *signing_kp,
+ uint64_t rev_counter)
{
int ret;
int i;
@@ -161,7 +163,7 @@ hs_helper_build_hs_desc_impl(unsigned int no_ip,
&signing_kp->pubkey, now, 3600,
CERT_FLAG_INCLUDE_SIGNING_KEY);
tt_assert(desc->plaintext_data.signing_key_cert);
- desc->plaintext_data.revision_counter = 42;
+ desc->plaintext_data.revision_counter = rev_counter;
desc->plaintext_data.lifetime_sec = 3 * 60 * 60;
hs_get_subcredential(&signing_kp->pubkey, &blinded_kp.pubkey,
@@ -185,6 +187,7 @@ hs_helper_build_hs_desc_impl(unsigned int no_ip,
desc->encrypted_data.create2_ntor = 1;
desc->encrypted_data.intro_auth_types = smartlist_new();
desc->encrypted_data.single_onion_service = 1;
+ desc->encrypted_data.flow_control_pv = tor_strdup("FlowCtrl=1-2");
smartlist_add(desc->encrypted_data.intro_auth_types, tor_strdup("ed25519"));
desc->encrypted_data.intro_points = smartlist_new();
if (!no_ip) {
@@ -226,18 +229,26 @@ hs_helper_get_subcred_from_identity_keypair(ed25519_keypair_t *signing_kp,
subcred_out);
}
+/* Build a descriptor with a specific rev counter. */
+hs_descriptor_t *
+hs_helper_build_hs_desc_with_rev_counter(const ed25519_keypair_t *signing_kp,
+ uint64_t revision_counter)
+{
+ return hs_helper_build_hs_desc_impl(0, signing_kp, revision_counter);
+}
+
/* Build a descriptor with introduction points. */
hs_descriptor_t *
hs_helper_build_hs_desc_with_ip(const ed25519_keypair_t *signing_kp)
{
- return hs_helper_build_hs_desc_impl(0, signing_kp);
+ return hs_helper_build_hs_desc_impl(0, signing_kp, 42);
}
/* Build a descriptor without any introduction points. */
hs_descriptor_t *
hs_helper_build_hs_desc_no_ip(const ed25519_keypair_t *signing_kp)
{
- return hs_helper_build_hs_desc_impl(1, signing_kp);
+ return hs_helper_build_hs_desc_impl(1, signing_kp, 42);
}
hs_descriptor_t *
@@ -247,7 +258,7 @@ hs_helper_build_hs_desc_with_client_auth(
const ed25519_keypair_t *signing_kp)
{
curve25519_keypair_t auth_ephemeral_kp;
- hs_descriptor_t *desc = hs_helper_build_hs_desc_impl(0, signing_kp);
+ hs_descriptor_t *desc = hs_helper_build_hs_desc_impl(0, signing_kp, 42);
hs_desc_authorized_client_t *desc_client;
/* The number of client authorized auth has tobe a multiple of
@@ -323,6 +334,10 @@ hs_helper_desc_equal(const hs_descriptor_t *desc1,
/* Encrypted data section. */
tt_uint_op(desc1->encrypted_data.create2_ntor, OP_EQ,
desc2->encrypted_data.create2_ntor);
+ tt_uint_op(desc1->encrypted_data.single_onion_service, OP_EQ,
+ desc2->encrypted_data.single_onion_service);
+ tt_str_op(desc1->encrypted_data.flow_control_pv, OP_EQ,
+ desc2->encrypted_data.flow_control_pv);
/* Authentication type. */
tt_int_op(!!desc1->encrypted_data.intro_auth_types, OP_EQ,
diff --git a/src/test/hs_test_helpers.h b/src/test/hs_test_helpers.h
index 23d11f2a4a..ec9ee60116 100644
--- a/src/test/hs_test_helpers.h
+++ b/src/test/hs_test_helpers.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017-2020, The Tor Project, Inc. */
+/* Copyright (c) 2017-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#ifndef TOR_HS_TEST_HELPERS_H
@@ -17,6 +17,10 @@ hs_descriptor_t *hs_helper_build_hs_desc_no_ip(
const ed25519_keypair_t *signing_kp);
hs_descriptor_t *hs_helper_build_hs_desc_with_ip(
const ed25519_keypair_t *signing_kp);
+hs_descriptor_t *
+hs_helper_build_hs_desc_with_rev_counter(const ed25519_keypair_t *signing_kp,
+ uint64_t revision_counter);
+
hs_descriptor_t *hs_helper_build_hs_desc_with_client_auth(
const uint8_t *descriptor_cookie,
const curve25519_public_key_t *client_pk,
diff --git a/src/test/include.am b/src/test/include.am
index ba802e7b04..2765cf27d0 100644
--- a/src/test/include.am
+++ b/src/test/include.am
@@ -8,11 +8,7 @@ TESTS_ENVIRONMENT = \
export abs_top_builddir="$(abs_top_builddir)"; \
export builddir="$(builddir)"; \
export TESTING_TOR_BINARY="$(TESTING_TOR_BINARY)"; \
- export CARGO="$(CARGO)"; \
- export EXTRA_CARGO_OPTIONS="$(EXTRA_CARGO_OPTIONS)"; \
- export CARGO_ONLINE="$(CARGO_ONLINE)"; \
- export CCLD="$(CCLD)"; \
- export RUSTFLAGS="-C linker=`echo '$(CC)' | cut -d' ' -f 1` $(RUST_LINKER_OPTIONS)";
+ export CCLD="$(CCLD)";
TESTSCRIPTS = \
src/test/fuzz_static_testcases.sh \
@@ -35,11 +31,6 @@ TESTSCRIPTS = \
src/test/unittest_part7.sh \
src/test/unittest_part8.sh
-if USE_RUST
-TESTSCRIPTS += \
- src/test/test_rust.sh
-endif
-
if USEPYTHON
TESTSCRIPTS += \
src/test/test_ntor.sh \
@@ -82,7 +73,8 @@ TEST_CHUTNEY_FLAVOR_QUICK_IPV6 = single-onion-v3-ipv6-md
TEST_CHUTNEY_FLAVORS = basic-min bridges-min hs-v3-min single-onion-v3
# only run if we can ping ::1 (localhost)
-TEST_CHUTNEY_FLAVORS_IPV6 = bridges+ipv6-min ipv6-exit-min hs-v3-ipv6 single-onion-v3-ipv6-md
+TEST_CHUTNEY_FLAVORS_IPV6 = bridges+ipv6-min ipv6-exit-min hs-v3-ipv6 \
+ single-onion-v3-ipv6-md
# only run if we can find a stable (or simply another) version of tor
TEST_CHUTNEY_FLAVORS_MIXED = mixed+hs-v3
@@ -129,7 +121,6 @@ src_test_test_SOURCES += \
src/test/log_test_helpers.c \
src/test/hs_test_helpers.c \
src/test/opts_test_helpers.c \
- src/test/rend_test_helpers.c \
src/test/resolve_test_helpers.c \
src/test/rng_test_helpers.c \
src/test/test.c \
@@ -170,6 +161,7 @@ src_test_test_SOURCES += \
src/test/test_crypto_rng.c \
src/test/test_data.c \
src/test/test_dir.c \
+ src/test/test_dirauth_ports.c \
src/test/test_dirvote.c \
src/test/test_dir_common.c \
src/test/test_dir_handle_get.c \
@@ -180,7 +172,6 @@ src_test_test_SOURCES += \
src/test/test_geoip.c \
src/test/test_guardfraction.c \
src/test/test_extorport.c \
- src/test/test_hs.c \
src/test/test_hs_common.c \
src/test/test_hs_config.c \
src/test/test_hs_cell.c \
@@ -195,7 +186,6 @@ 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_introduce.c \
src/test/test_keypin.c \
src/test/test_link_handshake.c \
src/test/test_logging.c \
@@ -205,6 +195,7 @@ src_test_test_SOURCES += \
src/test/test_namemap.c \
src/test/test_netinfo.c \
src/test/test_nodelist.c \
+ src/test/test_ntor_v3.c \
src/test/test_oom.c \
src/test/test_oos.c \
src/test/test_options.c \
@@ -226,12 +217,12 @@ src_test_test_SOURCES += \
src/test/test_relay.c \
src/test/test_relaycell.c \
src/test/test_relaycrypt.c \
- src/test/test_rendcache.c \
src/test/test_replay.c \
src/test/test_router.c \
src/test/test_routerkeys.c \
src/test/test_routerlist.c \
src/test/test_routerset.c \
+ src/test/test_sandbox.c \
src/test/test_scheduler.c \
src/test/test_sendme.c \
src/test/test_shared_random.c \
@@ -306,7 +297,6 @@ src_test_test_switch_id_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS)
src_test_test_switch_id_LDFLAGS = @TOR_LDFLAGS_zlib@
src_test_test_switch_id_LDADD = \
$(TOR_UTIL_TESTING_LIBS) \
- $(rust_ldadd) \
@TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ \
@TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_SHLWAPI@ @TOR_LIB_USERENV@ \
@TOR_LZMA_LIBS@ @TOR_ZSTD_LIBS@ @TOR_TRACE_LIBS@
@@ -314,7 +304,6 @@ src_test_test_LDFLAGS = @TOR_LDFLAGS_zlib@ $(TOR_LDFLAGS_CRYPTLIB) \
@TOR_LDFLAGS_libevent@
src_test_test_LDADD = \
src/test/libtor-testing.a \
- $(rust_ldadd) \
@TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ @TOR_LIBEVENT_LIBS@ \
$(TOR_LIBS_CRYPTLIB) @TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_SHLWAPI@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@ \
@CURVE25519_LIBS@ \
@@ -343,7 +332,6 @@ src_test_bench_LDFLAGS = @TOR_LDFLAGS_zlib@ $(TOR_LDFLAGS_CRYPTLIB) \
@TOR_LDFLAGS_libevent@
src_test_bench_LDADD = \
libtor.a \
- $(rust_ldadd) \
@TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ @TOR_LIBEVENT_LIBS@ \
$(TOR_LIBS_CRYPTLIB) @TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_SHLWAPI@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@ \
@CURVE25519_LIBS@ \
@@ -353,7 +341,6 @@ src_test_test_workqueue_LDFLAGS = @TOR_LDFLAGS_zlib@ $(TOR_LDFLAGS_CRYPTLIB) \
@TOR_LDFLAGS_libevent@
src_test_test_workqueue_LDADD = \
src/test/libtor-testing.a \
- $(rust_ldadd) \
@TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ @TOR_LIBEVENT_LIBS@ \
$(TOR_LIBS_CRYPTLIB) @TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_SHLWAPI@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@ \
@CURVE25519_LIBS@ \
@@ -365,7 +352,6 @@ src_test_test_timers_LDADD = \
src/lib/libtor-evloop-testing.a \
$(TOR_CRYPTO_TESTING_LIBS) \
$(TOR_UTIL_TESTING_LIBS) \
- $(rust_ldadd) \
@TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ @TOR_LIBEVENT_LIBS@ \
$(TOR_LIBS_CRYPTLIB) @TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_SHLWAPI@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@ \
@CURVE25519_LIBS@ \
@@ -379,7 +365,6 @@ noinst_HEADERS+= \
src/test/hs_test_helpers.h \
src/test/log_test_helpers.h \
src/test/opts_test_helpers.h \
- src/test/rend_test_helpers.h \
src/test/resolve_test_helpers.h \
src/test/rng_test_helpers.h \
src/test/test.h \
@@ -402,7 +387,6 @@ src_test_test_ntor_cl_SOURCES = src/test/test_ntor_cl.c
src_test_test_ntor_cl_LDFLAGS = @TOR_LDFLAGS_zlib@ $(TOR_LDFLAGS_CRYPTLIB)
src_test_test_ntor_cl_LDADD = \
libtor.a \
- $(rust_ldadd) \
@TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ \
$(TOR_LIBS_CRYPTLIB) @TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_SHLWAPI@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@ \
@CURVE25519_LIBS@ @TOR_LZMA_LIBS@ @TOR_TRACE_LIBS@
@@ -425,7 +409,6 @@ noinst_PROGRAMS += src/test/test-bt-cl
src_test_test_bt_cl_SOURCES = src/test/test_bt_cl.c
src_test_test_bt_cl_LDADD = \
$(TOR_UTIL_TESTING_LIBS) \
- $(rust_ldadd) \
@TOR_LIB_MATH@ \
@TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_SHLWAPI@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@ \
@TOR_TRACE_LIBS@
@@ -447,13 +430,11 @@ EXTRA_DIST += \
src/test/test_include.py \
src/test/zero_length_keys.sh \
scripts/maint/run_check_subsystem_order.sh \
- src/test/rust_supp.txt \
src/test/test_keygen.sh \
src/test/test_key_expiration.sh \
src/test/test_zero_length_keys.sh \
src/test/test_ntor.sh src/test/test_hs_ntor.sh src/test/test_bt.sh \
src/test/test-network.sh \
- src/test/test_rust.sh \
src/test/test_switch_id.sh \
src/test/test_workqueue_cancel.sh \
src/test/test_workqueue_efd.sh \
@@ -471,6 +452,3 @@ EXTRA_DIST += \
src/test/unittest_part6.sh \
src/test/unittest_part7.sh \
src/test/unittest_part8.sh
-
-test-rust:
- $(TESTS_ENVIRONMENT) "$(abs_top_srcdir)/src/test/test_rust.sh"
diff --git a/src/test/log_test_helpers.c b/src/test/log_test_helpers.c
index 5e60d6b282..8928f39634 100644
--- a/src/test/log_test_helpers.c
+++ b/src/test/log_test_helpers.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2020, The Tor Project, Inc. */
+/* Copyright (c) 2015-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define LOG_PRIVATE
#include "lib/log/log.h"
diff --git a/src/test/log_test_helpers.h b/src/test/log_test_helpers.h
index c2d71c6bcd..e7de9b6015 100644
--- a/src/test/log_test_helpers.h
+++ b/src/test/log_test_helpers.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2020, The Tor Project, Inc. */
+/* Copyright (c) 2014-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "core/or/or.h"
diff --git a/src/test/ntor_v3_ref.py b/src/test/ntor_v3_ref.py
new file mode 100755
index 0000000000..28bc077105
--- /dev/null
+++ b/src/test/ntor_v3_ref.py
@@ -0,0 +1,308 @@
+#!/usr/bin/python
+
+import binascii
+import hashlib
+import os
+import struct
+
+import donna25519
+from Crypto.Cipher import AES
+from Crypto.Util import Counter
+
+# Define basic wrappers.
+
+DIGEST_LEN = 32
+ENC_KEY_LEN = 32
+PUB_KEY_LEN = 32
+SEC_KEY_LEN = 32
+IDENTITY_LEN = 32
+
+def sha3_256(s):
+ d = hashlib.sha3_256(s).digest()
+ assert len(d) == DIGEST_LEN
+ return d
+
+def shake_256(s):
+ # Note: In reality, you wouldn't want to generate more bytes than needed.
+ MAX_KEY_BYTES = 1024
+ return hashlib.shake_256(s).digest(MAX_KEY_BYTES)
+
+def curve25519(pk, sk):
+ assert len(pk) == PUB_KEY_LEN
+ assert len(sk) == SEC_KEY_LEN
+ private = donna25519.PrivateKey.load(sk)
+ public = donna25519.PublicKey(pk)
+ return private.do_exchange(public)
+
+def keygen():
+ private = donna25519.PrivateKey()
+ public = private.get_public()
+ return (private.private, public.public)
+
+def aes256_ctr(k, s):
+ assert len(k) == ENC_KEY_LEN
+ cipher = AES.new(k, AES.MODE_CTR, counter=Counter.new(128, initial_value=0))
+ return cipher.encrypt(s)
+
+# Byte-oriented helper. We use this for decoding keystreams and messages.
+
+class ByteSeq:
+ def __init__(self, data):
+ self.data = data
+
+ def take(self, n):
+ assert n <= len(self.data)
+ result = self.data[:n]
+ self.data = self.data[n:]
+ return result
+
+ def exhausted(self):
+ return len(self.data) == 0
+
+ def remaining(self):
+ return len(self.data)
+
+# Low-level functions
+
+MAC_KEY_LEN = 32
+MAC_LEN = DIGEST_LEN
+
+hash_func = sha3_256
+
+def encapsulate(s):
+ """encapsulate `s` with a length prefix.
+
+ We use this whenever we need to avoid message ambiguities in
+ cryptographic inputs.
+ """
+ assert len(s) <= 0xffffffff
+ header = b"\0\0\0\0" + struct.pack("!L", len(s))
+ assert len(header) == 8
+ return header + s
+
+def h(s, tweak):
+ return hash_func(encapsulate(tweak) + s)
+
+def mac(s, key, tweak):
+ return hash_func(encapsulate(tweak) + encapsulate(key) + s)
+
+def kdf(s, tweak):
+ data = shake_256(encapsulate(tweak) + s)
+ return ByteSeq(data)
+
+def enc(s, k):
+ return aes256_ctr(k, s)
+
+# Tweaked wrappers
+
+PROTOID = b"ntor3-curve25519-sha3_256-1"
+T_KDF_PHASE1 = PROTOID + b":kdf_phase1"
+T_MAC_PHASE1 = PROTOID + b":msg_mac"
+T_KDF_FINAL = PROTOID + b":kdf_final"
+T_KEY_SEED = PROTOID + b":key_seed"
+T_VERIFY = PROTOID + b":verify"
+T_AUTH = PROTOID + b":auth_final"
+
+def kdf_phase1(s):
+ return kdf(s, T_KDF_PHASE1)
+
+def kdf_final(s):
+ return kdf(s, T_KDF_FINAL)
+
+def mac_phase1(s, key):
+ return mac(s, key, T_MAC_PHASE1)
+
+def h_key_seed(s):
+ return h(s, T_KEY_SEED)
+
+def h_verify(s):
+ return h(s, T_VERIFY)
+
+def h_auth(s):
+ return h(s, T_AUTH)
+
+# Handshake.
+
+def client_phase1(msg, verification, B, ID):
+ assert len(B) == PUB_KEY_LEN
+ assert len(ID) == IDENTITY_LEN
+
+ (x,X) = keygen()
+ p(["x", "X"], locals())
+ p(["msg", "verification"], locals())
+ Bx = curve25519(B, x)
+ secret_input_phase1 = Bx + ID + X + B + PROTOID + encapsulate(verification)
+
+ phase1_keys = kdf_phase1(secret_input_phase1)
+ enc_key = phase1_keys.take(ENC_KEY_LEN)
+ mac_key = phase1_keys.take(MAC_KEY_LEN)
+ p(["enc_key", "mac_key"], locals())
+
+ msg_0 = ID + B + X + enc(msg, enc_key)
+ mac = mac_phase1(msg_0, mac_key)
+ p(["mac"], locals())
+
+ client_handshake = msg_0 + mac
+ state = dict(x=x, X=X, B=B, ID=ID, Bx=Bx, mac=mac, verification=verification)
+
+ p(["client_handshake"], locals())
+
+ return (client_handshake, state)
+
+# server.
+
+class Reject(Exception):
+ pass
+
+def server_part1(cmsg, verification, b, B, ID):
+ assert len(B) == PUB_KEY_LEN
+ assert len(ID) == IDENTITY_LEN
+ assert len(b) == SEC_KEY_LEN
+
+ if len(cmsg) < (IDENTITY_LEN + PUB_KEY_LEN * 2 + MAC_LEN):
+ raise Reject()
+
+ mac_covered_portion = cmsg[0:-MAC_LEN]
+ cmsg = ByteSeq(cmsg)
+ cmsg_id = cmsg.take(IDENTITY_LEN)
+ cmsg_B = cmsg.take(PUB_KEY_LEN)
+ cmsg_X = cmsg.take(PUB_KEY_LEN)
+ cmsg_msg = cmsg.take(cmsg.remaining() - MAC_LEN)
+ cmsg_mac = cmsg.take(MAC_LEN)
+
+ assert cmsg.exhausted()
+
+ # XXXX for real purposes, you would use constant-time checks here
+ if cmsg_id != ID or cmsg_B != B:
+ raise Reject()
+
+ Xb = curve25519(cmsg_X, b)
+ secret_input_phase1 = Xb + ID + cmsg_X + B + PROTOID + encapsulate(verification)
+
+ phase1_keys = kdf_phase1(secret_input_phase1)
+ enc_key = phase1_keys.take(ENC_KEY_LEN)
+ mac_key = phase1_keys.take(MAC_KEY_LEN)
+
+ mac_received = mac_phase1(mac_covered_portion, mac_key)
+ if mac_received != cmsg_mac:
+ raise Reject()
+
+ client_msg = enc(cmsg_msg, enc_key)
+ state = dict(
+ b=b,
+ B=B,
+ X=cmsg_X,
+ mac_received=mac_received,
+ Xb=Xb,
+ ID=ID,
+ verification=verification)
+
+ return (client_msg, state)
+
+def server_part2(state, server_msg):
+ X = state['X']
+ Xb = state['Xb']
+ B = state['B']
+ b = state['b']
+ ID = state['ID']
+ mac_received = state['mac_received']
+ verification = state['verification']
+
+ p(["server_msg"], locals())
+
+ (y,Y) = keygen()
+ p(["y", "Y"], locals())
+ Xy = curve25519(X, y)
+
+ secret_input = Xy + Xb + ID + B + X + Y + PROTOID + encapsulate(verification)
+ key_seed = h_key_seed(secret_input)
+ verify = h_verify(secret_input)
+ p(["key_seed", "verify"], locals())
+
+ keys = kdf_final(key_seed)
+ server_enc_key = keys.take(ENC_KEY_LEN)
+ p(["server_enc_key"], locals())
+
+ smsg_msg = enc(server_msg, server_enc_key)
+
+ auth_input = verify + ID + B + Y + X + mac_received + encapsulate(smsg_msg) + PROTOID + b"Server"
+
+ auth = h_auth(auth_input)
+ server_handshake = Y + auth + smsg_msg
+ p(["auth", "server_handshake"], locals())
+
+ return (server_handshake, keys)
+
+def client_phase2(state, smsg):
+ x = state['x']
+ X = state['X']
+ B = state['B']
+ ID = state['ID']
+ Bx = state['Bx']
+ mac_sent = state['mac']
+ verification = state['verification']
+
+ if len(smsg) < PUB_KEY_LEN + DIGEST_LEN:
+ raise Reject()
+
+ smsg = ByteSeq(smsg)
+ Y = smsg.take(PUB_KEY_LEN)
+ auth_received = smsg.take(DIGEST_LEN)
+ server_msg = smsg.take(smsg.remaining())
+
+ Yx = curve25519(Y,x)
+
+ secret_input = Yx + Bx + ID + B + X + Y + PROTOID + encapsulate(verification)
+ key_seed = h_key_seed(secret_input)
+ verify = h_verify(secret_input)
+
+ auth_input = verify + ID + B + Y + X + mac_sent + encapsulate(server_msg) + PROTOID + b"Server"
+
+ auth = h_auth(auth_input)
+ if auth != auth_received:
+ raise Reject()
+
+ keys = kdf_final(key_seed)
+ enc_key = keys.take(ENC_KEY_LEN)
+
+ server_msg_decrypted = enc(server_msg, enc_key)
+
+ return (keys, server_msg_decrypted)
+
+def p(varnames, localvars):
+ for v in varnames:
+ label = v
+ val = localvars[label]
+ print('{} = "{}"'.format(label, binascii.b2a_hex(val).decode("ascii")))
+
+def test():
+ (b,B) = keygen()
+ ID = os.urandom(IDENTITY_LEN)
+
+ p(["b", "B", "ID"], locals())
+
+ print("# ============")
+ (c_handshake, c_state) = client_phase1(b"hello world", b"xyzzy", B, ID)
+
+ print("# ============")
+
+ (c_msg_got, s_state) = server_part1(c_handshake, b"xyzzy", b, B, ID)
+
+ #print(repr(c_msg_got))
+
+ (s_handshake, s_keys) = server_part2(s_state, b"Hola Mundo")
+
+ print("# ============")
+
+ (c_keys, s_msg_got) = client_phase2(c_state, s_handshake)
+
+ #print(repr(s_msg_got))
+
+ c_keys_256 = c_keys.take(256)
+ p(["c_keys_256"], locals())
+
+ assert (c_keys_256 == s_keys.take(256))
+
+
+if __name__ == '__main__':
+ test()
diff --git a/src/test/opts_test_helpers.c b/src/test/opts_test_helpers.c
index 619ca40733..2c0f8dbd82 100644
--- a/src/test/opts_test_helpers.c
+++ b/src/test/opts_test_helpers.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/test/opts_test_helpers.h b/src/test/opts_test_helpers.h
index f925194e63..a6d31551a4 100644
--- a/src/test/opts_test_helpers.h
+++ b/src/test/opts_test_helpers.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/test/prob_distr_mpfr_ref.c b/src/test/prob_distr_mpfr_ref.c
index de4179c4e0..060cdf74ae 100644
--- a/src/test/prob_distr_mpfr_ref.c
+++ b/src/test/prob_distr_mpfr_ref.c
@@ -1,4 +1,4 @@
-/* Copyright 2012-2020, The Tor Project, Inc
+/* Copyright 2012-2021, The Tor Project, Inc
* See LICENSE for licensing information */
/** prob_distr_mpfr_ref.c
diff --git a/src/test/ptr_helpers.c b/src/test/ptr_helpers.c
index 0e0995df7c..536006be5d 100644
--- a/src/test/ptr_helpers.c
+++ b/src/test/ptr_helpers.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "test/ptr_helpers.h"
diff --git a/src/test/ptr_helpers.h b/src/test/ptr_helpers.h
index 0999fdf5d2..a283c525eb 100644
--- a/src/test/ptr_helpers.h
+++ b/src/test/ptr_helpers.h
@@ -1,6 +1,6 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#ifndef TOR_PTR_HELPERS_H
diff --git a/src/test/rend_test_helpers.c b/src/test/rend_test_helpers.c
deleted file mode 100644
index 8e40167aeb..0000000000
--- a/src/test/rend_test_helpers.c
+++ /dev/null
@@ -1,99 +0,0 @@
-/* Copyright (c) 2014-2020, The Tor Project, Inc. */
-/* See LICENSE for licensing information */
-
-#include "core/or/or.h"
-#include "core/or/extendinfo.h"
-#include "lib/crypt_ops/crypto_rand.h"
-#include "test/test.h"
-#include "feature/rend/rendcommon.h"
-#include "test/rend_test_helpers.h"
-
-#include "core/or/extend_info_st.h"
-#include "feature/rend/rend_intro_point_st.h"
-#include "feature/rend/rend_service_descriptor_st.h"
-
-void
-generate_desc(int time_diff, rend_encoded_v2_service_descriptor_t **desc,
- char **service_id, int intro_points)
-{
- rend_service_descriptor_t *generated = NULL;
- smartlist_t *descs = smartlist_new();
- time_t now;
-
- now = time(NULL) + time_diff;
- create_descriptor(&generated, service_id, intro_points);
- generated->timestamp = now;
-
- rend_encode_v2_descriptors(descs, generated, now, 0, REND_NO_AUTH, NULL,
- NULL);
- tor_assert(smartlist_len(descs) > 1);
- *desc = smartlist_get(descs, 0);
- smartlist_set(descs, 0, NULL);
-
- SMARTLIST_FOREACH(descs, rend_encoded_v2_service_descriptor_t *, d,
- rend_encoded_v2_service_descriptor_free(d));
- smartlist_free(descs);
- rend_service_descriptor_free(generated);
-}
-
-void
-create_descriptor(rend_service_descriptor_t **generated, char **service_id,
- int intro_points)
-{
- crypto_pk_t *pk1 = NULL;
- crypto_pk_t *pk2 = NULL;
- int i;
-
- *service_id = tor_malloc(REND_SERVICE_ID_LEN_BASE32+1);
- pk1 = pk_generate(0);
- pk2 = pk_generate(1);
-
- *generated = tor_malloc_zero(sizeof(rend_service_descriptor_t));
- (*generated)->pk = crypto_pk_dup_key(pk1);
- rend_get_service_id((*generated)->pk, *service_id);
-
- (*generated)->version = 2;
- (*generated)->protocols = 42;
- (*generated)->intro_nodes = smartlist_new();
-
- for (i = 0; i < intro_points; i++) {
- rend_intro_point_t *intro = tor_malloc_zero(sizeof(rend_intro_point_t));
- crypto_pk_t *okey = pk_generate(2 + i);
- intro->extend_info =
- extend_info_new(NULL, NULL, NULL, NULL, NULL, NULL, 0);
- intro->extend_info->onion_key = okey;
- crypto_pk_get_digest(intro->extend_info->onion_key,
- intro->extend_info->identity_digest);
- intro->extend_info->nickname[0] = '$';
- base16_encode(intro->extend_info->nickname + 1,
- sizeof(intro->extend_info->nickname) - 1,
- intro->extend_info->identity_digest, DIGEST_LEN);
- tor_addr_t addr;
- uint16_t port;
- /* Does not cover all IP addresses. */
- tor_addr_from_ipv4h(&addr, crypto_rand_int(65536) + 1);
- port = 1 + crypto_rand_int(65535);
- extend_info_add_orport(intro->extend_info, &addr, port);
- intro->intro_key = crypto_pk_dup_key(pk2);
- smartlist_add((*generated)->intro_nodes, intro);
- }
-
- crypto_pk_free(pk1);
- crypto_pk_free(pk2);
-}
-
-rend_data_t *
-mock_rend_data(const char *onion_address)
-{
- rend_data_v2_t *v2_data = tor_malloc_zero(sizeof(*v2_data));
- rend_data_t *rend_query = &v2_data->base_;
- rend_query->version = 2;
-
- strlcpy(v2_data->onion_address, onion_address,
- sizeof(v2_data->onion_address));
- v2_data->auth_type = REND_NO_AUTH;
- rend_query->hsdirs_fp = smartlist_new();
- smartlist_add(rend_query->hsdirs_fp, tor_memdup("aaaaaaaaaaaaaaaaaaaaaaaa",
- DIGEST_LEN));
- return rend_query;
-}
diff --git a/src/test/rend_test_helpers.h b/src/test/rend_test_helpers.h
deleted file mode 100644
index b1078ce866..0000000000
--- a/src/test/rend_test_helpers.h
+++ /dev/null
@@ -1,16 +0,0 @@
-/* Copyright (c) 2014-2020, The Tor Project, Inc. */
-/* See LICENSE for licensing information */
-
-#include "core/or/or.h"
-
-#ifndef TOR_REND_TEST_HELPERS_H
-#define TOR_REND_TEST_HELPERS_H
-
-void generate_desc(int time_diff, rend_encoded_v2_service_descriptor_t **desc,
- char **service_id, int intro_points);
-void create_descriptor(rend_service_descriptor_t **generated,
- char **service_id, int intro_points);
-rend_data_t *mock_rend_data(const char *onion_address);
-
-#endif /* !defined(TOR_REND_TEST_HELPERS_H) */
-
diff --git a/src/test/resolve_test_helpers.c b/src/test/resolve_test_helpers.c
index ed5853c359..6be5ab0b9f 100644
--- a/src/test/resolve_test_helpers.c
+++ b/src/test/resolve_test_helpers.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/test/resolve_test_helpers.h b/src/test/resolve_test_helpers.h
index ca642d6c63..c7d610379f 100644
--- a/src/test/resolve_test_helpers.h
+++ b/src/test/resolve_test_helpers.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/test/rng_test_helpers.c b/src/test/rng_test_helpers.c
index b7d7cb0dfa..058c5e0ccd 100644
--- a/src/test/rng_test_helpers.c
+++ b/src/test/rng_test_helpers.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2018-2020, The Tor Project, Inc. */
+/* Copyright (c) 2018-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/test/rng_test_helpers.h b/src/test/rng_test_helpers.h
index 6fcdaa2653..a6ca7d792f 100644
--- a/src/test/rng_test_helpers.h
+++ b/src/test/rng_test_helpers.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017-2020, The Tor Project, Inc. */
+/* Copyright (c) 2017-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#ifndef TOR_RNG_TEST_HELPERS_H
diff --git a/src/test/test-memwipe.c b/src/test/test-memwipe.c
index 5e4cc7678e..192fa9ec31 100644
--- a/src/test/test-memwipe.c
+++ b/src/test/test-memwipe.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2020, The Tor Project, Inc. */
+/* Copyright (c) 2015-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
diff --git a/src/test/test-process.c b/src/test/test-process.c
index f5a1f1a54e..a1e37b119a 100644
--- a/src/test/test-process.c
+++ b/src/test/test-process.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2020, The Tor Project, Inc. */
+/* Copyright (c) 2011-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
diff --git a/src/test/test-timers.c b/src/test/test-timers.c
index 18e2191a09..b2ba58b9dd 100644
--- a/src/test/test-timers.c
+++ b/src/test/test-timers.c
@@ -1,4 +1,4 @@
-/* Copyright 2016-2020, The Tor Project, Inc. */
+/* Copyright 2016-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
diff --git a/src/test/test.c b/src/test/test.c
index ffea158141..6b7e0b6442 100644
--- a/src/test/test.c
+++ b/src/test/test.c
@@ -1,6 +1,5 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
-->a * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -45,9 +44,6 @@
#include "app/config/config.h"
#include "core/or/connection_edge.h"
#include "core/or/extendinfo.h"
-#include "feature/rend/rendcommon.h"
-#include "feature/rend/rendcache.h"
-#include "feature/rend/rendparse.h"
#include "test/test.h"
#include "core/mainloop/mainloop.h"
#include "lib/memarea/memarea.h"
@@ -56,14 +52,13 @@
#include "core/crypto/onion_fast.h"
#include "core/crypto/onion_tap.h"
#include "core/or/policies.h"
+#include "lib/sandbox/sandbox.h"
#include "app/config/statefile.h"
#include "lib/crypt_ops/crypto_curve25519.h"
+#include "feature/nodelist/networkstatus.h"
#include "core/or/extend_info_st.h"
#include "core/or/or_circuit_st.h"
-#include "feature/rend/rend_encoded_v2_service_descriptor_st.h"
-#include "feature/rend/rend_intro_point_st.h"
-#include "feature/rend/rend_service_descriptor_st.h"
#include "feature/relay/onion_queue.h"
/** Run unit tests for the onion handshake code. */
@@ -355,6 +350,227 @@ test_onion_queues(void *arg)
tor_free(onionskin);
}
+/**
+ * Test onion queue priority, separation, and resulting
+ * ordering.
+ *
+ * create and add a mix of TAP, NTOR2, and NTORv3. Ensure
+ * they all end up in the right queue. In particular, ntorv2
+ * and ntorv3 should share a queue, but TAP should be separate,
+ * and lower prioritt.
+ *
+ * We test this by way of adding TAP first, and then an interleaving
+ * order of ntor2 and ntor3, and check that the ntor2 and ntor3 are
+ * still interleaved, but TAP comes last. */
+static void
+test_onion_queue_order(void *arg)
+{
+ uint8_t buf_tap[TAP_ONIONSKIN_CHALLENGE_LEN] = {0};
+ uint8_t buf_ntor[NTOR_ONIONSKIN_LEN] = {0};
+ uint8_t buf_ntor3[CELL_PAYLOAD_SIZE] = {0};
+
+ or_circuit_t *circ_tap = or_circuit_new(0, NULL);
+ or_circuit_t *circ_ntor = or_circuit_new(0, NULL);
+ or_circuit_t *circ_ntor3 = or_circuit_new(0, NULL);
+
+ create_cell_t *onionskin = NULL;
+ create_cell_t *create_tap1 = tor_malloc_zero(sizeof(create_cell_t));
+ create_cell_t *create_ntor1 = tor_malloc_zero(sizeof(create_cell_t));
+ create_cell_t *create_ntor2 = tor_malloc_zero(sizeof(create_cell_t));
+ create_cell_t *create_v3ntor1 = tor_malloc_zero(sizeof(create_cell_t));
+ create_cell_t *create_v3ntor2 = tor_malloc_zero(sizeof(create_cell_t));
+ (void)arg;
+
+ create_cell_init(create_tap1, CELL_CREATE, ONION_HANDSHAKE_TYPE_TAP,
+ TAP_ONIONSKIN_CHALLENGE_LEN, buf_tap);
+ create_cell_init(create_ntor1, CELL_CREATE, ONION_HANDSHAKE_TYPE_NTOR,
+ NTOR_ONIONSKIN_LEN, buf_ntor);
+ create_cell_init(create_ntor2, CELL_CREATE, ONION_HANDSHAKE_TYPE_NTOR,
+ NTOR_ONIONSKIN_LEN, buf_ntor);
+ create_cell_init(create_v3ntor1, CELL_CREATE2, ONION_HANDSHAKE_TYPE_NTOR_V3,
+ NTOR_ONIONSKIN_LEN, buf_ntor3);
+ create_cell_init(create_v3ntor2, CELL_CREATE2, ONION_HANDSHAKE_TYPE_NTOR_V3,
+ NTOR_ONIONSKIN_LEN, buf_ntor3);
+
+ /* sanity check queue init */
+ tt_int_op(0,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_TAP));
+ tt_int_op(0,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR));
+ tt_int_op(0,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR_V3));
+
+ /* Add tap first so we can ensure it comes out last */
+ tt_int_op(0,OP_EQ, onion_pending_add(circ_tap, create_tap1));
+ tt_int_op(1,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_TAP));
+ tt_int_op(0,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR));
+ tt_int_op(0,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR_V3));
+
+ /* Now add interleaving ntor2 and ntor3, to ensure they share
+ * the same queue and come out in this order */
+ tt_int_op(0,OP_EQ, onion_pending_add(circ_ntor, create_ntor1));
+ tt_int_op(1,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_TAP));
+ tt_int_op(1,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR));
+ tt_int_op(1,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR_V3));
+
+ tt_int_op(0,OP_EQ, onion_pending_add(circ_ntor3, create_v3ntor1));
+ tt_int_op(1,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_TAP));
+ tt_int_op(2,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR));
+ tt_int_op(2,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR_V3));
+
+ tt_int_op(0,OP_EQ, onion_pending_add(circ_ntor, create_ntor2));
+ tt_int_op(1,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_TAP));
+ tt_int_op(3,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR));
+ tt_int_op(3,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR_V3));
+
+ tt_int_op(0,OP_EQ, onion_pending_add(circ_ntor3, create_v3ntor2));
+ tt_int_op(1,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_TAP));
+ tt_int_op(4,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR));
+ tt_int_op(4,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR_V3));
+
+ /* Now remove 5 tasks, ensuring order and queue sizes */
+ tt_ptr_op(circ_ntor, OP_EQ, onion_next_task(&onionskin));
+ tt_int_op(1,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_TAP));
+ tt_int_op(3,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR));
+ tt_int_op(3,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR_V3));
+ tt_ptr_op(onionskin, OP_EQ, create_ntor1);
+
+ tt_ptr_op(circ_ntor3, OP_EQ, onion_next_task(&onionskin));
+ tt_int_op(1,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_TAP));
+ tt_int_op(2,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR));
+ tt_int_op(2,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR_V3));
+ tt_ptr_op(onionskin, OP_EQ, create_v3ntor1);
+
+ tt_ptr_op(circ_ntor, OP_EQ, onion_next_task(&onionskin));
+ tt_int_op(1,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_TAP));
+ tt_int_op(1,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR));
+ tt_int_op(1,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR_V3));
+ tt_ptr_op(onionskin, OP_EQ, create_ntor2);
+
+ tt_ptr_op(circ_ntor3, OP_EQ, onion_next_task(&onionskin));
+ tt_int_op(1,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_TAP));
+ tt_int_op(0,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR));
+ tt_int_op(0,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR_V3));
+ tt_ptr_op(onionskin, OP_EQ, create_v3ntor2);
+
+ tt_ptr_op(circ_tap, OP_EQ, onion_next_task(&onionskin));
+ tt_int_op(0,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_TAP));
+ tt_int_op(0,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR));
+ tt_int_op(0,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR_V3));
+ tt_ptr_op(onionskin, OP_EQ, create_tap1);
+
+ clear_pending_onions();
+ tt_int_op(0,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_TAP));
+ tt_int_op(0,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR));
+
+ done:
+ circuit_free_(TO_CIRCUIT(circ_tap));
+ circuit_free_(TO_CIRCUIT(circ_ntor));
+ circuit_free_(TO_CIRCUIT(circ_ntor3));
+ tor_free(create_tap1);
+ tor_free(create_ntor1);
+ tor_free(create_ntor2);
+ tor_free(create_v3ntor1);
+ tor_free(create_v3ntor2);
+}
+
+static int32_t cbtnummodes = 10;
+
+static int32_t
+mock_xm_networkstatus_get_param(
+ const networkstatus_t *ns, const char *param_name, int32_t default_val,
+ int32_t min_val, int32_t max_val)
+{
+ (void)ns;
+ (void)default_val;
+ (void)min_val;
+ (void)max_val;
+ // only support cbtnummodes right now
+ tor_assert(strcmp(param_name, "cbtnummodes")==0);
+ return cbtnummodes;
+}
+
+static void
+test_circuit_timeout_xm_alpha(void *arg)
+{
+ circuit_build_times_t cbt;
+ build_time_t Xm;
+ int alpha_ret;
+ circuit_build_times_init(&cbt);
+ (void)arg;
+
+ /* Plan:
+ * 1. Create array of build times with 10 modes.
+ * 2. Make sure Xm calc is sane for 1,3,5,10,15,20 modes.
+ * 3. Make sure alpha calc is sane for 1,3,5,10,15,20 modes.
+ */
+
+ /* 110 build times, 9 modes, 8 mode ties, 10 abandoned */
+ build_time_t circuit_build_times[] = {
+ 100, 20, 1000, 500, 200, 5000, 30, 600, 200, 300, CBT_BUILD_ABANDONED,
+ 101, 21, 1001, 501, 201, 5001, 31, 601, 201, 301, CBT_BUILD_ABANDONED,
+ 102, 22, 1002, 502, 202, 5002, 32, 602, 202, 302, CBT_BUILD_ABANDONED,
+ 103, 23, 1003, 503, 203, 5003, 33, 603, 203, 303, CBT_BUILD_ABANDONED,
+ 104, 24, 1004, 504, 204, 5004, 34, 604, 204, 304, CBT_BUILD_ABANDONED,
+ 105, 25, 1005, 505, 205, 5005, 35, 605, 205, 305, CBT_BUILD_ABANDONED,
+ 106, 26, 1006, 506, 206, 5006, 36, 606, 206, 306, CBT_BUILD_ABANDONED,
+ 107, 27, 1007, 507, 207, 5007, 37, 607, 207, 307, CBT_BUILD_ABANDONED,
+ 108, 28, 1008, 508, 208, 5008, 38, 608, 208, 308, CBT_BUILD_ABANDONED,
+ 109, 29, 1009, 509, 209, 5009, 39, 609, 209, 309, CBT_BUILD_ABANDONED
+ };
+
+ memcpy(cbt.circuit_build_times, circuit_build_times,
+ sizeof(circuit_build_times));
+ cbt.total_build_times = 110;
+
+ MOCK(networkstatus_get_param, mock_xm_networkstatus_get_param);
+
+#define CBT_ALPHA_PRECISION 0.00001
+ cbtnummodes = 1;
+ Xm = circuit_build_times_get_xm(&cbt);
+ alpha_ret = circuit_build_times_update_alpha(&cbt);
+ tt_int_op(alpha_ret, OP_EQ, 1);
+ tt_int_op(Xm, OP_EQ, 205);
+ tt_assert(fabs(cbt.alpha - 1.394401) < CBT_ALPHA_PRECISION);
+
+ cbtnummodes = 3;
+ Xm = circuit_build_times_get_xm(&cbt);
+ alpha_ret = circuit_build_times_update_alpha(&cbt);
+ tt_int_op(alpha_ret, OP_EQ, 1);
+ tt_int_op(Xm, OP_EQ, 117);
+ tt_assert(fabs(cbt.alpha - 0.902313) < CBT_ALPHA_PRECISION);
+
+ cbtnummodes = 5;
+ Xm = circuit_build_times_get_xm(&cbt);
+ alpha_ret = circuit_build_times_update_alpha(&cbt);
+ tt_int_op(alpha_ret, OP_EQ, 1);
+ tt_int_op(Xm, OP_EQ, 146);
+ tt_assert(fabs(cbt.alpha - 1.049032) < CBT_ALPHA_PRECISION);
+
+ cbtnummodes = 10;
+ Xm = circuit_build_times_get_xm(&cbt);
+ alpha_ret = circuit_build_times_update_alpha(&cbt);
+ tt_int_op(alpha_ret, OP_EQ, 1);
+ tt_int_op(Xm, OP_EQ, 800);
+ tt_assert(fabs(cbt.alpha - 4.851754) < CBT_ALPHA_PRECISION);
+
+ cbtnummodes = 15;
+ Xm = circuit_build_times_get_xm(&cbt);
+ alpha_ret = circuit_build_times_update_alpha(&cbt);
+ tt_int_op(alpha_ret, OP_EQ, 1);
+ tt_int_op(Xm, OP_EQ, 800);
+ tt_assert(fabs(cbt.alpha - 4.851754) < CBT_ALPHA_PRECISION);
+
+ cbtnummodes = 20;
+ Xm = circuit_build_times_get_xm(&cbt);
+ alpha_ret = circuit_build_times_update_alpha(&cbt);
+ tt_int_op(alpha_ret, OP_EQ, 1);
+ tt_int_op(Xm, OP_EQ, 800);
+ tt_assert(fabs(cbt.alpha - 4.851754) < CBT_ALPHA_PRECISION);
+
+ done:
+#undef CBT_ALPHA_PRECISION
+ UNMOCK(networkstatus_get_param);
+ circuit_build_times_free_timeouts(&cbt);
+}
+
static void
test_circuit_timeout(void *arg)
{
@@ -373,7 +589,6 @@ test_circuit_timeout(void *arg)
double timeout1, timeout2;
or_state_t *state=NULL;
int i, runs;
- double close_ms;
(void)arg;
initialize_periodic_events();
@@ -394,18 +609,11 @@ test_circuit_timeout(void *arg)
circuit_build_times_initial_alpha(&initial,
CBT_DEFAULT_QUANTILE_CUTOFF/100.0,
timeout0);
- close_ms = MAX(circuit_build_times_calculate_timeout(&initial,
- CBT_DEFAULT_CLOSE_QUANTILE/100.0),
- CBT_DEFAULT_TIMEOUT_INITIAL_VALUE);
do {
for (i=0; i < CBT_DEFAULT_MIN_CIRCUITS_TO_OBSERVE; i++) {
build_time_t sample = circuit_build_times_generate_sample(&initial,0,1);
- if (sample > close_ms) {
- circuit_build_times_add_time(&estimate, CBT_BUILD_ABANDONED);
- } else {
- circuit_build_times_add_time(&estimate, sample);
- }
+ circuit_build_times_add_time(&estimate, sample);
}
circuit_build_times_update_alpha(&estimate);
timeout1 = circuit_build_times_calculate_timeout(&estimate,
@@ -526,127 +734,6 @@ test_circuit_timeout(void *arg)
testing_disable_deterministic_rng();
}
-/** Test encoding and parsing of rendezvous service descriptors. */
-static void
-test_rend_fns(void *arg)
-{
- rend_service_descriptor_t *generated = NULL, *parsed = NULL;
- char service_id[DIGEST_LEN];
- char service_id_base32[REND_SERVICE_ID_LEN_BASE32+1];
- const char *next_desc;
- smartlist_t *descs = smartlist_new();
- char computed_desc_id[DIGEST_LEN];
- char parsed_desc_id[DIGEST_LEN];
- crypto_pk_t *pk1 = NULL, *pk2 = NULL;
- time_t now;
- char *intro_points_encrypted = NULL;
- size_t intro_points_size;
- size_t encoded_size;
- int i;
-
- (void)arg;
-
- /* Initialize the service cache. */
- rend_cache_init();
-
- pk1 = pk_generate(0);
- pk2 = pk_generate(1);
- generated = tor_malloc_zero(sizeof(rend_service_descriptor_t));
- generated->pk = crypto_pk_dup_key(pk1);
- crypto_pk_get_digest(generated->pk, service_id);
- base32_encode(service_id_base32, REND_SERVICE_ID_LEN_BASE32+1,
- service_id, REND_SERVICE_ID_LEN);
- now = time(NULL);
- generated->timestamp = now;
- generated->version = 2;
- generated->protocols = 42;
- generated->intro_nodes = smartlist_new();
-
- for (i = 0; i < 3; i++) {
- rend_intro_point_t *intro = tor_malloc_zero(sizeof(rend_intro_point_t));
- crypto_pk_t *okey = pk_generate(2 + i);
- intro->extend_info =
- extend_info_new(NULL, NULL, NULL, NULL, NULL, NULL, 0);
- intro->extend_info->onion_key = okey;
- crypto_pk_get_digest(intro->extend_info->onion_key,
- intro->extend_info->identity_digest);
- //crypto_rand(info->identity_digest, DIGEST_LEN); /* Would this work? */
- intro->extend_info->nickname[0] = '$';
- base16_encode(intro->extend_info->nickname + 1,
- sizeof(intro->extend_info->nickname) - 1,
- intro->extend_info->identity_digest, DIGEST_LEN);
- tor_addr_t addr;
- uint16_t port;
- /* Does not cover all IP addresses. */
- tor_addr_from_ipv4h(&addr, crypto_rand_int(65536) + 1);
- port = 1 + crypto_rand_int(65535);
- extend_info_add_orport(intro->extend_info, &addr, port);
- intro->intro_key = crypto_pk_dup_key(pk2);
- smartlist_add(generated->intro_nodes, intro);
- }
- int rv = rend_encode_v2_descriptors(descs, generated, now, 0,
- REND_NO_AUTH, NULL, NULL);
- tt_int_op(rv, OP_GT, 0);
- rv = rend_compute_v2_desc_id(computed_desc_id, service_id_base32, NULL,
- now, 0);
- tt_int_op(rv, OP_EQ, 0);
- tt_mem_op(((rend_encoded_v2_service_descriptor_t *)
- smartlist_get(descs, 0))->desc_id, OP_EQ,
- computed_desc_id, DIGEST_LEN);
- rv = rend_parse_v2_service_descriptor(&parsed, parsed_desc_id,
- &intro_points_encrypted, &intro_points_size, &encoded_size,
- &next_desc,
- ((rend_encoded_v2_service_descriptor_t *)smartlist_get(descs, 0))
- ->desc_str, 1);
- tt_int_op(rv, OP_EQ, 0);
- tt_assert(parsed);
- tt_mem_op(((rend_encoded_v2_service_descriptor_t *)
- smartlist_get(descs, 0))->desc_id,OP_EQ, parsed_desc_id, DIGEST_LEN);
- tt_int_op(rend_parse_introduction_points(parsed, intro_points_encrypted,
- intro_points_size),OP_EQ, 3);
- tt_assert(!crypto_pk_cmp_keys(generated->pk, parsed->pk));
- tt_int_op(parsed->timestamp,OP_EQ, now);
- tt_int_op(parsed->version,OP_EQ, 2);
- tt_int_op(parsed->protocols,OP_EQ, 42);
- tt_int_op(smartlist_len(parsed->intro_nodes),OP_EQ, 3);
- for (i = 0; i < smartlist_len(parsed->intro_nodes); i++) {
- rend_intro_point_t *par_intro = smartlist_get(parsed->intro_nodes, i),
- *gen_intro = smartlist_get(generated->intro_nodes, i);
- extend_info_t *par_info = par_intro->extend_info;
- extend_info_t *gen_info = gen_intro->extend_info;
- tt_assert(!crypto_pk_cmp_keys(gen_info->onion_key, par_info->onion_key));
- tt_mem_op(gen_info->identity_digest,OP_EQ, par_info->identity_digest,
- DIGEST_LEN);
- tt_str_op(gen_info->nickname,OP_EQ, par_info->nickname);
- const tor_addr_port_t *a1, *a2;
- a1 = extend_info_get_orport(gen_info, AF_INET);
- a2 = extend_info_get_orport(par_info, AF_INET);
- tt_assert(a1 && a2);
- tt_assert(tor_addr_eq(&a1->addr, &a2->addr));
- tt_int_op(a2->port,OP_EQ, a2->port);
- }
-
- rend_service_descriptor_free(parsed);
- rend_service_descriptor_free(generated);
- parsed = generated = NULL;
-
- done:
- if (descs) {
- for (i = 0; i < smartlist_len(descs); i++)
- rend_encoded_v2_service_descriptor_free_(smartlist_get(descs, i));
- smartlist_free(descs);
- }
- if (parsed)
- rend_service_descriptor_free(parsed);
- if (generated)
- rend_service_descriptor_free(generated);
- if (pk1)
- crypto_pk_free(pk1);
- if (pk2)
- crypto_pk_free(pk2);
- tor_free(intro_points_encrypted);
-}
-
#define ENT(name) \
{ #name, test_ ## name , 0, NULL, NULL }
#define FORK(name) \
@@ -656,10 +743,11 @@ static struct testcase_t test_array[] = {
ENT(onion_handshake),
{ "bad_onion_handshake", test_bad_onion_handshake, 0, NULL, NULL },
ENT(onion_queues),
+ ENT(onion_queue_order),
{ "ntor_handshake", test_ntor_handshake, 0, NULL, NULL },
{ "fast_handshake", test_fast_handshake, 0, NULL, NULL },
FORK(circuit_timeout),
- FORK(rend_fns),
+ FORK(circuit_timeout_xm_alpha),
END_OF_TESTCASES
};
@@ -707,6 +795,7 @@ struct testgroup_t testgroups[] = {
{ "crypto/pem/", pem_tests },
{ "crypto/rng/", crypto_rng_tests },
{ "dir/", dir_tests },
+ { "dir/auth/ports/", dirauth_port_tests },
{ "dir/auth/process_descs/", process_descs_tests },
{ "dir/md/", microdesc_tests },
{ "dirauth/dirvote/", dirvote_tests},
@@ -734,15 +823,14 @@ struct testgroup_t testgroups[] = {
{ "hs_ntor/", hs_ntor_tests },
{ "hs_ob/", hs_ob_tests },
{ "hs_service/", hs_service_tests },
- { "introduce/", introduce_tests },
{ "keypin/", keypin_tests },
- { "legacy_hs/", hs_tests },
{ "link-handshake/", link_handshake_tests },
{ "mainloop/", mainloop_tests },
{ "metrics/", metrics_tests },
{ "netinfo/", netinfo_tests },
{ "nodelist/", nodelist_tests },
{ "oom/", oom_tests },
+ { "onion-handshake/ntor-v3/", ntor_v3_tests },
{ "oos/", oos_tests },
{ "options/", options_tests },
{ "options/act/", options_act_tests },
@@ -762,12 +850,14 @@ struct testgroup_t testgroups[] = {
{ "relay/" , relay_tests },
{ "relaycell/", relaycell_tests },
{ "relaycrypt/", relaycrypt_tests },
- { "rend_cache/", rend_cache_tests },
{ "replaycache/", replaycache_tests },
{ "router/", router_tests },
{ "routerkeys/", routerkeys_tests },
{ "routerlist/", routerlist_tests },
{ "routerset/" , routerset_tests },
+#ifdef USE_LIBSECCOMP
+ { "sandbox/" , sandbox_tests },
+#endif
{ "scheduler/", scheduler_tests },
{ "sendme/", sendme_tests },
{ "shared-random/", sr_tests },
diff --git a/src/test/test.h b/src/test/test.h
index 56037648d3..e17bce427c 100644
--- a/src/test/test.h
+++ b/src/test/test.h
@@ -1,6 +1,6 @@
/* Copyright (c) 2001-2003, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#ifndef TOR_TEST_H
@@ -120,6 +120,7 @@ extern struct testcase_t crypto_ope_tests[];
extern struct testcase_t crypto_openssl_tests[];
extern struct testcase_t crypto_rng_tests[];
extern struct testcase_t crypto_tests[];
+extern struct testcase_t dirauth_port_tests[];
extern struct testcase_t dir_handle_get_tests[];
extern struct testcase_t dir_tests[];
extern struct testcase_t dirvote_tests[];
@@ -145,8 +146,6 @@ 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_service_tests[];
-extern struct testcase_t hs_tests[];
-extern struct testcase_t introduce_tests[];
extern struct testcase_t keypin_tests[];
extern struct testcase_t link_handshake_tests[];
extern struct testcase_t logging_tests[];
@@ -156,6 +155,7 @@ extern struct testcase_t microdesc_tests[];
extern struct testcase_t namemap_tests[];
extern struct testcase_t netinfo_tests[];
extern struct testcase_t nodelist_tests[];
+extern struct testcase_t ntor_v3_tests[];
extern struct testcase_t oom_tests[];
extern struct testcase_t oos_tests[];
extern struct testcase_t options_tests[];
@@ -179,12 +179,12 @@ extern struct testcase_t pubsub_msg_tests[];
extern struct testcase_t relay_tests[];
extern struct testcase_t relaycell_tests[];
extern struct testcase_t relaycrypt_tests[];
-extern struct testcase_t rend_cache_tests[];
extern struct testcase_t replaycache_tests[];
extern struct testcase_t router_tests[];
extern struct testcase_t routerkeys_tests[];
extern struct testcase_t routerlist_tests[];
extern struct testcase_t routerset_tests[];
+extern struct testcase_t sandbox_tests[];
extern struct testcase_t scheduler_tests[];
extern struct testcase_t sendme_tests[];
extern struct testcase_t socks_tests[];
diff --git a/src/test/test_accounting.c b/src/test/test_accounting.c
index 7933df5e35..4cc2c0733c 100644
--- a/src/test/test_accounting.c
+++ b/src/test/test_accounting.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2020, The Tor Project, Inc. */
+/* Copyright (c) 2014-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "core/or/or.h"
diff --git a/src/test/test_addr.c b/src/test/test_addr.c
index dbc581288d..f368326902 100644
--- a/src/test/test_addr.c
+++ b/src/test/test_addr.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define ADDRESSMAP_PRIVATE
diff --git a/src/test/test_address.c b/src/test/test_address.c
index e7007f22f3..015ca0807c 100644
--- a/src/test/test_address.c
+++ b/src/test/test_address.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2020, The Tor Project, Inc. */
+/* Copyright (c) 2014-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define ADDRESS_PRIVATE
@@ -1326,6 +1326,42 @@ test_address_dirserv_router_addr_private(void *opt_dir_allow_private)
UNMOCK(get_options);
}
+static void
+test_address_parse_port_range(void *arg)
+{
+ int ret;
+ uint16_t min_out = 0;
+ uint16_t max_out = 0;
+
+ (void) arg;
+
+ /* Invalid. */
+ ret = parse_port_range("0x00", &min_out, &max_out);
+ tt_int_op(ret, OP_EQ, -1);
+ ret = parse_port_range("0x01", &min_out, &max_out);
+ tt_int_op(ret, OP_EQ, -1);
+ ret = parse_port_range("1817161", &min_out, &max_out);
+ tt_int_op(ret, OP_EQ, -1);
+ ret = parse_port_range("65536", &min_out, &max_out);
+ tt_int_op(ret, OP_EQ, -1);
+ ret = parse_port_range("1-65536", &min_out, &max_out);
+ tt_int_op(ret, OP_EQ, -1);
+
+ /* Valid. */
+ ret = parse_port_range("65535", &min_out, &max_out);
+ tt_int_op(ret, OP_EQ, 0);
+ tt_int_op(min_out, OP_EQ, 65535);
+ tt_int_op(max_out, OP_EQ, 65535);
+
+ ret = parse_port_range("1-65535", &min_out, &max_out);
+ tt_int_op(ret, OP_EQ, 0);
+ tt_int_op(min_out, OP_EQ, 1);
+ tt_int_op(max_out, OP_EQ, 65535);
+
+ done:
+ ;
+}
+
#define ADDRESS_TEST(name, flags) \
{ #name, test_address_ ## name, flags, NULL, NULL }
#define ADDRESS_TEST_STR_ARG(name, flags, str_arg) \
@@ -1364,5 +1400,6 @@ struct testcase_t address_tests[] = {
ADDRESS_TEST(tor_node_in_same_network_family, 0),
ADDRESS_TEST(dirserv_router_addr_private, 0),
ADDRESS_TEST_STR_ARG(dirserv_router_addr_private, 0, "allow_private"),
+ ADDRESS_TEST(parse_port_range, 0),
END_OF_TESTCASES
};
diff --git a/src/test/test_address_set.c b/src/test/test_address_set.c
index 37688f4c1d..6860906791 100644
--- a/src/test/test_address_set.c
+++ b/src/test/test_address_set.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017-2020, The Tor Project, Inc. */
+/* Copyright (c) 2017-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "core/or/or.h"
diff --git a/src/test/test_bridges.c b/src/test/test_bridges.c
index 1942a8cb89..f778710e1b 100644
--- a/src/test/test_bridges.c
+++ b/src/test/test_bridges.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2018-2020, The Tor Project, Inc. */
+/* Copyright (c) 2018-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/test/test_bt_cl.c b/src/test/test_bt_cl.c
index 5f9a88705c..fd3778d801 100644
--- a/src/test/test_bt_cl.c
+++ b/src/test/test_bt_cl.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2020, The Tor Project, Inc. */
+/* Copyright (c) 2012-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
diff --git a/src/test/test_btrack.c b/src/test/test_btrack.c
index 2b2f34fc23..16fe7c4bd7 100644
--- a/src/test/test_btrack.c
+++ b/src/test/test_btrack.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2020, The Tor Project, Inc. */
+/* Copyright (c) 2013-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "core/or/or.h"
diff --git a/src/test/test_buffers.c b/src/test/test_buffers.c
index fbaa628fd7..888adb4956 100644
--- a/src/test/test_buffers.c
+++ b/src/test/test_buffers.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define BUFFERS_PRIVATE
diff --git a/src/test/test_bwmgt.c b/src/test/test_bwmgt.c
index 4cf83e45d0..a034c369d1 100644
--- a/src/test/test_bwmgt.c
+++ b/src/test/test_bwmgt.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2018-2020, The Tor Project, Inc. */
+/* Copyright (c) 2018-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/test/test_cell_formats.c b/src/test/test_cell_formats.c
index cae25d00ec..b7b149cd66 100644
--- a/src/test/test_cell_formats.c
+++ b/src/test/test_cell_formats.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
diff --git a/src/test/test_cell_queue.c b/src/test/test_cell_queue.c
index b778c07802..d9a002c594 100644
--- a/src/test/test_cell_queue.c
+++ b/src/test/test_cell_queue.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2020, The Tor Project, Inc. */
+/* Copyright (c) 2013-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define CIRCUITLIST_PRIVATE
diff --git a/src/test/test_channel.c b/src/test/test_channel.c
index d43f6e010a..a74d69fefc 100644
--- a/src/test/test_channel.c
+++ b/src/test/test_channel.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2020, The Tor Project, Inc. */
+/* Copyright (c) 2013-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define CHANNEL_OBJECT_PRIVATE
diff --git a/src/test/test_channelpadding.c b/src/test/test_channelpadding.c
index 63a591583d..261e1f8a37 100644
--- a/src/test/test_channelpadding.c
+++ b/src/test/test_channelpadding.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2020, The Tor Project, Inc. */
+/* Copyright (c) 2016-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define CHANNEL_OBJECT_PRIVATE
diff --git a/src/test/test_channeltls.c b/src/test/test_channeltls.c
index 0227779e8b..ca7fee2c53 100644
--- a/src/test/test_channeltls.c
+++ b/src/test/test_channeltls.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2020, The Tor Project, Inc. */
+/* Copyright (c) 2014-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
@@ -20,6 +20,7 @@
#include "lib/tls/tortls.h"
#include "core/or/or_connection_st.h"
+#include "core/or/congestion_control_common.h"
/* Test suite stuff */
#include "test/test.h"
@@ -155,7 +156,7 @@ test_channeltls_num_bytes_queued(void *arg)
* - 2 cells.
*/
n = ch->num_cells_writeable(ch);
- tt_int_op(n, OP_EQ, CEIL_DIV(OR_CONN_HIGHWATER, 512) - 2);
+ tt_int_op(n, OP_EQ, CEIL_DIV(or_conn_highwatermark(), 512) - 2);
UNMOCK(buf_datalen);
tlschan_buf_datalen_mock_target = NULL;
tlschan_buf_datalen_mock_size = 0;
diff --git a/src/test/test_checkdir.c b/src/test/test_checkdir.c
index 186a55cc8c..5579be7206 100644
--- a/src/test/test_checkdir.c
+++ b/src/test/test_checkdir.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2020, The Tor Project, Inc. */
+/* Copyright (c) 2014-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
diff --git a/src/test/test_circuitbuild.c b/src/test/test_circuitbuild.c
index 299908ce82..0a5c3530bd 100644
--- a/src/test/test_circuitbuild.c
+++ b/src/test/test_circuitbuild.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define CIRCUITBUILD_PRIVATE
@@ -113,7 +113,7 @@ test_new_route_len_safe_exit(void *arg)
/* hidden service connecting to introduction point */
r = new_route_len(CIRCUIT_PURPOSE_S_ESTABLISH_INTRO, &dummy_ei,
&dummy_nodes);
- tt_int_op(DEFAULT_ROUTE_LEN, OP_EQ, r);
+ tt_int_op(DEFAULT_ROUTE_LEN+1, OP_EQ, r);
/* router testing its own reachability */
r = new_route_len(CIRCUIT_PURPOSE_TESTING, &dummy_ei, &dummy_nodes);
diff --git a/src/test/test_circuitlist.c b/src/test/test_circuitlist.c
index 63c4418f29..4bcff57fc3 100644
--- a/src/test/test_circuitlist.c
+++ b/src/test/test_circuitlist.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2020, The Tor Project, Inc. */
+/* Copyright (c) 2013-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define CHANNEL_OBJECT_PRIVATE
@@ -203,6 +203,10 @@ test_rend_token_maps(void *arg)
c4 = or_circuit_new(0, NULL);
c5 = origin_circuit_new();
+ ed25519_public_key_t intro_pk1 = { {1} }; /* Junk, not important. */
+ ed25519_public_key_t intro_pk2 = { {2} }; /* Junk, not important. */
+ ed25519_public_key_t intro_pk3 = { {3} }; /* Junk, not important. */
+
/* Make sure we really filled up the tok* variables */
tt_int_op(tok1[REND_TOKEN_LEN-1], OP_EQ, 'y');
tt_int_op(tok2[REND_TOKEN_LEN-1], OP_EQ, ' ');
@@ -210,31 +214,37 @@ test_rend_token_maps(void *arg)
/* No maps; nothing there. */
tt_ptr_op(NULL, OP_EQ, hs_circuitmap_get_rend_circ_relay_side(tok1));
- tt_ptr_op(NULL, OP_EQ, hs_circuitmap_get_intro_circ_v2_relay_side(tok1));
+ tt_ptr_op(NULL, OP_EQ,
+ hs_circuitmap_get_intro_circ_v3_relay_side(&intro_pk1));
hs_circuitmap_register_rend_circ_relay_side(c1, tok1);
- hs_circuitmap_register_intro_circ_v2_relay_side(c2, tok2);
+ hs_circuitmap_register_intro_circ_v3_relay_side(c2, &intro_pk2);
tt_ptr_op(NULL, OP_EQ, hs_circuitmap_get_rend_circ_relay_side(tok3));
- tt_ptr_op(NULL, OP_EQ, hs_circuitmap_get_intro_circ_v2_relay_side(tok3));
+ tt_ptr_op(NULL, OP_EQ,
+ hs_circuitmap_get_intro_circ_v3_relay_side(&intro_pk3));
tt_ptr_op(NULL, OP_EQ, hs_circuitmap_get_rend_circ_relay_side(tok2));
- tt_ptr_op(NULL, OP_EQ, hs_circuitmap_get_intro_circ_v2_relay_side(tok1));
+ tt_ptr_op(NULL, OP_EQ,
+ hs_circuitmap_get_intro_circ_v3_relay_side(&intro_pk2));
/* Without purpose set, we don't get the circuits */
tt_ptr_op(NULL, OP_EQ, hs_circuitmap_get_rend_circ_relay_side(tok1));
- tt_ptr_op(NULL, OP_EQ, hs_circuitmap_get_intro_circ_v2_relay_side(tok2));
+ tt_ptr_op(NULL, OP_EQ,
+ hs_circuitmap_get_intro_circ_v3_relay_side(&intro_pk2));
c1->base_.purpose = CIRCUIT_PURPOSE_REND_POINT_WAITING;
c2->base_.purpose = CIRCUIT_PURPOSE_INTRO_POINT;
/* Okay, make sure they show up now. */
tt_ptr_op(c1, OP_EQ, hs_circuitmap_get_rend_circ_relay_side(tok1));
- tt_ptr_op(c2, OP_EQ, hs_circuitmap_get_intro_circ_v2_relay_side(tok2));
+ tt_ptr_op(c2, OP_EQ,
+ hs_circuitmap_get_intro_circ_v3_relay_side(&intro_pk2));
/* Two items at the same place with the same token. */
c3->base_.purpose = CIRCUIT_PURPOSE_REND_POINT_WAITING;
hs_circuitmap_register_rend_circ_relay_side(c3, tok2);
- tt_ptr_op(c2, OP_EQ, hs_circuitmap_get_intro_circ_v2_relay_side(tok2));
+ tt_ptr_op(c2, OP_EQ,
+ hs_circuitmap_get_intro_circ_v3_relay_side(&intro_pk2));
tt_ptr_op(c3, OP_EQ, hs_circuitmap_get_rend_circ_relay_side(tok2));
/* Marking a circuit makes it not get returned any more */
@@ -246,31 +256,36 @@ test_rend_token_maps(void *arg)
/* Freeing a circuit makes it not get returned any more. */
circuit_free_(TO_CIRCUIT(c2));
c2 = NULL;
- tt_ptr_op(NULL, OP_EQ, hs_circuitmap_get_intro_circ_v2_relay_side(tok2));
+ tt_ptr_op(NULL, OP_EQ,
+ hs_circuitmap_get_intro_circ_v3_relay_side(&intro_pk2));
/* c3 -- are you still there? */
tt_ptr_op(c3, OP_EQ, hs_circuitmap_get_rend_circ_relay_side(tok2));
/* Change its cookie. This never happens in Tor per se, but hey. */
c3->base_.purpose = CIRCUIT_PURPOSE_INTRO_POINT;
- hs_circuitmap_register_intro_circ_v2_relay_side(c3, tok3);
+ hs_circuitmap_register_intro_circ_v3_relay_side(c3, &intro_pk3);
tt_ptr_op(NULL, OP_EQ, hs_circuitmap_get_rend_circ_relay_side(tok2));
- tt_ptr_op(c3, OP_EQ, hs_circuitmap_get_intro_circ_v2_relay_side(tok3));
+ tt_ptr_op(c3, OP_EQ,
+ hs_circuitmap_get_intro_circ_v3_relay_side(&intro_pk3));
/* Now replace c3 with c4. */
c4->base_.purpose = CIRCUIT_PURPOSE_INTRO_POINT;
- hs_circuitmap_register_intro_circ_v2_relay_side(c4, tok3);
+ hs_circuitmap_register_intro_circ_v3_relay_side(c4, &intro_pk3);
- tt_ptr_op(c4, OP_EQ, hs_circuitmap_get_intro_circ_v2_relay_side(tok3));
+ tt_ptr_op(c4, OP_EQ,
+ hs_circuitmap_get_intro_circ_v3_relay_side(&intro_pk3));
tt_ptr_op(TO_CIRCUIT(c3)->hs_token, OP_EQ, NULL);
tt_ptr_op(TO_CIRCUIT(c4)->hs_token, OP_NE, NULL);
- tt_mem_op(TO_CIRCUIT(c4)->hs_token->token, OP_EQ, tok3, REND_TOKEN_LEN);
+ tt_mem_op(TO_CIRCUIT(c4)->hs_token->token, OP_EQ, &intro_pk3,
+ REND_TOKEN_LEN);
/* Now clear c4's cookie. */
hs_circuitmap_remove_circuit(TO_CIRCUIT(c4));
tt_ptr_op(TO_CIRCUIT(c4)->hs_token, OP_EQ, NULL);
- tt_ptr_op(NULL, OP_EQ, hs_circuitmap_get_intro_circ_v2_relay_side(tok3));
+ tt_ptr_op(NULL, OP_EQ,
+ hs_circuitmap_get_intro_circ_v3_relay_side(&intro_pk3));
/* Now let's do a check for the client-side rend circuitmap */
c5->base_.purpose = CIRCUIT_PURPOSE_C_ESTABLISH_REND;
@@ -401,6 +416,9 @@ test_hs_circuitmap_isolation(void *arg)
hs_circuitmap_init();
+ ed25519_public_key_t intro_pk1 = { {1} }; /* Junk, not important. */
+ ed25519_public_key_t intro_pk2 = { {2} }; /* Junk, not important. */
+
{
const uint8_t tok1[REND_TOKEN_LEN] = "bet i got some of th";
@@ -416,7 +434,8 @@ test_hs_circuitmap_isolation(void *arg)
/* check that service-side getters don't work */
tt_ptr_op(NULL, OP_EQ, hs_circuitmap_get_rend_circ_service_side(tok1));
- tt_ptr_op(NULL, OP_EQ, hs_circuitmap_get_intro_circ_v2_service_side(tok1));
+ tt_ptr_op(NULL, OP_EQ,
+ hs_circuitmap_get_intro_circ_v3_service_side(&intro_pk1));
/* Check that the right getter works. */
tt_ptr_op(circ1, OP_EQ, hs_circuitmap_get_rend_circ_relay_side(tok1));
@@ -436,17 +455,18 @@ test_hs_circuitmap_isolation(void *arg)
circ4->base_.purpose = CIRCUIT_PURPOSE_S_ESTABLISH_INTRO;
/* Register circ2 with tok2 as service-side intro v2 circ */
- hs_circuitmap_register_intro_circ_v2_service_side(circ2, tok2);
+ hs_circuitmap_register_intro_circ_v3_service_side(circ2, &intro_pk2);
/* Register circ3 with tok2 again but for different purpose */
- hs_circuitmap_register_intro_circ_v2_relay_side(circ3, tok2);
+ hs_circuitmap_register_intro_circ_v3_relay_side(circ3, &intro_pk2);
/* Check that the getters work */
tt_ptr_op(circ2, OP_EQ,
- hs_circuitmap_get_intro_circ_v2_service_side(tok2));
- tt_ptr_op(circ3, OP_EQ, hs_circuitmap_get_intro_circ_v2_relay_side(tok2));
+ hs_circuitmap_get_intro_circ_v3_service_side(&intro_pk2));
+ tt_ptr_op(circ3, OP_EQ,
+ hs_circuitmap_get_intro_circ_v3_relay_side(&intro_pk2));
/* Register circ4 with tok2: it should override circ2 */
- hs_circuitmap_register_intro_circ_v2_service_side(circ4, tok2);
+ hs_circuitmap_register_intro_circ_v3_service_side(circ4, &intro_pk2);
/* check that relay-side getters don't work */
tt_ptr_op(NULL, OP_EQ, hs_circuitmap_get_rend_circ_relay_side(tok2));
@@ -454,7 +474,7 @@ test_hs_circuitmap_isolation(void *arg)
/* Check that the getter returns circ4; the last circuit registered with
* that token. */
tt_ptr_op(circ4, OP_EQ,
- hs_circuitmap_get_intro_circ_v2_service_side(tok2));
+ hs_circuitmap_get_intro_circ_v3_service_side(&intro_pk2));
}
done:
diff --git a/src/test/test_circuitmux.c b/src/test/test_circuitmux.c
index d6e3300a30..43f0af3f5f 100644
--- a/src/test/test_circuitmux.c
+++ b/src/test/test_circuitmux.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2020, The Tor Project, Inc. */
+/* Copyright (c) 2013-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define CHANNEL_OBJECT_PRIVATE
diff --git a/src/test/test_circuitmux_ewma.c b/src/test/test_circuitmux_ewma.c
index 27601e0c7d..2a1e14eea2 100644
--- a/src/test/test_circuitmux_ewma.c
+++ b/src/test/test_circuitmux_ewma.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2020, The Tor Project, Inc. */
+/* Copyright (c) 2013-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define CIRCUITMUX_PRIVATE
diff --git a/src/test/test_circuitpadding.c b/src/test/test_circuitpadding.c
index 86baf54f40..63b7136a11 100644
--- a/src/test/test_circuitpadding.c
+++ b/src/test/test_circuitpadding.c
@@ -1367,7 +1367,7 @@ test_circuitpadding_wronghop(void *arg)
tt_ptr_op(client_side->padding_info[0], OP_NE, NULL);
tt_ptr_op(relay_side->padding_machine[0], OP_NE, NULL);
tt_ptr_op(relay_side->padding_info[0], OP_NE, NULL);
- tt_int_op(n_relay_cells, OP_EQ, 3);
+ tt_int_op(n_relay_cells, OP_EQ, 2);
tt_int_op(n_client_cells, OP_EQ, 2);
/* 6. Sending negotiated command to relay does nothing */
@@ -1396,11 +1396,9 @@ test_circuitpadding_wronghop(void *arg)
/* verify no padding was negotiated */
tt_ptr_op(relay_side->padding_machine[0], OP_EQ, NULL);
tt_ptr_op(client_side->padding_machine[0], OP_EQ, NULL);
- tt_int_op(n_relay_cells, OP_EQ, 3);
- tt_int_op(n_client_cells, OP_EQ, 2);
/* verify no echo was sent */
- tt_int_op(n_relay_cells, OP_EQ, 3);
+ tt_int_op(n_relay_cells, OP_EQ, 2);
tt_int_op(n_client_cells, OP_EQ, 2);
/* Finish circuit */
@@ -1611,7 +1609,7 @@ simulate_single_hop_extend(circuit_t *client, circuit_t *mid_relay,
hop->extend_info = extend_info_new(
padding ? "padding" : "non-padding",
digest, NULL, NULL, NULL,
- &addr, padding);
+ &addr, padding, NULL, false);
cpath_init_circuit_crypto(hop, whatevs_key, sizeof(whatevs_key), 0, 0);
diff --git a/src/test/test_circuitstats.c b/src/test/test_circuitstats.c
index 00ca1b544c..889adc1523 100644
--- a/src/test/test_circuitstats.c
+++ b/src/test/test_circuitstats.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017-2020, The Tor Project, Inc. */
+/* Copyright (c) 2017-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define CIRCUITBUILD_PRIVATE
diff --git a/src/test/test_circuituse.c b/src/test/test_circuituse.c
index 49438d9d3b..b6e945c36e 100644
--- a/src/test/test_circuituse.c
+++ b/src/test/test_circuituse.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define CIRCUITLIST_PRIVATE
diff --git a/src/test/test_compat_libevent.c b/src/test/test_compat_libevent.c
index 5376e08fb3..7295550e13 100644
--- a/src/test/test_compat_libevent.c
+++ b/src/test/test_compat_libevent.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2020, The Tor Project, Inc. */
+/* Copyright (c) 2010-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define COMPAT_LIBEVENT_PRIVATE
diff --git a/src/test/test_config.c b/src/test/test_config.c
index 1654968705..3ebe095a6a 100644
--- a/src/test/test_config.c
+++ b/src/test/test_config.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
@@ -41,8 +41,6 @@
#include "feature/nodelist/networkstatus.h"
#include "feature/nodelist/nodelist.h"
#include "core/or/policies.h"
-#include "feature/rend/rendclient.h"
-#include "feature/rend/rendservice.h"
#include "feature/relay/relay_find_addr.h"
#include "feature/relay/router.h"
#include "feature/relay/routermode.h"
@@ -1217,7 +1215,7 @@ get_interface_address6_replacement(int severity, sa_family_t family,
return 0;
}
-#endif
+#endif /* 0 */
static int n_get_interface_address6_failure = 0;
@@ -6043,7 +6041,7 @@ test_config_include_wildcards(void *data)
tt_ptr_op(result, OP_EQ, NULL);
tt_int_op(include_used, OP_EQ, 1);
config_free_lines(result);
-#endif
+#endif /* !defined(_WIN32) */
// test pattern *.conf
tor_snprintf(torrc_contents, sizeof(torrc_contents),
@@ -6183,9 +6181,9 @@ test_config_include_hidden(void *data)
len++;
}
tt_int_op(len, OP_EQ, 1);
-#else
+#else /* !defined(_WIN32) */
tt_ptr_op(result, OP_EQ, NULL);
-#endif
+#endif /* defined(_WIN32) */
config_free_lines(result);
// test wildcards match hidden folders when explicitly in the pattern
@@ -6995,7 +6993,7 @@ test_config_multifamily_port(void *arg)
#define CONFIG_TEST_SETUP(suffix, name, flags, setup, setup_data) \
{ #name#suffix, test_config_ ## name, flags, setup, setup_data }
-#endif
+#endif /* !defined(COCCI) */
struct testcase_t config_tests[] = {
CONFIG_TEST(adding_trusted_dir_server, TT_FORK),
diff --git a/src/test/test_confmgr.c b/src/test/test_confmgr.c
index a647b92e0a..00e24f6123 100644
--- a/src/test/test_confmgr.c
+++ b/src/test/test_confmgr.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/*
diff --git a/src/test/test_confparse.c b/src/test/test_confparse.c
index abd53dea68..391f6241da 100644
--- a/src/test/test_confparse.c
+++ b/src/test/test_confparse.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/*
diff --git a/src/test/test_connection.c b/src/test/test_connection.c
index cf5626ead7..fbf9d6a5ab 100644
--- a/src/test/test_connection.c
+++ b/src/test/test_connection.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2020, The Tor Project, Inc. */
+/* Copyright (c) 2015-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
@@ -19,7 +19,6 @@
#include "feature/nodelist/microdesc.h"
#include "feature/nodelist/nodelist.h"
#include "feature/nodelist/networkstatus.h"
-#include "feature/rend/rendcache.h"
#include "feature/dircommon/directory.h"
#include "core/or/connection_or.h"
#include "lib/net/resolve.h"
@@ -38,10 +37,6 @@ static void * test_conn_get_basic_setup(const struct testcase_t *tc);
static int test_conn_get_basic_teardown(const struct testcase_t *tc,
void *arg);
-static void * test_conn_get_rend_setup(const struct testcase_t *tc);
-static int test_conn_get_rend_teardown(const struct testcase_t *tc,
- void *arg);
-
static void * test_conn_get_rsrc_setup(const struct testcase_t *tc);
static int test_conn_get_rsrc_teardown(const struct testcase_t *tc,
void *arg);
@@ -179,52 +174,6 @@ test_conn_get_basic_teardown(const struct testcase_t *tc, void *arg)
return 0;
}
-static void *
-test_conn_get_rend_setup(const struct testcase_t *tc)
-{
- dir_connection_t *conn = DOWNCAST(dir_connection_t,
- test_conn_get_connection(
- TEST_CONN_STATE,
- TEST_CONN_TYPE,
- TEST_CONN_REND_PURPOSE));
- tt_assert(conn);
- assert_connection_ok(&conn->base_, time(NULL));
-
- rend_cache_init();
-
- /* TODO: use directory_initiate_request() to do this - maybe? */
- tor_assert(strlen(TEST_CONN_REND_ADDR) == REND_SERVICE_ID_LEN_BASE32);
- conn->rend_data = rend_data_client_create(TEST_CONN_REND_ADDR, NULL, NULL,
- REND_NO_AUTH);
- assert_connection_ok(&conn->base_, time(NULL));
- return conn;
-
- /* On failure */
- done:
- test_conn_get_rend_teardown(tc, conn);
- /* Returning NULL causes the unit test to fail */
- return NULL;
-}
-
-static int
-test_conn_get_rend_teardown(const struct testcase_t *tc, void *arg)
-{
- dir_connection_t *conn = DOWNCAST(dir_connection_t, arg);
- int rv = 0;
-
- tt_assert(conn);
- assert_connection_ok(&conn->base_, time(NULL));
-
- /* avoid a last-ditch attempt to refetch the descriptor */
- conn->base_.purpose = TEST_CONN_REND_PURPOSE_SUCCESSFUL;
-
- /* connection_free_() cleans up rend_data */
- rv = test_conn_get_basic_teardown(tc, arg);
- done:
- rend_cache_free_all();
- return rv;
-}
-
static dir_connection_t *
test_conn_download_status_add_a_connection(const char *resource)
{
@@ -369,10 +318,6 @@ static struct testcase_setup_t test_conn_get_basic_st = {
test_conn_get_basic_setup, test_conn_get_basic_teardown
};
-static struct testcase_setup_t test_conn_get_rend_st = {
- test_conn_get_rend_setup, test_conn_get_rend_teardown
-};
-
static struct testcase_setup_t test_conn_get_rsrc_st = {
test_conn_get_rsrc_setup, test_conn_get_rsrc_teardown
};
@@ -489,37 +434,6 @@ test_conn_get_basic(void *arg)
;
}
-static void
-test_conn_get_rend(void *arg)
-{
- dir_connection_t *conn = DOWNCAST(dir_connection_t, arg);
- tt_assert(conn);
- assert_connection_ok(&conn->base_, time(NULL));
-
- tt_assert(connection_get_by_type_state_rendquery(
- conn->base_.type,
- conn->base_.state,
- rend_data_get_address(
- conn->rend_data))
- == TO_CONN(conn));
- tt_assert(connection_get_by_type_state_rendquery(
- TEST_CONN_TYPE,
- TEST_CONN_STATE,
- TEST_CONN_REND_ADDR)
- == TO_CONN(conn));
- tt_assert(connection_get_by_type_state_rendquery(TEST_CONN_REND_TYPE_2,
- !conn->base_.state,
- "")
- == NULL);
- tt_assert(connection_get_by_type_state_rendquery(TEST_CONN_REND_TYPE_2,
- !TEST_CONN_STATE,
- TEST_CONN_REND_ADDR_2)
- == NULL);
-
- done:
- ;
-}
-
#define sl_is_conn_assert(sl_input, conn) \
do { \
the_sl = (sl_input); \
@@ -912,6 +826,7 @@ test_failed_orconn_tracker(void *arg)
/* Prepare the OR connection that will be used in this test */
or_connection_t or_conn;
+ memset(&or_conn, 0, sizeof(or_conn));
tt_int_op(AF_INET,OP_EQ, tor_addr_parse(&or_conn.canonical_orport.addr,
"18.0.0.1"));
tt_int_op(AF_INET,OP_EQ, tor_addr_parse(&or_conn.base_.addr, "18.0.0.1"));
@@ -1078,12 +993,12 @@ test_conn_describe(void *arg)
#define STR(x) #x
/* where arg is an expression (constant, variable, compound expression) */
-#define CONNECTION_TESTCASE_ARG(name, fork, setup, arg) \
- { #name "_" STR(x), \
+#define CONNECTION_TESTCASE_ARG(name, extra, fork, setup, arg) \
+ { STR(name)"/"extra, \
test_conn_##name, \
- fork, \
- &setup, \
- (void *)arg }
+ (fork), \
+ &(setup), \
+ (void *)(arg) }
#endif /* !defined(COCCI) */
static const unsigned int PROXY_CONNECT_ARG = PROXY_CONNECT;
@@ -1091,17 +1006,16 @@ static const unsigned int PROXY_HAPROXY_ARG = PROXY_HAPROXY;
struct testcase_t connection_tests[] = {
CONNECTION_TESTCASE(get_basic, TT_FORK, test_conn_get_basic_st),
- CONNECTION_TESTCASE(get_rend, TT_FORK, test_conn_get_rend_st),
CONNECTION_TESTCASE(get_rsrc, TT_FORK, test_conn_get_rsrc_st),
- CONNECTION_TESTCASE_ARG(download_status, TT_FORK,
+ CONNECTION_TESTCASE_ARG(download_status, "microdesc", TT_FORK,
test_conn_download_status_st, "microdesc"),
- CONNECTION_TESTCASE_ARG(download_status, TT_FORK,
+ CONNECTION_TESTCASE_ARG(download_status, "ns", TT_FORK,
test_conn_download_status_st, "ns"),
- CONNECTION_TESTCASE_ARG(https_proxy_connect, TT_FORK,
+ CONNECTION_TESTCASE_ARG(https_proxy_connect, "https", TT_FORK,
test_conn_proxy_connect_st, &PROXY_CONNECT_ARG),
- CONNECTION_TESTCASE_ARG(haproxy_proxy_connect, TT_FORK,
+ CONNECTION_TESTCASE_ARG(haproxy_proxy_connect, "haproxy", TT_FORK,
test_conn_proxy_connect_st, &PROXY_HAPROXY_ARG),
//CONNECTION_TESTCASE(func_suffix, TT_FORK, setup_func_pair),
diff --git a/src/test/test_connection.h b/src/test/test_connection.h
index bf327c0a3d..dc20c500dc 100644
--- a/src/test/test_connection.h
+++ b/src/test/test_connection.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2020, The Tor Project, Inc. */
+/* Copyright (c) 2014-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#ifndef TOR_TEST_CONNECTION_H
diff --git a/src/test/test_conscache.c b/src/test/test_conscache.c
index c805774fa3..5254efbf00 100644
--- a/src/test/test_conscache.c
+++ b/src/test/test_conscache.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017-2020, The Tor Project, Inc. */
+/* Copyright (c) 2017-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "core/or/or.h"
diff --git a/src/test/test_consdiff.c b/src/test/test_consdiff.c
index 242e2f7818..4527a6df3e 100644
--- a/src/test/test_consdiff.c
+++ b/src/test/test_consdiff.c
@@ -1,5 +1,5 @@
/* Copyright (c) 2014, Daniel Martí
- * Copyright (c) 2014-2020, The Tor Project, Inc. */
+ * Copyright (c) 2014-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define CONSDIFF_PRIVATE
diff --git a/src/test/test_consdiffmgr.c b/src/test/test_consdiffmgr.c
index f4adf43549..808d6f55b6 100644
--- a/src/test/test_consdiffmgr.c
+++ b/src/test/test_consdiffmgr.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017-2020, The Tor Project, Inc. */
+/* Copyright (c) 2017-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define CONSDIFFMGR_PRIVATE
diff --git a/src/test/test_containers.c b/src/test/test_containers.c
index 6072148d1b..6d390c9584 100644
--- a/src/test/test_containers.c
+++ b/src/test/test_containers.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
diff --git a/src/test/test_controller.c b/src/test/test_controller.c
index 49efeb5f88..85042e9ec2 100644
--- a/src/test/test_controller.c
+++ b/src/test/test_controller.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2020, The Tor Project, Inc. */
+/* Copyright (c) 2015-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define CONTROL_CMD_PRIVATE
@@ -16,7 +16,6 @@
#include "feature/dircache/dirserv.h"
#include "feature/hs/hs_common.h"
#include "feature/nodelist/networkstatus.h"
-#include "feature/rend/rendservice.h"
#include "feature/nodelist/authcert.h"
#include "feature/nodelist/nodelist.h"
#include "feature/stats/rephist.h"
@@ -317,110 +316,6 @@ test_add_onion_helper_keyarg_v3(void *arg)
}
static void
-test_add_onion_helper_keyarg_v2(void *arg)
-{
- int ret, hs_version;
- add_onion_secret_key_t pk;
- crypto_pk_t *pk1 = NULL;
- const char *key_new_alg = NULL;
- char *key_new_blob = NULL;
- char *encoded = NULL;
- char *arg_str = NULL;
-
- (void) arg;
- MOCK(control_write_reply, mock_control_write_reply);
-
- memset(&pk, 0, sizeof(pk));
-
- /* Test explicit RSA1024 key generation. */
- tor_free(reply_str);
- ret = add_onion_helper_keyarg("NEW:RSA1024", 0, &key_new_alg, &key_new_blob,
- &pk, &hs_version, NULL);
- tt_int_op(ret, OP_EQ, 0);
- tt_int_op(hs_version, OP_EQ, HS_VERSION_TWO);
- tt_assert(pk.v2);
- tt_str_op(key_new_alg, OP_EQ, "RSA1024");
- tt_assert(key_new_blob);
- tt_ptr_op(reply_str, OP_EQ, NULL);
-
- /* Test discarding the private key. */
- crypto_pk_free(pk.v2); pk.v2 = NULL;
- tor_free(key_new_blob);
- ret = add_onion_helper_keyarg("NEW:RSA1024", 1, &key_new_alg, &key_new_blob,
- &pk, &hs_version, NULL);
- tt_int_op(ret, OP_EQ, 0);
- tt_int_op(hs_version, OP_EQ, HS_VERSION_TWO);
- tt_assert(pk.v2);
- tt_ptr_op(key_new_alg, OP_EQ, NULL);
- tt_ptr_op(key_new_blob, OP_EQ, NULL);
- tt_ptr_op(reply_str, OP_EQ, NULL);
-
- /* Test generating a invalid key type. */
- crypto_pk_free(pk.v2); pk.v2 = NULL;
- ret = add_onion_helper_keyarg("NEW:RSA512", 0, &key_new_alg, &key_new_blob,
- &pk, &hs_version, NULL);
- tt_int_op(ret, OP_EQ, -1);
- tt_int_op(hs_version, OP_EQ, HS_VERSION_TWO);
- tt_assert(!pk.v2);
- tt_ptr_op(key_new_alg, OP_EQ, NULL);
- tt_ptr_op(key_new_blob, OP_EQ, NULL);
- tt_assert(reply_str);
-
- /* Test loading a RSA1024 key. */
- tor_free(reply_str);
- pk1 = pk_generate(0);
- tt_int_op(0, OP_EQ, crypto_pk_base64_encode_private(pk1, &encoded));
- tor_asprintf(&arg_str, "RSA1024:%s", encoded);
- ret = add_onion_helper_keyarg(arg_str, 0, &key_new_alg, &key_new_blob,
- &pk, &hs_version, NULL);
- tt_int_op(ret, OP_EQ, 0);
- tt_int_op(hs_version, OP_EQ, HS_VERSION_TWO);
- tt_assert(pk.v2);
- tt_ptr_op(key_new_alg, OP_EQ, NULL);
- tt_ptr_op(key_new_blob, OP_EQ, NULL);
- tt_ptr_op(reply_str, OP_EQ, NULL);
- tt_int_op(crypto_pk_cmp_keys(pk1, pk.v2), OP_EQ, 0);
-
- /* Test loading a invalid key type. */
- tor_free(arg_str);
- crypto_pk_free(pk1); pk1 = NULL;
- crypto_pk_free(pk.v2); pk.v2 = NULL;
- tor_asprintf(&arg_str, "RSA512:%s", encoded);
- ret = add_onion_helper_keyarg(arg_str, 0, &key_new_alg, &key_new_blob,
- &pk, &hs_version, NULL);
- tt_int_op(ret, OP_EQ, -1);
- tt_int_op(hs_version, OP_EQ, HS_VERSION_TWO);
- tt_assert(!pk.v2);
- tt_ptr_op(key_new_alg, OP_EQ, NULL);
- tt_ptr_op(key_new_blob, OP_EQ, NULL);
- tt_assert(reply_str);
-
- /* Test loading a invalid key. */
- tor_free(arg_str);
- crypto_pk_free(pk.v2); pk.v2 = NULL;
- tor_free(reply_str);
- encoded[strlen(encoded)/2] = '\0';
- tor_asprintf(&arg_str, "RSA1024:%s", encoded);
- ret = add_onion_helper_keyarg(arg_str, 0, &key_new_alg, &key_new_blob,
- &pk, &hs_version, NULL);
- tt_int_op(ret, OP_EQ, -1);
- tt_int_op(hs_version, OP_EQ, HS_VERSION_TWO);
- tt_assert(!pk.v2);
- tt_ptr_op(key_new_alg, OP_EQ, NULL);
- tt_ptr_op(key_new_blob, OP_EQ, NULL);
- tt_assert(reply_str);
-
- done:
- crypto_pk_free(pk1);
- crypto_pk_free(pk.v2);
- tor_free(key_new_blob);
- tor_free(reply_str);
- tor_free(encoded);
- tor_free(arg_str);
- UNMOCK(control_write_reply);
-}
-
-static void
test_getinfo_helper_onion(void *arg)
{
(void)arg;
@@ -460,50 +355,50 @@ test_getinfo_helper_onion(void *arg)
}
static void
-test_rend_service_parse_port_config(void *arg)
+test_hs_parse_port_config(void *arg)
{
const char *sep = ",";
- rend_service_port_config_t *cfg = NULL;
+ hs_port_config_t *cfg = NULL;
char *err_msg = NULL;
(void)arg;
/* Test "VIRTPORT" only. */
- cfg = rend_service_parse_port_config("80", sep, &err_msg);
+ cfg = hs_parse_port_config("80", sep, &err_msg);
tt_assert(cfg);
tt_ptr_op(err_msg, OP_EQ, NULL);
/* Test "VIRTPORT,TARGET" (Target is port). */
- rend_service_port_config_free(cfg);
- cfg = rend_service_parse_port_config("80,8080", sep, &err_msg);
+ hs_port_config_free(cfg);
+ cfg = hs_parse_port_config("80,8080", sep, &err_msg);
tt_assert(cfg);
tt_ptr_op(err_msg, OP_EQ, NULL);
/* Test "VIRTPORT,TARGET" (Target is IPv4:port). */
- rend_service_port_config_free(cfg);
- cfg = rend_service_parse_port_config("80,192.0.2.1:8080", sep, &err_msg);
+ hs_port_config_free(cfg);
+ cfg = hs_parse_port_config("80,192.0.2.1:8080", sep, &err_msg);
tt_assert(cfg);
tt_ptr_op(err_msg, OP_EQ, NULL);
/* Test "VIRTPORT,TARGET" (Target is IPv6:port). */
- rend_service_port_config_free(cfg);
- cfg = rend_service_parse_port_config("80,[2001:db8::1]:8080", sep, &err_msg);
+ hs_port_config_free(cfg);
+ cfg = hs_parse_port_config("80,[2001:db8::1]:8080", sep, &err_msg);
tt_assert(cfg);
tt_ptr_op(err_msg, OP_EQ, NULL);
- rend_service_port_config_free(cfg);
+ hs_port_config_free(cfg);
cfg = NULL;
/* XXX: Someone should add tests for AF_UNIX targets if supported. */
/* Test empty config. */
- rend_service_port_config_free(cfg);
- cfg = rend_service_parse_port_config("", sep, &err_msg);
+ hs_port_config_free(cfg);
+ cfg = hs_parse_port_config("", sep, &err_msg);
tt_ptr_op(cfg, OP_EQ, NULL);
tt_assert(err_msg);
/* Test invalid port. */
tor_free(err_msg);
- cfg = rend_service_parse_port_config("90001", sep, &err_msg);
+ cfg = hs_parse_port_config("90001", sep, &err_msg);
tt_ptr_op(cfg, OP_EQ, NULL);
tt_assert(err_msg);
tor_free(err_msg);
@@ -513,24 +408,24 @@ test_rend_service_parse_port_config(void *arg)
/* quoted unix port */
tor_free(err_msg);
- cfg = rend_service_parse_port_config("100 unix:\"/tmp/foo bar\"",
+ cfg = hs_parse_port_config("100 unix:\"/tmp/foo bar\"",
" ", &err_msg);
tt_assert(cfg);
tt_ptr_op(err_msg, OP_EQ, NULL);
- rend_service_port_config_free(cfg);
+ hs_port_config_free(cfg);
cfg = NULL;
/* quoted unix port */
tor_free(err_msg);
- cfg = rend_service_parse_port_config("100 unix:\"/tmp/foo bar\"",
+ cfg = hs_parse_port_config("100 unix:\"/tmp/foo bar\"",
" ", &err_msg);
tt_assert(cfg);
tt_ptr_op(err_msg, OP_EQ, NULL);
- rend_service_port_config_free(cfg);
+ hs_port_config_free(cfg);
cfg = NULL;
/* quoted unix port, missing end quote */
- cfg = rend_service_parse_port_config("100 unix:\"/tmp/foo bar",
+ cfg = hs_parse_port_config("100 unix:\"/tmp/foo bar",
" ", &err_msg);
tt_ptr_op(cfg, OP_EQ, NULL);
tt_str_op(err_msg, OP_EQ, "Couldn't process address <unix:\"/tmp/foo bar> "
@@ -539,7 +434,7 @@ test_rend_service_parse_port_config(void *arg)
/* bogus IP address */
MOCK(tor_addr_lookup, mock_tor_addr_lookup__fail_on_bad_addrs);
- cfg = rend_service_parse_port_config("100 foo!!.example.com:9000",
+ cfg = hs_parse_port_config("100 foo!!.example.com:9000",
" ", &err_msg);
UNMOCK(tor_addr_lookup);
tt_ptr_op(cfg, OP_EQ, NULL);
@@ -548,7 +443,7 @@ test_rend_service_parse_port_config(void *arg)
tor_free(err_msg);
/* bogus port port */
- cfg = rend_service_parse_port_config("100 99999",
+ cfg = hs_parse_port_config("100 99999",
" ", &err_msg);
tt_ptr_op(cfg, OP_EQ, NULL);
tt_str_op(err_msg, OP_EQ, "Unparseable or out-of-range port \"99999\" "
@@ -556,69 +451,17 @@ test_rend_service_parse_port_config(void *arg)
tor_free(err_msg);
/* Wrong target address and port separation */
- cfg = rend_service_parse_port_config("80,127.0.0.1 1234", sep,
+ cfg = hs_parse_port_config("80,127.0.0.1 1234", sep,
&err_msg);
tt_ptr_op(cfg, OP_EQ, NULL);
tt_assert(err_msg);
tor_free(err_msg);
done:
- rend_service_port_config_free(cfg);
+ hs_port_config_free(cfg);
tor_free(err_msg);
}
-static void
-test_add_onion_helper_clientauth(void *arg)
-{
- rend_authorized_client_t *client = NULL;
- int created = 0;
-
- (void)arg;
-
- MOCK(control_write_reply, mock_control_write_reply);
- /* Test "ClientName" only. */
- tor_free(reply_str);
- client = add_onion_helper_clientauth("alice", &created, NULL);
- tt_assert(client);
- tt_assert(created);
- tt_ptr_op(reply_str, OP_EQ, NULL);
- rend_authorized_client_free(client);
-
- /* Test "ClientName:Blob" */
- tor_free(reply_str);
- client = add_onion_helper_clientauth("alice:475hGBHPlq7Mc0cRZitK/B",
- &created, NULL);
- tt_assert(client);
- tt_assert(!created);
- tt_ptr_op(reply_str, OP_EQ, NULL);
- rend_authorized_client_free(client);
-
- /* Test invalid client names */
- tor_free(reply_str);
- client = add_onion_helper_clientauth("no*asterisks*allowed", &created,
- NULL);
- tt_ptr_op(client, OP_EQ, NULL);
- tt_assert(reply_str);
-
- /* Test invalid auth cookie */
- tor_free(reply_str);
- client = add_onion_helper_clientauth("alice:12345", &created, NULL);
- tt_ptr_op(client, OP_EQ, NULL);
- tt_assert(reply_str);
-
- /* Test invalid syntax */
- tor_free(reply_str);
- client = add_onion_helper_clientauth(":475hGBHPlq7Mc0cRZitK/B", &created,
- NULL);
- tt_ptr_op(client, OP_EQ, NULL);
- tt_assert(reply_str);
-
- done:
- rend_authorized_client_free(client);
- tor_free(reply_str);
- UNMOCK(control_write_reply);
-}
-
/* Mocks and data/variables used for GETINFO download status tests */
static const download_status_t dl_status_default =
@@ -2209,15 +2052,11 @@ struct testcase_t controller_tests[] = {
PARSER_TEST(no_args_one_obj),
PARSER_TEST(no_args_kwargs),
PARSER_TEST(one_arg_kwargs),
- { "add_onion_helper_keyarg_v2", test_add_onion_helper_keyarg_v2, 0,
- NULL, NULL },
{ "add_onion_helper_keyarg_v3", test_add_onion_helper_keyarg_v3, 0,
NULL, NULL },
{ "getinfo_helper_onion", test_getinfo_helper_onion, 0, NULL, NULL },
- { "rend_service_parse_port_config", test_rend_service_parse_port_config, 0,
+ { "hs_parse_port_config", test_hs_parse_port_config, 0,
NULL, NULL },
- { "add_onion_helper_clientauth", test_add_onion_helper_clientauth, 0, NULL,
- NULL },
{ "download_status_consensus", test_download_status_consensus, 0, NULL,
NULL },
{"getinfo_helper_current_consensus_from_cache",
diff --git a/src/test/test_controller_events.c b/src/test/test_controller_events.c
index 3cd529fa10..8abe89dc24 100644
--- a/src/test/test_controller_events.c
+++ b/src/test/test_controller_events.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2020, The Tor Project, Inc. */
+/* Copyright (c) 2013-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define CONNECTION_PRIVATE
diff --git a/src/test/test_crypto.c b/src/test/test_crypto.c
index ffd6a25bd5..87e309f25a 100644
--- a/src/test/test_crypto.c
+++ b/src/test/test_crypto.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
diff --git a/src/test/test_crypto_ope.c b/src/test/test_crypto_ope.c
index 119ebc114a..a17af181db 100644
--- a/src/test/test_crypto_ope.c
+++ b/src/test/test_crypto_ope.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
diff --git a/src/test/test_crypto_openssl.c b/src/test/test_crypto_openssl.c
index 989f4a56ca..56428f2e8c 100644
--- a/src/test/test_crypto_openssl.c
+++ b/src/test/test_crypto_openssl.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
diff --git a/src/test/test_crypto_rng.c b/src/test/test_crypto_rng.c
index b0dc4c117c..3ae97bd499 100644
--- a/src/test/test_crypto_rng.c
+++ b/src/test/test_crypto_rng.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
diff --git a/src/test/test_crypto_slow.c b/src/test/test_crypto_slow.c
index 1702427b08..bcfea10cf6 100644
--- a/src/test/test_crypto_slow.c
+++ b/src/test/test_crypto_slow.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
diff --git a/src/test/test_data.c b/src/test/test_data.c
index 30c14fcfff..de333f1211 100644
--- a/src/test/test_data.c
+++ b/src/test/test_data.c
@@ -1,6 +1,6 @@
/* Copyright 2001-2004 Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "test/test.h"
diff --git a/src/test/test_dir.c b/src/test/test_dir.c
index 63cc621964..186e09f236 100644
--- a/src/test/test_dir.c
+++ b/src/test/test_dir.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
@@ -4848,9 +4848,6 @@ test_dir_purpose_needs_anonymity_returns_true_for_bridges(void *arg)
tt_int_op(1, OP_EQ, purpose_needs_anonymity(0, ROUTER_PURPOSE_BRIDGE, NULL));
tt_int_op(1, OP_EQ, purpose_needs_anonymity(0, ROUTER_PURPOSE_BRIDGE,
"foobar"));
- tt_int_op(1, OP_EQ,
- purpose_needs_anonymity(DIR_PURPOSE_HAS_FETCHED_RENDDESC_V2,
- ROUTER_PURPOSE_BRIDGE, NULL));
done: ;
}
@@ -4865,21 +4862,6 @@ test_dir_purpose_needs_anonymity_returns_false_for_own_bridge_desc(void *arg)
}
static void
-test_dir_purpose_needs_anonymity_returns_true_for_sensitive_purpose(void *arg)
-{
- (void)arg;
-
- tt_int_op(1, OP_EQ, purpose_needs_anonymity(
- DIR_PURPOSE_HAS_FETCHED_RENDDESC_V2,
- ROUTER_PURPOSE_GENERAL, NULL));
- tt_int_op(1, OP_EQ, purpose_needs_anonymity(
- DIR_PURPOSE_UPLOAD_RENDDESC_V2, 0, NULL));
- tt_int_op(1, OP_EQ, purpose_needs_anonymity(
- DIR_PURPOSE_FETCH_RENDDESC_V2, 0, NULL));
- done: ;
-}
-
-static void
test_dir_purpose_needs_anonymity_ret_false_for_non_sensitive_conn(void *arg)
{
(void)arg;
@@ -4937,12 +4919,6 @@ test_dir_fetch_type(void *arg)
tt_int_op(dir_fetch_type(DIR_PURPOSE_FETCH_MICRODESC, ROUTER_PURPOSE_GENERAL,
NULL), OP_EQ, MICRODESC_DIRINFO);
- /* This will give a warning, because this function isn't supposed to be
- * used for HS descriptors. */
- setup_full_capture_of_logs(LOG_WARN);
- tt_int_op(dir_fetch_type(DIR_PURPOSE_FETCH_RENDDESC_V2,
- ROUTER_PURPOSE_GENERAL, NULL), OP_EQ, NO_DIRINFO);
- expect_single_log_msg_containing("Unexpected purpose");
done:
teardown_capture_of_logs();
}
@@ -5300,10 +5276,6 @@ test_dir_conn_purpose_to_string(void *data)
EXPECT_CONN_PURPOSE(DIR_PURPOSE_FETCH_STATUS_VOTE, "status vote fetch");
EXPECT_CONN_PURPOSE(DIR_PURPOSE_FETCH_DETACHED_SIGNATURES,
"consensus signature fetch");
- EXPECT_CONN_PURPOSE(DIR_PURPOSE_FETCH_RENDDESC_V2,
- "hidden-service v2 descriptor fetch");
- EXPECT_CONN_PURPOSE(DIR_PURPOSE_UPLOAD_RENDDESC_V2,
- "hidden-service v2 descriptor upload");
EXPECT_CONN_PURPOSE(DIR_PURPOSE_FETCH_MICRODESC, "microdescriptor fetch");
/* This will give a warning, because there is no purpose 1024. */
@@ -6680,13 +6652,7 @@ test_dir_find_dl_min_delay(void* data)
dls.schedule = DL_SCHED_BRIDGE;
/* client */
- mock_options->ClientOnly = 1;
- mock_options->UseBridges = 1;
- if (num_bridges_usable(0) > 0) {
- tt_int_op(find_dl_min_delay(&dls, mock_options), OP_EQ, bridge);
- } else {
- tt_int_op(find_dl_min_delay(&dls, mock_options), OP_EQ, bridge_bootstrap);
- }
+ tt_int_op(find_dl_min_delay(&dls, mock_options), OP_EQ, bridge_bootstrap);
done:
UNMOCK(networkstatus_consensus_is_bootstrapping);
@@ -7286,7 +7252,6 @@ struct testcase_t dir_tests[] = {
DIR(purpose_needs_anonymity_returns_true_for_bridges, 0),
DIR(purpose_needs_anonymity_returns_false_for_own_bridge_desc, 0),
DIR(purpose_needs_anonymity_returns_true_by_default, 0),
- DIR(purpose_needs_anonymity_returns_true_for_sensitive_purpose, 0),
DIR(purpose_needs_anonymity_ret_false_for_non_sensitive_conn, 0),
DIR(post_parsing, 0),
DIR(fetch_type, 0),
diff --git a/src/test/test_dir_common.c b/src/test/test_dir_common.c
index 77e3851183..201ea900ff 100644
--- a/src/test/test_dir_common.c
+++ b/src/test/test_dir_common.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
diff --git a/src/test/test_dir_common.h b/src/test/test_dir_common.h
index d37496465c..12dd654812 100644
--- a/src/test/test_dir_common.h
+++ b/src/test/test_dir_common.h
@@ -1,6 +1,6 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#ifndef TOR_TEST_DIR_COMMON_H
diff --git a/src/test/test_dir_handle_get.c b/src/test/test_dir_handle_get.c
index 95339160c3..a7f9fa1d7b 100644
--- a/src/test/test_dir_handle_get.c
+++ b/src/test/test_dir_handle_get.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define RENDCOMMON_PRIVATE
@@ -18,14 +18,11 @@
#include "feature/dircache/dircache.h"
#include "test/test.h"
#include "lib/compress/compress.h"
-#include "feature/rend/rendcommon.h"
-#include "feature/rend/rendcache.h"
#include "feature/relay/relay_config.h"
#include "feature/relay/router.h"
#include "feature/nodelist/authcert.h"
#include "feature/nodelist/dirlist.h"
#include "feature/nodelist/routerlist.h"
-#include "test/rend_test_helpers.h"
#include "feature/nodelist/microdesc.h"
#include "test/test_helpers.h"
#include "feature/nodelist/nodelist.h"
@@ -44,7 +41,6 @@
#include "feature/dircommon/dir_connection_st.h"
#include "feature/dirclient/dir_server_st.h"
#include "feature/nodelist/networkstatus_st.h"
-#include "feature/rend/rend_encoded_v2_service_descriptor_st.h"
#include "feature/nodelist/routerinfo_st.h"
#include "feature/nodelist/routerlist_st.h"
@@ -261,125 +257,6 @@ test_dir_handle_get_robots_txt(void *data)
tor_free(body);
}
-#define RENDEZVOUS2_GET(descid) GET("/tor/rendezvous2/" descid)
-static void
-test_dir_handle_get_rendezvous2_not_found_if_not_encrypted(void *data)
-{
- dir_connection_t *conn = NULL;
- char *header = NULL;
- (void) data;
-
- MOCK(connection_write_to_buf_impl_, connection_write_to_buf_mock);
-
- conn = new_dir_conn();
-
- // connection is not encrypted
- tt_assert(!connection_dir_is_encrypted(conn));
-
- tt_int_op(directory_handle_command_get(conn, RENDEZVOUS2_GET(), NULL, 0),
- OP_EQ, 0);
- fetch_from_buf_http(TO_CONN(conn)->outbuf, &header, MAX_HEADERS_SIZE,
- NULL, NULL, 1, 0);
-
- tt_str_op(NOT_FOUND, OP_EQ, header);
-
- done:
- UNMOCK(connection_write_to_buf_impl_);
- connection_free_minimal(TO_CONN(conn));
- tor_free(header);
-}
-
-static void
-test_dir_handle_get_rendezvous2_on_encrypted_conn_with_invalid_desc_id(
- void *data)
-{
- dir_connection_t *conn = NULL;
- char *header = NULL;
- (void) data;
-
- MOCK(connection_write_to_buf_impl_, connection_write_to_buf_mock);
- conn = new_dir_conn();
-
- // connection is encrypted
- TO_CONN(conn)->linked = 1;
- tt_assert(connection_dir_is_encrypted(conn));
-
- tt_int_op(directory_handle_command_get(conn,
- RENDEZVOUS2_GET("invalid-desc-id"), NULL, 0), OP_EQ, 0);
- fetch_from_buf_http(TO_CONN(conn)->outbuf, &header, MAX_HEADERS_SIZE,
- NULL, NULL, 1, 0);
-
- tt_str_op(header, OP_EQ, NOT_FOUND);
-
- done:
- UNMOCK(connection_write_to_buf_impl_);
- connection_free_minimal(TO_CONN(conn));
- tor_free(header);
-}
-
-static void
-test_dir_handle_get_rendezvous2_on_encrypted_conn_not_well_formed(void *data)
-{
- dir_connection_t *conn = NULL;
- char *header = NULL;
- (void) data;
-
- MOCK(connection_write_to_buf_impl_, connection_write_to_buf_mock);
- conn = new_dir_conn();
-
- // connection is encrypted
- TO_CONN(conn)->linked = 1;
- tt_assert(connection_dir_is_encrypted(conn));
-
- //TODO: this can't be reached because rend_valid_descriptor_id() prevents
- //this case to happen. This test is the same as
- //test_dir_handle_get_rendezvous2_on_encrypted_conn_with_invalid_desc_id We
- //should refactor to remove the case from the switch.
-
- const char *req = RENDEZVOUS2_GET("1bababababababababababababababab");
- tt_int_op(directory_handle_command_get(conn, req, NULL, 0), OP_EQ, 0);
-
- fetch_from_buf_http(TO_CONN(conn)->outbuf, &header, MAX_HEADERS_SIZE,
- NULL, NULL, 1, 0);
-
- tt_str_op(header, OP_EQ, NOT_FOUND);
-
- done:
- UNMOCK(connection_write_to_buf_impl_);
- connection_free_minimal(TO_CONN(conn));
- tor_free(header);
-}
-
-static void
-test_dir_handle_get_rendezvous2_not_found(void *data)
-{
- dir_connection_t *conn = NULL;
- char *header = NULL;
- (void) data;
-
- MOCK(connection_write_to_buf_impl_, connection_write_to_buf_mock);
- conn = new_dir_conn();
-
- rend_cache_init();
-
- // connection is encrypted
- TO_CONN(conn)->linked = 1;
- tt_assert(connection_dir_is_encrypted(conn));
-
- const char *req = RENDEZVOUS2_GET("3xqunszqnaolrrfmtzgaki7mxelgvkje");
- tt_int_op(directory_handle_command_get(conn, req, NULL, 0), OP_EQ, 0);
- fetch_from_buf_http(TO_CONN(conn)->outbuf, &header, MAX_HEADERS_SIZE,
- NULL, NULL, 1, 0);
-
- tt_str_op(NOT_FOUND, OP_EQ, header);
-
- done:
- UNMOCK(connection_write_to_buf_impl_);
- connection_free_minimal(TO_CONN(conn));
- tor_free(header);
- rend_cache_free_all();
-}
-
static const routerinfo_t * dhg_tests_router_get_my_routerinfo(void);
ATTR_UNUSED static int dhg_tests_router_get_my_routerinfo_called = 0;
@@ -2864,10 +2741,6 @@ struct testcase_t dir_handle_get_tests[] = {
DIR_HANDLE_CMD(v1_command_not_found, 0),
DIR_HANDLE_CMD(v1_command, 0),
DIR_HANDLE_CMD(robots_txt, 0),
- DIR_HANDLE_CMD(rendezvous2_not_found_if_not_encrypted, 0),
- DIR_HANDLE_CMD(rendezvous2_not_found, 0),
- DIR_HANDLE_CMD(rendezvous2_on_encrypted_conn_with_invalid_desc_id, 0),
- DIR_HANDLE_CMD(rendezvous2_on_encrypted_conn_not_well_formed, 0),
DIR_HANDLE_CMD(micro_d_not_found, 0),
DIR_HANDLE_CMD(micro_d_server_busy, 0),
DIR_HANDLE_CMD(micro_d, 0),
diff --git a/src/test/test_dirauth_ports.c b/src/test/test_dirauth_ports.c
new file mode 100644
index 0000000000..5dc0b0b631
--- /dev/null
+++ b/src/test/test_dirauth_ports.c
@@ -0,0 +1,152 @@
+/* Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#include "orconfig.h"
+#define CONFIG_PRIVATE
+
+#include "core/or/or.h"
+#include "feature/dirclient/dir_server_st.h"
+#include "feature/nodelist/dirlist.h"
+#include "app/config/config.h"
+#include "test/test.h"
+#include "test/log_test_helpers.h"
+
+static void
+test_dirauth_port_parsing(void *arg)
+{
+ (void)arg;
+
+ // This one is okay.
+ int rv = parse_dir_authority_line(
+ "moria1 orport=9101 "
+ "v3ident=D586D18309DED4CD6D57C18FDB97EFA96D330566 "
+ "upload=http://128.31.0.39:9131/ "
+ "download=http://128.31.0.39:9131 "
+ "vote=http://128.31.0.39:9131/ "
+ "128.31.0.39:9131 9695 DFC3 5FFE B861 329B 9F1A B04C 4639 7020 CE31",
+ NO_DIRINFO, 1);
+ tt_int_op(rv,OP_EQ,0);
+
+ // These have bad syntax.
+ setup_capture_of_logs(LOG_WARN);
+ rv = parse_dir_authority_line(
+ "moria1 orport=9101 "
+ "v3ident=D586D18309DED4CD6D57C18FDB97EFA96D330566 "
+ "uploadx=http://128.31.0.39:9131/ "
+ "128.31.0.39:9131 9695 DFC3 5FFE B861 329B 9F1A B04C 4639 7020 CE31",
+ NO_DIRINFO, 1);
+ tt_int_op(rv,OP_EQ,0);
+ expect_log_msg_containing("Unrecognized flag");
+ mock_clean_saved_logs();
+
+ rv = parse_dir_authority_line(
+ "moria1 orport=9101 "
+ "v3ident=D586D18309DED4CD6D57C18FDB97EFA96D330566 "
+ "upload=https://128.31.0.39:9131/ " // https is not recognized
+ "128.31.0.39:9131 9695 DFC3 5FFE B861 329B 9F1A B04C 4639 7020 CE31",
+ NO_DIRINFO, 1);
+ tt_int_op(rv,OP_EQ,-1);
+ expect_log_msg_containing("Unsupported URL scheme");
+ mock_clean_saved_logs();
+
+ rv = parse_dir_authority_line(
+ "moria1 orport=9101 "
+ "v3ident=D586D18309DED4CD6D57C18FDB97EFA96D330566 "
+ "upload=http://128.31.0.39:9131/tor " // suffix is not supported
+ "128.31.0.39:9131 9695 DFC3 5FFE B861 329B 9F1A B04C 4639 7020 CE31",
+ NO_DIRINFO, 1);
+ tt_int_op(rv,OP_EQ,-1);
+ expect_log_msg_containing("Unsupported URL prefix");
+ mock_clean_saved_logs();
+
+ rv = parse_dir_authority_line(
+ "moria1 orport=9101 "
+ "v3ident=D586D18309DED4CD6D57C18FDB97EFA96D330566 "
+ "upload=http://128.31.0.256:9131/ " // "256" is not ipv4.
+ "128.31.0.39:9131 9695 DFC3 5FFE B861 329B 9F1A B04C 4639 7020 CE31",
+ NO_DIRINFO, 1);
+ tt_int_op(rv,OP_EQ,-1);
+ expect_log_msg_containing("Unable to parse address");
+
+ rv = parse_dir_authority_line(
+ "moria1 orport=9101 "
+ "v3ident=D586D18309DED4CD6D57C18FDB97EFA96D330566 "
+ "upload=http://xyz.example.com/ " // hostnames not supported.
+ "128.31.0.39:9131 9695 DFC3 5FFE B861 329B 9F1A B04C 4639 7020 CE31",
+ NO_DIRINFO, 1);
+ tt_int_op(rv,OP_EQ,-1);
+ expect_log_msg_containing("Unable to parse address");
+
+ done:
+ teardown_capture_of_logs();
+}
+
+static void
+test_dirauth_port_lookup(void *arg)
+{
+ (void)arg;
+
+ clear_dir_servers();
+
+ int rv = parse_dir_authority_line(
+ "moria1 orport=9101 "
+ "v3ident=D586D18309DED4CD6D57C18FDB97EFA96D330566 "
+ "upload=http://128.31.0.40:9132/ "
+ "download=http://128.31.0.41:9133 "
+ "vote=http://128.31.0.42:9134/ "
+ "128.31.0.39:9131 9695 DFC3 5FFE B861 329B 9F1A B04C 4639 7020 CE31",
+ NO_DIRINFO, 0);
+ tt_int_op(rv,OP_EQ,0);
+
+ rv = parse_dir_authority_line(
+ "morgoth orport=9101 "
+ "v3ident=D586D18309DED4CDFFFFFFFFDB97EFA96D330566 "
+ "upload=http://128.31.0.43:9140/ "
+ "128.31.0.44:9131 9695 DFC3 5FFE B861 329B 9F1A B04C 4639 7020 CE31",
+ NO_DIRINFO, 0);
+ tt_int_op(rv,OP_EQ,0);
+
+ const smartlist_t *servers = router_get_trusted_dir_servers();
+ tt_assert(servers);
+ tt_int_op(smartlist_len(servers), OP_EQ, 2);
+ const dir_server_t *moria = smartlist_get(servers, 0);
+ const dir_server_t *morgoth = smartlist_get(servers, 1);
+ tt_str_op(moria->nickname, OP_EQ, "moria1");
+ tt_str_op(morgoth->nickname, OP_EQ, "morgoth");
+
+ const tor_addr_port_t *dirport;
+
+ dirport = trusted_dir_server_get_dirport(moria,
+ AUTH_USAGE_UPLOAD, AF_INET);
+ tt_int_op(dirport->port, OP_EQ, 9132);
+ dirport = trusted_dir_server_get_dirport(moria,
+ AUTH_USAGE_DOWNLOAD, AF_INET);
+ tt_int_op(dirport->port, OP_EQ, 9133);
+ dirport = trusted_dir_server_get_dirport(moria,
+ AUTH_USAGE_VOTING, AF_INET);
+ tt_int_op(dirport->port, OP_EQ, 9134);
+
+ dirport = trusted_dir_server_get_dirport(morgoth,
+ AUTH_USAGE_UPLOAD, AF_INET);
+ tt_int_op(dirport->port, OP_EQ, 9140);
+ dirport = trusted_dir_server_get_dirport(morgoth,
+ AUTH_USAGE_DOWNLOAD, AF_INET);
+ tt_int_op(dirport->port, OP_EQ, 9131); // fallback
+ dirport = trusted_dir_server_get_dirport(morgoth,
+ AUTH_USAGE_VOTING, AF_INET);
+ tt_int_op(dirport->port, OP_EQ, 9131); // fallback
+
+ done:
+ ;
+}
+
+#define T(name) \
+ { #name, test_dirauth_port_ ## name, TT_FORK, NULL, NULL }
+
+struct testcase_t dirauth_port_tests[] = {
+ T(parsing),
+ T(lookup),
+ END_OF_TESTCASES
+};
diff --git a/src/test/test_dirvote.c b/src/test/test_dirvote.c
index b5e57ad071..2b53955107 100644
--- a/src/test/test_dirvote.c
+++ b/src/test/test_dirvote.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2020, The Tor Project, Inc. */
+/* Copyright (c) 2020-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -656,6 +656,30 @@ done:
ROUTER_FREE(pppp);
}
+static void
+test_dirvote_parse_param_buggy(void *arg)
+{
+ (void)arg;
+
+ /* Tests for behavior with bug emulation to migrate away from bug 19011. */
+ tt_i64_op(extract_param_buggy("blah blah", "bwweightscale", 10000),
+ OP_EQ, 10000);
+ tt_i64_op(extract_param_buggy("bwweightscale=7", "bwweightscale", 10000),
+ OP_EQ, 7);
+ tt_i64_op(extract_param_buggy("bwweightscale=7 foo=9",
+ "bwweightscale", 10000),
+ OP_EQ, 10000);
+ tt_i64_op(extract_param_buggy("foo=7 bwweightscale=777 bar=9",
+ "bwweightscale", 10000),
+ OP_EQ, 10000);
+ tt_i64_op(extract_param_buggy("foo=7 bwweightscale=1234",
+ "bwweightscale", 10000),
+ OP_EQ, 1234);
+
+ done:
+ ;
+}
+
#define NODE(name, flags) \
{ \
#name, test_dirvote_##name, (flags), NULL, NULL \
@@ -668,4 +692,5 @@ struct testcase_t dirvote_tests[] = {
NODE(get_sybil_by_ip_version_ipv4, TT_FORK),
NODE(get_sybil_by_ip_version_ipv6, TT_FORK),
NODE(get_all_possible_sybil, TT_FORK),
+ NODE(parse_param_buggy, 0),
END_OF_TESTCASES};
diff --git a/src/test/test_dispatch.c b/src/test/test_dispatch.c
index f7f8ecdc03..902029a85c 100644
--- a/src/test/test_dispatch.c
+++ b/src/test/test_dispatch.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2018-2020, The Tor Project, Inc. */
+/* Copyright (c) 2018-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define DISPATCH_NEW_PRIVATE
diff --git a/src/test/test_dns.c b/src/test/test_dns.c
index d2b0777d6b..6612391127 100644
--- a/src/test/test_dns.c
+++ b/src/test/test_dns.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2020, The Tor Project, Inc. */
+/* Copyright (c) 2015-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
diff --git a/src/test/test_dos.c b/src/test/test_dos.c
index 850bbef59b..a34420024f 100644
--- a/src/test/test_dos.c
+++ b/src/test/test_dos.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2018-2020, The Tor Project, Inc. */
+/* Copyright (c) 2018-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define DOS_PRIVATE
@@ -79,6 +79,9 @@ test_dos_conn_creation(void *arg)
{ /* 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);
dos_new_client_conn(&or_conn, NULL);
}
}
@@ -470,7 +473,7 @@ test_known_relay(void *arg)
GEOIP_CLIENT_CONNECT);
tt_assert(entry);
/* We should have a count of 0. */
- tt_uint_op(entry->dos_stats.concurrent_count, OP_EQ, 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. */
@@ -483,7 +486,7 @@ test_known_relay(void *arg)
GEOIP_CLIENT_CONNECT);
tt_assert(entry);
/* We should have a count of 2. */
- tt_uint_op(entry->dos_stats.concurrent_count, OP_EQ, 2);
+ tt_uint_op(entry->dos_stats.conn_stats.concurrent_count, OP_EQ, 2);
done:
routerstatus_free(rs); routerinfo_free(ri); microdesc_free(md);
@@ -496,11 +499,69 @@ test_known_relay(void *arg)
UNMOCK(get_param_cc_enabled);
}
+/** Test that the connection tracker of the DoS subsystem will block clients
+ * who try to establish too many connections */
+static void
+test_dos_conn_rate(void *arg)
+{
+ (void) arg;
+
+ 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 */
+ 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;
+ update_approx_time(now);
+
+ /* Get DoS subsystem limits */
+ dos_init();
+ uint32_t burst_conn = get_param_conn_connect_burst(NULL);
+
+ /* Introduce new client */
+ geoip_note_client_seen(GEOIP_CLIENT_CONNECT, addr, NULL, now);
+ { /* Register many conns from this client but not enough to get it blocked */
+ unsigned int i;
+ for (i = 0; i < burst_conn - 1; i++) {
+ dos_new_client_conn(&or_conn, NULL);
+ }
+ }
+
+ /* Check that new conns are still permitted */
+ tt_int_op(DOS_CONN_DEFENSE_NONE, OP_EQ,
+ dos_conn_addr_get_defense_type(addr));
+
+ /* Register another conn and check that new conns are not allowed anymore.
+ * We should have reached our burst. */
+ dos_new_client_conn(&or_conn, NULL);
+ tt_int_op(DOS_CONN_DEFENSE_CLOSE, OP_EQ,
+ dos_conn_addr_get_defense_type(addr));
+
+ /* Advance the time 12 hours. It should still be blocked. */
+ update_approx_time(now + (12 * 60 * 60));
+ tt_int_op(DOS_CONN_DEFENSE_CLOSE, OP_EQ,
+ dos_conn_addr_get_defense_type(addr));
+
+ /* Advance the time 24 hours plus 13 hours. It should be unblocked.
+ * Remember, we had a random value between 24 hours and rand(24/2) thus
+ * adding 13 hours is safe. */
+ update_approx_time(now + (37 * 60 * 60));
+ tt_int_op(DOS_CONN_DEFENSE_NONE, OP_EQ,
+ dos_conn_addr_get_defense_type(addr));
+
+ done:
+ dos_free_all();
+}
+
struct testcase_t dos_tests[] = {
{ "conn_creation", test_dos_conn_creation, TT_FORK, NULL, NULL },
{ "circuit_creation", test_dos_circuit_creation, TT_FORK, NULL, NULL },
{ "bucket_refill", test_dos_bucket_refill, TT_FORK, NULL, NULL },
{ "known_relay" , test_known_relay, TT_FORK,
NULL, NULL },
+ { "conn_rate", test_dos_conn_rate, TT_FORK, NULL, NULL },
END_OF_TESTCASES
};
diff --git a/src/test/test_entryconn.c b/src/test/test_entryconn.c
index 75018260f7..9ab43a90ad 100644
--- a/src/test/test_entryconn.c
+++ b/src/test/test_entryconn.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2020, The Tor Project, Inc. */
+/* Copyright (c) 2014-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
@@ -17,7 +17,6 @@
#include "feature/nodelist/nodelist.h"
#include "feature/hs/hs_cache.h"
-#include "feature/rend/rendcache.h"
#include "core/or/entry_connection_st.h"
#include "core/or/socks_request_st.h"
@@ -307,7 +306,7 @@ test_entryconn_rewrite_cached_dns_ipv4(void *arg)
tor_strdup("240.240.241.241"),
expires,
ADDRMAPSRC_DNS,
- 0, 0);
+ 0, 0, 0);
strlcpy(ec->socks_request->address, "www.friendly.example.com",
sizeof(ec->socks_request->address));
@@ -359,7 +358,7 @@ test_entryconn_rewrite_cached_dns_ipv6(void *arg)
tor_strdup("[::f00f]"),
expires,
ADDRMAPSRC_DNS,
- 0, 0);
+ 0, 0, 0);
strlcpy(ec->socks_request->address, "www.friendly.example.com",
sizeof(ec->socks_request->address));
@@ -748,7 +747,6 @@ test_entryconn_rewrite_onion_v3(void *arg)
/* Make an onion connection using the SOCKS request */
conn->entry_cfg.onion_traffic = 1;
ENTRY_TO_CONN(conn)->state = AP_CONN_STATE_SOCKS_WAIT;
- tt_assert(!ENTRY_TO_EDGE_CONN(conn)->rend_data);
tt_assert(!ENTRY_TO_EDGE_CONN(conn)->hs_ident);
/* Handle SOCKS and rewrite! */
@@ -763,7 +761,6 @@ test_entryconn_rewrite_onion_v3(void *arg)
"25njqamcweflpvkl73j4szahhihoc4xt3ktcgjnpaingr5yhkenl5sid");
/* check that HS information got attached to the connection */
tt_assert(ENTRY_TO_EDGE_CONN(conn)->hs_ident);
- tt_assert(!ENTRY_TO_EDGE_CONN(conn)->rend_data);
done:
hs_free_all();
diff --git a/src/test/test_entrynodes.c b/src/test/test_entrynodes.c
index 589876db2a..118b66dfa7 100644
--- a/src/test/test_entrynodes.c
+++ b/src/test/test_entrynodes.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2020, The Tor Project, Inc. */
+/* Copyright (c) 2014-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
@@ -92,6 +92,12 @@ bfn_mock_node_get_by_id(const char *id)
return NULL;
}
+static int
+mock_router_have_minimum_dir_info(void)
+{
+ return 1;
+}
+
/* Helper function to free a test node. */
static void
test_node_free(node_t *n)
@@ -3087,6 +3093,38 @@ test_entry_guard_vanguard_path_selection(void *arg)
circuit_free_(circ);
}
+static void
+test_entry_guard_layer2_guards(void *arg)
+{
+ (void) arg;
+ MOCK(router_have_minimum_dir_info, mock_router_have_minimum_dir_info);
+
+ /* First check the enable/disable switch */
+ get_options_mutable()->VanguardsLiteEnabled = 0;
+ tt_int_op(vanguards_lite_is_enabled(), OP_EQ, 0);
+
+ get_options_mutable()->VanguardsLiteEnabled = 1;
+ tt_int_op(vanguards_lite_is_enabled(), OP_EQ, 1);
+
+ get_options_mutable()->VanguardsLiteEnabled = -1;
+ tt_int_op(vanguards_lite_is_enabled(), OP_EQ, 1);
+
+ /* OK now let's move to actual testing */
+
+ /* Remove restrictions to route around Big Fake Network restrictions */
+ get_options_mutable()->EnforceDistinctSubnets = 0;
+
+ /* Create the L2 guardset */
+ maintain_layer2_guards();
+
+ const routerset_t *l2_guards = get_layer2_guards();
+ tt_assert(l2_guards);
+ tt_int_op(routerset_len(l2_guards), OP_EQ, 4);
+
+ done:
+ UNMOCK(router_have_minimum_dir_info);
+}
+
static const struct testcase_setup_t big_fake_network = {
big_fake_network_setup, big_fake_network_cleanup
};
@@ -3152,6 +3190,8 @@ struct testcase_t entrynodes_tests[] = {
BFN_TEST(manage_primary),
BFN_TEST(correct_cascading_order),
+ BFN_TEST(layer2_guards),
+
EN_TEST_FORK(guard_preferred),
BFN_TEST(select_for_circuit_no_confirmed),
diff --git a/src/test/test_extorport.c b/src/test/test_extorport.c
index 7935530653..201a702d19 100644
--- a/src/test/test_extorport.c
+++ b/src/test/test_extorport.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2020, The Tor Project, Inc. */
+/* Copyright (c) 2013-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define CONNECTION_PRIVATE
@@ -24,60 +24,6 @@
#include <sys/stat.h>
#endif
-/* Test connection_or_remove_from_ext_or_id_map and
- * connection_or_set_ext_or_identifier */
-static void
-test_ext_or_id_map(void *arg)
-{
- or_connection_t *c1 = NULL, *c2 = NULL, *c3 = NULL;
- char *idp = NULL, *idp2 = NULL;
- (void)arg;
-
- /* pre-initialization */
- tt_ptr_op(NULL, OP_EQ,
- connection_or_get_by_ext_or_id("xxxxxxxxxxxxxxxxxxxx"));
-
- c1 = or_connection_new(CONN_TYPE_EXT_OR, AF_INET);
- c2 = or_connection_new(CONN_TYPE_EXT_OR, AF_INET);
- c3 = or_connection_new(CONN_TYPE_OR, AF_INET);
-
- tt_ptr_op(c1->ext_or_conn_id, OP_NE, NULL);
- tt_ptr_op(c2->ext_or_conn_id, OP_NE, NULL);
- tt_ptr_op(c3->ext_or_conn_id, OP_EQ, NULL);
-
- tt_ptr_op(c1, OP_EQ, connection_or_get_by_ext_or_id(c1->ext_or_conn_id));
- tt_ptr_op(c2, OP_EQ, connection_or_get_by_ext_or_id(c2->ext_or_conn_id));
- tt_ptr_op(NULL, OP_EQ,
- connection_or_get_by_ext_or_id("xxxxxxxxxxxxxxxxxxxx"));
-
- idp = tor_memdup(c2->ext_or_conn_id, EXT_OR_CONN_ID_LEN);
-
- /* Give c2 a new ID. */
- connection_or_set_ext_or_identifier(c2);
- tt_mem_op(idp, OP_NE, c2->ext_or_conn_id, EXT_OR_CONN_ID_LEN);
- idp2 = tor_memdup(c2->ext_or_conn_id, EXT_OR_CONN_ID_LEN);
- tt_assert(!tor_digest_is_zero(idp2));
-
- tt_ptr_op(NULL, OP_EQ, connection_or_get_by_ext_or_id(idp));
- tt_ptr_op(c2, OP_EQ, connection_or_get_by_ext_or_id(idp2));
-
- /* Now remove it. */
- connection_or_remove_from_ext_or_id_map(c2);
- tt_ptr_op(NULL, OP_EQ, connection_or_get_by_ext_or_id(idp));
- tt_ptr_op(NULL, OP_EQ, connection_or_get_by_ext_or_id(idp2));
-
- done:
- if (c1)
- connection_free_minimal(TO_CONN(c1));
- if (c2)
- connection_free_minimal(TO_CONN(c2));
- if (c3)
- connection_free_minimal(TO_CONN(c3));
- tor_free(idp);
- tor_free(idp2);
- connection_or_clear_ext_or_id_map();
-}
-
/* Simple connection_write_to_buf_impl_ replacement that unconditionally
* writes to outbuf. */
static void
@@ -527,7 +473,7 @@ test_ext_or_handshake(void *arg)
tt_int_op(handshake_start_called,OP_EQ,1);
tt_int_op(TO_CONN(conn)->type, OP_EQ, CONN_TYPE_OR);
tt_int_op(TO_CONN(conn)->state, OP_EQ, 0);
- close_closeable_connections();
+ connection_free_(TO_CONN(conn));
conn = NULL;
/* Okay, this time let's succeed the handshake but fail the USERADDR
@@ -581,7 +527,6 @@ test_ext_or_handshake(void *arg)
}
struct testcase_t extorport_tests[] = {
- { "id_map", test_ext_or_id_map, TT_FORK, NULL, NULL },
{ "write_command", test_ext_or_write_command, TT_FORK, NULL, NULL },
{ "init_auth", test_ext_or_init_auth, TT_FORK, NULL, NULL },
{ "cookie_auth", test_ext_or_cookie_auth, TT_FORK, NULL, NULL },
diff --git a/src/test/test_geoip.c b/src/test/test_geoip.c
index 95afe4d6c4..b980f10096 100644
--- a/src/test/test_geoip.c
+++ b/src/test/test_geoip.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
diff --git a/src/test/test_guardfraction.c b/src/test/test_guardfraction.c
index 6019dfc2b1..77a5425cd0 100644
--- a/src/test/test_guardfraction.c
+++ b/src/test/test_guardfraction.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2020, The Tor Project, Inc. */
+/* Copyright (c) 2014-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define GUARDFRACTION_PRIVATE
diff --git a/src/test/test_handles.c b/src/test/test_handles.c
index dbb5b1a18e..52274558ec 100644
--- a/src/test/test_handles.c
+++ b/src/test/test_handles.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2020, The Tor Project, Inc. */
+/* Copyright (c) 2016-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
diff --git a/src/test/test_helpers.c b/src/test/test_helpers.c
index 20d4582e74..2edaa746f1 100644
--- a/src/test/test_helpers.c
+++ b/src/test/test_helpers.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2020, The Tor Project, Inc. */
+/* Copyright (c) 2014-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/test/test_helpers.h b/src/test/test_helpers.h
index f02ecbb0ac..e9695c55d5 100644
--- a/src/test/test_helpers.h
+++ b/src/test/test_helpers.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017-2020, The Tor Project, Inc. */
+/* Copyright (c) 2017-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#ifndef TOR_TEST_HELPERS_H
diff --git a/src/test/test_hs.c b/src/test/test_hs.c
deleted file mode 100644
index 46b4493a3d..0000000000
--- a/src/test/test_hs.c
+++ /dev/null
@@ -1,1005 +0,0 @@
-/* Copyright (c) 2007-2020, The Tor Project, Inc. */
-/* See LICENSE for licensing information */
-
-/**
- * \file test_hs.c
- * \brief Unit tests for hidden service.
- **/
-
-#define CONTROL_EVENTS_PRIVATE
-#define CIRCUITBUILD_PRIVATE
-#define RENDCOMMON_PRIVATE
-#define RENDSERVICE_PRIVATE
-#define HS_SERVICE_PRIVATE
-
-#include "core/or/or.h"
-#include "test/test.h"
-#include "feature/control/control.h"
-#include "feature/control/control_events.h"
-#include "feature/control/control_fmt.h"
-#include "app/config/config.h"
-#include "feature/hs/hs_common.h"
-#include "feature/rend/rendcommon.h"
-#include "feature/rend/rendservice.h"
-#include "feature/nodelist/routerlist.h"
-#include "feature/nodelist/routerset.h"
-#include "core/or/circuitbuild.h"
-
-#include "feature/nodelist/node_st.h"
-#include "feature/rend/rend_encoded_v2_service_descriptor_st.h"
-#include "feature/rend/rend_intro_point_st.h"
-#include "feature/nodelist/routerinfo_st.h"
-
-#include "test/test_helpers.h"
-
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-
-/* mock ID digest and longname for node that's in nodelist */
-#define HSDIR_EXIST_ID "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA" \
- "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA"
-#define STR_HSDIR_EXIST_LONGNAME \
- "$AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=TestDir"
-/* mock ID digest and longname for node that's not in nodelist */
-#define HSDIR_NONE_EXIST_ID "\xBB\xBB\xBB\xBB\xBB\xBB\xBB\xBB\xBB\xBB" \
- "\xBB\xBB\xBB\xBB\xBB\xBB\xBB\xBB\xBB\xBB"
-#define STR_HSDIR_NONE_EXIST_LONGNAME \
- "$BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB"
-
-/* DuckDuckGo descriptor as an example. This one has extra "\r" at the end so
- * the control port is happy. */
-static const char *hs_desc_content_control = "\
-rendezvous-service-descriptor g5ojobzupf275beh5ra72uyhb3dkpxwg\r\n\
-version 2\r\n\
-permanent-key\r\n\
------BEGIN RSA PUBLIC KEY-----\r\n\
-MIGJAoGBAJ/SzzgrXPxTlFrKVhXh3buCWv2QfcNgncUpDpKouLn3AtPH5Ocys0jE\r\n\
-aZSKdvaiQ62md2gOwj4x61cFNdi05tdQjS+2thHKEm/KsB9BGLSLBNJYY356bupg\r\n\
-I5gQozM65ENelfxYlysBjJ52xSDBd8C4f/p9umdzaaaCmzXG/nhzAgMBAAE=\r\n\
------END RSA PUBLIC KEY-----\r\n\
-secret-id-part anmjoxxwiupreyajjt5yasimfmwcnxlf\r\n\
-publication-time 2015-03-11 19:00:00\r\n\
-protocol-versions 2,3\r\n\
-introduction-points\r\n\
------BEGIN MESSAGE-----\r\n\
-aW50cm9kdWN0aW9uLXBvaW50IDd1bnd4cmg2dG5kNGh6eWt1Z3EzaGZzdHduc2ll\r\n\
-cmhyCmlwLWFkZHJlc3MgMTg4LjEzOC4xMjEuMTE4Cm9uaW9uLXBvcnQgOTAwMQpv\r\n\
-bmlvbi1rZXkKLS0tLS1CRUdJTiBSU0EgUFVCTElDIEtFWS0tLS0tCk1JR0pBb0dC\r\n\
-QUxGRVVyeVpDbk9ROEhURmV5cDVjMTRObWVqL1BhekFLTTBxRENTNElKUWh0Y3g1\r\n\
-NXpRSFdOVWIKQ2hHZ0JqR1RjV3ZGRnA0N3FkdGF6WUZhVXE2c0lQKzVqeWZ5b0Q4\r\n\
-UmJ1bzBwQmFWclJjMmNhYUptWWM0RDh6Vgpuby9sZnhzOVVaQnZ1cWY4eHIrMDB2\r\n\
-S0JJNmFSMlA2OE1WeDhrMExqcUpUU2RKOE9idm9yQWdNQkFBRT0KLS0tLS1FTkQg\r\n\
-UlNBIFBVQkxJQyBLRVktLS0tLQpzZXJ2aWNlLWtleQotLS0tLUJFR0lOIFJTQSBQ\r\n\
-VUJMSUMgS0VZLS0tLS0KTUlHSkFvR0JBTnJHb0ozeTlHNXQzN2F2ekI1cTlwN1hG\r\n\
-VUplRUVYMUNOaExnWmJXWGJhVk5OcXpoZFhyL0xTUQppM1Z6dW5OaUs3cndUVnE2\r\n\
-K2QyZ1lRckhMMmIvMXBBY3ZKWjJiNSs0bTRRc0NibFpjRENXTktRbHJnRWN5WXRJ\r\n\
-CkdscXJTbFFEaXA0ZnNrUFMvNDVkWTI0QmJsQ3NGU1k3RzVLVkxJck4zZFpGbmJr\r\n\
-NEZIS1hBZ01CQUFFPQotLS0tLUVORCBSU0EgUFVCTElDIEtFWS0tLS0tCmludHJv\r\n\
-ZHVjdGlvbi1wb2ludCBiNGM3enlxNXNheGZzN2prNXFibG1wN3I1b3pwdHRvagpp\r\n\
-cC1hZGRyZXNzIDEwOS4xNjkuNDUuMjI2Cm9uaW9uLXBvcnQgOTAwMQpvbmlvbi1r\r\n\
-ZXkKLS0tLS1CRUdJTiBSU0EgUFVCTElDIEtFWS0tLS0tCk1JR0pBb0dCQU8xSXpw\r\n\
-WFFUTUY3RXZUb1NEUXpzVnZiRVFRQUQrcGZ6NzczMVRXZzVaUEJZY1EyUkRaeVp4\r\n\
-OEQKNUVQSU1FeUE1RE83cGd0ak5LaXJvYXJGMC8yempjMkRXTUlSaXZyU29YUWVZ\r\n\
-ZXlMM1pzKzFIajJhMDlCdkYxZAp6MEswblRFdVhoNVR5V3lyMHdsbGI1SFBnTlI0\r\n\
-MS9oYkprZzkwZitPVCtIeGhKL1duUml2QWdNQkFBRT0KLS0tLS1FTkQgUlNBIFBV\r\n\
-QkxJQyBLRVktLS0tLQpzZXJ2aWNlLWtleQotLS0tLUJFR0lOIFJTQSBQVUJMSUMg\r\n\
-S0VZLS0tLS0KTUlHSkFvR0JBSzNWZEJ2ajFtQllLL3JrcHNwcm9Ub0llNUtHVmth\r\n\
-QkxvMW1tK1I2YUVJek1VZFE1SjkwNGtyRwpCd3k5NC8rV0lGNFpGYXh5Z2phejl1\r\n\
-N2pKY1k3ZGJhd1pFeG1hYXFCRlRwL2h2ZG9rcHQ4a1ByRVk4OTJPRHJ1CmJORUox\r\n\
-N1FPSmVMTVZZZk5Kcjl4TWZCQ3JQai8zOGh2RUdrbWVRNmRVWElvbVFNaUJGOVRB\r\n\
-Z01CQUFFPQotLS0tLUVORCBSU0EgUFVCTElDIEtFWS0tLS0tCmludHJvZHVjdGlv\r\n\
-bi1wb2ludCBhdjVtcWl0Y2Q3cjJkandsYmN0c2Jlc2R3eGt0ZWtvegppcC1hZGRy\r\n\
-ZXNzIDE0NC43Ni44LjczCm9uaW9uLXBvcnQgNDQzCm9uaW9uLWtleQotLS0tLUJF\r\n\
-R0lOIFJTQSBQVUJMSUMgS0VZLS0tLS0KTUlHSkFvR0JBTzVweVZzQmpZQmNmMXBE\r\n\
-dklHUlpmWXUzQ05nNldka0ZLMGlvdTBXTGZtejZRVDN0NWhzd3cyVwpjejlHMXhx\r\n\
-MmN0Nkd6VWkrNnVkTDlITTRVOUdHTi9BbW8wRG9GV1hKWHpBQkFXd2YyMVdsd1lW\r\n\
-eFJQMHRydi9WCkN6UDkzcHc5OG5vSmdGUGRUZ05iMjdKYmVUZENLVFBrTEtscXFt\r\n\
-b3NveUN2RitRa25vUS9BZ01CQUFFPQotLS0tLUVORCBSU0EgUFVCTElDIEtFWS0t\r\n\
-LS0tCnNlcnZpY2Uta2V5Ci0tLS0tQkVHSU4gUlNBIFBVQkxJQyBLRVktLS0tLQpN\r\n\
-SUdKQW9HQkFMVjNKSmtWN3lTNU9jc1lHMHNFYzFQOTVRclFRR3ZzbGJ6Wi9zRGxl\r\n\
-RlpKYXFSOUYvYjRUVERNClNGcFMxcU1GbldkZDgxVmRGMEdYRmN2WVpLamRJdHU2\r\n\
-SndBaTRJeEhxeXZtdTRKdUxrcXNaTEFLaXRLVkx4eGsKeERlMjlDNzRWMmJrOTRJ\r\n\
-MEgybTNKS2tzTHVwc3VxWWRVUmhOVXN0SElKZmgyZmNIalF0bEFnTUJBQUU9Ci0t\r\n\
-LS0tRU5EIFJTQSBQVUJMSUMgS0VZLS0tLS0KCg==\r\n\
------END MESSAGE-----\r\n\
-signature\r\n\
------BEGIN SIGNATURE-----\r\n\
-d4OuCE5OLAOnRB6cQN6WyMEmg/BHem144Vec+eYgeWoKwx3MxXFplUjFxgnMlmwN\r\n\
-PcftsZf2ztN0sbNCtPgDL3d0PqvxY3iHTQAI8EbaGq/IAJUZ8U4y963dD5+Bn6JQ\r\n\
-myE3ctmh0vy5+QxSiRjmQBkuEpCyks7LvWvHYrhnmcg=\r\n\
------END SIGNATURE-----";
-
-/* DuckDuckGo descriptor as an example. */
-static const char *hs_desc_content = "\
-rendezvous-service-descriptor g5ojobzupf275beh5ra72uyhb3dkpxwg\n\
-version 2\n\
-permanent-key\n\
------BEGIN RSA PUBLIC KEY-----\n\
-MIGJAoGBAJ/SzzgrXPxTlFrKVhXh3buCWv2QfcNgncUpDpKouLn3AtPH5Ocys0jE\n\
-aZSKdvaiQ62md2gOwj4x61cFNdi05tdQjS+2thHKEm/KsB9BGLSLBNJYY356bupg\n\
-I5gQozM65ENelfxYlysBjJ52xSDBd8C4f/p9umdzaaaCmzXG/nhzAgMBAAE=\n\
------END RSA PUBLIC KEY-----\n\
-secret-id-part anmjoxxwiupreyajjt5yasimfmwcnxlf\n\
-publication-time 2015-03-11 19:00:00\n\
-protocol-versions 2,3\n\
-introduction-points\n\
------BEGIN MESSAGE-----\n\
-aW50cm9kdWN0aW9uLXBvaW50IDd1bnd4cmg2dG5kNGh6eWt1Z3EzaGZzdHduc2ll\n\
-cmhyCmlwLWFkZHJlc3MgMTg4LjEzOC4xMjEuMTE4Cm9uaW9uLXBvcnQgOTAwMQpv\n\
-bmlvbi1rZXkKLS0tLS1CRUdJTiBSU0EgUFVCTElDIEtFWS0tLS0tCk1JR0pBb0dC\n\
-QUxGRVVyeVpDbk9ROEhURmV5cDVjMTRObWVqL1BhekFLTTBxRENTNElKUWh0Y3g1\n\
-NXpRSFdOVWIKQ2hHZ0JqR1RjV3ZGRnA0N3FkdGF6WUZhVXE2c0lQKzVqeWZ5b0Q4\n\
-UmJ1bzBwQmFWclJjMmNhYUptWWM0RDh6Vgpuby9sZnhzOVVaQnZ1cWY4eHIrMDB2\n\
-S0JJNmFSMlA2OE1WeDhrMExqcUpUU2RKOE9idm9yQWdNQkFBRT0KLS0tLS1FTkQg\n\
-UlNBIFBVQkxJQyBLRVktLS0tLQpzZXJ2aWNlLWtleQotLS0tLUJFR0lOIFJTQSBQ\n\
-VUJMSUMgS0VZLS0tLS0KTUlHSkFvR0JBTnJHb0ozeTlHNXQzN2F2ekI1cTlwN1hG\n\
-VUplRUVYMUNOaExnWmJXWGJhVk5OcXpoZFhyL0xTUQppM1Z6dW5OaUs3cndUVnE2\n\
-K2QyZ1lRckhMMmIvMXBBY3ZKWjJiNSs0bTRRc0NibFpjRENXTktRbHJnRWN5WXRJ\n\
-CkdscXJTbFFEaXA0ZnNrUFMvNDVkWTI0QmJsQ3NGU1k3RzVLVkxJck4zZFpGbmJr\n\
-NEZIS1hBZ01CQUFFPQotLS0tLUVORCBSU0EgUFVCTElDIEtFWS0tLS0tCmludHJv\n\
-ZHVjdGlvbi1wb2ludCBiNGM3enlxNXNheGZzN2prNXFibG1wN3I1b3pwdHRvagpp\n\
-cC1hZGRyZXNzIDEwOS4xNjkuNDUuMjI2Cm9uaW9uLXBvcnQgOTAwMQpvbmlvbi1r\n\
-ZXkKLS0tLS1CRUdJTiBSU0EgUFVCTElDIEtFWS0tLS0tCk1JR0pBb0dCQU8xSXpw\n\
-WFFUTUY3RXZUb1NEUXpzVnZiRVFRQUQrcGZ6NzczMVRXZzVaUEJZY1EyUkRaeVp4\n\
-OEQKNUVQSU1FeUE1RE83cGd0ak5LaXJvYXJGMC8yempjMkRXTUlSaXZyU29YUWVZ\n\
-ZXlMM1pzKzFIajJhMDlCdkYxZAp6MEswblRFdVhoNVR5V3lyMHdsbGI1SFBnTlI0\n\
-MS9oYkprZzkwZitPVCtIeGhKL1duUml2QWdNQkFBRT0KLS0tLS1FTkQgUlNBIFBV\n\
-QkxJQyBLRVktLS0tLQpzZXJ2aWNlLWtleQotLS0tLUJFR0lOIFJTQSBQVUJMSUMg\n\
-S0VZLS0tLS0KTUlHSkFvR0JBSzNWZEJ2ajFtQllLL3JrcHNwcm9Ub0llNUtHVmth\n\
-QkxvMW1tK1I2YUVJek1VZFE1SjkwNGtyRwpCd3k5NC8rV0lGNFpGYXh5Z2phejl1\n\
-N2pKY1k3ZGJhd1pFeG1hYXFCRlRwL2h2ZG9rcHQ4a1ByRVk4OTJPRHJ1CmJORUox\n\
-N1FPSmVMTVZZZk5Kcjl4TWZCQ3JQai8zOGh2RUdrbWVRNmRVWElvbVFNaUJGOVRB\n\
-Z01CQUFFPQotLS0tLUVORCBSU0EgUFVCTElDIEtFWS0tLS0tCmludHJvZHVjdGlv\n\
-bi1wb2ludCBhdjVtcWl0Y2Q3cjJkandsYmN0c2Jlc2R3eGt0ZWtvegppcC1hZGRy\n\
-ZXNzIDE0NC43Ni44LjczCm9uaW9uLXBvcnQgNDQzCm9uaW9uLWtleQotLS0tLUJF\n\
-R0lOIFJTQSBQVUJMSUMgS0VZLS0tLS0KTUlHSkFvR0JBTzVweVZzQmpZQmNmMXBE\n\
-dklHUlpmWXUzQ05nNldka0ZLMGlvdTBXTGZtejZRVDN0NWhzd3cyVwpjejlHMXhx\n\
-MmN0Nkd6VWkrNnVkTDlITTRVOUdHTi9BbW8wRG9GV1hKWHpBQkFXd2YyMVdsd1lW\n\
-eFJQMHRydi9WCkN6UDkzcHc5OG5vSmdGUGRUZ05iMjdKYmVUZENLVFBrTEtscXFt\n\
-b3NveUN2RitRa25vUS9BZ01CQUFFPQotLS0tLUVORCBSU0EgUFVCTElDIEtFWS0t\n\
-LS0tCnNlcnZpY2Uta2V5Ci0tLS0tQkVHSU4gUlNBIFBVQkxJQyBLRVktLS0tLQpN\n\
-SUdKQW9HQkFMVjNKSmtWN3lTNU9jc1lHMHNFYzFQOTVRclFRR3ZzbGJ6Wi9zRGxl\n\
-RlpKYXFSOUYvYjRUVERNClNGcFMxcU1GbldkZDgxVmRGMEdYRmN2WVpLamRJdHU2\n\
-SndBaTRJeEhxeXZtdTRKdUxrcXNaTEFLaXRLVkx4eGsKeERlMjlDNzRWMmJrOTRJ\n\
-MEgybTNKS2tzTHVwc3VxWWRVUmhOVXN0SElKZmgyZmNIalF0bEFnTUJBQUU9Ci0t\n\
-LS0tRU5EIFJTQSBQVUJMSUMgS0VZLS0tLS0KCg==\n\
------END MESSAGE-----\n\
-signature\n\
------BEGIN SIGNATURE-----\n\
-d4OuCE5OLAOnRB6cQN6WyMEmg/BHem144Vec+eYgeWoKwx3MxXFplUjFxgnMlmwN\n\
-PcftsZf2ztN0sbNCtPgDL3d0PqvxY3iHTQAI8EbaGq/IAJUZ8U4y963dD5+Bn6JQ\n\
-myE3ctmh0vy5+QxSiRjmQBkuEpCyks7LvWvHYrhnmcg=\n\
------END SIGNATURE-----";
-
-/* Helper global variable for hidden service descriptor event test.
- * It's used as a pointer to dynamically created message buffer in
- * send_control_event_string_replacement function, which mocks
- * send_control_event_string function.
- *
- * Always free it after use! */
-static char *received_msg = NULL;
-
-/** Mock function for send_control_event_string
- */
-static void
-queue_control_event_string_replacement(uint16_t event, char *msg)
-{
- (void) event;
- tor_free(received_msg);
- received_msg = msg;
-}
-
-/** Mock function for node_describe_longname_by_id, it returns either
- * STR_HSDIR_EXIST_LONGNAME or STR_HSDIR_NONE_EXIST_LONGNAME
- */
-static const char *
-node_describe_longname_by_id_replacement(const char *id_digest)
-{
- if (!strcmp(id_digest, HSDIR_EXIST_ID)) {
- return STR_HSDIR_EXIST_LONGNAME;
- } else {
- return STR_HSDIR_NONE_EXIST_LONGNAME;
- }
-}
-
-/** Test that we can parse a hardcoded v2 HS desc. */
-static void
-test_hs_parse_static_v2_desc(void *arg)
-{
- int ret;
- rend_encoded_v2_service_descriptor_t desc;
-
- (void) arg;
-
- /* Test an obviously not parseable string */
- desc.desc_str = tor_strdup("ceci n'est pas un HS descriptor");
- ret = rend_desc_v2_is_parsable(&desc);
- tor_free(desc.desc_str);
- tt_int_op(ret, OP_EQ, 0);
-
- /* Test an actual descriptor */
- desc.desc_str = tor_strdup(hs_desc_content);
- ret = rend_desc_v2_is_parsable(&desc);
- tor_free(desc.desc_str);
- tt_int_op(ret, OP_EQ, 1);
-
- done: ;
-}
-
-/** Make sure each hidden service descriptor async event generation
- *
- * function generates the message in expected format.
- */
-static void
-test_hs_desc_event(void *arg)
-{
- #define STR_HS_ADDR "ajhb7kljbiru65qo"
- #define STR_HS_CONTENT_DESC_ID "g5ojobzupf275beh5ra72uyhb3dkpxwg"
- #define STR_DESC_ID_BASE32 "hba3gmcgpfivzfhx5rtfqkfdhv65yrj3"
-
- int ret;
- rend_data_v2_t rend_query;
- const char *expected_msg;
- char desc_id_base32[REND_DESC_ID_V2_LEN_BASE32 + 1];
-
- (void) arg;
- MOCK(queue_control_event_string,
- queue_control_event_string_replacement);
- MOCK(node_describe_longname_by_id,
- node_describe_longname_by_id_replacement);
-
- /* setup rend_query struct */
- memset(&rend_query, 0, sizeof(rend_query));
- rend_query.base_.version = 2;
- strncpy(rend_query.onion_address, STR_HS_ADDR,
- REND_SERVICE_ID_LEN_BASE32+1);
- rend_query.auth_type = REND_NO_AUTH;
- rend_query.base_.hsdirs_fp = smartlist_new();
- smartlist_add(rend_query.base_.hsdirs_fp, tor_memdup(HSDIR_EXIST_ID,
- DIGEST_LEN));
-
- /* Compute descriptor ID for replica 0, should be STR_DESC_ID_BASE32. */
- ret = rend_compute_v2_desc_id(rend_query.descriptor_id[0],
- rend_query.onion_address,
- NULL, 0, 0);
- tt_int_op(ret, OP_EQ, 0);
- base32_encode(desc_id_base32, sizeof(desc_id_base32),
- rend_query.descriptor_id[0], DIGEST_LEN);
- /* Make sure rend_compute_v2_desc_id works properly. */
- tt_mem_op(desc_id_base32, OP_EQ, STR_DESC_ID_BASE32,
- sizeof(desc_id_base32));
-
- /* test request event */
- control_event_hs_descriptor_requested(rend_query.onion_address,
- rend_query.auth_type, HSDIR_EXIST_ID,
- STR_DESC_ID_BASE32, NULL);
- expected_msg = "650 HS_DESC REQUESTED "STR_HS_ADDR" NO_AUTH "\
- STR_HSDIR_EXIST_LONGNAME " " STR_DESC_ID_BASE32 "\r\n";
- tt_assert(received_msg);
- tt_str_op(received_msg,OP_EQ, expected_msg);
- tor_free(received_msg);
-
- /* test received event */
- rend_query.auth_type = REND_BASIC_AUTH;
- control_event_hsv2_descriptor_received(rend_query.onion_address,
- &rend_query.base_, HSDIR_EXIST_ID);
- expected_msg = "650 HS_DESC RECEIVED "STR_HS_ADDR" BASIC_AUTH "\
- STR_HSDIR_EXIST_LONGNAME " " STR_DESC_ID_BASE32"\r\n";
- tt_assert(received_msg);
- tt_str_op(received_msg,OP_EQ, expected_msg);
- tor_free(received_msg);
-
- /* test failed event */
- rend_query.auth_type = REND_STEALTH_AUTH;
- control_event_hsv2_descriptor_failed(&rend_query.base_,
- HSDIR_NONE_EXIST_ID,
- "QUERY_REJECTED");
- expected_msg = "650 HS_DESC FAILED "STR_HS_ADDR" STEALTH_AUTH "\
- STR_HSDIR_NONE_EXIST_LONGNAME" REASON=QUERY_REJECTED\r\n";
- tt_assert(received_msg);
- tt_str_op(received_msg,OP_EQ, expected_msg);
- tor_free(received_msg);
-
- /* test invalid auth type */
- rend_query.auth_type = 999;
- control_event_hsv2_descriptor_failed(&rend_query.base_,
- HSDIR_EXIST_ID,
- "QUERY_REJECTED");
- expected_msg = "650 HS_DESC FAILED "STR_HS_ADDR" UNKNOWN "\
- STR_HSDIR_EXIST_LONGNAME " " STR_DESC_ID_BASE32\
- " REASON=QUERY_REJECTED\r\n";
- tt_assert(received_msg);
- tt_str_op(received_msg,OP_EQ, expected_msg);
- tor_free(received_msg);
-
- /* test no HSDir fingerprint type */
- rend_query.auth_type = REND_NO_AUTH;
- control_event_hsv2_descriptor_failed(&rend_query.base_, NULL,
- "QUERY_NO_HSDIR");
- expected_msg = "650 HS_DESC FAILED "STR_HS_ADDR" NO_AUTH " \
- "UNKNOWN REASON=QUERY_NO_HSDIR\r\n";
- tt_assert(received_msg);
- tt_str_op(received_msg,OP_EQ, expected_msg);
- tor_free(received_msg);
-
- /* test HSDir rate limited */
- rend_query.auth_type = REND_NO_AUTH;
- control_event_hsv2_descriptor_failed(&rend_query.base_, NULL,
- "QUERY_RATE_LIMITED");
- expected_msg = "650 HS_DESC FAILED "STR_HS_ADDR" NO_AUTH " \
- "UNKNOWN REASON=QUERY_RATE_LIMITED\r\n";
- tt_assert(received_msg);
- tt_str_op(received_msg,OP_EQ, expected_msg);
- tor_free(received_msg);
-
- /* Test invalid content with no HSDir fingerprint. */
- char *exp_msg;
- control_event_hs_descriptor_content(rend_query.onion_address,
- STR_HS_CONTENT_DESC_ID, NULL, NULL);
- tor_asprintf(&exp_msg, "650+HS_DESC_CONTENT " STR_HS_ADDR " "\
- STR_HS_CONTENT_DESC_ID " UNKNOWN" \
- "\r\n\r\n.\r\n650 OK\r\n");
- tt_assert(received_msg);
- tt_str_op(received_msg, OP_EQ, exp_msg);
- tor_free(received_msg);
- tor_free(exp_msg);
-
- /* test valid content. */
- control_event_hs_descriptor_content(rend_query.onion_address,
- STR_HS_CONTENT_DESC_ID, HSDIR_EXIST_ID,
- hs_desc_content_control);
- tor_asprintf(&exp_msg, "650+HS_DESC_CONTENT " STR_HS_ADDR " "\
- STR_HS_CONTENT_DESC_ID " " STR_HSDIR_EXIST_LONGNAME\
- "\r\n%s\r\n.\r\n650 OK\r\n", hs_desc_content_control);
-
- tt_assert(received_msg);
- tt_str_op(received_msg, OP_EQ, exp_msg);
- tor_free(received_msg);
- tor_free(exp_msg);
- SMARTLIST_FOREACH(rend_query.base_.hsdirs_fp, char *, d, tor_free(d));
- smartlist_free(rend_query.base_.hsdirs_fp);
-
- done:
- UNMOCK(queue_control_event_string);
- UNMOCK(node_describe_longname_by_id);
- tor_free(received_msg);
-}
-
-/* Make sure rend_data_t is valid at creation, destruction and when
- * duplicated. */
-static void
-test_hs_rend_data(void *arg)
-{
- int rep;
- rend_data_t *client = NULL, *client_dup = NULL;
- /* Binary format of a descriptor ID. */
- char desc_id[DIGEST_LEN];
- char client_cookie[REND_DESC_COOKIE_LEN];
- time_t now = time(NULL);
- rend_data_t *service_dup = NULL;
- rend_data_t *service = NULL;
-
- (void)arg;
-
- base32_decode(desc_id, sizeof(desc_id), STR_DESC_ID_BASE32,
- REND_DESC_ID_V2_LEN_BASE32);
- memset(client_cookie, 'e', sizeof(client_cookie));
-
- client = rend_data_client_create(STR_HS_ADDR, desc_id, client_cookie,
- REND_NO_AUTH);
- tt_assert(client);
- rend_data_v2_t *client_v2 = TO_REND_DATA_V2(client);
- tt_int_op(client_v2->auth_type, OP_EQ, REND_NO_AUTH);
- tt_str_op(client_v2->onion_address, OP_EQ, STR_HS_ADDR);
- tt_mem_op(client_v2->desc_id_fetch, OP_EQ, desc_id, sizeof(desc_id));
- tt_mem_op(client_v2->descriptor_cookie, OP_EQ, client_cookie,
- sizeof(client_cookie));
- tt_assert(client->hsdirs_fp);
- tt_int_op(smartlist_len(client->hsdirs_fp), OP_EQ, 0);
- for (rep = 0; rep < REND_NUMBER_OF_NON_CONSECUTIVE_REPLICAS; rep++) {
- int ret = rend_compute_v2_desc_id(desc_id, client_v2->onion_address,
- client_v2->descriptor_cookie, now, rep);
- /* That shouldn't never fail. */
- tt_int_op(ret, OP_EQ, 0);
- tt_mem_op(client_v2->descriptor_id[rep], OP_EQ, desc_id,
- sizeof(desc_id));
- }
- /* The rest should be zeroed because this is a client request. */
- tt_int_op(tor_digest_is_zero(client_v2->rend_pk_digest), OP_EQ, 1);
- tt_int_op(tor_digest_is_zero(client->rend_cookie), OP_EQ, 1);
-
- /* Test dup(). */
- client_dup = rend_data_dup(client);
- tt_assert(client_dup);
- rend_data_v2_t *client_dup_v2 = TO_REND_DATA_V2(client_dup);
- tt_int_op(client_dup_v2->auth_type, OP_EQ, client_v2->auth_type);
- tt_str_op(client_dup_v2->onion_address, OP_EQ, client_v2->onion_address);
- tt_mem_op(client_dup_v2->desc_id_fetch, OP_EQ, client_v2->desc_id_fetch,
- sizeof(client_dup_v2->desc_id_fetch));
- tt_mem_op(client_dup_v2->descriptor_cookie, OP_EQ,
- client_v2->descriptor_cookie,
- sizeof(client_dup_v2->descriptor_cookie));
-
- tt_assert(client_dup->hsdirs_fp);
- tt_int_op(smartlist_len(client_dup->hsdirs_fp), OP_EQ, 0);
- for (rep = 0; rep < REND_NUMBER_OF_NON_CONSECUTIVE_REPLICAS; rep++) {
- tt_mem_op(client_dup_v2->descriptor_id[rep], OP_EQ,
- client_v2->descriptor_id[rep], DIGEST_LEN);
- }
- /* The rest should be zeroed because this is a client request. */
- tt_int_op(tor_digest_is_zero(client_dup_v2->rend_pk_digest), OP_EQ, 1);
- tt_int_op(tor_digest_is_zero(client_dup->rend_cookie), OP_EQ, 1);
- rend_data_free(client);
- client = NULL;
- rend_data_free(client_dup);
- client_dup = NULL;
-
- /* Reset state. */
- base32_decode(desc_id, sizeof(desc_id), STR_DESC_ID_BASE32,
- REND_DESC_ID_V2_LEN_BASE32);
- memset(client_cookie, 'e', sizeof(client_cookie));
-
- /* Try with different parameters here for which some content should be
- * zeroed out. */
- client = rend_data_client_create(NULL, desc_id, NULL, REND_BASIC_AUTH);
- tt_assert(client);
- client_v2 = TO_REND_DATA_V2(client);
- tt_int_op(client_v2->auth_type, OP_EQ, REND_BASIC_AUTH);
- tt_int_op(strlen(client_v2->onion_address), OP_EQ, 0);
- tt_mem_op(client_v2->desc_id_fetch, OP_EQ, desc_id, sizeof(desc_id));
- tt_int_op(fast_mem_is_zero(client_v2->descriptor_cookie,
- sizeof(client_v2->descriptor_cookie)), OP_EQ, 1);
- tt_assert(client->hsdirs_fp);
- tt_int_op(smartlist_len(client->hsdirs_fp), OP_EQ, 0);
- for (rep = 0; rep < REND_NUMBER_OF_NON_CONSECUTIVE_REPLICAS; rep++) {
- tt_int_op(tor_digest_is_zero(client_v2->descriptor_id[rep]), OP_EQ, 1);
- }
- /* The rest should be zeroed because this is a client request. */
- tt_int_op(tor_digest_is_zero(client_v2->rend_pk_digest), OP_EQ, 1);
- tt_int_op(tor_digest_is_zero(client->rend_cookie), OP_EQ, 1);
- rend_data_free(client);
- client = NULL;
-
- /* Let's test the service object now. */
- char rend_pk_digest[DIGEST_LEN];
- uint8_t rend_cookie[DIGEST_LEN];
- memset(rend_pk_digest, 'f', sizeof(rend_pk_digest));
- memset(rend_cookie, 'g', sizeof(rend_cookie));
-
- service = rend_data_service_create(STR_HS_ADDR, rend_pk_digest,
- rend_cookie, REND_NO_AUTH);
- tt_assert(service);
- rend_data_v2_t *service_v2 = TO_REND_DATA_V2(service);
- tt_int_op(service_v2->auth_type, OP_EQ, REND_NO_AUTH);
- tt_str_op(service_v2->onion_address, OP_EQ, STR_HS_ADDR);
- tt_mem_op(service_v2->rend_pk_digest, OP_EQ, rend_pk_digest,
- sizeof(rend_pk_digest));
- tt_mem_op(service->rend_cookie, OP_EQ, rend_cookie, sizeof(rend_cookie));
- tt_assert(service->hsdirs_fp);
- tt_int_op(smartlist_len(service->hsdirs_fp), OP_EQ, 0);
- for (rep = 0; rep < REND_NUMBER_OF_NON_CONSECUTIVE_REPLICAS; rep++) {
- tt_int_op(tor_digest_is_zero(service_v2->descriptor_id[rep]), OP_EQ, 1);
- }
- /* The rest should be zeroed because this is a service request. */
- tt_int_op(tor_digest_is_zero(service_v2->descriptor_cookie), OP_EQ, 1);
- tt_int_op(tor_digest_is_zero(service_v2->desc_id_fetch), OP_EQ, 1);
-
- /* Test dup(). */
- service_dup = rend_data_dup(service);
- rend_data_v2_t *service_dup_v2 = TO_REND_DATA_V2(service_dup);
- tt_assert(service_dup);
- tt_int_op(service_dup_v2->auth_type, OP_EQ, service_v2->auth_type);
- tt_str_op(service_dup_v2->onion_address, OP_EQ, service_v2->onion_address);
- tt_mem_op(service_dup_v2->rend_pk_digest, OP_EQ, service_v2->rend_pk_digest,
- sizeof(service_dup_v2->rend_pk_digest));
- tt_mem_op(service_dup->rend_cookie, OP_EQ, service->rend_cookie,
- sizeof(service_dup->rend_cookie));
- tt_assert(service_dup->hsdirs_fp);
- tt_int_op(smartlist_len(service_dup->hsdirs_fp), OP_EQ, 0);
- for (rep = 0; rep < REND_NUMBER_OF_NON_CONSECUTIVE_REPLICAS; rep++) {
- tt_assert(tor_digest_is_zero(service_dup_v2->descriptor_id[rep]));
- }
- /* The rest should be zeroed because this is a service request. */
- tt_int_op(tor_digest_is_zero(service_dup_v2->descriptor_cookie), OP_EQ, 1);
- tt_int_op(tor_digest_is_zero(service_dup_v2->desc_id_fetch), OP_EQ, 1);
-
- done:
- rend_data_free(service);
- rend_data_free(service_dup);
- rend_data_free(client);
- rend_data_free(client_dup);
-}
-
-/* Test encoding and decoding service authorization cookies */
-static void
-test_hs_auth_cookies(void *arg)
-{
-#define TEST_COOKIE_RAW ((const uint8_t *) "abcdefghijklmnop")
-#define TEST_COOKIE_ENCODED "YWJjZGVmZ2hpamtsbW5vcA"
-#define TEST_COOKIE_ENCODED_STEALTH "YWJjZGVmZ2hpamtsbW5vcB"
-#define TEST_COOKIE_ENCODED_INVALID "YWJjZGVmZ2hpamtsbW5vcD"
-
- char *encoded_cookie = NULL;
- uint8_t raw_cookie[REND_DESC_COOKIE_LEN];
- rend_auth_type_t auth_type;
- char *err_msg = NULL;
- int re;
-
- (void)arg;
-
- /* Test that encoding gives the expected result */
- encoded_cookie = rend_auth_encode_cookie(TEST_COOKIE_RAW, REND_BASIC_AUTH);
- tt_str_op(encoded_cookie, OP_EQ, TEST_COOKIE_ENCODED);
- tor_free(encoded_cookie);
-
- encoded_cookie = rend_auth_encode_cookie(TEST_COOKIE_RAW, REND_STEALTH_AUTH);
- tt_str_op(encoded_cookie, OP_EQ, TEST_COOKIE_ENCODED_STEALTH);
- tor_free(encoded_cookie);
-
- /* Decoding should give the original value */
- re = rend_auth_decode_cookie(TEST_COOKIE_ENCODED, raw_cookie, &auth_type,
- &err_msg);
- tt_assert(!re);
- tt_ptr_op(err_msg, OP_EQ, NULL);
- tt_mem_op(raw_cookie, OP_EQ, TEST_COOKIE_RAW, REND_DESC_COOKIE_LEN);
- tt_int_op(auth_type, OP_EQ, REND_BASIC_AUTH);
- memset(raw_cookie, 0, sizeof(raw_cookie));
-
- re = rend_auth_decode_cookie(TEST_COOKIE_ENCODED_STEALTH, raw_cookie,
- &auth_type, &err_msg);
- tt_assert(!re);
- tt_ptr_op(err_msg, OP_EQ, NULL);
- tt_mem_op(raw_cookie, OP_EQ, TEST_COOKIE_RAW, REND_DESC_COOKIE_LEN);
- tt_int_op(auth_type, OP_EQ, REND_STEALTH_AUTH);
- memset(raw_cookie, 0, sizeof(raw_cookie));
-
- /* Decoding with padding characters should also work */
- re = rend_auth_decode_cookie(TEST_COOKIE_ENCODED "==", raw_cookie, NULL,
- &err_msg);
- tt_assert(!re);
- tt_ptr_op(err_msg, OP_EQ, NULL);
- tt_mem_op(raw_cookie, OP_EQ, TEST_COOKIE_RAW, REND_DESC_COOKIE_LEN);
-
- /* Decoding with an unknown type should fail */
- re = rend_auth_decode_cookie(TEST_COOKIE_ENCODED_INVALID, raw_cookie,
- &auth_type, &err_msg);
- tt_int_op(re, OP_LT, 0);
- tt_assert(err_msg);
- tor_free(err_msg);
-
- done:
- tor_free(encoded_cookie);
- tor_free(err_msg);
-
- return;
-}
-
-static int mock_get_options_calls = 0;
-static or_options_t *mock_options = NULL;
-
-static void
-reset_options(or_options_t *options, int *get_options_calls)
-{
- memset(options, 0, sizeof(or_options_t));
- options->TestingTorNetwork = 1;
-
- *get_options_calls = 0;
-}
-
-static const or_options_t *
-mock_get_options(void)
-{
- ++mock_get_options_calls;
- tor_assert(mock_options);
- return mock_options;
-}
-
-/* arg can't be 0 (the test fails) or 2 (the test is skipped) */
-#define CREATE_HS_DIR_NONE ((intptr_t)0x04)
-#define CREATE_HS_DIR1 ((intptr_t)0x08)
-#define CREATE_HS_DIR2 ((intptr_t)0x10)
-
-/* Test that single onion poisoning works. */
-static void
-test_single_onion_poisoning(void *arg)
-{
- or_options_t opt;
- mock_options = &opt;
- reset_options(mock_options, &mock_get_options_calls);
- MOCK(get_options, mock_get_options);
-
- int ret = -1;
- intptr_t create_dir_mask = (intptr_t)arg;
- /* Get directories with a random suffix so we can repeat the tests */
- mock_options->DataDirectory = tor_strdup(get_fname_rnd("test_data_dir"));
- rend_service_t *service_1 = tor_malloc_zero(sizeof(rend_service_t));
- char *dir1 = tor_strdup(get_fname_rnd("test_hs_dir1"));
- rend_service_t *service_2 = tor_malloc_zero(sizeof(rend_service_t));
- char *dir2 = tor_strdup(get_fname_rnd("test_hs_dir2"));
- smartlist_t *services = smartlist_new();
- char *poison_path = NULL;
- char *err_msg = NULL;
-
- mock_options->HiddenServiceSingleHopMode = 1;
- mock_options->HiddenServiceNonAnonymousMode = 1;
-
- /* Create the data directory, and, if the correct bit in arg is set,
- * create a directory for that service.
- * The data directory is required for the lockfile, which is used when
- * loading keys. */
- ret = check_private_dir(mock_options->DataDirectory, CPD_CREATE, NULL);
- tt_int_op(ret, OP_EQ, 0);
- if (create_dir_mask & CREATE_HS_DIR1) {
- ret = check_private_dir(dir1, CPD_CREATE, NULL);
- tt_int_op(ret, OP_EQ, 0);
- }
- if (create_dir_mask & CREATE_HS_DIR2) {
- ret = check_private_dir(dir2, CPD_CREATE, NULL);
- tt_int_op(ret, OP_EQ, 0);
- }
-
- service_1->directory = dir1;
- service_2->directory = dir2;
- /* The services own the directory pointers now */
- dir1 = dir2 = NULL;
- /* Add port to service 1 */
- service_1->ports = smartlist_new();
- service_2->ports = smartlist_new();
- rend_service_port_config_t *port1 = rend_service_parse_port_config("80", " ",
- &err_msg);
- tt_assert(port1);
- tt_ptr_op(err_msg, OP_EQ, NULL);
- smartlist_add(service_1->ports, port1);
-
- rend_service_port_config_t *port2 = rend_service_parse_port_config("90", " ",
- &err_msg);
- /* Add port to service 2 */
- tt_assert(port2);
- tt_ptr_op(err_msg, OP_EQ, NULL);
- smartlist_add(service_2->ports, port2);
-
- /* No services, a service to verify, no problem! */
- mock_options->HiddenServiceSingleHopMode = 0;
- mock_options->HiddenServiceNonAnonymousMode = 0;
- ret = rend_service_verify_single_onion_poison(service_1, mock_options);
- tt_int_op(ret, OP_EQ, 0);
- ret = rend_service_verify_single_onion_poison(service_2, mock_options);
- tt_int_op(ret, OP_EQ, 0);
-
- /* Either way, no problem. */
- mock_options->HiddenServiceSingleHopMode = 1;
- mock_options->HiddenServiceNonAnonymousMode = 1;
- ret = rend_service_verify_single_onion_poison(service_1, mock_options);
- tt_int_op(ret, OP_EQ, 0);
- ret = rend_service_verify_single_onion_poison(service_2, mock_options);
- tt_int_op(ret, OP_EQ, 0);
-
- /* Add the first service */
- ret = hs_check_service_private_dir(mock_options->User, service_1->directory,
- service_1->dir_group_readable, 1);
- tt_int_op(ret, OP_EQ, 0);
- smartlist_add(services, service_1);
- /* But don't add the second service yet. */
-
- /* Service directories, but no previous keys, no problem! */
- mock_options->HiddenServiceSingleHopMode = 0;
- mock_options->HiddenServiceNonAnonymousMode = 0;
- ret = rend_service_verify_single_onion_poison(service_1, mock_options);
- tt_int_op(ret, OP_EQ, 0);
- ret = rend_service_verify_single_onion_poison(service_2, mock_options);
- tt_int_op(ret, OP_EQ, 0);
-
- /* Either way, no problem. */
- mock_options->HiddenServiceSingleHopMode = 1;
- mock_options->HiddenServiceNonAnonymousMode = 1;
- ret = rend_service_verify_single_onion_poison(service_1, mock_options);
- tt_int_op(ret, OP_EQ, 0);
- ret = rend_service_verify_single_onion_poison(service_2, mock_options);
- tt_int_op(ret, OP_EQ, 0);
-
- /* Poison! Poison! Poison!
- * This can only be done in HiddenServiceSingleHopMode. */
- mock_options->HiddenServiceSingleHopMode = 1;
- mock_options->HiddenServiceNonAnonymousMode = 1;
- ret = rend_service_poison_new_single_onion_dir(service_1, mock_options);
- tt_int_op(ret, OP_EQ, 0);
- /* Poisoning twice is a no-op. */
- ret = rend_service_poison_new_single_onion_dir(service_1, mock_options);
- tt_int_op(ret, OP_EQ, 0);
-
- /* Poisoned service directories, but no previous keys, no problem! */
- mock_options->HiddenServiceSingleHopMode = 0;
- mock_options->HiddenServiceNonAnonymousMode = 0;
- ret = rend_service_verify_single_onion_poison(service_1, mock_options);
- tt_int_op(ret, OP_EQ, 0);
- ret = rend_service_verify_single_onion_poison(service_2, mock_options);
- tt_int_op(ret, OP_EQ, 0);
-
- /* Either way, no problem. */
- mock_options->HiddenServiceSingleHopMode = 1;
- mock_options->HiddenServiceNonAnonymousMode = 1;
- ret = rend_service_verify_single_onion_poison(service_1, mock_options);
- tt_int_op(ret, OP_EQ, 0);
- ret = rend_service_verify_single_onion_poison(service_2, mock_options);
- tt_int_op(ret, OP_EQ, 0);
-
- /* Now add some keys, and we'll have a problem. */
- ret = rend_service_load_all_keys(services);
- tt_int_op(ret, OP_EQ, 0);
-
- /* Poisoned service directories with previous keys are not allowed. */
- mock_options->HiddenServiceSingleHopMode = 0;
- mock_options->HiddenServiceNonAnonymousMode = 0;
- ret = rend_service_verify_single_onion_poison(service_1, mock_options);
- tt_int_op(ret, OP_LT, 0);
- ret = rend_service_verify_single_onion_poison(service_2, mock_options);
- tt_int_op(ret, OP_EQ, 0);
-
- /* But they are allowed if we're in non-anonymous mode. */
- mock_options->HiddenServiceSingleHopMode = 1;
- mock_options->HiddenServiceNonAnonymousMode = 1;
- ret = rend_service_verify_single_onion_poison(service_1, mock_options);
- tt_int_op(ret, OP_EQ, 0);
- ret = rend_service_verify_single_onion_poison(service_2, mock_options);
- tt_int_op(ret, OP_EQ, 0);
-
- /* Re-poisoning directories with existing keys is a no-op, because
- * directories with existing keys are ignored. */
- mock_options->HiddenServiceSingleHopMode = 1;
- mock_options->HiddenServiceNonAnonymousMode = 1;
- ret = rend_service_poison_new_single_onion_dir(service_1, mock_options);
- tt_int_op(ret, OP_EQ, 0);
- /* And it keeps the poison. */
- ret = rend_service_verify_single_onion_poison(service_1, mock_options);
- tt_int_op(ret, OP_EQ, 0);
- ret = rend_service_verify_single_onion_poison(service_2, mock_options);
- tt_int_op(ret, OP_EQ, 0);
-
- /* Now add the second service: it has no key and no poison file */
- ret = hs_check_service_private_dir(mock_options->User, service_2->directory,
- service_2->dir_group_readable, 1);
- tt_int_op(ret, OP_EQ, 0);
- smartlist_add(services, service_2);
-
- /* A new service, and an existing poisoned service. Not ok. */
- mock_options->HiddenServiceSingleHopMode = 0;
- mock_options->HiddenServiceNonAnonymousMode = 0;
- ret = rend_service_verify_single_onion_poison(service_1, mock_options);
- tt_int_op(ret, OP_LT, 0);
- ret = rend_service_verify_single_onion_poison(service_2, mock_options);
- tt_int_op(ret, OP_EQ, 0);
-
- /* But ok to add in non-anonymous mode. */
- mock_options->HiddenServiceSingleHopMode = 1;
- mock_options->HiddenServiceNonAnonymousMode = 1;
- ret = rend_service_verify_single_onion_poison(service_1, mock_options);
- tt_int_op(ret, OP_EQ, 0);
- ret = rend_service_verify_single_onion_poison(service_2, mock_options);
- tt_int_op(ret, OP_EQ, 0);
-
- /* Now remove the poisoning from the first service, and we have the opposite
- * problem. */
- poison_path = rend_service_sos_poison_path(service_1);
- tt_assert(poison_path);
- ret = unlink(poison_path);
- tt_int_op(ret, OP_EQ, 0);
-
- /* Unpoisoned service directories with previous keys are ok, as are empty
- * directories. */
- mock_options->HiddenServiceSingleHopMode = 0;
- mock_options->HiddenServiceNonAnonymousMode = 0;
- ret = rend_service_verify_single_onion_poison(service_1, mock_options);
- tt_int_op(ret, OP_EQ, 0);
- ret = rend_service_verify_single_onion_poison(service_2, mock_options);
- tt_int_op(ret, OP_EQ, 0);
-
- /* But the existing unpoisoned key is not ok in non-anonymous mode, even if
- * there is an empty service. */
- mock_options->HiddenServiceSingleHopMode = 1;
- mock_options->HiddenServiceNonAnonymousMode = 1;
- ret = rend_service_verify_single_onion_poison(service_1, mock_options);
- tt_int_op(ret, OP_LT, 0);
- ret = rend_service_verify_single_onion_poison(service_2, mock_options);
- tt_int_op(ret, OP_EQ, 0);
-
- /* Poisoning directories with existing keys is a no-op, because directories
- * with existing keys are ignored. But the new directory should poison. */
- mock_options->HiddenServiceSingleHopMode = 1;
- mock_options->HiddenServiceNonAnonymousMode = 1;
- ret = rend_service_poison_new_single_onion_dir(service_1, mock_options);
- tt_int_op(ret, OP_EQ, 0);
- ret = rend_service_poison_new_single_onion_dir(service_2, mock_options);
- tt_int_op(ret, OP_EQ, 0);
- /* And the old directory remains unpoisoned. */
- ret = rend_service_verify_single_onion_poison(service_1, mock_options);
- tt_int_op(ret, OP_LT, 0);
- ret = rend_service_verify_single_onion_poison(service_2, mock_options);
- tt_int_op(ret, OP_EQ, 0);
-
- /* And the new directory should be ignored, because it has no key. */
- mock_options->HiddenServiceSingleHopMode = 0;
- mock_options->HiddenServiceNonAnonymousMode = 0;
- ret = rend_service_verify_single_onion_poison(service_1, mock_options);
- tt_int_op(ret, OP_EQ, 0);
- ret = rend_service_verify_single_onion_poison(service_2, mock_options);
- tt_int_op(ret, OP_EQ, 0);
-
- /* Re-poisoning directories without existing keys is a no-op. */
- mock_options->HiddenServiceSingleHopMode = 1;
- mock_options->HiddenServiceNonAnonymousMode = 1;
- ret = rend_service_poison_new_single_onion_dir(service_1, mock_options);
- tt_int_op(ret, OP_EQ, 0);
- ret = rend_service_poison_new_single_onion_dir(service_2, mock_options);
- tt_int_op(ret, OP_EQ, 0);
- /* And the old directory remains unpoisoned. */
- ret = rend_service_verify_single_onion_poison(service_1, mock_options);
- tt_int_op(ret, OP_LT, 0);
- ret = rend_service_verify_single_onion_poison(service_2, mock_options);
- tt_int_op(ret, OP_EQ, 0);
-
- done:
- /* The test harness deletes the directories at exit */
- tor_free(poison_path);
- tor_free(dir1);
- tor_free(dir2);
- smartlist_free(services);
- rend_service_free(service_1);
- rend_service_free(service_2);
- UNMOCK(get_options);
- tor_free(mock_options->DataDirectory);
- tor_free(err_msg);
-}
-
-static rend_service_t *
-helper_create_rend_service(const char *path)
-{
- rend_service_t *s = tor_malloc_zero(sizeof(rend_service_t));
- s->ports = smartlist_new();
- s->intro_nodes = smartlist_new();
- s->expiring_nodes = smartlist_new();
- if (path) {
- s->directory = tor_strdup(path);
- }
- return s;
-}
-
-static void
-test_prune_services_on_reload(void *arg)
-{
- smartlist_t *new = smartlist_new(), *old = smartlist_new();
- /* Non ephemeral service. */
- rend_service_t *s1 = helper_create_rend_service("SomePath");
- /* Create a non ephemeral service with the _same_ path as so we can test the
- * transfer of introduction point between the same services on reload. */
- rend_service_t *s2 = helper_create_rend_service(s1->directory);
- /* Ephemeral service (directory is NULL). */
- rend_service_t *e1 = helper_create_rend_service(NULL);
- rend_service_t *e2 = helper_create_rend_service(NULL);
-
- (void) arg;
-
- {
- /* Add both services to the old list. */
- smartlist_add(old, s1);
- smartlist_add(old, e1);
- /* Only put the non ephemeral in the new list. */
- smartlist_add(new, s1);
- set_rend_service_list(old);
- set_rend_rend_service_staging_list(new);
- rend_service_prune_list_impl_();
- /* We expect that the ephemeral one is in the new list but removed from
- * the old one. */
- tt_int_op(smartlist_len(old), OP_EQ, 1);
- tt_assert(smartlist_get(old, 0) == s1);
- tt_int_op(smartlist_len(new), OP_EQ, 2);
- tt_assert(smartlist_get(new, 0) == s1);
- tt_assert(smartlist_get(new, 1) == e1);
- /* Cleanup for next test. */
- smartlist_clear(new);
- smartlist_clear(old);
- }
-
- {
- /* This test will make sure that only the ephemeral service is kept if the
- * new list is empty. The old list should contain only the non ephemeral
- * one. */
- smartlist_add(old, s1);
- smartlist_add(old, e1);
- set_rend_service_list(old);
- set_rend_rend_service_staging_list(new);
- rend_service_prune_list_impl_();
- tt_int_op(smartlist_len(old), OP_EQ, 1);
- tt_assert(smartlist_get(old, 0) == s1);
- tt_int_op(smartlist_len(new), OP_EQ, 1);
- tt_assert(smartlist_get(new, 0) == e1);
- /* Cleanup for next test. */
- smartlist_clear(new);
- smartlist_clear(old);
- }
-
- {
- /* This test makes sure that the new list stays the same even from the old
- * list being completely different. */
- smartlist_add(new, s1);
- smartlist_add(new, e1);
- set_rend_service_list(old);
- set_rend_rend_service_staging_list(new);
- rend_service_prune_list_impl_();
- tt_int_op(smartlist_len(old), OP_EQ, 0);
- tt_int_op(smartlist_len(new), OP_EQ, 2);
- tt_assert(smartlist_get(new, 0) == s1);
- tt_assert(smartlist_get(new, 1) == e1);
- /* Cleanup for next test. */
- smartlist_clear(new);
- }
-
- {
- rend_intro_point_t ip1;
- /* This IP should be found in the s2 service after pruning. */
- smartlist_add(s1->intro_nodes, &ip1);
- /* Setup our list. */
- smartlist_add(old, s1);
- smartlist_add(new, s2);
- set_rend_service_list(old);
- set_rend_rend_service_staging_list(new);
- rend_service_prune_list_impl_();
- tt_int_op(smartlist_len(old), OP_EQ, 1);
- /* Intro nodes have been moved to the s2 in theory so it must be empty. */
- tt_int_op(smartlist_len(s1->intro_nodes), OP_EQ, 0);
- tt_int_op(smartlist_len(new), OP_EQ, 1);
- rend_service_t *elem = smartlist_get(new, 0);
- tt_assert(elem);
- tt_assert(elem == s2);
- tt_int_op(smartlist_len(elem->intro_nodes), OP_EQ, 1);
- tt_assert(smartlist_get(elem->intro_nodes, 0) == &ip1);
- smartlist_clear(s1->intro_nodes);
- smartlist_clear(s2->intro_nodes);
- /* Cleanup for next test. */
- smartlist_clear(new);
- smartlist_clear(old);
- }
-
- {
- /* Test two ephemeral services. */
- smartlist_add(old, e1);
- smartlist_add(old, e2);
- set_rend_service_list(old);
- set_rend_rend_service_staging_list(new);
- rend_service_prune_list_impl_();
- /* Check if they've all been transferred. */
- tt_int_op(smartlist_len(old), OP_EQ, 0);
- tt_int_op(smartlist_len(new), OP_EQ, 2);
- }
-
- done:
- rend_service_free(s1);
- rend_service_free(s2);
- rend_service_free(e1);
- rend_service_free(e2);
- smartlist_free(new);
- smartlist_free(old);
-}
-
-struct testcase_t hs_tests[] = {
- { "hs_rend_data", test_hs_rend_data, TT_FORK,
- NULL, NULL },
- { "hs_parse_static_v2_desc", test_hs_parse_static_v2_desc, TT_FORK,
- NULL, NULL },
- { "hs_desc_event", test_hs_desc_event, TT_FORK,
- NULL, NULL },
- { "hs_auth_cookies", test_hs_auth_cookies, TT_FORK,
- NULL, NULL },
- { "single_onion_poisoning_create_dir_none", test_single_onion_poisoning,
- TT_FORK, &passthrough_setup, (void*)(CREATE_HS_DIR_NONE) },
- { "single_onion_poisoning_create_dir1", test_single_onion_poisoning,
- TT_FORK, &passthrough_setup, (void*)(CREATE_HS_DIR1) },
- { "single_onion_poisoning_create_dir2", test_single_onion_poisoning,
- TT_FORK, &passthrough_setup, (void*)(CREATE_HS_DIR2) },
- { "single_onion_poisoning_create_dir_both", test_single_onion_poisoning,
- TT_FORK, &passthrough_setup, (void*)(CREATE_HS_DIR1 | CREATE_HS_DIR2) },
- { "prune_services_on_reload", test_prune_services_on_reload, TT_FORK,
- NULL, NULL },
-
- END_OF_TESTCASES
-};
diff --git a/src/test/test_hs_cache.c b/src/test/test_hs_cache.c
index df96b2c791..25d98fa819 100644
--- a/src/test/test_hs_cache.c
+++ b/src/test/test_hs_cache.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2020, The Tor Project, Inc. */
+/* Copyright (c) 2016-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -14,7 +14,6 @@
#include "trunnel/ed25519_cert.h"
#include "feature/hs/hs_cache.h"
-#include "feature/rend/rendcache.h"
#include "feature/dircache/dircache.h"
#include "feature/dirclient/dirclient.h"
#include "feature/nodelist/networkstatus.h"
@@ -51,8 +50,6 @@ init_test(void)
{
/* Always needed. Initialize the subsystem. */
hs_cache_init();
- /* We need the v2 cache since our OOM and cache cleanup does poke at it. */
- rend_cache_init();
}
static void
diff --git a/src/test/test_hs_cell.c b/src/test/test_hs_cell.c
index 5406339276..cf7af8a38a 100644
--- a/src/test/test_hs_cell.c
+++ b/src/test/test_hs_cell.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017-2020, The Tor Project, Inc. */
+/* Copyright (c) 2017-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -20,7 +20,7 @@
#include "feature/hs/hs_service.h"
/* Trunnel. */
-#include "trunnel/hs/cell_common.h"
+#include "trunnel/extension.h"
#include "trunnel/hs/cell_establish_intro.h"
/** We simulate the creation of an outgoing ESTABLISH_INTRO cell, and then we
@@ -132,7 +132,7 @@ test_gen_establish_intro_dos_ext(void *arg)
ssize_t ret;
hs_service_config_t config;
hs_service_intro_point_t *ip = NULL;
- trn_cell_extension_t *extensions = NULL;
+ trn_extension_t *extensions = NULL;
trn_cell_extension_dos_t *dos = NULL;
(void) arg;
@@ -144,8 +144,8 @@ test_gen_establish_intro_dos_ext(void *arg)
/* Case 1: No DoS parameters so no extension to be built. */
extensions = build_establish_intro_extensions(&config, ip);
- tt_int_op(trn_cell_extension_get_num(extensions), OP_EQ, 0);
- trn_cell_extension_free(extensions);
+ tt_int_op(trn_extension_get_num(extensions), OP_EQ, 0);
+ trn_extension_free(extensions);
extensions = NULL;
/* Case 2: Enable the DoS extension. Parameter set to 0 should indicate to
@@ -153,15 +153,15 @@ test_gen_establish_intro_dos_ext(void *arg)
* nonetheless in the cell. */
config.has_dos_defense_enabled = 1;
extensions = build_establish_intro_extensions(&config, ip);
- tt_int_op(trn_cell_extension_get_num(extensions), OP_EQ, 1);
+ tt_int_op(trn_extension_get_num(extensions), OP_EQ, 1);
/* Validate the extension. */
- const trn_cell_extension_field_t *field =
- trn_cell_extension_getconst_fields(extensions, 0);
- tt_int_op(trn_cell_extension_field_get_field_type(field), OP_EQ,
+ 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_CELL_EXTENSION_TYPE_DOS);
ret = trn_cell_extension_dos_parse(&dos,
- trn_cell_extension_field_getconstarray_field(field),
- trn_cell_extension_field_getlen_field(field));
+ trn_extension_field_getconstarray_field(field),
+ trn_extension_field_getlen_field(field));
tt_int_op(ret, OP_EQ, 19);
/* Rate per sec param. */
const trn_cell_extension_dos_param_t *param =
@@ -175,21 +175,21 @@ test_gen_establish_intro_dos_ext(void *arg)
TRUNNEL_DOS_PARAM_TYPE_INTRO2_BURST_PER_SEC);
tt_u64_op(trn_cell_extension_dos_param_get_value(param), OP_EQ, 0);
trn_cell_extension_dos_free(dos); dos = NULL;
- trn_cell_extension_free(extensions); extensions = NULL;
+ trn_extension_free(extensions); extensions = NULL;
/* Case 3: Enable the DoS extension. Parameter set to some normal values. */
config.has_dos_defense_enabled = 1;
config.intro_dos_rate_per_sec = 42;
config.intro_dos_burst_per_sec = 250;
extensions = build_establish_intro_extensions(&config, ip);
- tt_int_op(trn_cell_extension_get_num(extensions), OP_EQ, 1);
+ tt_int_op(trn_extension_get_num(extensions), OP_EQ, 1);
/* Validate the extension. */
- field = trn_cell_extension_getconst_fields(extensions, 0);
- tt_int_op(trn_cell_extension_field_get_field_type(field), OP_EQ,
+ field = trn_extension_getconst_fields(extensions, 0);
+ tt_int_op(trn_extension_field_get_field_type(field), OP_EQ,
TRUNNEL_CELL_EXTENSION_TYPE_DOS);
ret = trn_cell_extension_dos_parse(&dos,
- trn_cell_extension_field_getconstarray_field(field),
- trn_cell_extension_field_getlen_field(field));
+ trn_extension_field_getconstarray_field(field),
+ trn_extension_field_getlen_field(field));
tt_int_op(ret, OP_EQ, 19);
/* Rate per sec param. */
param = trn_cell_extension_dos_getconst_params(dos, 0);
@@ -202,12 +202,12 @@ test_gen_establish_intro_dos_ext(void *arg)
TRUNNEL_DOS_PARAM_TYPE_INTRO2_BURST_PER_SEC);
tt_u64_op(trn_cell_extension_dos_param_get_value(param), OP_EQ, 250);
trn_cell_extension_dos_free(dos); dos = NULL;
- trn_cell_extension_free(extensions); extensions = NULL;
+ trn_extension_free(extensions); extensions = NULL;
done:
service_intro_point_free(ip);
trn_cell_extension_dos_free(dos);
- trn_cell_extension_free(extensions);
+ trn_extension_free(extensions);
}
struct testcase_t hs_cell_tests[] = {
diff --git a/src/test/test_hs_client.c b/src/test/test_hs_client.c
index f59b3a59cd..11a5589d21 100644
--- a/src/test/test_hs_client.c
+++ b/src/test/test_hs_client.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2020, The Tor Project, Inc. */
+/* Copyright (c) 2016-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -19,7 +19,6 @@
#include "test/test.h"
#include "test/test_helpers.h"
#include "test/log_test_helpers.h"
-#include "test/rend_test_helpers.h"
#include "test/hs_test_helpers.h"
#include "app/config/config.h"
@@ -38,7 +37,6 @@
#include "feature/hs/hs_config.h"
#include "feature/hs/hs_ident.h"
#include "feature/hs/hs_cache.h"
-#include "feature/rend/rendcache.h"
#include "core/or/circuitlist.h"
#include "core/or/circuitbuild.h"
#include "core/or/extendinfo.h"
@@ -56,6 +54,9 @@
#include "core/or/origin_circuit_st.h"
#include "core/or/socks_request_st.h"
+#define TOR_CONGESTION_CONTROL_PRIVATE
+#include "core/or/congestion_control_common.h"
+
static int
mock_connection_ap_handshake_send_begin(entry_connection_t *ap_conn)
{
@@ -137,12 +138,9 @@ helper_add_random_client_auth(const ed25519_public_key_t *service_pk)
* hidden service. */
static int
helper_get_circ_and_stream_for_test(origin_circuit_t **circ_out,
- connection_t **conn_out,
- int is_legacy)
+ connection_t **conn_out)
{
- int retval;
channel_tls_t *n_chan=NULL;
- rend_data_t *conn_rend_data = NULL;
origin_circuit_t *or_circ = NULL;
connection_t *conn = NULL;
ed25519_public_key_t service_pk;
@@ -151,20 +149,13 @@ helper_get_circ_and_stream_for_test(origin_circuit_t **circ_out,
conn = test_conn_get_connection(AP_CONN_STATE_CIRCUIT_WAIT,
CONN_TYPE_AP /* ??? */,
0);
- if (is_legacy) {
- /* Legacy: Setup rend_data of stream */
- char service_id[REND_SERVICE_ID_LEN_BASE32+1] = {0};
- TO_EDGE_CONN(conn)->rend_data = mock_rend_data(service_id);
- conn_rend_data = TO_EDGE_CONN(conn)->rend_data;
- } else {
- /* prop224: Setup hs conn identifier on the stream */
- ed25519_secret_key_t sk;
- tt_int_op(0, OP_EQ, ed25519_secret_key_generate(&sk, 0));
- tt_int_op(0, OP_EQ, ed25519_public_key_generate(&service_pk, &sk));
-
- /* Setup hs_conn_identifier of stream */
- TO_EDGE_CONN(conn)->hs_ident = hs_ident_edge_conn_new(&service_pk);
- }
+ /* prop224: Setup hs conn identifier on the stream */
+ ed25519_secret_key_t sk;
+ tt_int_op(0, OP_EQ, ed25519_secret_key_generate(&sk, 0));
+ tt_int_op(0, OP_EQ, ed25519_public_key_generate(&service_pk, &sk));
+
+ /* Setup hs_conn_identifier of stream */
+ TO_EDGE_CONN(conn)->hs_ident = hs_ident_edge_conn_new(&service_pk);
/* Make it wait for circuit */
connection_ap_mark_as_pending_circuit(TO_ENTRY_CONN(conn));
@@ -184,23 +175,8 @@ helper_get_circ_and_stream_for_test(origin_circuit_t **circ_out,
or_circ->build_state = tor_malloc_zero(sizeof(cpath_build_state_t));
or_circ->build_state->is_internal = 1;
- if (is_legacy) {
- /* Legacy: Setup rend data and final cpath */
- or_circ->build_state->pending_final_cpath =
- tor_malloc_zero(sizeof(crypt_path_t));
- or_circ->build_state->pending_final_cpath->magic = CRYPT_PATH_MAGIC;
- or_circ->build_state->pending_final_cpath->rend_dh_handshake_state =
- crypto_dh_new(DH_TYPE_REND);
- tt_assert(
- or_circ->build_state->pending_final_cpath->rend_dh_handshake_state);
- retval = crypto_dh_generate_public(
- or_circ->build_state->pending_final_cpath->rend_dh_handshake_state);
- tt_int_op(retval, OP_EQ, 0);
- or_circ->rend_data = rend_data_dup(conn_rend_data);
- } else {
- /* prop224: Setup hs ident on the circuit */
- or_circ->hs_ident = hs_ident_circuit_new(&service_pk);
- }
+ /* prop224: Setup hs ident on the circuit */
+ or_circ->hs_ident = hs_ident_circuit_new(&service_pk);
TO_CIRCUIT(or_circ)->state = CIRCUIT_STATE_OPEN;
@@ -219,91 +195,6 @@ helper_get_circ_and_stream_for_test(origin_circuit_t **circ_out,
return -1;
}
-/* Test: Ensure that setting up legacy e2e rendezvous circuits works
- * correctly. */
-static void
-test_e2e_rend_circuit_setup_legacy(void *arg)
-{
- ssize_t retval;
- origin_circuit_t *or_circ = NULL;
- connection_t *conn = NULL;
-
- (void) arg;
-
- /** In this test we create a v2 legacy HS stream and a circuit with the same
- * hidden service destination. We make the stream wait for circuits to be
- * established to the hidden service, and then we complete the circuit using
- * the hs_circuit_setup_e2e_rend_circ_legacy_client() function. We then
- * check that the end-to-end cpath was setup correctly and that the stream
- * was attached to the circuit as expected. */
-
- MOCK(connection_ap_handshake_send_begin,
- mock_connection_ap_handshake_send_begin);
-
- /* Setup */
- retval = helper_get_circ_and_stream_for_test( &or_circ, &conn, 1);
- tt_int_op(retval, OP_EQ, 0);
- tt_assert(or_circ);
- tt_assert(conn);
-
- /* Check number of hops */
- retval = cpath_get_n_hops(&or_circ->cpath);
- tt_int_op(retval, OP_EQ, 0);
-
- /* Check that our stream is not attached on any circuits */
- tt_ptr_op(TO_EDGE_CONN(conn)->on_circuit, OP_EQ, NULL);
-
- /********************************************** */
-
- /* Make a good RENDEZVOUS1 cell body because it needs to pass key exchange
- * digest verification... */
- uint8_t rend_cell_body[DH1024_KEY_LEN+DIGEST_LEN] = {2};
- {
- char keys[DIGEST_LEN+CPATH_KEY_MATERIAL_LEN];
- crypto_dh_t *dh_state =
- or_circ->build_state->pending_final_cpath->rend_dh_handshake_state;
- /* compute and overwrite digest of cell body with the right value */
- retval = crypto_dh_compute_secret(LOG_PROTOCOL_WARN, dh_state,
- (char*)rend_cell_body, DH1024_KEY_LEN,
- keys, DIGEST_LEN+CPATH_KEY_MATERIAL_LEN);
- tt_int_op(retval, OP_GT, 0);
- memcpy(rend_cell_body+DH1024_KEY_LEN, keys, DIGEST_LEN);
- }
-
- /* Setup the circuit */
- retval = hs_circuit_setup_e2e_rend_circ_legacy_client(or_circ,
- rend_cell_body);
- tt_int_op(retval, OP_EQ, 0);
-
- /**********************************************/
-
- /* See that a hop was added to the circuit's cpath */
- retval = cpath_get_n_hops(&or_circ->cpath);
- tt_int_op(retval, OP_EQ, 1);
-
- /* Check the digest algo */
- tt_int_op(
- crypto_digest_get_algorithm(or_circ->cpath->pvt_crypto.f_digest),
- OP_EQ, DIGEST_SHA1);
- tt_int_op(
- crypto_digest_get_algorithm(or_circ->cpath->pvt_crypto.b_digest),
- OP_EQ, DIGEST_SHA1);
- tt_assert(or_circ->cpath->pvt_crypto.f_crypto);
- tt_assert(or_circ->cpath->pvt_crypto.b_crypto);
-
- /* Ensure that circ purpose was changed */
- tt_int_op(or_circ->base_.purpose, OP_EQ, CIRCUIT_PURPOSE_C_REND_JOINED);
-
- /* Test that stream got attached */
- tt_ptr_op(TO_EDGE_CONN(conn)->on_circuit, OP_EQ, TO_CIRCUIT(or_circ));
-
- done:
- connection_free_minimal(conn);
- if (or_circ)
- tor_free(TO_CIRCUIT(or_circ)->n_chan);
- circuit_free_(TO_CIRCUIT(or_circ));
-}
-
/* Test: Ensure that setting up v3 rendezvous circuits works correctly. */
static void
test_e2e_rend_circuit_setup(void *arg)
@@ -326,7 +217,7 @@ test_e2e_rend_circuit_setup(void *arg)
mock_connection_ap_handshake_send_begin);
/* Setup */
- retval = helper_get_circ_and_stream_for_test(&or_circ, &conn, 0);
+ retval = helper_get_circ_and_stream_for_test(&or_circ, &conn);
tt_int_op(retval, OP_EQ, 0);
tt_assert(or_circ);
tt_assert(conn);
@@ -883,6 +774,7 @@ test_desc_has_arrived_cleanup(void *arg)
(void) arg;
hs_init();
+ congestion_control_set_cc_enabled();
MOCK(networkstatus_get_reasonably_live_consensus,
mock_networkstatus_get_reasonably_live_consensus);
@@ -974,7 +866,6 @@ test_close_intro_circuits_new_desc(void *arg)
(void) arg;
hs_init();
- rend_cache_init();
/* This is needed because of the client cache expiration timestamp is based
* on having a consensus. See cached_client_descriptor_has_expired(). */
@@ -1120,7 +1011,6 @@ test_close_intro_circuits_cache_clean(void *arg)
(void) arg;
hs_init();
- rend_cache_init();
/* This is needed because of the client cache expiration timestamp is based
* on having a consensus. See cached_client_descriptor_has_expired(). */
@@ -1189,7 +1079,6 @@ test_close_intro_circuits_cache_clean(void *arg)
circuit_free(circ);
hs_descriptor_free(desc1);
hs_free_all();
- rend_cache_free_all();
UNMOCK(networkstatus_get_reasonably_live_consensus);
}
@@ -1301,7 +1190,7 @@ test_socks_hs_errors(void *arg)
/* Code path will log this exit so build it. */
ocirc->build_state->chosen_exit = extend_info_new("TestNickname", digest,
NULL, NULL, NULL, &addr,
- 4242);
+ 4242, NULL, false);
/* Attach socks connection to this rendezvous circuit. */
ocirc->p_streams = ENTRY_TO_EDGE_CONN(socks_conn);
/* Trigger the rendezvous failure. Timeout the circuit and free. */
@@ -1396,7 +1285,7 @@ test_close_intro_circuit_failure(void *arg)
/* Code path will log this exit so build it. */
ocirc->build_state->chosen_exit = extend_info_new("TestNickname", digest,
NULL, NULL, NULL, &addr,
- 4242);
+ 4242, NULL, false);
ed25519_pubkey_copy(&ocirc->hs_ident->intro_auth_pk, &intro_kp.pubkey);
/* We'll make for close the circuit for a timeout failure. It should _NOT_
@@ -1423,7 +1312,7 @@ test_close_intro_circuit_failure(void *arg)
/* Code path will log this exit so build it. */
ocirc->build_state->chosen_exit = extend_info_new("TestNickname", digest,
NULL, NULL, NULL, &addr,
- 4242);
+ 4242, NULL, false);
ed25519_pubkey_copy(&ocirc->hs_ident->intro_auth_pk, &intro_kp.pubkey);
/* On free, we should get an unreachable failure. */
@@ -1446,7 +1335,7 @@ test_close_intro_circuit_failure(void *arg)
/* Code path will log this exit so build it. */
ocirc->build_state->chosen_exit = extend_info_new("TestNickname", digest,
NULL, NULL, NULL, &addr,
- 4242);
+ 4242, NULL, false);
ed25519_pubkey_copy(&ocirc->hs_ident->intro_auth_pk, &intro_kp.pubkey);
circuit_mark_for_close(circ, END_CIRC_REASON_TIMEOUT);
@@ -1554,8 +1443,6 @@ test_purge_ephemeral_client_auth(void *arg)
}
struct testcase_t hs_client_tests[] = {
- { "e2e_rend_circuit_setup_legacy", test_e2e_rend_circuit_setup_legacy,
- TT_FORK, NULL, NULL },
{ "e2e_rend_circuit_setup", test_e2e_rend_circuit_setup,
TT_FORK, NULL, NULL },
{ "client_pick_intro", test_client_pick_intro,
diff --git a/src/test/test_hs_common.c b/src/test/test_hs_common.c
index fccf638a07..347a5b7174 100644
--- a/src/test/test_hs_common.c
+++ b/src/test/test_hs_common.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017-2020, The Tor Project, Inc. */
+/* Copyright (c) 2017-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -787,7 +787,6 @@ test_parse_extended_hostname(void *arg)
hostname_type_t type;
char address1[] = "fooaddress.onion";
- char address2[] = "aaaaaaaaaaaaaaaa.onion";
char address3[] = "fooaddress.exit";
char address4[] = "www.torproject.org";
char address5[] = "foo.abcdefghijklmnop.onion";
@@ -803,9 +802,6 @@ test_parse_extended_hostname(void *arg)
tt_assert(!parse_extended_hostname(address1, &type));
tt_int_op(type, OP_EQ, BAD_HOSTNAME);
- tt_assert(!parse_extended_hostname(address2, &type));
- tt_int_op(type, OP_EQ, BAD_HOSTNAME);
-
tt_assert(parse_extended_hostname(address3, &type));
tt_int_op(type, OP_EQ, EXIT_HOSTNAME);
diff --git a/src/test/test_hs_config.c b/src/test/test_hs_config.c
index 20e6b014ee..74f823f897 100644
--- a/src/test/test_hs_config.c
+++ b/src/test/test_hs_config.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2020, The Tor Project, Inc. */
+/* Copyright (c) 2016-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -18,7 +18,6 @@
#include "feature/hs/hs_common.h"
#include "feature/hs/hs_config.h"
#include "feature/hs/hs_service.h"
-#include "feature/rend/rendservice.h"
static int
helper_config_service(const char *conf, int validate_only)
@@ -53,18 +52,6 @@ test_invalid_service(void *arg)
teardown_capture_of_logs();
}
- /* Version 2 not accepted anymore. */
- {
- const char *conf =
- "HiddenServiceDir /tmp/tor-test-hs-RANDOM/hs1\n"
- "HiddenServiceVersion 2\n";
- setup_full_capture_of_logs(LOG_WARN);
- ret = helper_config_service(conf, 1);
- tt_int_op(ret, OP_EQ, -1);
- expect_log_msg_containing("HiddenServiceVersion must be 3, not 2");
- teardown_capture_of_logs();
- }
-
/* Bad value of HiddenServiceAllowUnknownPorts. */
{
const char *conf =
@@ -194,7 +181,6 @@ test_valid_service(void *arg)
(void) arg;
- /* v3. */
{
const char *conf =
"HiddenServiceDir /tmp/tor-test-hs-RANDOM/hs2\n"
@@ -342,8 +328,6 @@ test_staging_service_v3(void *arg)
tt_int_op(ret, OP_EQ, 0);
/* Ok, we have a service in our map! Registration went well. */
tt_int_op(get_hs_service_staging_list_size(), OP_EQ, 1);
- /* Make sure we don't have a magic v2 service out of this. */
- tt_int_op(rend_num_services(), OP_EQ, 0);
done:
hs_free_all();
diff --git a/src/test/test_hs_control.c b/src/test/test_hs_control.c
index 6e41c4994f..c32803b380 100644
--- a/src/test/test_hs_control.c
+++ b/src/test/test_hs_control.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017-2020, The Tor Project, Inc. */
+/* Copyright (c) 2017-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -7,15 +7,17 @@
**/
#define CONTROL_EVENTS_PRIVATE
+#define CONTROL_CMD_PRIVATE
#define HS_CLIENT_PRIVATE
+#define HS_SERVICE_PRIVATE
#include "core/or/or.h"
#include "test/test.h"
#include "test/test_helpers.h"
#include "core/mainloop/connection.h"
#include "feature/control/control.h"
-#include "feature/control/control_events.h"
#include "feature/control/control_cmd.h"
+#include "feature/control/control_events.h"
#include "feature/control/control_fmt.h"
#include "feature/control/control_connection_st.h"
#include "app/config/config.h"
@@ -26,6 +28,7 @@
#include "feature/nodelist/node_st.h"
#include "feature/nodelist/routerstatus_st.h"
+#include "lib/container/smartlist.h"
#include "lib/crypt_ops/crypto_format.h"
#ifdef HAVE_SYS_STAT_H
@@ -735,6 +738,130 @@ test_hs_control_add_onion_with_bad_pubkey(void *arg)
tor_free(conn.current_cmd);
}
+/** Test that we can add the service via the control port. */
+static void
+test_hs_control_add_auth_onion_service(void *arg)
+{
+ control_connection_t conn;
+ char *args = NULL, *cp1 = NULL;
+ size_t sz;
+
+ (void) arg;
+
+ hs_init();
+
+ memset(&conn, 0, sizeof(control_connection_t));
+ TO_CONN(&conn)->outbuf = buf_new();
+ conn.current_cmd = tor_strdup("ADD_ONION");
+ args = tor_strdup("ED25519-V3:KLMQ4CLKwlDCHuMPn8j3od33cU5LhnrLNoZh7CWChl3VkY"
+ "pNAkeP5dGW8xeKR9HxQBWQ/w7Kr12lA/U8Pd/oxw== "
+ "ClientAuthV3=dz4q5xqlb4ldnbs72iarrml4ephk3du4i7o2cgiva5lwr6wkquja "
+ "Flags=V3Auth Port=9735,127.0.0.1");
+ handle_control_command(&conn, (uint32_t) strlen(args), args);
+ cp1 = buf_get_contents(TO_CONN(&conn)->outbuf, &sz);
+ tt_str_op(cp1, OP_EQ,
+ "250-ServiceID=n35etu3yjxrqjpntmfziom5sjwspoydchmelc4xleoy4jk2u4lziz2yd\r\n"
+ "250-ClientAuthV3=dz4q5xqlb4ldnbs72iarrml4ephk3du4i7o2cgiva5lwr6wkquja\r\n"
+ "250 OK\r\n");
+ tor_free(args);
+ tor_free(cp1);
+
+ args = tor_strdup("ED25519-V3:iIU8EBi71qE7G6UTsROU1kWN0JMrRP/YukC0Xk5WLGyil3"
+ "gm4u3wEBXr+/TaCpXS+65Pcdqz+PG+4+oWHLN05A== "
+ "ClientAuthV3=dummy Flags=V3Auth Port=9735,127.0.0.1");
+ handle_control_command(&conn, (uint32_t) strlen(args), args);
+ cp1 = buf_get_contents(TO_CONN(&conn)->outbuf, &sz);
+ tt_str_op(cp1, OP_EQ, "512 Cannot decode v3 client auth key\r\n");
+
+ done:
+ tor_free(args);
+ tor_free(cp1);
+ tor_free(conn.current_cmd);
+ buf_free(TO_CONN(&conn)->outbuf);
+ SMARTLIST_FOREACH(conn.ephemeral_onion_services, char *,
+ service, tor_free(service));
+ smartlist_free(conn.ephemeral_onion_services);
+ hs_client_free_all();
+}
+
+/** Test that add_onion_helper_add_service can add the service. */
+static void
+test_hs_control_add_onion_helper_add_service(void *arg)
+{
+ int hs_version_good, hs_version_bad;
+ add_onion_secret_key_t sk_good, sk_bad;
+ ed25519_public_key_t pk_good, pk_bad;
+ char *key_new_blob_good = NULL, *key_new_blob_bad = NULL;
+ const char *key_new_alg_good = NULL, *key_new_alg_bad = NULL;
+ hs_service_authorized_client_t *client_good, *client_bad;
+ smartlist_t *list_good, *list_bad;
+ hs_service_ht *global_map;
+ hs_port_config_t *portcfg;
+ smartlist_t *portcfgs;
+ char *address_out_good = NULL, *address_out_bad = NULL;
+ hs_service_t *service_good = NULL;
+ hs_service_t *service_bad = NULL;
+
+ (void) arg;
+
+ hs_init();
+ global_map = get_hs_service_map();
+
+ portcfg = hs_parse_port_config("8080", ",", NULL);
+ portcfgs = smartlist_new();
+ smartlist_add(portcfgs, portcfg);
+
+ memset(&sk_good, 0, sizeof(sk_good));
+ memset(&sk_bad, 0, sizeof(sk_bad));
+
+ add_onion_helper_keyarg("NEW:ED25519-V3", 0, &key_new_alg_good,
+ &key_new_blob_good, &sk_good, &hs_version_good, NULL);
+ add_onion_helper_keyarg("NEW:ED25519-V3", 0, &key_new_alg_bad,
+ &key_new_blob_bad, &sk_bad, &hs_version_bad, NULL);
+
+ ed25519_public_key_generate(&pk_good, sk_good.v3);
+ ed25519_public_key_generate(&pk_bad, sk_bad.v3);
+
+ client_good = parse_authorized_client_key(
+ "N2NU7BSRL6YODZCYPN4CREB54TYLKGIE2KYOQWLFYC23ZJVCE5DQ", LOG_INFO);
+ client_bad = parse_authorized_client_key("dummy", LOG_INFO);
+
+ list_good = smartlist_new();
+ smartlist_add(list_good, client_good);
+
+ add_onion_helper_add_service(HS_VERSION_THREE, &sk_good, portcfgs, 1, 1,
+ list_good, &address_out_good);
+
+ service_good = find_service(global_map, &pk_good);
+ tt_int_op(smartlist_len(service_good->config.clients), OP_EQ, 1);
+
+ remove_service(global_map, service_good);
+ hs_service_free(service_good);
+
+ list_bad = smartlist_new();
+ smartlist_add(list_bad, client_bad);
+
+ portcfg = hs_parse_port_config("8080", ",", NULL);
+ portcfgs = smartlist_new();
+ smartlist_add(portcfgs, portcfg);
+
+ add_onion_helper_add_service(HS_VERSION_THREE, &sk_bad, portcfgs, 1, 1,
+ list_bad, &address_out_bad);
+
+ service_bad = find_service(global_map, &pk_bad);
+
+ tt_int_op(smartlist_len(service_bad->config.clients), OP_EQ, 0);
+
+ done:
+ tor_free(key_new_blob_good);
+ tor_free(key_new_blob_bad);
+ tor_free(address_out_good);
+ tor_free(address_out_bad);
+
+ hs_service_free(service_good);
+ hs_service_free(service_bad);
+}
+
struct testcase_t hs_control_tests[] = {
{ "hs_desc_event", test_hs_desc_event, TT_FORK,
NULL, NULL },
@@ -748,6 +875,10 @@ struct testcase_t hs_control_tests[] = {
test_hs_control_store_permanent_creds, TT_FORK, NULL, NULL },
{ "hs_control_add_onion_with_bad_pubkey",
test_hs_control_add_onion_with_bad_pubkey, TT_FORK, NULL, NULL },
+ { "hs_control_add_auth_onion_service",
+ test_hs_control_add_auth_onion_service, TT_FORK, NULL, NULL},
+ { "hs_control_add_onion_helper_add_service",
+ test_hs_control_add_onion_helper_add_service, TT_FORK, NULL, NULL},
END_OF_TESTCASES
};
diff --git a/src/test/test_hs_descriptor.c b/src/test/test_hs_descriptor.c
index b6e13c79a8..469e3c39f9 100644
--- a/src/test/test_hs_descriptor.c
+++ b/src/test/test_hs_descriptor.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2020, The Tor Project, Inc. */
+/* Copyright (c) 2016-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -24,6 +24,9 @@
#include "test/log_test_helpers.h"
#include "test/rng_test_helpers.h"
+#define TOR_CONGESTION_CONTROL_PRIVATE
+#include "core/or/congestion_control_common.h"
+
#ifdef HAVE_CFLAG_WOVERLENGTH_STRINGS
DISABLE_GCC_WARNING("-Woverlength-strings")
/* We allow huge string constants in the unit tests, but not in the code
@@ -247,6 +250,8 @@ test_decode_descriptor(void *arg)
(void) arg;
+ congestion_control_set_cc_enabled();
+
ret = ed25519_keypair_generate(&signing_kp, 0);
tt_int_op(ret, OP_EQ, 0);
desc = hs_helper_build_hs_desc_with_ip(&signing_kp);
@@ -835,6 +840,44 @@ test_build_authorized_client(void *arg)
testing_disable_prefilled_rng();
}
+static void
+test_validate_sendme(void *arg)
+{
+ (void)arg;
+
+ /* Test basic operation: factors of 2X 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));
+
+ /* Test basic operation: Exceeding 2X fails */
+ cc_sendme_inc = 31;
+ tt_assert(!congestion_control_validate_sendme_increment(14));
+ tt_assert(!congestion_control_validate_sendme_increment(63));
+
+ /* 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;
+ tt_assert(congestion_control_validate_sendme_increment(255));
+ tt_assert(congestion_control_validate_sendme_increment(127));
+ tt_assert(!congestion_control_validate_sendme_increment(126));
+
+ /* Test 0 case */
+ cc_sendme_inc = 1;
+ tt_assert(!congestion_control_validate_sendme_increment(0));
+
+done:
+ ;
+}
+
struct testcase_t hs_descriptor[] = {
/* Encoding tests. */
{ "cert_encoding", test_cert_encoding, TT_FORK,
@@ -855,6 +898,8 @@ struct testcase_t hs_descriptor[] = {
NULL, NULL },
{ "decode_bad_signature", test_decode_bad_signature, TT_FORK,
NULL, NULL },
+ { "validate_sendme", test_validate_sendme, TT_FORK,
+ NULL, NULL },
/* Misc. */
{ "version", test_supported_version, TT_FORK,
diff --git a/src/test/test_hs_dos.c b/src/test/test_hs_dos.c
index 642513efce..70f2ef412f 100644
--- a/src/test/test_hs_dos.c
+++ b/src/test/test_hs_dos.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017-2020, The Tor Project, Inc. */
+/* Copyright (c) 2017-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/test/test_hs_intropoint.c b/src/test/test_hs_intropoint.c
index 5f7dfc4f84..cbcdeade92 100644
--- a/src/test/test_hs_intropoint.c
+++ b/src/test/test_hs_intropoint.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2020, The Tor Project, Inc. */
+/* Copyright (c) 2016-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -21,7 +21,6 @@
#include "core/or/circuituse.h"
#include "ht.h"
#include "core/or/relay.h"
-#include "feature/rend/rendservice.h"
#include "feature/hs/hs_cell.h"
#include "feature/hs/hs_circuitmap.h"
@@ -34,9 +33,9 @@
#include "core/or/or_circuit_st.h"
/* Trunnel. */
+#include "trunnel/extension.h"
#include "trunnel/hs/cell_establish_intro.h"
#include "trunnel/hs/cell_introduce1.h"
-#include "trunnel/hs/cell_common.h"
static size_t
new_establish_intro_cell(const char *circ_nonce,
@@ -160,8 +159,8 @@ helper_create_introduce1_cell(void)
/* Set the cell extensions to none. */
{
- trn_cell_extension_t *ext = trn_cell_extension_new();
- trn_cell_extension_set_num(ext, 0);
+ trn_extension_t *ext = trn_extension_new();
+ trn_extension_set_num(ext, 0);
trn_cell_introduce1_set_extensions(cell, ext);
}
@@ -535,7 +534,7 @@ test_circuitmap_free_all(void)
;
}
-/** Successfully register a v2 intro point and a v3 intro point. Ensure that HS
+/** Successfully register a v3 intro point. Ensure that HS
* circuitmap is maintained properly. */
static void
test_intro_point_registration(void *arg)
@@ -656,31 +655,6 @@ test_introduce1_suitable_circuit(void *arg)
}
static void
-test_introduce1_is_legacy(void *arg)
-{
- int ret;
- uint8_t request[256];
-
- (void) arg;
-
- /* For a cell to be considered legacy, according to the specification, the
- * first 20 bytes MUST BE non-zero else it's a v3 cell. */
- memset(request, 'a', DIGEST_LEN);
- memset(request + DIGEST_LEN, 0, sizeof(request) - DIGEST_LEN);
- ret = introduce1_cell_is_legacy(request);
- tt_int_op(ret, OP_EQ, 1);
-
- /* This is a NON legacy cell. */
- memset(request, 0, DIGEST_LEN);
- memset(request + DIGEST_LEN, 'a', sizeof(request) - DIGEST_LEN);
- ret = introduce1_cell_is_legacy(request);
- tt_int_op(ret, OP_EQ, 0);
-
- done:
- ;
-}
-
-static void
test_introduce1_validation(void *arg)
{
int ret;
@@ -693,20 +667,6 @@ test_introduce1_validation(void *arg)
cell = helper_create_introduce1_cell();
tt_assert(cell);
-#ifndef ALL_BUGS_ARE_FATAL
- /* It should NOT be a legacy cell which will trigger a BUG(). */
- memset(cell->legacy_key_id, 'a', sizeof(cell->legacy_key_id));
- tor_capture_bugs_(1);
- ret = validate_introduce1_parsed_cell(cell);
- tor_end_capture_bugs_();
- tt_int_op(ret, OP_EQ, -1);
-#endif /* !defined(ALL_BUGS_ARE_FATAL) */
-
- /* Reset legacy ID and make sure it's correct. */
- memset(cell->legacy_key_id, 0, sizeof(cell->legacy_key_id));
- ret = validate_introduce1_parsed_cell(cell);
- tt_int_op(ret, OP_EQ, 0);
-
/* Non existing auth key type. */
cell->auth_key_type = 42;
ret = validate_introduce1_parsed_cell(cell);
@@ -813,35 +773,6 @@ test_received_introduce1_handling(void *arg)
tt_int_op(ret, OP_EQ, 0);
}
- /* Valid legacy cell. */
- {
- tor_free(request);
- trn_cell_introduce1_free(cell);
- cell = helper_create_introduce1_cell();
- uint8_t *legacy_key_id = trn_cell_introduce1_getarray_legacy_key_id(cell);
- memset(legacy_key_id, 'a', DIGEST_LEN);
- /* Add an arbitrary amount of data for the payload of a v2 cell. */
- size_t request_len = trn_cell_introduce1_encoded_len(cell) + 256;
- tt_size_op(request_len, OP_GT, 0);
- request = tor_malloc_zero(request_len + 256);
- ssize_t encoded_len =
- trn_cell_introduce1_encode(request, request_len, cell);
- tt_int_op((int)encoded_len, OP_GT, 0);
-
- circ = helper_create_intro_circuit();
- or_circuit_t *service_circ = helper_create_intro_circuit();
- circuit_change_purpose(TO_CIRCUIT(service_circ),
- CIRCUIT_PURPOSE_INTRO_POINT);
- /* Register the circuit in the map for the auth key of the cell. */
- uint8_t token[REND_TOKEN_LEN];
- memcpy(token, legacy_key_id, sizeof(token));
- hs_circuitmap_register_intro_circ_v2_relay_side(service_circ, token);
- ret = hs_intro_received_introduce1(circ, request, request_len);
- circuit_free_(TO_CIRCUIT(circ));
- circuit_free_(TO_CIRCUIT(service_circ));
- tt_int_op(ret, OP_EQ, 0);
- }
-
done:
trn_cell_introduce1_free(cell);
tor_free(request);
@@ -1045,9 +976,6 @@ struct testcase_t hs_intropoint_tests[] = {
{ "introduce1_suitable_circuit",
test_introduce1_suitable_circuit, TT_FORK, NULL, &test_setup},
- { "introduce1_is_legacy",
- test_introduce1_is_legacy, TT_FORK, NULL, &test_setup},
-
{ "introduce1_validation",
test_introduce1_validation, TT_FORK, NULL, &test_setup},
diff --git a/src/test/test_hs_metrics.c b/src/test/test_hs_metrics.c
index 326212ae1d..8625933df7 100644
--- a/src/test/test_hs_metrics.c
+++ b/src/test/test_hs_metrics.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2020, The Tor Project, Inc. */
+/* Copyright (c) 2020-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/test/test_hs_ntor.c b/src/test/test_hs_ntor.c
index 7867740a1a..c507b95a60 100644
--- a/src/test/test_hs_ntor.c
+++ b/src/test/test_hs_ntor.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017-2020, The Tor Project, Inc. */
+/* Copyright (c) 2017-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/test/test_hs_ntor_cl.c b/src/test/test_hs_ntor_cl.c
index 3acd7ef0bc..cbce9c45b5 100644
--- a/src/test/test_hs_ntor_cl.c
+++ b/src/test/test_hs_ntor_cl.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017-2020, The Tor Project, Inc. */
+/* Copyright (c) 2017-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/** This is a wrapper over the little-t-tor HS ntor functions. The wrapper is
diff --git a/src/test/test_hs_ob.c b/src/test/test_hs_ob.c
index 7f40187b5f..2f69bf31e0 100644
--- a/src/test/test_hs_ob.c
+++ b/src/test/test_hs_ob.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2020, The Tor Project, Inc. */
+/* Copyright (c) 2020-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -174,6 +174,7 @@ test_get_subcredentials(void *arg)
hs_subcredential_t *subcreds = NULL;
(void) arg;
+ memset(&config, 0, sizeof(config));
MOCK(networkstatus_get_live_consensus,
mock_networkstatus_get_live_consensus);
diff --git a/src/test/test_hs_service.c b/src/test/test_hs_service.c
index 287d25f825..482ee1a014 100644
--- a/src/test/test_hs_service.c
+++ b/src/test/test_hs_service.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2020, The Tor Project, Inc. */
+/* Copyright (c) 2016-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -26,7 +26,6 @@
#include "test/test.h"
#include "test/test_helpers.h"
#include "test/log_test_helpers.h"
-#include "test/rend_test_helpers.h"
#include "test/hs_test_helpers.h"
#include "core/or/or.h"
@@ -58,7 +57,6 @@
#include "feature/hs/hs_service.h"
#include "feature/nodelist/networkstatus.h"
#include "feature/nodelist/nodelist.h"
-#include "feature/rend/rendservice.h"
#include "lib/crypt_ops/crypto_rand.h"
#include "lib/fs/dir.h"
@@ -343,7 +341,6 @@ helper_create_service_with_clients(int num_clients)
int i;
hs_service_t *service = helper_create_service();
tt_assert(service);
- service->config.is_client_auth_enabled = 1;
service->config.clients = smartlist_new();
for (i = 0; i < num_clients; i++) {
@@ -383,14 +380,13 @@ test_load_keys(void *arg)
{
int ret;
char *conf = NULL;
- char *hsdir_v2 = tor_strdup(get_fname("hs2"));
char *hsdir_v3 = tor_strdup(get_fname("hs3"));
char addr[HS_SERVICE_ADDR_LEN_BASE32 + 1];
(void) arg;
- /* We'll register two services, a v2 and a v3, then we'll load keys and
- * validate that both are in a correct state. */
+ /* We'll register one service then we'll load keys and validate that both
+ * are in a correct state. */
hs_init();
@@ -399,12 +395,6 @@ test_load_keys(void *arg)
"HiddenServiceVersion %d\n" \
"HiddenServicePort 65535\n"
- /* v2 service. */
- tor_asprintf(&conf, conf_fmt, hsdir_v2, HS_VERSION_TWO);
- ret = helper_config_service(conf);
- tor_free(conf);
- tt_int_op(ret, OP_EQ, -1);
-
/* v3 service. */
tor_asprintf(&conf, conf_fmt, hsdir_v3, HS_VERSION_THREE);
ret = helper_config_service(conf);
@@ -434,11 +424,7 @@ test_load_keys(void *arg)
tt_int_op(hs_address_is_valid(addr), OP_EQ, 1);
tt_str_op(addr, OP_EQ, s->onion_address);
- /* Check that the is_client_auth_enabled is not set. */
- tt_assert(!s->config.is_client_auth_enabled);
-
done:
- tor_free(hsdir_v2);
tor_free(hsdir_v3);
hs_free_all();
}
@@ -587,9 +573,6 @@ test_load_keys_with_client_auth(void *arg)
tt_int_op(smartlist_len(service->config.clients), OP_EQ,
smartlist_len(pubkey_b32_list));
- /* Test that the is_client_auth_enabled flag is set. */
- tt_assert(service->config.is_client_auth_enabled);
-
/* Test that the keys in clients are correct. */
SMARTLIST_FOREACH_BEGIN(pubkey_b32_list, char *, pubkey_b32) {
@@ -631,8 +614,8 @@ test_access_service(void *arg)
(void) arg;
- /* We'll register two services, a v2 and a v3, then we'll load keys and
- * validate that both are in a correct state. */
+ /* We'll register one service then we'll load keys and validate that both
+ * are in a correct state. */
hs_init();
@@ -2347,6 +2330,7 @@ test_intro2_handling(void *arg)
intro_circ->cpath->prev = intro_circ->cpath;
intro_circ->hs_ident = tor_malloc_zero(sizeof(*intro_circ->hs_ident));
origin_circuit_t rend_circ;
+ TO_CIRCUIT(&rend_circ)->ccontrol = NULL;
rend_circ.hs_ident = tor_malloc_zero(sizeof(*rend_circ.hs_ident));
curve25519_keypair_generate(&rend_circ.hs_ident->rendezvous_client_kp, 0);
memset(rend_circ.hs_ident->rendezvous_cookie, 'r', HS_REND_COOKIE_LEN);
diff --git a/src/test/test_include.sh b/src/test/test_include.sh
index 6cf695fe44..10d3bc502d 100755
--- a/src/test/test_include.sh
+++ b/src/test/test_include.sh
@@ -48,6 +48,9 @@ if "${TOR_BINARY}" --list-modules | grep -q "relay: no"; then
fi
tmpdir=
+# For some reasons, shellcheck is not seeing that we can call this
+# function from the trap below.
+# shellcheck disable=SC2317
clean () {
if [ -n "$tmpdir" ] && [ -d "$tmpdir" ]; then
rm -rf "$tmpdir"
diff --git a/src/test/test_introduce.c b/src/test/test_introduce.c
deleted file mode 100644
index 0ae78496b2..0000000000
--- a/src/test/test_introduce.c
+++ /dev/null
@@ -1,539 +0,0 @@
-/* Copyright (c) 2012-2020, The Tor Project, Inc. */
-/* See LICENSE for licensing information */
-
-#include "orconfig.h"
-#include "lib/crypt_ops/crypto_cipher.h"
-#include "core/or/or.h"
-#include "test/test.h"
-
-#define RENDSERVICE_PRIVATE
-#include "feature/rend/rendservice.h"
-
-static uint8_t v0_test_plaintext[] =
- /* 20 bytes of rendezvous point nickname */
- { 0x4e, 0x69, 0x63, 0x6b, 0x6e, 0x61, 0x6d, 0x65,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- /* 20 bytes dummy rendezvous cookie */
- 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
- 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
- 0x10, 0x11, 0x12, 0x13,
- /* 128 bytes dummy DH handshake data */
- 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
- 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
- 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08,
- 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00,
- 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
- 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
- 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08,
- 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00,
- 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
- 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
- 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08,
- 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00,
- 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
- 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
- 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08,
- 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00 };
-
-static uint8_t v1_test_plaintext[] =
- /* Version byte */
- { 0x01,
- /* 42 bytes of dummy rendezvous point hex digest */
- 0x24, 0x30, 0x30, 0x30, 0x31, 0x30, 0x32, 0x30,
- 0x33, 0x30, 0x34, 0x30, 0x35, 0x30, 0x36, 0x30,
- 0x37, 0x30, 0x38, 0x30, 0x39, 0x30, 0x41, 0x30,
- 0x42, 0x30, 0x43, 0x30, 0x44, 0x30, 0x45, 0x30,
- 0x46, 0x31, 0x30, 0x31, 0x31, 0x31, 0x32, 0x31,
- 0x33, 0x00,
- /* 20 bytes dummy rendezvous cookie */
- 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
- 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
- 0x10, 0x11, 0x12, 0x13,
- /* 128 bytes dummy DH handshake data */
- 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
- 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
- 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08,
- 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00,
- 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
- 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
- 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08,
- 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00,
- 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
- 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
- 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08,
- 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00,
- 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
- 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
- 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08,
- 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00 };
-
-static uint8_t v2_test_plaintext[] =
- /* Version byte */
- { 0x02,
- /* 4 bytes rendezvous point's IP address */
- 0xc0, 0xa8, 0x00, 0x01,
- /* 2 bytes rendezvous point's OR port */
- 0x23, 0x5a,
- /* 20 bytes dummy rendezvous point's identity digest */
- 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
- 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
- 0x10, 0x11, 0x12, 0x13,
- /* 2 bytes length of onion key */
- 0x00, 0x8c,
- /* Onion key (140 bytes taken from live test) */
- 0x30, 0x81, 0x89, 0x02, 0x81, 0x81, 0x00, 0xb1,
- 0xcd, 0x46, 0xa9, 0x18, 0xd2, 0x0f, 0x01, 0xf8,
- 0xb2, 0xad, 0xa4, 0x79, 0xb4, 0xbb, 0x4b, 0xf4,
- 0x54, 0x1e, 0x3f, 0x03, 0x54, 0xcf, 0x7c, 0xb6,
- 0xb5, 0xf0, 0xfe, 0xed, 0x4b, 0x7d, 0xd7, 0x61,
- 0xdb, 0x6d, 0xd9, 0x19, 0xe2, 0x72, 0x04, 0xaa,
- 0x3e, 0x89, 0x26, 0x14, 0x62, 0x9a, 0x6c, 0x11,
- 0x0b, 0x35, 0x99, 0x2c, 0x9f, 0x2c, 0x64, 0xa1,
- 0xd9, 0xe2, 0x88, 0xce, 0xf6, 0x54, 0xfe, 0x1d,
- 0x37, 0x5e, 0x6d, 0x73, 0x95, 0x54, 0x90, 0xf0,
- 0x7b, 0xfa, 0xd4, 0x44, 0xac, 0xb2, 0x23, 0x9f,
- 0x75, 0x36, 0xe2, 0x78, 0x62, 0x82, 0x80, 0xa4,
- 0x23, 0x22, 0xc9, 0xbf, 0xc4, 0x36, 0xd1, 0x31,
- 0x33, 0x8e, 0x64, 0xb4, 0xa9, 0x74, 0xa1, 0xcb,
- 0x42, 0x8d, 0x60, 0xc7, 0xbb, 0x8e, 0x6e, 0x0f,
- 0x36, 0x74, 0x8e, 0xf4, 0x08, 0x99, 0x06, 0x92,
- 0xb1, 0x3f, 0xb3, 0xdd, 0xed, 0xf7, 0xc9, 0x02,
- 0x03, 0x01, 0x00, 0x01,
- /* 20 bytes dummy rendezvous cookie */
- 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
- 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
- 0x10, 0x11, 0x12, 0x13,
- /* 128 bytes dummy DH handshake data */
- 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
- 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
- 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08,
- 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00,
- 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
- 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
- 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08,
- 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00,
- 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
- 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
- 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08,
- 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00,
- 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
- 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
- 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08,
- 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00 };
-
-static uint8_t v3_no_auth_test_plaintext[] =
- /* Version byte */
- { 0x03,
- /* Auth type (0 for no auth len/auth data) */
- 0x00,
- /* Timestamp */
- 0x50, 0x0b, 0xb5, 0xaa,
- /* 4 bytes rendezvous point's IP address */
- 0xc0, 0xa8, 0x00, 0x01,
- /* 2 bytes rendezvous point's OR port */
- 0x23, 0x5a,
- /* 20 bytes dummy rendezvous point's identity digest */
- 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
- 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
- 0x10, 0x11, 0x12, 0x13,
- /* 2 bytes length of onion key */
- 0x00, 0x8c,
- /* Onion key (140 bytes taken from live test) */
- 0x30, 0x81, 0x89, 0x02, 0x81, 0x81, 0x00, 0xb1,
- 0xcd, 0x46, 0xa9, 0x18, 0xd2, 0x0f, 0x01, 0xf8,
- 0xb2, 0xad, 0xa4, 0x79, 0xb4, 0xbb, 0x4b, 0xf4,
- 0x54, 0x1e, 0x3f, 0x03, 0x54, 0xcf, 0x7c, 0xb6,
- 0xb5, 0xf0, 0xfe, 0xed, 0x4b, 0x7d, 0xd7, 0x61,
- 0xdb, 0x6d, 0xd9, 0x19, 0xe2, 0x72, 0x04, 0xaa,
- 0x3e, 0x89, 0x26, 0x14, 0x62, 0x9a, 0x6c, 0x11,
- 0x0b, 0x35, 0x99, 0x2c, 0x9f, 0x2c, 0x64, 0xa1,
- 0xd9, 0xe2, 0x88, 0xce, 0xf6, 0x54, 0xfe, 0x1d,
- 0x37, 0x5e, 0x6d, 0x73, 0x95, 0x54, 0x90, 0xf0,
- 0x7b, 0xfa, 0xd4, 0x44, 0xac, 0xb2, 0x23, 0x9f,
- 0x75, 0x36, 0xe2, 0x78, 0x62, 0x82, 0x80, 0xa4,
- 0x23, 0x22, 0xc9, 0xbf, 0xc4, 0x36, 0xd1, 0x31,
- 0x33, 0x8e, 0x64, 0xb4, 0xa9, 0x74, 0xa1, 0xcb,
- 0x42, 0x8d, 0x60, 0xc7, 0xbb, 0x8e, 0x6e, 0x0f,
- 0x36, 0x74, 0x8e, 0xf4, 0x08, 0x99, 0x06, 0x92,
- 0xb1, 0x3f, 0xb3, 0xdd, 0xed, 0xf7, 0xc9, 0x02,
- 0x03, 0x01, 0x00, 0x01,
- /* 20 bytes dummy rendezvous cookie */
- 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
- 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
- 0x10, 0x11, 0x12, 0x13,
- /* 128 bytes dummy DH handshake data */
- 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
- 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
- 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08,
- 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00,
- 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
- 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
- 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08,
- 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00,
- 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
- 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
- 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08,
- 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00,
- 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
- 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
- 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08,
- 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00 };
-
-static uint8_t v3_basic_auth_test_plaintext[] =
- /* Version byte */
- { 0x03,
- /* Auth type (1 for REND_BASIC_AUTH) */
- 0x01,
- /* Auth len (must be 16 bytes for REND_BASIC_AUTH) */
- 0x00, 0x10,
- /* Auth data (a 16-byte dummy descriptor cookie) */
- 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
- 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
- /* Timestamp */
- 0x50, 0x0b, 0xb5, 0xaa,
- /* 4 bytes rendezvous point's IP address */
- 0xc0, 0xa8, 0x00, 0x01,
- /* 2 bytes rendezvous point's OR port */
- 0x23, 0x5a,
- /* 20 bytes dummy rendezvous point's identity digest */
- 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
- 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
- 0x10, 0x11, 0x12, 0x13,
- /* 2 bytes length of onion key */
- 0x00, 0x8c,
- /* Onion key (140 bytes taken from live test) */
- 0x30, 0x81, 0x89, 0x02, 0x81, 0x81, 0x00, 0xb1,
- 0xcd, 0x46, 0xa9, 0x18, 0xd2, 0x0f, 0x01, 0xf8,
- 0xb2, 0xad, 0xa4, 0x79, 0xb4, 0xbb, 0x4b, 0xf4,
- 0x54, 0x1e, 0x3f, 0x03, 0x54, 0xcf, 0x7c, 0xb6,
- 0xb5, 0xf0, 0xfe, 0xed, 0x4b, 0x7d, 0xd7, 0x61,
- 0xdb, 0x6d, 0xd9, 0x19, 0xe2, 0x72, 0x04, 0xaa,
- 0x3e, 0x89, 0x26, 0x14, 0x62, 0x9a, 0x6c, 0x11,
- 0x0b, 0x35, 0x99, 0x2c, 0x9f, 0x2c, 0x64, 0xa1,
- 0xd9, 0xe2, 0x88, 0xce, 0xf6, 0x54, 0xfe, 0x1d,
- 0x37, 0x5e, 0x6d, 0x73, 0x95, 0x54, 0x90, 0xf0,
- 0x7b, 0xfa, 0xd4, 0x44, 0xac, 0xb2, 0x23, 0x9f,
- 0x75, 0x36, 0xe2, 0x78, 0x62, 0x82, 0x80, 0xa4,
- 0x23, 0x22, 0xc9, 0xbf, 0xc4, 0x36, 0xd1, 0x31,
- 0x33, 0x8e, 0x64, 0xb4, 0xa9, 0x74, 0xa1, 0xcb,
- 0x42, 0x8d, 0x60, 0xc7, 0xbb, 0x8e, 0x6e, 0x0f,
- 0x36, 0x74, 0x8e, 0xf4, 0x08, 0x99, 0x06, 0x92,
- 0xb1, 0x3f, 0xb3, 0xdd, 0xed, 0xf7, 0xc9, 0x02,
- 0x03, 0x01, 0x00, 0x01,
- /* 20 bytes dummy rendezvous cookie */
- 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
- 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
- 0x10, 0x11, 0x12, 0x13,
- /* 128 bytes dummy DH handshake data */
- 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
- 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
- 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08,
- 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00,
- 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
- 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
- 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08,
- 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00,
- 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
- 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
- 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08,
- 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00,
- 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
- 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
- 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08,
- 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00 };
-
-static void do_decrypt_test(uint8_t *plaintext, size_t plaintext_len);
-static void do_early_parse_test(uint8_t *plaintext, size_t plaintext_len);
-static void do_late_parse_test(uint8_t *plaintext, size_t plaintext_len);
-static void do_parse_test(uint8_t *plaintext, size_t plaintext_len, int phase);
-static ssize_t make_intro_from_plaintext(
- void *buf, size_t len, crypto_pk_t *key, void **cell_out);
-
-#define EARLY_PARSE_ONLY 1
-#define DECRYPT_ONLY 2
-#define ALL_PARSING 3
-
-static void
-do_early_parse_test(uint8_t *plaintext, size_t plaintext_len)
-{
- do_parse_test(plaintext, plaintext_len, EARLY_PARSE_ONLY);
-}
-
-static void
-do_decrypt_test(uint8_t *plaintext, size_t plaintext_len)
-{
- do_parse_test(plaintext, plaintext_len, DECRYPT_ONLY);
-}
-
-static void
-do_late_parse_test(uint8_t *plaintext, size_t plaintext_len)
-{
- do_parse_test(plaintext, plaintext_len, ALL_PARSING);
-}
-
-/** Test utility function: checks that the <b>plaintext_len</b>-byte string at
- * <b>plaintext</b> is at least superficially parseable.
- */
-static void
-do_parse_test(uint8_t *plaintext, size_t plaintext_len, int phase)
-{
- crypto_pk_t *k = NULL;
- ssize_t r;
- uint8_t *cell = NULL;
- size_t cell_len;
- rend_intro_cell_t *parsed_req = NULL;
- char *err_msg = NULL;
- char digest[DIGEST_LEN];
-
- /* Get a key */
- k = crypto_pk_new();
- tt_assert(k);
- r = crypto_pk_read_private_key_from_string(k, AUTHORITY_SIGNKEY_1, -1);
- tt_assert(!r);
-
- /* Get digest for future comparison */
- r = crypto_pk_get_digest(k, digest);
- tt_assert(r >= 0);
-
- /* Make a cell out of it */
- r = make_intro_from_plaintext(
- plaintext, plaintext_len,
- k, (void **)(&cell));
- tt_assert(r > 0);
- tt_assert(cell);
- cell_len = r;
-
- /* Do early parsing */
- parsed_req = rend_service_begin_parse_intro(cell, cell_len, 2, &err_msg);
- tt_assert(parsed_req);
- tt_ptr_op(err_msg, OP_EQ, NULL);
- tt_mem_op(parsed_req->pk,OP_EQ, digest, DIGEST_LEN);
- tt_assert(parsed_req->ciphertext);
- tt_assert(parsed_req->ciphertext_len > 0);
-
- if (phase == EARLY_PARSE_ONLY)
- goto done;
-
- /* Do decryption */
- r = rend_service_decrypt_intro(parsed_req, k, &err_msg);
- tt_assert(!r);
- tt_ptr_op(err_msg, OP_EQ, NULL);
- tt_assert(parsed_req->plaintext);
- tt_assert(parsed_req->plaintext_len > 0);
-
- if (phase == DECRYPT_ONLY)
- goto done;
-
- /* Do late parsing */
- r = rend_service_parse_intro_plaintext(parsed_req, &err_msg);
- tt_assert(!r);
- tt_ptr_op(err_msg, OP_EQ, NULL);
- tt_assert(parsed_req->parsed);
-
- done:
- tor_free(cell);
- crypto_pk_free(k);
- rend_service_free_intro(parsed_req);
- tor_free(err_msg);
-}
-
-/** Given the plaintext of the encrypted part of an INTRODUCE1/2 and a key,
- * construct the encrypted cell for testing.
- */
-
-static ssize_t
-make_intro_from_plaintext(
- void *buf, size_t len, crypto_pk_t *key, void **cell_out)
-{
- char *cell = NULL;
- ssize_t cell_len = -1, r;
- /* Assemble key digest and ciphertext, then construct the cell */
- ssize_t ciphertext_size;
-
- if (!(buf && key && len > 0 && cell_out)) goto done;
-
- /*
- * Figure out an upper bound on how big the ciphertext will be
- * (see crypto_pk_obsolete_public_hybrid_encrypt())
- */
- ciphertext_size = PKCS1_OAEP_PADDING_OVERHEAD;
- ciphertext_size += crypto_pk_keysize(key);
- ciphertext_size += CIPHER_KEY_LEN;
- ciphertext_size += len;
-
- /*
- * Allocate space for the cell
- */
- cell = tor_malloc(DIGEST_LEN + ciphertext_size);
-
- /* Compute key digest (will be first DIGEST_LEN octets of cell) */
- r = crypto_pk_get_digest(key, cell);
- tt_assert(r >= 0);
-
- /* Do encryption */
- r = crypto_pk_obsolete_public_hybrid_encrypt(
- key, cell + DIGEST_LEN, ciphertext_size,
- buf, len,
- PK_PKCS1_OAEP_PADDING, 0);
- tt_assert(r >= 0);
-
- /* Figure out cell length */
- cell_len = DIGEST_LEN + r;
-
- /* Output the cell */
- *cell_out = cell;
- cell = NULL;
-
- done:
- tor_free(cell);
- return cell_len;
-}
-
-/** Test v0 INTRODUCE2 parsing through decryption only
- */
-
-static void
-test_introduce_decrypt_v0(void *arg)
-{
- (void)arg;
- do_decrypt_test(v0_test_plaintext, sizeof(v0_test_plaintext));
-}
-
-/** Test v1 INTRODUCE2 parsing through decryption only
- */
-
-static void
-test_introduce_decrypt_v1(void *arg)
-{
- (void)arg;
- do_decrypt_test(v1_test_plaintext, sizeof(v1_test_plaintext));
-}
-
-/** Test v2 INTRODUCE2 parsing through decryption only
- */
-
-static void
-test_introduce_decrypt_v2(void *arg)
-{
- (void)arg;
- do_decrypt_test(v2_test_plaintext, sizeof(v2_test_plaintext));
-}
-
-/** Test v3 INTRODUCE2 parsing through decryption only
- */
-
-static void
-test_introduce_decrypt_v3(void *arg)
-{
- (void)arg;
- do_decrypt_test(
- v3_no_auth_test_plaintext, sizeof(v3_no_auth_test_plaintext));
- do_decrypt_test(
- v3_basic_auth_test_plaintext, sizeof(v3_basic_auth_test_plaintext));
-}
-
-/** Test v0 INTRODUCE2 parsing through early parsing only
- */
-
-static void
-test_introduce_early_parse_v0(void *arg)
-{
- (void)arg;
- do_early_parse_test(v0_test_plaintext, sizeof(v0_test_plaintext));
-}
-
-/** Test v1 INTRODUCE2 parsing through early parsing only
- */
-
-static void
-test_introduce_early_parse_v1(void *arg)
-{
- (void)arg;
- do_early_parse_test(v1_test_plaintext, sizeof(v1_test_plaintext));
-}
-
-/** Test v2 INTRODUCE2 parsing through early parsing only
- */
-
-static void
-test_introduce_early_parse_v2(void *arg)
-{
- (void)arg;
- do_early_parse_test(v2_test_plaintext, sizeof(v2_test_plaintext));
-}
-
-/** Test v3 INTRODUCE2 parsing through early parsing only
- */
-
-static void
-test_introduce_early_parse_v3(void *arg)
-{
- (void)arg;
- do_early_parse_test(
- v3_no_auth_test_plaintext, sizeof(v3_no_auth_test_plaintext));
- do_early_parse_test(
- v3_basic_auth_test_plaintext, sizeof(v3_basic_auth_test_plaintext));
-}
-
-/** Test v0 INTRODUCE2 parsing
- */
-
-static void
-test_introduce_late_parse_v0(void *arg)
-{
- (void)arg;
- do_late_parse_test(v0_test_plaintext, sizeof(v0_test_plaintext));
-}
-
-/** Test v1 INTRODUCE2 parsing
- */
-
-static void
-test_introduce_late_parse_v1(void *arg)
-{
- (void)arg;
- do_late_parse_test(v1_test_plaintext, sizeof(v1_test_plaintext));
-}
-
-/** Test v2 INTRODUCE2 parsing
- */
-
-static void
-test_introduce_late_parse_v2(void *arg)
-{
- (void)arg;
- do_late_parse_test(v2_test_plaintext, sizeof(v2_test_plaintext));
-}
-
-/** Test v3 INTRODUCE2 parsing
- */
-
-static void
-test_introduce_late_parse_v3(void *arg)
-{
- (void)arg;
- do_late_parse_test(
- v3_no_auth_test_plaintext, sizeof(v3_no_auth_test_plaintext));
- do_late_parse_test(
- v3_basic_auth_test_plaintext, sizeof(v3_basic_auth_test_plaintext));
-}
-
-#define INTRODUCE_LEGACY(name) \
- { #name, test_introduce_ ## name , 0, NULL, NULL }
-
-struct testcase_t introduce_tests[] = {
- INTRODUCE_LEGACY(early_parse_v0),
- INTRODUCE_LEGACY(early_parse_v1),
- INTRODUCE_LEGACY(early_parse_v2),
- INTRODUCE_LEGACY(early_parse_v3),
- INTRODUCE_LEGACY(decrypt_v0),
- INTRODUCE_LEGACY(decrypt_v1),
- INTRODUCE_LEGACY(decrypt_v2),
- INTRODUCE_LEGACY(decrypt_v3),
- INTRODUCE_LEGACY(late_parse_v0),
- INTRODUCE_LEGACY(late_parse_v1),
- INTRODUCE_LEGACY(late_parse_v2),
- INTRODUCE_LEGACY(late_parse_v3),
- END_OF_TESTCASES
-};
diff --git a/src/test/test_key_expiration.sh b/src/test/test_key_expiration.sh
index 1ba8179aa1..2e2745e0a3 100755
--- a/src/test/test_key_expiration.sh
+++ b/src/test/test_key_expiration.sh
@@ -107,7 +107,7 @@ TOR="${TOR_BINARY} --DisableNetwork 1 --ShutdownWaitLength 0 --ORPort 12345 --Ex
# Step 1: Start Tor with --list-fingerprint --quiet. Make sure everything is there.
echo "Setup step #1"
-${TOR} --list-fingerprint ${SILENTLY} > /dev/null
+${TOR} ${SILENTLY} --list-fingerprint > /dev/null
check_dir "${DATA_DIR}/keys"
check_file "${DATA_DIR}/keys/ed25519_master_id_public_key"
diff --git a/src/test/test_keygen.sh b/src/test/test_keygen.sh
index 6812f8883d..be1fde9e32 100755
--- a/src/test/test_keygen.sh
+++ b/src/test/test_keygen.sh
@@ -120,7 +120,7 @@ TOR="${TOR_BINARY} ${QUIETLY} --DisableNetwork 1 --ShutdownWaitLength 0 --ORPort
# Step 1: Start Tor with --list-fingerprint --quiet. Make sure everything is there.
mkdir "${DATA_DIR}/orig"
-${TOR} --DataDirectory "${DATA_DIR}/orig" --list-fingerprint ${SILENTLY} > /dev/null
+${TOR} --DataDirectory "${DATA_DIR}/orig" ${SILENTLY} --list-fingerprint > /dev/null
check_dir "${DATA_DIR}/orig/keys"
check_file "${DATA_DIR}/orig/keys/ed25519_master_id_public_key"
@@ -206,7 +206,7 @@ SRC="${DATA_DIR}/orig"
mkdir -p "${ME}/keys"
cp "${SRC}/keys/ed25519_master_id_"* "${ME}/keys/"
-${TOR} --DataDirectory "${ME}" --list-fingerprint ${SILENTLY} >/dev/null || die "Tor failed when starting with only master key"
+${TOR} --DataDirectory "${ME}" ${SILENTLY} --list-fingerprint >/dev/null || die "Tor failed when starting with only master key"
check_files_eq "${SRC}/keys/ed25519_master_id_public_key" "${ME}/keys/ed25519_master_id_public_key"
check_files_eq "${SRC}/keys/ed25519_master_id_secret_key" "${ME}/keys/ed25519_master_id_secret_key"
check_file "${ME}/keys/ed25519_signing_cert"
@@ -264,11 +264,11 @@ SRC="${DATA_DIR}/orig"
mkdir -p "${ME}/keys"
cp "${SRC}/keys/ed25519_master_id_secret_key" "${ME}/keys/"
-${TOR} --DataDirectory "${ME}" --list-fingerprint ${SILENTLY} > "${ME}/fp1" || die "Tor wouldn't start with only unencrypted secret key"
+${TOR} --DataDirectory "${ME}" ${SILENTLY} --list-fingerprint > "${ME}/fp1" || die "Tor wouldn't start with only unencrypted secret key"
check_file "${ME}/keys/ed25519_master_id_public_key"
check_file "${ME}/keys/ed25519_signing_cert"
check_file "${ME}/keys/ed25519_signing_secret_key"
-${TOR} --DataDirectory "${ME}" --list-fingerprint ${SILENTLY} > "${ME}/fp2" || die "Tor wouldn't start again after starting once with only unencrypted secret key."
+${TOR} --DataDirectory "${ME}" ${SILENTLY} --list-fingerprint > "${ME}/fp2" || die "Tor wouldn't start again after starting once with only unencrypted secret key."
check_files_eq "${ME}/fp1" "${ME}/fp2"
@@ -330,7 +330,7 @@ cp "${SRC}/keys/ed25519_master_id_secret_key" "${ME}/keys/"
cp "${SRC}/keys/ed25519_signing_cert" "${ME}/keys/"
cp "${SRC}/keys/ed25519_signing_secret_key" "${ME}/keys/"
-${TOR} --DataDirectory "${ME}" --list-fingerprint ${SILENTLY} >/dev/null || die "Failed when starting with missing public key"
+${TOR} --DataDirectory "${ME}" ${SILENTLY} --list-fingerprint >/dev/null || die "Failed when starting with missing public key"
check_keys_eq ed25519_master_id_secret_key
check_keys_eq ed25519_master_id_public_key
check_keys_eq ed25519_signing_secret_key
@@ -352,7 +352,7 @@ cp "${SRC}/keys/ed25519_master_id_public_key" "${ME}/keys/"
cp "${SRC}/keys/ed25519_signing_cert" "${ME}/keys/"
cp "${SRC}/keys/ed25519_signing_secret_key" "${ME}/keys/"
-${TOR} --DataDirectory "${ME}" --list-fingerprint ${SILENTLY} >/dev/null || die "Failed when starting with offline secret key"
+${TOR} --DataDirectory "${ME}" ${SILENTLY} --list-fingerprint >/dev/null || die "Failed when starting with offline secret key"
check_no_file "${ME}/keys/ed25519_master_id_secret_key"
check_keys_eq ed25519_master_id_public_key
check_keys_eq ed25519_signing_secret_key
@@ -373,7 +373,7 @@ mkdir -p "${ME}/keys"
cp "${SRC}/keys/ed25519_signing_cert" "${ME}/keys/"
cp "${SRC}/keys/ed25519_signing_secret_key" "${ME}/keys/"
-${TOR} --DataDirectory "${ME}" --list-fingerprint ${SILENTLY} >/dev/null || die "Failed when starting with only signing material"
+${TOR} --DataDirectory "${ME}" ${SILENTLY} --list-fingerprint >/dev/null || die "Failed when starting with only signing material"
check_no_file "${ME}/keys/ed25519_master_id_secret_key"
check_file "${ME}/keys/ed25519_master_id_public_key"
check_keys_eq ed25519_signing_secret_key
diff --git a/src/test/test_keypin.c b/src/test/test_keypin.c
index ff6397f8c7..7b73e94b3a 100644
--- a/src/test/test_keypin.c
+++ b/src/test/test_keypin.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2020, The Tor Project, Inc. */
+/* Copyright (c) 2014-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
diff --git a/src/test/test_link_handshake.c b/src/test/test_link_handshake.c
index 06af299056..c9ddc843ac 100644
--- a/src/test/test_link_handshake.c
+++ b/src/test/test_link_handshake.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2020, The Tor Project, Inc. */
+/* Copyright (c) 2014-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
diff --git a/src/test/test_logging.c b/src/test/test_logging.c
index 58d0f24bd3..a77136deec 100644
--- a/src/test/test_logging.c
+++ b/src/test/test_logging.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2020, The Tor Project, Inc. */
+/* Copyright (c) 2013-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define CONFIG_PRIVATE
diff --git a/src/test/test_mainloop.c b/src/test/test_mainloop.c
index c4e60d9da5..ccd3378be5 100644
--- a/src/test/test_mainloop.c
+++ b/src/test/test_mainloop.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2018-2020, The Tor Project, Inc. */
+/* Copyright (c) 2018-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -231,6 +231,8 @@ test_mainloop_check_participation(void *arg)
const time_t start = 1542658829;
const time_t ONE_DAY = 24*60*60;
+ options->DormantTimeoutEnabled = 1;
+
// Suppose we've been idle for a day or two
reset_user_activity(start - 2*ONE_DAY);
set_network_participation(true);
diff --git a/src/test/test_metrics.c b/src/test/test_metrics.c
index 58628e8483..ba1a763f0c 100644
--- a/src/test/test_metrics.c
+++ b/src/test/test_metrics.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2020, The Tor Project, Inc. */
+/* Copyright (c) 2020-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/test/test_microdesc.c b/src/test/test_microdesc.c
index 6bd1f56859..c564805ecf 100644
--- a/src/test/test_microdesc.c
+++ b/src/test/test_microdesc.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2020, The Tor Project, Inc. */
+/* Copyright (c) 2010-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
diff --git a/src/test/test_namemap.c b/src/test/test_namemap.c
index e93d3fbc3c..4397784170 100644
--- a/src/test/test_namemap.c
+++ b/src/test/test_namemap.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2018-2020, The Tor Project, Inc. */
+/* Copyright (c) 2018-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "test/test.h"
diff --git a/src/test/test_netinfo.c b/src/test/test_netinfo.c
index 93892978dc..03a7a8a905 100644
--- a/src/test/test_netinfo.c
+++ b/src/test/test_netinfo.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2007-2020, The Tor Project, Inc. */
+/* Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
diff --git a/src/test/test_nodelist.c b/src/test/test_nodelist.c
index 96fb5a65ad..250db9a964 100644
--- a/src/test/test_nodelist.c
+++ b/src/test/test_nodelist.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2007-2020, The Tor Project, Inc. */
+/* Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/test/test_ntor_cl.c b/src/test/test_ntor_cl.c
index a1508d0afc..94270f1fd6 100644
--- a/src/test/test_ntor_cl.c
+++ b/src/test/test_ntor_cl.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2020, The Tor Project, Inc. */
+/* Copyright (c) 2012-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
diff --git a/src/test/test_ntor_v3.c b/src/test/test_ntor_v3.c
new file mode 100644
index 0000000000..1d06403076
--- /dev/null
+++ b/src/test/test_ntor_v3.c
@@ -0,0 +1,311 @@
+/* Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#include "orconfig.h"
+#define ONION_NTOR_V3_PRIVATE
+#include "core/or/or.h"
+#include "test/test.h"
+#include "lib/crypt_ops/crypto_curve25519.h"
+#include "lib/crypt_ops/crypto_ed25519.h"
+#include "core/crypto/onion_ntor_v3.h"
+#include "core/crypto/onion_crypto.h"
+#include "core/or/extend_info_st.h"
+#include "core/or/crypt_path_st.h"
+#define TOR_CONGESTION_CONTROL_PRIVATE
+#include "core/or/congestion_control_common.h"
+#include "app/config/config.h"
+
+#define unhex(arry, s) \
+ { tt_int_op(sizeof(arry), OP_EQ, \
+ base16_decode((char*)arry, sizeof(arry), s, strlen(s))); \
+ }
+
+static void
+test_ntor3_testvecs(void *arg)
+{
+ (void)arg;
+ char *mem_op_hex_tmp = NULL; // temp val to make test_memeq_hex work.
+
+ ntor3_server_handshake_state_t *relay_state = NULL;
+ uint8_t *onion_skin = NULL;
+ size_t onion_skin_len;
+ ntor3_handshake_state_t *client_state = NULL;
+ uint8_t *cm = NULL, *sm = NULL;
+ size_t cm_len, sm_len;
+ di_digest256_map_t *private_keys = NULL;
+ uint8_t *server_handshake = NULL;
+ size_t server_handshake_len;
+
+ // Test vectors from python implementation, confirmed with rust
+ // implementation.
+ curve25519_keypair_t relay_keypair_b;
+ curve25519_keypair_t client_keypair_x;
+ curve25519_keypair_t relay_keypair_y;
+ ed25519_public_key_t relay_id;
+
+ unhex(relay_keypair_b.seckey.secret_key,
+ "4051daa5921cfa2a1c27b08451324919538e79e788a81b38cbed097a5dff454a");
+ unhex(relay_keypair_b.pubkey.public_key,
+ "f8307a2bc1870b00b828bb74dbb8fd88e632a6375ab3bcd1ae706aaa8b6cdd1d");
+ unhex(relay_id.pubkey,
+ "9fad2af287ef942632833d21f946c6260c33fae6172b60006e86e4a6911753a2");
+ unhex(client_keypair_x.seckey.secret_key,
+ "b825a3719147bcbe5fb1d0b0fcb9c09e51948048e2e3283d2ab7b45b5ef38b49");
+ unhex(client_keypair_x.pubkey.public_key,
+ "252fe9ae91264c91d4ecb8501f79d0387e34ad8ca0f7c995184f7d11d5da4f46");
+ unhex(relay_keypair_y.seckey.secret_key,
+ "4865a5b7689dafd978f529291c7171bc159be076b92186405d13220b80e2a053");
+ unhex(relay_keypair_y.pubkey.public_key,
+ "4bf4814326fdab45ad5184f5518bd7fae25dc59374062698201a50a22954246d");
+
+ uint8_t client_message[11];
+ uint8_t verification[5];
+ unhex(client_message, "68656c6c6f20776f726c64");
+ unhex(verification, "78797a7a79");
+
+ // ========= Client handshake 1.
+
+ onion_skin_ntor3_create_nokeygen(
+ &client_keypair_x,
+ &relay_id,
+ &relay_keypair_b.pubkey,
+ verification,
+ sizeof(verification),
+ client_message,
+ sizeof(client_message),
+ &client_state,
+ &onion_skin,
+ &onion_skin_len);
+
+ const char expect_client_handshake[] = "9fad2af287ef942632833d21f946c6260c"
+ "33fae6172b60006e86e4a6911753a2f8307a2bc1870b00b828bb74dbb8fd88e632a6375"
+ "ab3bcd1ae706aaa8b6cdd1d252fe9ae91264c91d4ecb8501f79d0387e34ad8ca0f7c995"
+ "184f7d11d5da4f463bebd9151fd3b47c180abc9e044d53565f04d82bbb3bebed3d06cea"
+ "65db8be9c72b68cd461942088502f67";
+
+ tt_int_op(onion_skin_len, OP_EQ, strlen(expect_client_handshake)/2);
+ test_memeq_hex(onion_skin, expect_client_handshake);
+
+ // ========= Relay handshake.
+
+ dimap_add_entry(&private_keys,
+ relay_keypair_b.pubkey.public_key,
+ &relay_keypair_b);
+
+ int r = onion_skin_ntor3_server_handshake_part1(
+ private_keys,
+ &client_keypair_x,
+ &relay_id,
+ onion_skin,
+ onion_skin_len,
+ verification,
+ sizeof(verification),
+ &cm,
+ &cm_len,
+ &relay_state);
+ tt_int_op(r, OP_EQ, 0);
+ tt_int_op(cm_len, OP_EQ, sizeof(client_message));
+ tt_mem_op(cm, OP_EQ, client_message, cm_len);
+
+ uint8_t server_message[10];
+ unhex(server_message, "486f6c61204d756e646f");
+
+ uint8_t server_keys[256];
+ onion_skin_ntor3_server_handshake_part2_nokeygen(
+ &relay_keypair_y,
+ relay_state,
+ verification,
+ sizeof(verification),
+ server_message,
+ sizeof(server_message),
+ &server_handshake,
+ &server_handshake_len,
+ server_keys,
+ sizeof(server_keys));
+
+ const char expect_server_handshake[] = "4bf4814326fdab45ad5184f5518bd7fae25"
+ "dc59374062698201a50a22954246d2fc5f8773ca824542bc6cf6f57c7c29bbf4e5476461"
+ "ab130c5b18ab0a91276651202c3e1e87c0d32054c";
+ tt_int_op(server_handshake_len, OP_EQ, strlen(expect_server_handshake)/2);
+ test_memeq_hex(server_handshake, expect_server_handshake);
+
+ uint8_t expect_keys[256];
+ unhex(expect_keys, "9c19b631fd94ed86a817e01f6c80b0743a43f5faebd39cfaa8b00f"
+ "a8bcc65c3bfeaa403d91acbd68a821bf6ee8504602b094a254392a07737d5662768"
+ "c7a9fb1b2814bb34780eaee6e867c773e28c212ead563e98a1cd5d5b4576f5ee61c"
+ "59bde025ff2851bb19b721421694f263818e3531e43a9e4e3e2c661e2ad547d8984"
+ "caa28ebecd3e4525452299be26b9185a20a90ce1eac20a91f2832d731b54502b097"
+ "49b5a2a2949292f8cfcbeffb790c7790ed935a9d251e7e336148ea83b063a5618fc"
+ "ff674a44581585fd22077ca0e52c59a24347a38d1a1ceebddbf238541f226b8f88d"
+ "0fb9c07a1bcd2ea764bbbb5dacdaf5312a14c0b9e4f06309b0333b4a");
+ tt_mem_op(server_keys, OP_EQ, expect_keys, 256);
+
+ // ===== Client handshake 2
+
+ uint8_t client_keys[256];
+ r = onion_ntor3_client_handshake(
+ client_state,
+ server_handshake,
+ server_handshake_len,
+ verification,
+ sizeof(verification),
+ client_keys,
+ sizeof(client_keys),
+ &sm,
+ &sm_len);
+
+ tt_int_op(r, OP_EQ, 0);
+ tt_int_op(sm_len, OP_EQ, sizeof(server_message));
+ tt_mem_op(sm, OP_EQ, server_message, sizeof(server_message));
+ tt_mem_op(client_keys, OP_EQ, server_keys, 256);
+
+ done:
+ tor_free(onion_skin);
+ tor_free(server_handshake);
+ tor_free(mem_op_hex_tmp);
+ ntor3_handshake_state_free(client_state);
+ ntor3_server_handshake_state_free(relay_state);
+ tor_free(cm);
+ tor_free(sm);
+ dimap_free(private_keys, NULL);
+}
+
+static void
+run_full_handshake(circuit_params_t *serv_params_in,
+ circuit_params_t *client_params_out,
+ circuit_params_t *serv_params_out)
+{
+ extend_info_t info = {0};
+ uint8_t onionskin[CELL_PAYLOAD_SIZE];
+ int onionskin_len = 0;
+ int reply_len = 0;
+ onion_handshake_state_t handshake_state = {0};
+ server_onion_keys_t server_keys = {0};
+ curve25519_keypair_t relay_onion_key;
+ uint8_t serv_reply[CELL_PAYLOAD_SIZE];
+ uint8_t serv_keys[100];
+ uint8_t rend_nonce[DIGEST_LEN];
+ uint8_t client_keys[CELL_PAYLOAD_SIZE];
+ uint8_t rend_auth[DIGEST_LEN];
+
+ info.exit_supports_congestion_control = 1;
+
+ unhex(relay_onion_key.seckey.secret_key,
+ "4051daa5921cfa2a1c27b08451324919538e79e788a81b38cbed097a5dff454a");
+ unhex(relay_onion_key.pubkey.public_key,
+ "f8307a2bc1870b00b828bb74dbb8fd88e632a6375ab3bcd1ae706aaa8b6cdd1d");
+
+ memcpy(&info.curve25519_onion_key,
+ &relay_onion_key.pubkey, sizeof(info.curve25519_onion_key));
+ unhex(info.ed_identity.pubkey,
+ "9fad2af287ef942632833d21f946c6260c33fae6172b60006e86e4a6911753a2");
+
+ memcpy(&server_keys.my_ed_identity, &info.ed_identity,
+ sizeof(server_keys.my_ed_identity));
+
+ dimap_add_entry(&server_keys.curve25519_key_map,
+ relay_onion_key.pubkey.public_key,
+ &relay_onion_key);
+
+ onionskin_len = onion_skin_create(ONION_HANDSHAKE_TYPE_NTOR_V3, &info,
+ &handshake_state, onionskin,
+ sizeof(onionskin));
+ tt_int_op(onionskin_len, OP_NE, -1);
+
+ server_keys.junk_keypair = &handshake_state.u.ntor3->client_keypair;
+
+ reply_len = onion_skin_server_handshake(ONION_HANDSHAKE_TYPE_NTOR_V3,
+ onionskin, onionskin_len,
+ &server_keys, serv_params_in,
+ serv_reply, sizeof(serv_reply),
+ serv_keys, sizeof(serv_keys),
+ rend_nonce, serv_params_out);
+ tt_int_op(reply_len, OP_NE, -1);
+
+ tt_int_op(onion_skin_client_handshake(ONION_HANDSHAKE_TYPE_NTOR_V3,
+ &handshake_state,
+ serv_reply, reply_len,
+ client_keys, sizeof(client_keys),
+ rend_auth, client_params_out,
+ NULL), OP_EQ, 0);
+
+ done:
+ dimap_free(server_keys.curve25519_key_map, NULL);
+ ntor3_handshake_state_free(handshake_state.u.ntor3);
+
+ return;
+}
+
+/**
+ * Test congestion control negotiation logic.
+ *
+ * This tests that congestion control is only enabled when both
+ * client and server agree, via consensus param or torrc.
+ *
+ * It also tests that when they agree, they agree on the server's
+ * version of sendme_inc.
+ */
+static void
+test_ntor3_handshake(void *arg)
+{
+ (void)arg;
+ circuit_params_t client_params, serv_params, serv_ns_params;
+
+ serv_ns_params.sendme_inc_cells = congestion_control_sendme_inc();
+
+ /* client off, serv off -> off */
+ serv_ns_params.cc_enabled = 0;
+ run_full_handshake(&serv_ns_params, &client_params, &serv_params);
+ tt_int_op(client_params.cc_enabled, OP_EQ, 0);
+ tt_int_op(serv_params.cc_enabled, OP_EQ, 0);
+
+ /* client off, serv on -> off */
+ 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);
+ tt_int_op(serv_params.cc_enabled, OP_EQ, 0);
+
+ /* client off + param, serv on -> on */
+ serv_ns_params.cc_enabled = 1;
+ get_options_mutable()->AlwaysCongestionControl = 1;
+ run_full_handshake(&serv_ns_params, &client_params, &serv_params);
+ tt_int_op(client_params.cc_enabled, OP_EQ, 1);
+ tt_int_op(serv_params.cc_enabled, OP_EQ, 1);
+
+ /* client on, serv off -> off */
+ serv_ns_params.cc_enabled = 0;
+ congestion_control_set_cc_enabled();
+ run_full_handshake(&serv_ns_params, &client_params, &serv_params);
+ tt_int_op(client_params.cc_enabled, OP_EQ, 0);
+ tt_int_op(serv_params.cc_enabled, OP_EQ, 0);
+
+ /* client on, serv on -> on */
+ 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, 1);
+ tt_int_op(serv_params.cc_enabled, OP_EQ, 1);
+
+ /* client on, serv on, sendme_inc diff -> serv sendme_inc */
+ serv_ns_params.cc_enabled = 1;
+ serv_ns_params.sendme_inc_cells += 1;
+ run_full_handshake(&serv_ns_params, &client_params, &serv_params);
+ tt_int_op(client_params.cc_enabled, OP_EQ, 1);
+ tt_int_op(serv_params.cc_enabled, OP_EQ, 1);
+ tt_int_op(serv_params.sendme_inc_cells, OP_EQ,
+ client_params.sendme_inc_cells);
+ tt_int_op(client_params.sendme_inc_cells, OP_EQ,
+ serv_ns_params.sendme_inc_cells);
+ tt_int_op(client_params.sendme_inc_cells, OP_NE,
+ congestion_control_sendme_inc());
+
+ done:
+ return;
+}
+
+struct testcase_t ntor_v3_tests[] = {
+ { "testvecs", test_ntor3_testvecs, 0, NULL, NULL, },
+ { "handshake_negtotiation", test_ntor3_handshake, 0, NULL, NULL, },
+ END_OF_TESTCASES,
+};
diff --git a/src/test/test_oom.c b/src/test/test_oom.c
index 51c237ec2e..7cab0933f7 100644
--- a/src/test/test_oom.c
+++ b/src/test/test_oom.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2020, The Tor Project, Inc. */
+/* Copyright (c) 2014-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/* Unit tests for OOM handling logic */
diff --git a/src/test/test_oos.c b/src/test/test_oos.c
index f8c712a6b6..157f3aa9b3 100644
--- a/src/test/test_oos.c
+++ b/src/test/test_oos.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2020, The Tor Project, Inc. */
+/* Copyright (c) 2016-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/* Unit tests for OOS handler */
diff --git a/src/test/test_options.c b/src/test/test_options.c
index 714ee4767f..182e6dd572 100644
--- a/src/test/test_options.c
+++ b/src/test/test_options.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define CONFIG_PRIVATE
@@ -302,8 +302,6 @@ test_options_validate(void *arg)
"ServerTransportOptions did not parse",
LOG_WARN, "\"slingsnappy\" is not a k=v", PH_VALIDATE);
- WANT_ERR("DirPort 8080\nDirCache 0",
- "DirPort configured but DirCache disabled.", PH_VALIDATE);
WANT_ERR("BridgeRelay 1\nDirCache 0",
"We're a bridge but DirCache is disabled.", PH_VALIDATE);
@@ -1932,18 +1930,6 @@ test_options_validate__publish_server_descriptor(void *ignored)
"PublishServerDescriptor line.");
tor_free(msg);
- free_options_test_data(tdata);
- tdata = get_options_test_data("BridgeRelay 1\n"
- "DirPort 999\n");
-
- mock_clean_saved_logs();
- ret = options_validate(NULL, tdata->opt, &msg);
- tt_int_op(ret, OP_EQ, -1);
- expect_log_msg("Can't set a DirPort on a bridge "
- "relay; disabling DirPort\n");
- tt_assert(!tdata->opt->DirPort_lines);
- tt_assert(!tdata->opt->DirPort_set);
-
done:
teardown_capture_of_logs();
policies_free_all();
@@ -2389,14 +2375,6 @@ test_options_validate__rend(void *ignored)
"Failed to configure rendezvous options. See logs for details.");
tor_free(msg);
- free_options_test_data(tdata);
- tdata = get_options_test_data("HidServAuth failed\n");
- ret = options_validate(NULL, tdata->opt, &msg);
- tt_int_op(ret, OP_EQ, -1);
- tt_str_op(msg, OP_EQ, "Failed to configure client authorization for hidden "
- "services. See logs for details.");
- tor_free(msg);
-
done:
policies_free_all();
teardown_capture_of_logs();
@@ -3464,35 +3442,6 @@ test_options_validate__constrained_sockets(void *ignored)
"between 2048 and 262144 in 1024 byte increments.");
tor_free(msg);
- free_options_test_data(tdata);
- tdata = get_options_test_data("ConstrainedSockets 1\n"
- "ConstrainedSockSize 2048\n"
- "DirPort 999\n"
- "DirCache 1\n"
- );
- mock_clean_saved_logs();
- ret = options_validate(NULL, tdata->opt, &msg);
- tt_int_op(ret, OP_EQ, 0);
- expect_log_msg("You have requested constrained "
- "socket buffers while also serving directory entries via DirPort."
- " It is strongly suggested that you disable serving directory"
- " requests when system TCP buffer resources are scarce.\n");
- tor_free(msg);
-
- free_options_test_data(tdata);
- tdata = get_options_test_data("ConstrainedSockets 1\n"
- "ConstrainedSockSize 2048\n"
- );
- mock_clean_saved_logs();
- ret = options_validate(NULL, tdata->opt, &msg);
- tt_int_op(ret, OP_EQ, 0);
- expect_no_log_msg(
- "You have requested constrained socket buffers while also serving"
- " directory entries via DirPort. It is strongly suggested that "
- "you disable serving directory requests when system TCP buffer "
- "resources are scarce.\n");
- tor_free(msg);
-
done:
policies_free_all();
teardown_capture_of_logs();
diff --git a/src/test/test_options_act.c b/src/test/test_options_act.c
index 942584bffd..0044598962 100644
--- a/src/test/test_options_act.c
+++ b/src/test/test_options_act.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define CONFIG_PRIVATE
diff --git a/src/test/test_parsecommon.c b/src/test/test_parsecommon.c
index 9c22266da1..b32840264e 100644
--- a/src/test/test_parsecommon.c
+++ b/src/test/test_parsecommon.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "core/or/or.h"
@@ -326,18 +326,15 @@ test_parsecommon_get_next_token_parse_keys(void *arg)
const char *end2 = str2 + strlen(str2);
const char **s2 = (const char **)&str2;
- token_rule_t rule2 = T01("client-key", C_CLIENT_KEY, NO_ARGS,
- NEED_SKEY_1024);
-
+ token_rule_t rule2 = T01("client-key", C_CLIENT_KEY, NO_ARGS, OBJ_OK);
token2 = get_next_token(area, s2, end2, &rule2);
tt_assert(token2);
-
tt_int_op(token2->tp, OP_EQ, C_CLIENT_KEY);
tt_int_op(token2->n_args, OP_EQ, 0);
tt_str_op(token2->object_type, OP_EQ, "RSA PRIVATE KEY");
tt_int_op(token2->object_size, OP_EQ, 608);
tt_assert(token2->object_body);
- tt_assert(token2->key);
+ tt_assert(token2->key == NULL);
tt_assert(!token->error);
done:
diff --git a/src/test/test_pem.c b/src/test/test_pem.c
index 9772be124b..6397cbddfa 100644
--- a/src/test/test_pem.c
+++ b/src/test/test_pem.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
diff --git a/src/test/test_periodic_event.c b/src/test/test_periodic_event.c
index d3bc89673b..6a9569ae89 100644
--- a/src/test/test_periodic_event.c
+++ b/src/test/test_periodic_event.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2018-2020, The Tor Project, Inc. */
+/* Copyright (c) 2018-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/test/test_policy.c b/src/test/test_policy.c
index 0a0548d161..97606476a6 100644
--- a/src/test/test_policy.c
+++ b/src/test/test_policy.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2020, The Tor Project, Inc. */
+/* Copyright (c) 2013-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define CONFIG_PRIVATE
diff --git a/src/test/test_prob_distr.c b/src/test/test_prob_distr.c
index da65a0f26d..0eca435ab5 100644
--- a/src/test/test_prob_distr.c
+++ b/src/test/test_prob_distr.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2018-2020, The Tor Project, Inc. */
+/* Copyright (c) 2018-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/test/test_process.c b/src/test/test_process.c
index b5185242d3..fcfbc13431 100644
--- a/src/test/test_process.c
+++ b/src/test/test_process.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2018-2020, The Tor Project, Inc. */
+/* Copyright (c) 2018-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/test/test_process_descs.c b/src/test/test_process_descs.c
index 5c2301f873..abcb6ae2fe 100644
--- a/src/test/test_process_descs.c
+++ b/src/test/test_process_descs.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2019-2020, The Tor Project, Inc. */
+/* Copyright (c) 2019-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
@@ -21,9 +21,9 @@ test_process_descs_versions(void *arg)
// a non-tor program: don't reject.
{ "Wombat 0.1.2.3-alpha", false },
// some unsupported versions: reject.
+ { "Tor 0.2.9.100", true },
{ "Tor 0.2.9.4-alpha", true },
{ "Tor 0.2.9.5-alpha", true },
- { "Tor 0.2.9.100", true },
{ "Tor 0.3.0.0-alpha-dev", true },
{ "Tor 0.3.0.2-alpha", true },
{ "Tor 0.3.0.5", true },
@@ -34,17 +34,34 @@ test_process_descs_versions(void *arg)
{ "Tor 0.3.4.100", true },
{ "Tor 0.3.5.1-alpha", true },
{ "Tor 0.3.5.6-rc", true},
+ { "Tor 0.3.5.7", true },
+ { "Tor 0.3.5.8", true },
{ "Tor 0.4.0.1-alpha", true },
{ "Tor 0.4.0.5", true },
{ "Tor 0.4.1.1-alpha", true },
{ "Tor 0.4.1.4-rc", true },
{ "Tor 0.4.1.5", true },
- // new enough to be supported
- { "Tor 0.3.5.7", false },
- { "Tor 0.3.5.8", false },
- { "Tor 0.4.2.1-alpha", false },
- { "Tor 0.4.2.4-rc", false },
- { "Tor 0.4.3.0-alpha-dev", false },
+ { "Tor 0.4.2.1-alpha", true },
+ { "Tor 0.4.2.4-rc", true },
+ { "Tor 0.4.2.5", true },
+ { "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.6.0-alpha-dev", true },
+ { "Tor 0.4.6.1-alpha", true },
+ { "Tor 0.4.6.5", true },
+ { "Tor 0.4.6.50", true }, /* Non existing one in the 0.4.6 series */
+
+ { "Tor 0.4.7.0-alpha-dev", false },
+ { "Tor 0.4.7.3-alpha", false },
+ { "Tor 0.4.7.12", false },
+
// Very far in the future
{ "Tor 100.100.1.5", false },
};
diff --git a/src/test/test_process_slow.c b/src/test/test_process_slow.c
index f74d4adc9a..6cb1b01b50 100644
--- a/src/test/test_process_slow.c
+++ b/src/test/test_process_slow.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2018-2020, The Tor Project, Inc. */
+/* Copyright (c) 2018-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/test/test_procmon.c b/src/test/test_procmon.c
index 1752008f63..3e459edecc 100644
--- a/src/test/test_procmon.c
+++ b/src/test/test_procmon.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2020, The Tor Project, Inc. */
+/* Copyright (c) 2010-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
diff --git a/src/test/test_proto_haproxy.c b/src/test/test_proto_haproxy.c
index 040354ec1f..dade0d77ca 100644
--- a/src/test/test_proto_haproxy.c
+++ b/src/test/test_proto_haproxy.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2019-2020, The Tor Project, Inc. */
+/* Copyright (c) 2019-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/test/test_proto_http.c b/src/test/test_proto_http.c
index 481d78b2c1..6c859c0cb0 100644
--- a/src/test/test_proto_http.c
+++ b/src/test/test_proto_http.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017-2020, The Tor Project, Inc. */
+/* Copyright (c) 2017-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/test/test_proto_misc.c b/src/test/test_proto_misc.c
index 64bf5c4993..d575b8b3da 100644
--- a/src/test/test_proto_misc.c
+++ b/src/test/test_proto_misc.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017-2020, The Tor Project, Inc. */
+/* Copyright (c) 2017-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/test/test_protover.c b/src/test/test_protover.c
index 16f0279871..9d14fd678a 100644
--- a/src/test/test_protover.c
+++ b/src/test/test_protover.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2020, The Tor Project, Inc. */
+/* Copyright (c) 2016-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define PROTOVER_PRIVATE
@@ -23,13 +23,6 @@ static void
test_protover_parse(void *arg)
{
(void) arg;
-#ifdef HAVE_RUST
- /** This test is disabled on rust builds, because it only exists to test
- * internal C functions. */
- tt_skip();
- done:
- ;
-#else /* !defined(HAVE_RUST) */
char *re_encoded = NULL;
const char *orig = "Foo=1,3 Bar=3 Baz= Quux=9-12,14,15-16";
@@ -64,18 +57,12 @@ test_protover_parse(void *arg)
SMARTLIST_FOREACH(elts, proto_entry_t *, ent, proto_entry_free(ent));
smartlist_free(elts);
tor_free(re_encoded);
-#endif /* defined(HAVE_RUST) */
}
static void
test_protover_parse_fail(void *arg)
{
(void)arg;
-#ifdef HAVE_RUST
- /** This test is disabled on rust builds, because it only exists to test
- * internal C functions. */
- tt_skip();
-#else
smartlist_t *elts;
/* random junk */
@@ -108,7 +95,6 @@ test_protover_parse_fail(void *arg)
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
tt_ptr_op(elts, OP_EQ, NULL);
-#endif /* defined(HAVE_RUST) */
done:
;
}
@@ -265,7 +251,7 @@ test_protover_all_supported(void *arg)
#endif /* !defined(ALL_BUGS_ARE_FATAL) */
/* Protocol name too long */
-#if !defined(HAVE_RUST) && !defined(ALL_BUGS_ARE_FATAL)
+#if !defined(ALL_BUGS_ARE_FATAL)
tor_capture_bugs_(1);
tt_assert(protover_all_supported(
"DoSaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
@@ -273,7 +259,7 @@ test_protover_all_supported(void *arg)
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
"aaaaaaaaaaaa=1-65536", &msg));
tor_end_capture_bugs_();
-#endif /* !defined(HAVE_RUST) && !defined(ALL_BUGS_ARE_FATAL) */
+#endif /* !defined(ALL_BUGS_ARE_FATAL) */
done:
tor_end_capture_bugs_();
@@ -370,6 +356,8 @@ test_protover_supports_version(void *arg)
#define PROTOVER_FLOWCTRL_V1 1
+#define PROTOVER_RELAY_NTOR_V3 4
+
/* Make sure we haven't forgotten any supported protocols */
static void
test_protover_supported_protocols(void *arg)
@@ -641,7 +629,7 @@ test_protover_vote_roundtrip_ours(void *args)
*/
#define PROTOVER(proto_string, version_macro) \
(proto_string "=" STR(version_macro))
-#endif
+#endif /* defined(COCCI) */
#define DEBUG_PROTOVER(flags) \
STMT_BEGIN \
@@ -658,7 +646,8 @@ test_protover_vote_roundtrip_ours(void *args)
"supports_establish_intro_dos_extension: %d,\n" \
"supports_v3_hsdir: %d,\n" \
"supports_v3_rendezvous_point: %d,\n" \
- "supports_hs_setup_padding: %d.", \
+ "supports_hs_setup_padding: %d,\n" \
+ "supports_congestion_control: %d.", \
(flags).protocols_known, \
(flags).supports_extend2_cells, \
(flags).supports_accepting_ipv6_extends, \
@@ -670,7 +659,8 @@ test_protover_vote_roundtrip_ours(void *args)
(flags).supports_establish_intro_dos_extension, \
(flags).supports_v3_hsdir, \
(flags).supports_v3_rendezvous_point, \
- (flags).supports_hs_setup_padding); \
+ (flags).supports_hs_setup_padding, \
+ (flags).supports_congestion_control); \
STMT_END
/* Test that the proto_string version version_macro sets summary_flag. */
diff --git a/src/test/test_pt.c b/src/test/test_pt.c
index 893fec3674..07c5032933 100644
--- a/src/test/test_pt.c
+++ b/src/test/test_pt.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
@@ -233,6 +233,10 @@ test_pt_protocol(void *arg)
handle_proxy_line(line, mp);
tt_assert(mp->conf_state == PT_PROTO_ACCEPTING_METHODS);
+ strlcpy(line,"CMETHOD-ERROR fakename not supported",sizeof(line));
+ handle_proxy_line(line, mp);
+ tt_assert(mp->conf_state == PT_PROTO_ACCEPTING_METHODS);
+
strlcpy(line,"CMETHODS DONE",sizeof(line));
handle_proxy_line(line, mp);
tt_assert(mp->conf_state == PT_PROTO_CONFIGURED);
diff --git a/src/test/test_ptr_slow.c b/src/test/test_ptr_slow.c
index 25b893c4c0..7f72f0a578 100644
--- a/src/test/test_ptr_slow.c
+++ b/src/test/test_ptr_slow.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
diff --git a/src/test/test_pubsub_build.c b/src/test/test_pubsub_build.c
index 5f9005926c..288e075144 100644
--- a/src/test/test_pubsub_build.c
+++ b/src/test/test_pubsub_build.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2018-2020, The Tor Project, Inc. */
+/* Copyright (c) 2018-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define DISPATCH_PRIVATE
diff --git a/src/test/test_pubsub_msg.c b/src/test/test_pubsub_msg.c
index 3054db885d..566038dd28 100644
--- a/src/test/test_pubsub_msg.c
+++ b/src/test/test_pubsub_msg.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2018-2020, The Tor Project, Inc. */
+/* Copyright (c) 2018-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define DISPATCH_PRIVATE
diff --git a/src/test/test_rebind.sh b/src/test/test_rebind.sh
index 879008c1c1..aae2a9a6a0 100755
--- a/src/test/test_rebind.sh
+++ b/src/test/test_rebind.sh
@@ -46,6 +46,9 @@ if "${TOR_BINARY}" --list-modules | grep -q "relay: no"; then
fi
tmpdir=
+# For some reasons, shellcheck is not seeing that we can call this
+# function from the trap below.
+# shellcheck disable=SC2317
clean () {
if [ -n "$tmpdir" ] && [ -d "$tmpdir" ]; then
rm -rf "$tmpdir"
diff --git a/src/test/test_relay.c b/src/test/test_relay.c
index 8ed29b6282..dbedc021e4 100644
--- a/src/test/test_relay.c
+++ b/src/test/test_relay.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2020, The Tor Project, Inc. */
+/* Copyright (c) 2014-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define CIRCUITBUILD_PRIVATE
diff --git a/src/test/test_relaycell.c b/src/test/test_relaycell.c
index 6f5bc7e770..05e2b2e347 100644
--- a/src/test/test_relaycell.c
+++ b/src/test/test_relaycell.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2020, The Tor Project, Inc. */
+/* Copyright (c) 2014-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/* Unit tests for handling different kinds of relay cell */
diff --git a/src/test/test_relaycrypt.c b/src/test/test_relaycrypt.c
index 737c243e2d..3a615c53a3 100644
--- a/src/test/test_relaycrypt.c
+++ b/src/test/test_relaycrypt.c
@@ -1,6 +1,6 @@
/* Copyright 2001-2004 Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define CRYPT_PATH_PRIVATE
diff --git a/src/test/test_rendcache.c b/src/test/test_rendcache.c
deleted file mode 100644
index 06167635c1..0000000000
--- a/src/test/test_rendcache.c
+++ /dev/null
@@ -1,1248 +0,0 @@
-/* Copyright (c) 2010-2020, The Tor Project, Inc. */
-/* See LICENSE for licensing information */
-
-#include "orconfig.h"
-#include "core/or/or.h"
-
-#include "test/test.h"
-#define RENDCACHE_PRIVATE
-#include "feature/rend/rendcache.h"
-#include "feature/relay/router.h"
-#include "feature/nodelist/routerlist.h"
-#include "app/config/config.h"
-#include "feature/hs/hs_common.h"
-
-#include "core/or/extend_info_st.h"
-#include "feature/rend/rend_encoded_v2_service_descriptor_st.h"
-#include "feature/rend/rend_intro_point_st.h"
-#include "feature/rend/rend_service_descriptor_st.h"
-#include "feature/nodelist/routerinfo_st.h"
-
-#include "test/rend_test_helpers.h"
-#include "test/log_test_helpers.h"
-
-static const int RECENT_TIME = -10;
-static const int TIME_IN_THE_PAST = -(REND_CACHE_MAX_AGE + \
- REND_CACHE_MAX_SKEW + 60);
-static const int TIME_IN_THE_FUTURE = REND_CACHE_MAX_SKEW + 60;
-
-static void
-test_rend_cache_lookup_entry(void *data)
-{
- int ret;
- rend_data_t *mock_rend_query = NULL;
- char desc_id_base32[REND_DESC_ID_V2_LEN_BASE32 + 1];
- rend_cache_entry_t *entry = NULL;
- rend_encoded_v2_service_descriptor_t *desc_holder = NULL;
- char *service_id = NULL;
- (void)data;
-
- rend_cache_init();
-
- generate_desc(RECENT_TIME, &desc_holder, &service_id, 3);
-
- ret = rend_cache_lookup_entry("abababababababab", 0, NULL);
- tt_int_op(ret, OP_EQ, -ENOENT);
-
- ret = rend_cache_lookup_entry("invalid query", 2, NULL);
- tt_int_op(ret, OP_EQ, -EINVAL);
-
- ret = rend_cache_lookup_entry("abababababababab", 2, NULL);
- tt_int_op(ret, OP_EQ, -ENOENT);
-
- ret = rend_cache_lookup_entry("abababababababab", 4224, NULL);
- tt_int_op(ret, OP_EQ, -ENOENT);
-
- mock_rend_query = mock_rend_data(service_id);
- base32_encode(desc_id_base32, sizeof(desc_id_base32), desc_holder->desc_id,
- DIGEST_LEN);
- rend_cache_store_v2_desc_as_client(desc_holder->desc_str, desc_id_base32,
- mock_rend_query, NULL);
-
- ret = rend_cache_lookup_entry(service_id, 2, NULL);
- tt_int_op(ret, OP_EQ, 0);
-
- ret = rend_cache_lookup_entry(service_id, 2, &entry);
- tt_int_op(ret, OP_EQ, 0);
- tt_assert(entry);
- tt_int_op(entry->len, OP_EQ, strlen(desc_holder->desc_str));
- tt_str_op(entry->desc, OP_EQ, desc_holder->desc_str);
-
- done:
- rend_encoded_v2_service_descriptor_free(desc_holder);
- tor_free(service_id);
- rend_cache_free_all();
- rend_data_free(mock_rend_query);
-}
-
-static void
-test_rend_cache_store_v2_desc_as_client(void *data)
-{
- int ret;
- rend_data_t *mock_rend_query;
- char desc_id_base32[REND_DESC_ID_V2_LEN_BASE32 + 1];
- rend_cache_entry_t *entry = NULL;
- rend_encoded_v2_service_descriptor_t *desc_holder = NULL;
- char *service_id = NULL;
- char client_cookie[REND_DESC_COOKIE_LEN];
- (void)data;
-
- rend_cache_init();
-
- generate_desc(RECENT_TIME, &desc_holder, &service_id, 3);
-
- // Test success
- mock_rend_query = mock_rend_data(service_id);
- base32_encode(desc_id_base32, sizeof(desc_id_base32), desc_holder->desc_id,
- DIGEST_LEN);
- ret = rend_cache_store_v2_desc_as_client(desc_holder->desc_str,
- desc_id_base32, mock_rend_query,
- &entry);
-
- tt_int_op(ret, OP_EQ, 0);
- tt_assert(entry);
- tt_int_op(entry->len, OP_EQ, strlen(desc_holder->desc_str));
- tt_str_op(entry->desc, OP_EQ, desc_holder->desc_str);
-
- // Test various failure modes
-
- // TODO: a too long desc_id_base32 argument crashes the function
- /* ret = rend_cache_store_v2_desc_as_client( */
- /* desc_holder->desc_str, */
- /* "3TOOLONG3TOOLONG3TOOLONG3TOOLONG3TOOLONG3TOOLONG", */
- /* &mock_rend_query, NULL); */
- /* tt_int_op(ret, OP_EQ, -1); */
-
- // Test bad base32 failure
- // This causes an assertion failure if we're running with assertions.
- // But when building without asserts, we can test it.
-#ifdef DISABLE_ASSERTS_IN_UNIT_TESTS
- ret = rend_cache_store_v2_desc_as_client(desc_holder->desc_str,
- "!xqunszqnaolrrfmtzgaki7mxelgvkj", mock_rend_query, NULL);
- tt_int_op(ret, OP_EQ, -1);
-#endif
-
- // Test invalid descriptor
- ret = rend_cache_store_v2_desc_as_client("invalid descriptor",
- "3xqunszqnaolrrfmtzgaki7mxelgvkje", mock_rend_query, NULL);
- tt_int_op(ret, OP_EQ, -1);
-
- // TODO: it doesn't seem to be possible to test invalid service ID condition.
- // that means it is likely not possible to have that condition without
- // earlier conditions failing first (such as signature checking of the desc)
-
- rend_cache_free_all();
-
- // Test mismatch between service ID and onion address
- rend_cache_init();
- strncpy(TO_REND_DATA_V2(mock_rend_query)->onion_address, "abc",
- REND_SERVICE_ID_LEN_BASE32+1);
- ret = rend_cache_store_v2_desc_as_client(desc_holder->desc_str,
- desc_id_base32,
- mock_rend_query, NULL);
- tt_int_op(ret, OP_EQ, -1);
- rend_cache_free_all();
- rend_data_free(mock_rend_query);
-
- // Test incorrect descriptor ID
- rend_cache_init();
- mock_rend_query = mock_rend_data(service_id);
- char orig = desc_id_base32[0];
- if (desc_id_base32[0] == 'a')
- desc_id_base32[0] = 'b';
- else
- desc_id_base32[0] = 'a';
- ret = rend_cache_store_v2_desc_as_client(desc_holder->desc_str,
- desc_id_base32, mock_rend_query,
- NULL);
- tt_int_op(ret, OP_EQ, -1);
- desc_id_base32[0] = orig;
- rend_cache_free_all();
-
- // Test too old descriptor
- rend_cache_init();
- rend_encoded_v2_service_descriptor_free(desc_holder);
- tor_free(service_id);
- rend_data_free(mock_rend_query);
-
- generate_desc(TIME_IN_THE_PAST, &desc_holder, &service_id, 3);
- mock_rend_query = mock_rend_data(service_id);
- base32_encode(desc_id_base32, sizeof(desc_id_base32), desc_holder->desc_id,
- DIGEST_LEN);
-
- ret = rend_cache_store_v2_desc_as_client(desc_holder->desc_str,
- desc_id_base32,
- mock_rend_query, NULL);
- tt_int_op(ret, OP_EQ, -1);
- rend_cache_free_all();
-
- // Test too new descriptor (in the future)
- rend_cache_init();
- rend_encoded_v2_service_descriptor_free(desc_holder);
- tor_free(service_id);
- rend_data_free(mock_rend_query);
-
- generate_desc(TIME_IN_THE_FUTURE, &desc_holder, &service_id, 3);
- mock_rend_query = mock_rend_data(service_id);
- base32_encode(desc_id_base32, sizeof(desc_id_base32), desc_holder->desc_id,
- DIGEST_LEN);
-
- ret = rend_cache_store_v2_desc_as_client(desc_holder->desc_str,
- desc_id_base32, mock_rend_query,
- NULL);
- tt_int_op(ret, OP_EQ, -1);
- rend_cache_free_all();
-
- // Test when a descriptor is already in the cache
- rend_cache_init();
- rend_encoded_v2_service_descriptor_free(desc_holder);
- tor_free(service_id);
- rend_data_free(mock_rend_query);
-
- generate_desc(RECENT_TIME, &desc_holder, &service_id, 3);
- mock_rend_query = mock_rend_data(service_id);
- base32_encode(desc_id_base32, sizeof(desc_id_base32), desc_holder->desc_id,
- DIGEST_LEN);
-
- rend_cache_store_v2_desc_as_client(desc_holder->desc_str, desc_id_base32,
- mock_rend_query, NULL);
- ret = rend_cache_store_v2_desc_as_client(desc_holder->desc_str,
- desc_id_base32, mock_rend_query,
- NULL);
- tt_int_op(ret, OP_EQ, 0);
-
- ret = rend_cache_store_v2_desc_as_client(desc_holder->desc_str,
- desc_id_base32, mock_rend_query,
- &entry);
- tt_int_op(ret, OP_EQ, 0);
- tt_assert(entry);
- rend_cache_free_all();
-
- // Test unsuccessful decrypting of introduction points
- rend_cache_init();
- rend_encoded_v2_service_descriptor_free(desc_holder);
- tor_free(service_id);
- rend_data_free(mock_rend_query);
-
- generate_desc(RECENT_TIME, &desc_holder, &service_id, 3);
- mock_rend_query = mock_rend_data(service_id);
- TO_REND_DATA_V2(mock_rend_query)->auth_type = REND_BASIC_AUTH;
- client_cookie[0] = 'A';
- memcpy(TO_REND_DATA_V2(mock_rend_query)->descriptor_cookie, client_cookie,
- REND_DESC_COOKIE_LEN);
- base32_encode(desc_id_base32, sizeof(desc_id_base32), desc_holder->desc_id,
- DIGEST_LEN);
- ret = rend_cache_store_v2_desc_as_client(desc_holder->desc_str,
- desc_id_base32, mock_rend_query,
- NULL);
- tt_int_op(ret, OP_EQ, 0);
- rend_cache_free_all();
-
- // Test successful run when we have REND_BASIC_AUTH but not cookie
- rend_cache_init();
- rend_encoded_v2_service_descriptor_free(desc_holder);
- tor_free(service_id);
- rend_data_free(mock_rend_query);
-
- generate_desc(RECENT_TIME, &desc_holder, &service_id, 3);
- mock_rend_query = mock_rend_data(service_id);
- TO_REND_DATA_V2(mock_rend_query)->auth_type = REND_BASIC_AUTH;
- base32_encode(desc_id_base32, sizeof(desc_id_base32), desc_holder->desc_id,
- DIGEST_LEN);
- ret = rend_cache_store_v2_desc_as_client(desc_holder->desc_str,
- desc_id_base32, mock_rend_query,
- NULL);
- tt_int_op(ret, OP_EQ, 0);
-
- rend_cache_free_all();
-
- // Test when we have no introduction points
- rend_cache_init();
- rend_encoded_v2_service_descriptor_free(desc_holder);
- tor_free(service_id);
- rend_data_free(mock_rend_query);
-
- generate_desc(RECENT_TIME, &desc_holder, &service_id, 0);
- mock_rend_query = mock_rend_data(service_id);
- base32_encode(desc_id_base32, sizeof(desc_id_base32), desc_holder->desc_id,
- DIGEST_LEN);
- ret = rend_cache_store_v2_desc_as_client(desc_holder->desc_str,
- desc_id_base32, mock_rend_query,
- NULL);
- tt_int_op(ret, OP_EQ, -1);
- rend_cache_free_all();
-
- // Test when we have too many intro points
- rend_cache_init();
- rend_encoded_v2_service_descriptor_free(desc_holder);
- tor_free(service_id);
- rend_data_free(mock_rend_query);
-
- generate_desc(RECENT_TIME, &desc_holder, &service_id, MAX_INTRO_POINTS+1);
- mock_rend_query = mock_rend_data(service_id);
- base32_encode(desc_id_base32, sizeof(desc_id_base32), desc_holder->desc_id,
- DIGEST_LEN);
- ret = rend_cache_store_v2_desc_as_client(desc_holder->desc_str,
- desc_id_base32, mock_rend_query,
- NULL);
- tt_int_op(ret, OP_EQ, -1);
-
- done:
- rend_encoded_v2_service_descriptor_free(desc_holder);
- tor_free(service_id);
- rend_cache_free_all();
- rend_data_free(mock_rend_query);
-}
-
-static void
-test_rend_cache_store_v2_desc_as_client_with_different_time(void *data)
-{
- int ret;
- rend_data_t *mock_rend_query;
- char desc_id_base32[REND_DESC_ID_V2_LEN_BASE32 + 1];
- rend_service_descriptor_t *generated = NULL;
- smartlist_t *descs = smartlist_new();
- time_t t;
- char *service_id = NULL;
- rend_encoded_v2_service_descriptor_t *desc_holder_newer;
- rend_encoded_v2_service_descriptor_t *desc_holder_older;
-
- t = time(NULL);
- rend_cache_init();
-
- create_descriptor(&generated, &service_id, 3);
-
- generated->timestamp = t + RECENT_TIME;
- rend_encode_v2_descriptors(descs, generated, t + RECENT_TIME, 0,
- REND_NO_AUTH, NULL, NULL);
- desc_holder_newer = ((rend_encoded_v2_service_descriptor_t *)
- smartlist_get(descs, 0));
- smartlist_set(descs, 0, NULL);
-
- SMARTLIST_FOREACH(descs, rend_encoded_v2_service_descriptor_t *, d,
- rend_encoded_v2_service_descriptor_free(d));
- smartlist_free(descs);
- descs = smartlist_new();
-
- generated->timestamp = (t + RECENT_TIME) - 20;
- rend_encode_v2_descriptors(descs, generated, t + RECENT_TIME, 0,
- REND_NO_AUTH, NULL, NULL);
- desc_holder_older = ((rend_encoded_v2_service_descriptor_t *)
- smartlist_get(descs, 0));
- smartlist_set(descs, 0, NULL);
- (void)data;
-
- // Test when a descriptor is already in the cache and it is newer than the
- // one we submit
- mock_rend_query = mock_rend_data(service_id);
- base32_encode(desc_id_base32, sizeof(desc_id_base32),
- desc_holder_newer->desc_id, DIGEST_LEN);
- rend_cache_store_v2_desc_as_client(desc_holder_newer->desc_str,
- desc_id_base32, mock_rend_query, NULL);
- ret = rend_cache_store_v2_desc_as_client(desc_holder_older->desc_str,
- desc_id_base32, mock_rend_query,
- NULL);
- tt_int_op(ret, OP_EQ, 0);
-
- rend_cache_free_all();
-
- // Test when an old descriptor is in the cache and we submit a newer one
- rend_cache_init();
- rend_cache_store_v2_desc_as_client(desc_holder_older->desc_str,
- desc_id_base32, mock_rend_query, NULL);
- ret = rend_cache_store_v2_desc_as_client(desc_holder_newer->desc_str,
- desc_id_base32, mock_rend_query,
- NULL);
- tt_int_op(ret, OP_EQ, 0);
-
- done:
- rend_encoded_v2_service_descriptor_free(desc_holder_newer);
- rend_encoded_v2_service_descriptor_free(desc_holder_older);
- SMARTLIST_FOREACH(descs, rend_encoded_v2_service_descriptor_t *, d,
- rend_encoded_v2_service_descriptor_free(d));
- smartlist_free(descs);
- rend_service_descriptor_free(generated);
- tor_free(service_id);
- rend_cache_free_all();
- rend_data_free(mock_rend_query);
-}
-
-static const routerinfo_t *rcache_lookup_v2_as_dir_get_my_routerinfo(void);
-
-static routerinfo_t *mock_routerinfo;
-
-static const routerinfo_t *
-rcache_lookup_v2_as_dir_get_my_routerinfo(void)
-{
- if (!mock_routerinfo) {
- mock_routerinfo = tor_malloc(sizeof(routerinfo_t));
- }
-
- return mock_routerinfo;
-}
-
-static void
-test_rend_cache_lookup_v2_desc_as_dir(void *data)
-{
- int ret;
- char desc_id_base32[REND_DESC_ID_V2_LEN_BASE32 + 1];
- rend_encoded_v2_service_descriptor_t *desc_holder = NULL;
- char *service_id = NULL;
- const char *ret_desc = NULL;
-
- (void)data;
-
- MOCK(router_get_my_routerinfo,
- rcache_lookup_v2_as_dir_get_my_routerinfo);
-
- rend_cache_init();
-
- // Test invalid base32
- ret = rend_cache_lookup_v2_desc_as_dir("!bababababababab", NULL);
- tt_int_op(ret, OP_EQ, -1);
-
- // Test non-existent descriptor but well formed
- ret = rend_cache_lookup_v2_desc_as_dir("3xqunszqnaolrrfmtzgaki7mxelgvkje",
- NULL);
- tt_int_op(ret, OP_EQ, 0);
-
- // Test existing descriptor
- generate_desc(RECENT_TIME, &desc_holder, &service_id, 3);
- rend_cache_store_v2_desc_as_dir(desc_holder->desc_str);
- base32_encode(desc_id_base32, sizeof(desc_id_base32), desc_holder->desc_id,
- DIGEST_LEN);
- ret = rend_cache_lookup_v2_desc_as_dir(desc_id_base32, &ret_desc);
- tt_int_op(ret, OP_EQ, 1);
- tt_assert(ret_desc);
-
- done:
- UNMOCK(router_get_my_routerinfo);
- tor_free(mock_routerinfo);
- rend_cache_free_all();
- rend_encoded_v2_service_descriptor_free(desc_holder);
- tor_free(service_id);
-}
-
-static const routerinfo_t *rcache_store_v2_as_dir_get_my_routerinfo(void);
-
-static const routerinfo_t *
-rcache_store_v2_as_dir_get_my_routerinfo(void)
-{
- return mock_routerinfo;
-}
-
-static void
-test_rend_cache_store_v2_desc_as_dir(void *data)
-{
- (void)data;
- int ret;
- rend_encoded_v2_service_descriptor_t *desc_holder = NULL;
- char *service_id = NULL;
-
- MOCK(router_get_my_routerinfo,
- rcache_store_v2_as_dir_get_my_routerinfo);
-
- rend_cache_init();
-
- // Test when we can't parse the descriptor
- mock_routerinfo = tor_malloc(sizeof(routerinfo_t));
- ret = rend_cache_store_v2_desc_as_dir("unparseable");
- tt_int_op(ret, OP_EQ, -1);
-
- // Test when we have an old descriptor
- generate_desc(TIME_IN_THE_PAST, &desc_holder, &service_id, 3);
- ret = rend_cache_store_v2_desc_as_dir(desc_holder->desc_str);
- tt_int_op(ret, OP_EQ, 0);
-
- rend_encoded_v2_service_descriptor_free(desc_holder);
- tor_free(service_id);
-
- // Test when we have a descriptor in the future
- generate_desc(TIME_IN_THE_FUTURE, &desc_holder, &service_id, 3);
- ret = rend_cache_store_v2_desc_as_dir(desc_holder->desc_str);
- tt_int_op(ret, OP_EQ, 0);
-
- rend_encoded_v2_service_descriptor_free(desc_holder);
- tor_free(service_id);
-
- // Test when two descriptors
- generate_desc(TIME_IN_THE_FUTURE, &desc_holder, &service_id, 3);
- ret = rend_cache_store_v2_desc_as_dir(desc_holder->desc_str);
- tt_int_op(ret, OP_EQ, 0);
-
- rend_encoded_v2_service_descriptor_free(desc_holder);
- tor_free(service_id);
-
- // Test when asking for hidden service statistics HiddenServiceStatistics
- rend_cache_purge();
- generate_desc(RECENT_TIME, &desc_holder, &service_id, 3);
- get_options_mutable()->HiddenServiceStatistics = 1;
- ret = rend_cache_store_v2_desc_as_dir(desc_holder->desc_str);
- tt_int_op(ret, OP_EQ, 0);
-
- done:
- UNMOCK(router_get_my_routerinfo);
- rend_encoded_v2_service_descriptor_free(desc_holder);
- tor_free(service_id);
- rend_cache_free_all();
- tor_free(mock_routerinfo);
-}
-
-static void
-test_rend_cache_store_v2_desc_as_dir_with_different_time(void *data)
-{
- (void)data;
-
- int ret;
- rend_service_descriptor_t *generated = NULL;
- smartlist_t *descs = smartlist_new();
- time_t t;
- char *service_id = NULL;
- rend_encoded_v2_service_descriptor_t *desc_holder_newer;
- rend_encoded_v2_service_descriptor_t *desc_holder_older;
-
- MOCK(router_get_my_routerinfo,
- rcache_store_v2_as_dir_get_my_routerinfo);
-
- rend_cache_init();
-
- t = time(NULL);
-
- create_descriptor(&generated, &service_id, 3);
- generated->timestamp = t + RECENT_TIME;
- rend_encode_v2_descriptors(descs, generated, t + RECENT_TIME, 0,
- REND_NO_AUTH, NULL, NULL);
- desc_holder_newer = ((rend_encoded_v2_service_descriptor_t *)
- smartlist_get(descs, 0));
- smartlist_set(descs, 0, NULL);
- SMARTLIST_FOREACH(descs, rend_encoded_v2_service_descriptor_t *, d,
- rend_encoded_v2_service_descriptor_free(d));
- smartlist_free(descs);
- descs = smartlist_new();
-
- generated->timestamp = (t + RECENT_TIME) - 20;
- rend_encode_v2_descriptors(descs, generated, t + RECENT_TIME, 0,
- REND_NO_AUTH, NULL, NULL);
- desc_holder_older = ((rend_encoded_v2_service_descriptor_t *)
- smartlist_get(descs, 0));
- smartlist_set(descs, 0, NULL);
-
- // Test when we have a newer descriptor stored
- mock_routerinfo = tor_malloc(sizeof(routerinfo_t));
- rend_cache_store_v2_desc_as_dir(desc_holder_newer->desc_str);
- ret = rend_cache_store_v2_desc_as_dir(desc_holder_older->desc_str);
- tt_int_op(ret, OP_EQ, 0);
-
- // Test when we have an old descriptor stored
- rend_cache_purge();
- rend_cache_store_v2_desc_as_dir(desc_holder_older->desc_str);
- ret = rend_cache_store_v2_desc_as_dir(desc_holder_newer->desc_str);
- tt_int_op(ret, OP_EQ, 0);
-
- done:
- UNMOCK(router_get_my_routerinfo);
- rend_cache_free_all();
- rend_service_descriptor_free(generated);
- tor_free(service_id);
- SMARTLIST_FOREACH(descs, rend_encoded_v2_service_descriptor_t *, d,
- rend_encoded_v2_service_descriptor_free(d));
- smartlist_free(descs);
- rend_encoded_v2_service_descriptor_free(desc_holder_newer);
- rend_encoded_v2_service_descriptor_free(desc_holder_older);
- tor_free(mock_routerinfo);
-}
-
-static void
-test_rend_cache_store_v2_desc_as_dir_with_different_content(void *data)
-{
- (void)data;
-
- int ret;
- rend_service_descriptor_t *generated = NULL;
- smartlist_t *descs = smartlist_new();
- time_t t;
- char *service_id = NULL;
- rend_encoded_v2_service_descriptor_t *desc_holder_one = NULL;
- rend_encoded_v2_service_descriptor_t *desc_holder_two = NULL;
-
- MOCK(router_get_my_routerinfo,
- rcache_store_v2_as_dir_get_my_routerinfo);
-
- rend_cache_init();
-
- t = time(NULL);
-
- create_descriptor(&generated, &service_id, 3);
- generated->timestamp = t + RECENT_TIME;
- rend_encode_v2_descriptors(descs, generated, t + RECENT_TIME, 0,
- REND_NO_AUTH, NULL, NULL);
- desc_holder_one = ((rend_encoded_v2_service_descriptor_t *)
- smartlist_get(descs, 0));
- smartlist_set(descs, 0, NULL);
-
- SMARTLIST_FOREACH(descs, rend_encoded_v2_service_descriptor_t *, d,
- rend_encoded_v2_service_descriptor_free(d));
- smartlist_free(descs);
- descs = smartlist_new();
-
- generated->timestamp = t + RECENT_TIME;
- generated->protocols = 41;
- rend_encode_v2_descriptors(descs, generated, t + RECENT_TIME, 0,
- REND_NO_AUTH, NULL, NULL);
- desc_holder_two = ((rend_encoded_v2_service_descriptor_t *)
- smartlist_get(descs, 0));
- smartlist_set(descs, 0, NULL);
-
- // Test when we have another descriptor stored, with a different descriptor
- mock_routerinfo = tor_malloc(sizeof(routerinfo_t));
- rend_cache_store_v2_desc_as_dir(desc_holder_one->desc_str);
- ret = rend_cache_store_v2_desc_as_dir(desc_holder_two->desc_str);
- tt_int_op(ret, OP_EQ, 0);
-
- done:
- UNMOCK(router_get_my_routerinfo);
- rend_cache_free_all();
- rend_service_descriptor_free(generated);
- tor_free(service_id);
- SMARTLIST_FOREACH(descs, rend_encoded_v2_service_descriptor_t *, d,
- rend_encoded_v2_service_descriptor_free(d));
- smartlist_free(descs);
- rend_encoded_v2_service_descriptor_free(desc_holder_one);
- rend_encoded_v2_service_descriptor_free(desc_holder_two);
-}
-
-static void
-test_rend_cache_init(void *data)
-{
- (void)data;
-
- tt_assert_msg(!rend_cache, "rend_cache should be NULL when starting");
- tt_assert_msg(!rend_cache_v2_dir, "rend_cache_v2_dir should be NULL "
- "when starting");
- tt_assert_msg(!rend_cache_failure, "rend_cache_failure should be NULL when "
- "starting");
-
- rend_cache_init();
-
- tt_assert_msg(rend_cache, "rend_cache should not be NULL after initing");
- tt_assert_msg(rend_cache_v2_dir, "rend_cache_v2_dir should not be NULL "
- "after initing");
- tt_assert_msg(rend_cache_failure, "rend_cache_failure should not be NULL "
- "after initing");
-
- tt_int_op(strmap_size(rend_cache), OP_EQ, 0);
- tt_int_op(digestmap_size(rend_cache_v2_dir), OP_EQ, 0);
- tt_int_op(strmap_size(rend_cache_failure), OP_EQ, 0);
-
- done:
- rend_cache_free_all();
-}
-
-static void
-test_rend_cache_decrement_allocation(void *data)
-{
- (void)data;
-
- // Test when the cache has enough allocations
- rend_cache_total_allocation = 10;
- rend_cache_decrement_allocation(3);
- tt_int_op(rend_cache_total_allocation, OP_EQ, 7);
-
- // Test when there are not enough allocations
- rend_cache_total_allocation = 1;
- setup_full_capture_of_logs(LOG_WARN);
- rend_cache_decrement_allocation(2);
- tt_int_op(rend_cache_total_allocation, OP_EQ, 0);
- expect_single_log_msg_containing(
- "Underflow in rend_cache_decrement_allocation");
- teardown_capture_of_logs();
-
- // And again
- rend_cache_decrement_allocation(2);
- tt_int_op(rend_cache_total_allocation, OP_EQ, 0);
-
- done:
- teardown_capture_of_logs();
-}
-
-static void
-test_rend_cache_increment_allocation(void *data)
-{
- (void)data;
-
- // Test when the cache is not overflowing
- rend_cache_total_allocation = 5;
- rend_cache_increment_allocation(3);
- tt_int_op(rend_cache_total_allocation, OP_EQ, 8);
-
- // Test when there are too many allocations
- rend_cache_total_allocation = SIZE_MAX-1;
- setup_full_capture_of_logs(LOG_WARN);
- rend_cache_increment_allocation(2);
- tt_u64_op(rend_cache_total_allocation, OP_EQ, SIZE_MAX);
- expect_single_log_msg_containing(
- "Overflow in rend_cache_increment_allocation");
- teardown_capture_of_logs();
-
- // And again
- rend_cache_increment_allocation(2);
- tt_u64_op(rend_cache_total_allocation, OP_EQ, SIZE_MAX);
-
- done:
- teardown_capture_of_logs();
-}
-
-static void
-test_rend_cache_failure_intro_entry_new(void *data)
-{
- time_t now;
- rend_cache_failure_intro_t *entry;
- rend_intro_point_failure_t failure;
-
- (void)data;
-
- failure = INTRO_POINT_FAILURE_TIMEOUT;
- now = time(NULL);
- entry = rend_cache_failure_intro_entry_new(failure);
-
- tt_int_op(entry->failure_type, OP_EQ, INTRO_POINT_FAILURE_TIMEOUT);
- tt_int_op(entry->created_ts, OP_GE, now-5);
- tt_int_op(entry->created_ts, OP_LE, now+5);
-
- done:
- tor_free(entry);
-}
-
-static void
-test_rend_cache_failure_intro_lookup(void *data)
-{
- (void)data;
- int ret;
- rend_cache_failure_t *failure;
- rend_cache_failure_intro_t *ip;
- rend_cache_failure_intro_t *entry;
- const char key_ip_one[DIGEST_LEN] = "ip1";
- const char key_ip_two[DIGEST_LEN] = "ip2";
- const char key_foo[DIGEST_LEN] = "foo1";
-
- rend_cache_init();
-
- failure = rend_cache_failure_entry_new();
- ip = rend_cache_failure_intro_entry_new(INTRO_POINT_FAILURE_TIMEOUT);
- digestmap_set(failure->intro_failures, key_ip_one, ip);
- strmap_set_lc(rend_cache_failure, "foo1", failure);
-
- // Test not found
- ret = cache_failure_intro_lookup((const uint8_t *) key_foo, "foo2", NULL);
- tt_int_op(ret, OP_EQ, 0);
-
- // Test found with no intro failures in it
- ret = cache_failure_intro_lookup((const uint8_t *) key_ip_two, "foo1", NULL);
- tt_int_op(ret, OP_EQ, 0);
-
- // Test found
- ret = cache_failure_intro_lookup((const uint8_t *) key_ip_one, "foo1", NULL);
- tt_int_op(ret, OP_EQ, 1);
-
- // Test found and asking for entry
- cache_failure_intro_lookup((const uint8_t *) key_ip_one, "foo1", &entry);
- tt_assert(entry);
- tt_assert(entry == ip);
-
- done:
- rend_cache_free_all();
-}
-
-static void
-test_rend_cache_clean(void *data)
-{
- rend_cache_entry_t *one, *two;
- rend_service_descriptor_t *desc_one, *desc_two;
- strmap_iter_t *iter = NULL;
- const char *key;
- void *val;
-
- (void)data;
-
- rend_cache_init();
-
- // Test with empty rendcache
- rend_cache_clean(time(NULL), REND_CACHE_TYPE_CLIENT);
- tt_int_op(strmap_size(rend_cache), OP_EQ, 0);
-
- // Test with two old entries
- one = tor_malloc_zero(sizeof(rend_cache_entry_t));
- two = tor_malloc_zero(sizeof(rend_cache_entry_t));
- desc_one = tor_malloc_zero(sizeof(rend_service_descriptor_t));
- desc_two = tor_malloc_zero(sizeof(rend_service_descriptor_t));
- one->parsed = desc_one;
- two->parsed = desc_two;
-
- desc_one->timestamp = time(NULL) + TIME_IN_THE_PAST;
- desc_two->timestamp = (time(NULL) + TIME_IN_THE_PAST) - 10;
- desc_one->pk = pk_generate(0);
- desc_two->pk = pk_generate(1);
-
- strmap_set_lc(rend_cache, "foo1", one);
- rend_cache_increment_allocation(rend_cache_entry_allocation(one));
- strmap_set_lc(rend_cache, "foo2", two);
- rend_cache_increment_allocation(rend_cache_entry_allocation(two));
-
- rend_cache_clean(time(NULL), REND_CACHE_TYPE_CLIENT);
- tt_int_op(strmap_size(rend_cache), OP_EQ, 0);
-
- // Test with one old entry and one newer entry
- one = tor_malloc_zero(sizeof(rend_cache_entry_t));
- two = tor_malloc_zero(sizeof(rend_cache_entry_t));
- desc_one = tor_malloc_zero(sizeof(rend_service_descriptor_t));
- desc_two = tor_malloc_zero(sizeof(rend_service_descriptor_t));
- one->parsed = desc_one;
- two->parsed = desc_two;
-
- desc_one->timestamp = (time(NULL) + TIME_IN_THE_PAST) - 10;
- desc_two->timestamp = time(NULL) - 100;
- desc_one->pk = pk_generate(0);
- desc_two->pk = pk_generate(1);
-
- rend_cache_increment_allocation(rend_cache_entry_allocation(one));
- strmap_set_lc(rend_cache, "foo1", one);
- rend_cache_increment_allocation(rend_cache_entry_allocation(two));
- strmap_set_lc(rend_cache, "foo2", two);
-
- rend_cache_clean(time(NULL), REND_CACHE_TYPE_CLIENT);
- tt_int_op(strmap_size(rend_cache), OP_EQ, 1);
-
- iter = strmap_iter_init(rend_cache);
- strmap_iter_get(iter, &key, &val);
- tt_str_op(key, OP_EQ, "foo2");
-
- done:
- rend_cache_free_all();
-}
-
-static void
-test_rend_cache_failure_entry_new(void *data)
-{
- rend_cache_failure_t *failure;
-
- (void)data;
-
- failure = rend_cache_failure_entry_new();
- tt_assert(failure);
- tt_int_op(digestmap_size(failure->intro_failures), OP_EQ, 0);
-
- done:
- rend_cache_failure_entry_free(failure);
-}
-
-static void
-test_rend_cache_failure_entry_free(void *data)
-{
- (void)data;
-
- // Test that it can deal with a NULL argument
- rend_cache_failure_entry_free_(NULL);
-
- /* done: */
- /* (void)0; */
-}
-
-static void
-test_rend_cache_failure_clean(void *data)
-{
- rend_cache_failure_t *failure;
- rend_cache_failure_intro_t *ip_one, *ip_two;
-
- const char key_one[DIGEST_LEN] = "ip1";
- const char key_two[DIGEST_LEN] = "ip2";
-
- (void)data;
-
- rend_cache_init();
-
- // Test with empty failure cache
- rend_cache_failure_clean(time(NULL));
- tt_int_op(strmap_size(rend_cache_failure), OP_EQ, 0);
-
- // Test with one empty failure entry
- failure = rend_cache_failure_entry_new();
- strmap_set_lc(rend_cache_failure, "foo1", failure);
- rend_cache_failure_clean(time(NULL));
- tt_int_op(strmap_size(rend_cache_failure), OP_EQ, 0);
-
- // Test with one new intro point
- failure = rend_cache_failure_entry_new();
- ip_one = rend_cache_failure_intro_entry_new(INTRO_POINT_FAILURE_TIMEOUT);
- digestmap_set(failure->intro_failures, key_one, ip_one);
- strmap_set_lc(rend_cache_failure, "foo1", failure);
- rend_cache_failure_clean(time(NULL));
- tt_int_op(strmap_size(rend_cache_failure), OP_EQ, 1);
-
- // Test with one old intro point
- rend_cache_failure_purge();
- failure = rend_cache_failure_entry_new();
- ip_one = rend_cache_failure_intro_entry_new(INTRO_POINT_FAILURE_TIMEOUT);
- ip_one->created_ts = time(NULL) - 7*60;
- digestmap_set(failure->intro_failures, key_one, ip_one);
- strmap_set_lc(rend_cache_failure, "foo1", failure);
- rend_cache_failure_clean(time(NULL));
- tt_int_op(strmap_size(rend_cache_failure), OP_EQ, 0);
-
- // Test with one old intro point and one new one
- rend_cache_failure_purge();
- failure = rend_cache_failure_entry_new();
- ip_one = rend_cache_failure_intro_entry_new(INTRO_POINT_FAILURE_TIMEOUT);
- ip_one->created_ts = time(NULL) - 7*60;
- digestmap_set(failure->intro_failures, key_one, ip_one);
- ip_two = rend_cache_failure_intro_entry_new(INTRO_POINT_FAILURE_TIMEOUT);
- ip_two->created_ts = time(NULL) - 2*60;
- digestmap_set(failure->intro_failures, key_two, ip_two);
- strmap_set_lc(rend_cache_failure, "foo1", failure);
- rend_cache_failure_clean(time(NULL));
- tt_int_op(strmap_size(rend_cache_failure), OP_EQ, 1);
- tt_int_op(digestmap_size(failure->intro_failures), OP_EQ, 1);
-
- done:
- rend_cache_free_all();
-}
-
-static void
-test_rend_cache_failure_remove(void *data)
-{
- rend_service_descriptor_t *desc;
- (void)data;
-
- rend_cache_init();
-
- // Test that it deals well with a NULL desc
- rend_cache_failure_remove(NULL);
-
- // Test a descriptor that isn't in the cache
- desc = tor_malloc_zero(sizeof(rend_service_descriptor_t));
- desc->pk = pk_generate(0);
- rend_cache_failure_remove(desc);
-
- // There seems to not exist any way of getting rend_cache_failure_remove()
- // to fail because of a problem with rend_get_service_id from here
- rend_cache_free_all();
-
- rend_service_descriptor_free(desc);
- /* done: */
- /* (void)0; */
-}
-
-static void
-test_rend_cache_free_all(void *data)
-{
- rend_cache_failure_t *failure;
- rend_cache_entry_t *one;
- rend_service_descriptor_t *desc_one;
-
- (void)data;
-
- rend_cache_init();
-
- failure = rend_cache_failure_entry_new();
- strmap_set_lc(rend_cache_failure, "foo1", failure);
-
- one = tor_malloc_zero(sizeof(rend_cache_entry_t));
- desc_one = tor_malloc_zero(sizeof(rend_service_descriptor_t));
- one->parsed = desc_one;
- desc_one->timestamp = time(NULL) + TIME_IN_THE_PAST;
- desc_one->pk = pk_generate(0);
- rend_cache_increment_allocation(rend_cache_entry_allocation(one));
- strmap_set_lc(rend_cache, "foo1", one);
-
- rend_cache_free_all();
-
- tt_ptr_op(rend_cache, OP_EQ, NULL);
- tt_ptr_op(rend_cache_v2_dir, OP_EQ, NULL);
- tt_ptr_op(rend_cache_failure, OP_EQ, NULL);
- tt_assert(!rend_cache_total_allocation);
-
- done:
- rend_cache_free_all();
-}
-
-static void
-test_rend_cache_entry_free(void *data)
-{
- (void)data;
- rend_cache_entry_t *e;
-
- // Handles NULL correctly
- rend_cache_entry_free_(NULL);
-
- // Handles NULL descriptor correctly
- e = tor_malloc_zero(sizeof(rend_cache_entry_t));
- rend_cache_increment_allocation(rend_cache_entry_allocation(e));
- rend_cache_entry_free(e);
-
- // Handles non-NULL descriptor correctly
- e = tor_malloc_zero(sizeof(rend_cache_entry_t));
- e->desc = tor_malloc(10);
- rend_cache_increment_allocation(rend_cache_entry_allocation(e));
- rend_cache_entry_free(e);
-
- /* done: */
- /* (void)0; */
-}
-
-static void
-test_rend_cache_purge(void *data)
-{
- (void)data;
-
- // Deals with a NULL rend_cache
- rend_cache_purge();
- tt_assert(rend_cache);
- tt_assert(strmap_size(rend_cache) == 0);
-
- // Deals with existing rend_cache
- rend_cache_free_all();
- rend_cache_init();
- tt_assert(rend_cache);
- tt_assert(strmap_size(rend_cache) == 0);
-
- rend_cache_purge();
- tt_assert(rend_cache);
- tt_assert(strmap_size(rend_cache) == 0);
-
- done:
- rend_cache_free_all();
-}
-
-static void
-test_rend_cache_failure_intro_add(void *data)
-{
- (void)data;
- rend_cache_failure_t *fail_entry;
- rend_cache_failure_intro_t *entry;
- const char identity[DIGEST_LEN] = "foo1";
-
- rend_cache_init();
-
- // Adds non-existing entry
- cache_failure_intro_add((const uint8_t *) identity, "foo2",
- INTRO_POINT_FAILURE_TIMEOUT);
- fail_entry = strmap_get_lc(rend_cache_failure, "foo2");
- tt_assert(fail_entry);
- tt_int_op(digestmap_size(fail_entry->intro_failures), OP_EQ, 1);
- entry = digestmap_get(fail_entry->intro_failures, identity);
- tt_assert(entry);
-
- // Adds existing entry
- cache_failure_intro_add((const uint8_t *) identity, "foo2",
- INTRO_POINT_FAILURE_TIMEOUT);
- fail_entry = strmap_get_lc(rend_cache_failure, "foo2");
- tt_assert(fail_entry);
- tt_int_op(digestmap_size(fail_entry->intro_failures), OP_EQ, 1);
- entry = digestmap_get(fail_entry->intro_failures, identity);
- tt_assert(entry);
-
- done:
- rend_cache_free_all();
-}
-
-static void
-test_rend_cache_intro_failure_note(void *data)
-{
- (void)data;
- rend_cache_failure_t *fail_entry;
- rend_cache_failure_intro_t *entry;
- const char key[DIGEST_LEN] = "foo1";
-
- rend_cache_init();
-
- // Test not found
- rend_cache_intro_failure_note(INTRO_POINT_FAILURE_TIMEOUT,
- (const uint8_t *) key, "foo2");
- fail_entry = strmap_get_lc(rend_cache_failure, "foo2");
- tt_assert(fail_entry);
- tt_int_op(digestmap_size(fail_entry->intro_failures), OP_EQ, 1);
- entry = digestmap_get(fail_entry->intro_failures, key);
- tt_assert(entry);
- tt_int_op(entry->failure_type, OP_EQ, INTRO_POINT_FAILURE_TIMEOUT);
-
- // Test found
- rend_cache_intro_failure_note(INTRO_POINT_FAILURE_UNREACHABLE,
- (const uint8_t *) key, "foo2");
- tt_int_op(entry->failure_type, OP_EQ, INTRO_POINT_FAILURE_UNREACHABLE);
-
- done:
- rend_cache_free_all();
-}
-
-static void
-test_rend_cache_clean_v2_descs_as_dir(void *data)
-{
- rend_cache_entry_t *e;
- time_t now, cutoff;
- rend_service_descriptor_t *desc;
- now = time(NULL);
- cutoff = now - (REND_CACHE_MAX_AGE + REND_CACHE_MAX_SKEW);
- const char key[DIGEST_LEN] = "abcde";
-
- (void)data;
-
- rend_cache_init();
-
- // Test running with an empty cache
- rend_cache_clean_v2_descs_as_dir(cutoff);
- tt_int_op(digestmap_size(rend_cache_v2_dir), OP_EQ, 0);
-
- // Test with only one new entry
- e = tor_malloc_zero(sizeof(rend_cache_entry_t));
- e->last_served = now;
- desc = tor_malloc_zero(sizeof(rend_service_descriptor_t));
- desc->timestamp = now;
- desc->pk = pk_generate(0);
- e->parsed = desc;
- rend_cache_increment_allocation(rend_cache_entry_allocation(e));
- digestmap_set(rend_cache_v2_dir, key, e);
-
- /* Set the cutoff to minus 10 seconds. */
- rend_cache_clean_v2_descs_as_dir(cutoff - 10);
- tt_int_op(digestmap_size(rend_cache_v2_dir), OP_EQ, 1);
-
- // Test with one old entry
- desc->timestamp = cutoff - 1000;
- rend_cache_clean_v2_descs_as_dir(cutoff);
- tt_int_op(digestmap_size(rend_cache_v2_dir), OP_EQ, 0);
-
- done:
- rend_cache_free_all();
-}
-
-static void
-test_rend_cache_entry_allocation(void *data)
-{
- (void)data;
-
- size_t ret;
- rend_cache_entry_t *e = NULL;
-
- // Handles a null argument
- ret = rend_cache_entry_allocation(NULL);
- tt_int_op(ret, OP_EQ, 0);
-
- // Handles a non-null argument
- e = tor_malloc_zero(sizeof(rend_cache_entry_t));
- ret = rend_cache_entry_allocation(e);
- tt_int_op(ret, OP_GT, sizeof(rend_cache_entry_t));
-
- done:
- tor_free(e);
-}
-
-static void
-test_rend_cache_failure_intro_entry_free(void *data)
-{
- (void)data;
- rend_cache_failure_intro_t *entry;
-
- // Handles a null argument
- rend_cache_failure_intro_entry_free_(NULL);
-
- // Handles a non-null argument
- entry = rend_cache_failure_intro_entry_new(INTRO_POINT_FAILURE_TIMEOUT);
- rend_cache_failure_intro_entry_free(entry);
-}
-
-static void
-test_rend_cache_failure_purge(void *data)
-{
- (void)data;
-
- // Handles a null failure cache
- strmap_free(rend_cache_failure, rend_cache_failure_entry_free_void);
- rend_cache_failure = NULL;
-
- rend_cache_failure_purge();
-
- tt_ptr_op(rend_cache_failure, OP_NE, NULL);
- tt_int_op(strmap_size(rend_cache_failure), OP_EQ, 0);
-
- done:
- rend_cache_free_all();
-}
-
-static void
-test_rend_cache_validate_intro_point_failure(void *data)
-{
- (void)data;
- rend_service_descriptor_t *desc = NULL;
- char *service_id = NULL;
- rend_intro_point_t *intro = NULL;
- const char *identity = NULL;
- rend_cache_failure_t *failure;
- rend_cache_failure_intro_t *ip;
-
- rend_cache_init();
-
- create_descriptor(&desc, &service_id, 3);
- desc->timestamp = time(NULL) + RECENT_TIME;
-
- intro = (rend_intro_point_t *)smartlist_get(desc->intro_nodes, 0);
- identity = intro->extend_info->identity_digest;
-
- failure = rend_cache_failure_entry_new();
- ip = rend_cache_failure_intro_entry_new(INTRO_POINT_FAILURE_TIMEOUT);
- digestmap_set(failure->intro_failures, identity, ip);
- strmap_set_lc(rend_cache_failure, service_id, failure);
-
- // Test when we have an intro point in our cache
- validate_intro_point_failure(desc, service_id);
- tt_int_op(smartlist_len(desc->intro_nodes), OP_EQ, 2);
-
- done:
- rend_cache_free_all();
- rend_service_descriptor_free(desc);
- tor_free(service_id);
-}
-
-struct testcase_t rend_cache_tests[] = {
- { "init", test_rend_cache_init, 0, NULL, NULL },
- { "decrement_allocation", test_rend_cache_decrement_allocation, 0,
- NULL, NULL },
- { "increment_allocation", test_rend_cache_increment_allocation, 0,
- NULL, NULL },
- { "clean", test_rend_cache_clean, TT_FORK, NULL, NULL },
- { "clean_v2_descs_as_dir", test_rend_cache_clean_v2_descs_as_dir, 0,
- NULL, NULL },
- { "entry_allocation", test_rend_cache_entry_allocation, 0, NULL, NULL },
- { "entry_free", test_rend_cache_entry_free, 0, NULL, NULL },
- { "failure_intro_entry_free", test_rend_cache_failure_intro_entry_free, 0,
- NULL, NULL },
- { "free_all", test_rend_cache_free_all, 0, NULL, NULL },
- { "purge", test_rend_cache_purge, 0, NULL, NULL },
- { "failure_clean", test_rend_cache_failure_clean, 0, NULL, NULL },
- { "failure_entry_new", test_rend_cache_failure_entry_new, 0, NULL, NULL },
- { "failure_entry_free", test_rend_cache_failure_entry_free, 0, NULL, NULL },
- { "failure_intro_add", test_rend_cache_failure_intro_add, 0, NULL, NULL },
- { "failure_intro_entry_new", test_rend_cache_failure_intro_entry_new, 0,
- NULL, NULL },
- { "failure_intro_lookup", test_rend_cache_failure_intro_lookup, 0,
- NULL, NULL },
- { "failure_purge", test_rend_cache_failure_purge, 0, NULL, NULL },
- { "failure_remove", test_rend_cache_failure_remove, 0, NULL, NULL },
- { "intro_failure_note", test_rend_cache_intro_failure_note, 0, NULL, NULL },
- { "lookup", test_rend_cache_lookup_entry, 0, NULL, NULL },
- { "lookup_v2_desc_as_dir", test_rend_cache_lookup_v2_desc_as_dir, 0,
- NULL, NULL },
- { "store_v2_desc_as_client", test_rend_cache_store_v2_desc_as_client, 0,
- NULL, NULL },
- { "store_v2_desc_as_client_with_different_time",
- test_rend_cache_store_v2_desc_as_client_with_different_time, 0,
- NULL, NULL },
- { "store_v2_desc_as_dir", test_rend_cache_store_v2_desc_as_dir, 0,
- NULL, NULL },
- { "store_v2_desc_as_dir_with_different_time",
- test_rend_cache_store_v2_desc_as_dir_with_different_time, 0, NULL, NULL },
- { "store_v2_desc_as_dir_with_different_content",
- test_rend_cache_store_v2_desc_as_dir_with_different_content, 0,
- NULL, NULL },
- { "validate_intro_point_failure",
- test_rend_cache_validate_intro_point_failure, 0, NULL, NULL },
- END_OF_TESTCASES
-};
diff --git a/src/test/test_replay.c b/src/test/test_replay.c
index 1487b0a29d..e21ab5eca3 100644
--- a/src/test/test_replay.c
+++ b/src/test/test_replay.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2020, The Tor Project, Inc. */
+/* Copyright (c) 2012-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define REPLAYCACHE_PRIVATE
diff --git a/src/test/test_rng.c b/src/test/test_rng.c
index ebaffb74f5..6b830eda15 100644
--- a/src/test/test_rng.c
+++ b/src/test/test_rng.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2020, The Tor Project, Inc. */
+/* Copyright (c) 2016-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/*
diff --git a/src/test/test_router.c b/src/test/test_router.c
index 895178f788..15cc93fbfc 100644
--- a/src/test/test_router.c
+++ b/src/test/test_router.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017-2020, The Tor Project, Inc. */
+/* Copyright (c) 2017-2021, The Tor Project, Inc. */
/* Copyright (c) 2017, isis agora lovecruft */
/* See LICENSE for licensing information */
diff --git a/src/test/test_routerkeys.c b/src/test/test_routerkeys.c
index e5314046b9..1ff05d57c3 100644
--- a/src/test/test_routerkeys.c
+++ b/src/test/test_routerkeys.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
diff --git a/src/test/test_routerlist.c b/src/test/test_routerlist.c
index c7b65006f0..aaa647710a 100644
--- a/src/test/test_routerlist.c
+++ b/src/test/test_routerlist.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2020, The Tor Project, Inc. */
+/* Copyright (c) 2014-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
diff --git a/src/test/test_routerset.c b/src/test/test_routerset.c
index d00eefa23f..aff6bcb9c2 100644
--- a/src/test/test_routerset.c
+++ b/src/test/test_routerset.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2020, The Tor Project, Inc. */
+/* Copyright (c) 2014-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define ROUTERSET_PRIVATE
diff --git a/src/test/test_rust.sh b/src/test/test_rust.sh
deleted file mode 100755
index 804d2ada36..0000000000
--- a/src/test/test_rust.sh
+++ /dev/null
@@ -1,28 +0,0 @@
-#!/bin/sh
-# Test all Rust crates
-
-set -e
-
-export LSAN_OPTIONS=suppressions=${abs_top_srcdir:-../../..}/src/test/rust_supp.txt
-
-# When testing Cargo we pass a number of very specific linker flags down
-# through Cargo. We do not, however, want these flags to affect things like
-# build scripts, only the tests that we're compiling. To ensure this happens
-# we unconditionally pass `--target` into Cargo, ensuring that `RUSTFLAGS` in
-# the environment won't make their way into build scripts.
-rustc_host=$(rustc -vV | grep host | sed 's/host: //')
-
-for cargo_toml_dir in "${abs_top_srcdir:-../../..}"/src/rust/*; do
- if [ -e "${cargo_toml_dir}/Cargo.toml" ]; then
- # shellcheck disable=SC2086
- cd "${abs_top_builddir:-../../..}/src/rust" && \
- CARGO_TARGET_DIR="${abs_top_builddir:-../../..}/src/rust/target" \
- "${CARGO:-cargo}" test "${CARGO_ONLINE-'--frozen'}" \
- --features "test_linking_hack" \
- --target "$rustc_host" \
- ${EXTRA_CARGO_OPTIONS} \
- --manifest-path "${cargo_toml_dir}/Cargo.toml" || exitcode=1
- fi
-done
-
-exit $exitcode
diff --git a/src/test/test_sandbox.c b/src/test/test_sandbox.c
new file mode 100644
index 0000000000..7ec08a3546
--- /dev/null
+++ b/src/test/test_sandbox.c
@@ -0,0 +1,349 @@
+/* Copyright (c) 2021, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#ifndef _LARGEFILE64_SOURCE
+/**
+ * Temporarily required for O_LARGEFILE flag. Needs to be removed
+ * with the libevent fix.
+ */
+#define _LARGEFILE64_SOURCE
+#endif /* !defined(_LARGEFILE64_SOURCE) */
+
+#include "orconfig.h"
+
+#include "lib/sandbox/sandbox.h"
+
+#ifdef USE_LIBSECCOMP
+
+#include <dirent.h>
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include "core/or/or.h"
+
+#include "test/test.h"
+#include "test/log_test_helpers.h"
+
+typedef struct {
+ sandbox_cfg_t *cfg;
+
+ char *file_ops_allowed;
+ char *file_ops_blocked;
+
+ char *file_rename_target_allowed;
+
+ char *dir_ops_allowed;
+ char *dir_ops_blocked;
+} sandbox_data_t;
+
+/* All tests are skipped when coverage support is enabled (see further below)
+ * as the sandbox interferes with the use of gcov. Prevent a compiler warning
+ * by omitting these definitions in that case. */
+#ifndef ENABLE_COVERAGE
+static void *
+setup_sandbox(const struct testcase_t *testcase)
+{
+ sandbox_data_t *data = tor_malloc_zero(sizeof(*data));
+
+ (void)testcase;
+
+ /* Establish common file and directory names within the test suite's
+ * temporary directory. */
+ data->file_ops_allowed = tor_strdup(get_fname("file_ops_allowed"));
+ data->file_ops_blocked = tor_strdup(get_fname("file_ops_blocked"));
+
+ data->file_rename_target_allowed =
+ tor_strdup(get_fname("file_rename_target_allowed"));
+
+ data->dir_ops_allowed = tor_strdup(get_fname("dir_ops_allowed"));
+ data->dir_ops_blocked = tor_strdup(get_fname("dir_ops_blocked"));
+
+ /* Create the corresponding filesystem objects. */
+ creat(data->file_ops_allowed, S_IRWXU);
+ creat(data->file_ops_blocked, S_IRWXU);
+ mkdir(data->dir_ops_allowed, S_IRWXU);
+ mkdir(data->dir_ops_blocked, S_IRWXU);
+
+ /* Create the sandbox configuration. */
+ data->cfg = sandbox_cfg_new();
+
+ sandbox_cfg_allow_open_filename(&data->cfg,
+ tor_strdup(data->file_ops_allowed));
+ sandbox_cfg_allow_open_filename(&data->cfg,
+ tor_strdup(data->dir_ops_allowed));
+
+ sandbox_cfg_allow_chmod_filename(&data->cfg,
+ tor_strdup(data->file_ops_allowed));
+ sandbox_cfg_allow_chmod_filename(&data->cfg,
+ tor_strdup(data->dir_ops_allowed));
+ sandbox_cfg_allow_chown_filename(&data->cfg,
+ tor_strdup(data->file_ops_allowed));
+ sandbox_cfg_allow_chown_filename(&data->cfg,
+ tor_strdup(data->dir_ops_allowed));
+
+ sandbox_cfg_allow_rename(&data->cfg, tor_strdup(data->file_ops_allowed),
+ tor_strdup(data->file_rename_target_allowed));
+
+ sandbox_cfg_allow_openat_filename(&data->cfg,
+ tor_strdup(data->dir_ops_allowed));
+
+ sandbox_cfg_allow_opendir_dirname(&data->cfg,
+ tor_strdup(data->dir_ops_allowed));
+
+ sandbox_cfg_allow_stat_filename(&data->cfg,
+ tor_strdup(data->file_ops_allowed));
+ sandbox_cfg_allow_stat_filename(&data->cfg,
+ tor_strdup(data->dir_ops_allowed));
+
+ /* Activate the sandbox, which will remain in effect until the process
+ * terminates. */
+ sandbox_init(data->cfg);
+
+ return data;
+}
+
+static int
+cleanup_sandbox(const struct testcase_t *testcase, void *data_)
+{
+ sandbox_data_t *data = data_;
+
+ (void)testcase;
+
+ tor_free(data->dir_ops_blocked);
+ tor_free(data->dir_ops_allowed);
+ tor_free(data->file_rename_target_allowed);
+ tor_free(data->file_ops_blocked);
+ tor_free(data->file_ops_allowed);
+
+ tor_free(data);
+
+ return 1;
+}
+
+static const struct testcase_setup_t sandboxed_testcase_setup = {
+ .setup_fn = setup_sandbox,
+ .cleanup_fn = cleanup_sandbox
+};
+#endif /* !defined(ENABLE_COVERAGE) */
+
+static void
+test_sandbox_is_active(void *ignored)
+{
+ (void)ignored;
+
+ tt_assert(!sandbox_is_active());
+
+ sandbox_init(sandbox_cfg_new());
+ tt_assert(sandbox_is_active());
+
+ done:
+ (void)0;
+}
+
+static void
+test_sandbox_open_filename(void *arg)
+{
+ sandbox_data_t *data = arg;
+ int fd, errsv;
+
+ fd = open(sandbox_intern_string(data->file_ops_allowed), O_RDONLY);
+ if (fd == -1)
+ tt_abort_perror("open");
+ close(fd);
+
+ /* It might be nice to use sandbox_intern_string() in the line below as well
+ * (and likewise in the test cases that follow) but this would require
+ * capturing the warning message it logs, and the mechanism for doing so
+ * relies on system calls that are normally blocked by the sandbox and may
+ * vary across architectures. */
+ fd = open(data->file_ops_blocked, O_RDONLY);
+ errsv = errno;
+ tt_int_op(fd, OP_EQ, -1);
+ tt_int_op(errsv, OP_EQ, EPERM);
+
+ done:
+ if (fd >= 0)
+ close(fd);
+}
+
+static void
+test_sandbox_chmod_filename(void *arg)
+{
+ sandbox_data_t *data = arg;
+ int rc, errsv;
+
+ if (chmod(sandbox_intern_string(data->file_ops_allowed),
+ S_IRUSR | S_IWUSR) != 0)
+ tt_abort_perror("chmod");
+
+ rc = chmod(data->file_ops_blocked, S_IRUSR | S_IWUSR);
+ errsv = errno;
+ tt_int_op(rc, OP_EQ, -1);
+ tt_int_op(errsv, OP_EQ, EPERM);
+
+ done:
+ (void)0;
+}
+
+static void
+test_sandbox_chown_filename(void *arg)
+{
+ sandbox_data_t *data = arg;
+ int rc, errsv;
+
+ if (chown(sandbox_intern_string(data->file_ops_allowed), -1, -1) != 0)
+ tt_abort_perror("chown");
+
+ rc = chown(data->file_ops_blocked, -1, -1);
+ errsv = errno;
+ tt_int_op(rc, OP_EQ, -1);
+ tt_int_op(errsv, OP_EQ, EPERM);
+
+ done:
+ (void)0;
+}
+
+static void
+test_sandbox_rename_filename(void *arg)
+{
+ sandbox_data_t *data = arg;
+ const char *fname_old = sandbox_intern_string(data->file_ops_allowed),
+ *fname_new = sandbox_intern_string(data->file_rename_target_allowed);
+ int rc, errsv;
+
+ if (rename(fname_old, fname_new) != 0)
+ tt_abort_perror("rename");
+
+ rc = rename(fname_new, fname_old);
+ errsv = errno;
+ tt_int_op(rc, OP_EQ, -1);
+ tt_int_op(errsv, OP_EQ, EPERM);
+
+ done:
+ (void)0;
+}
+
+static void
+test_sandbox_openat_filename(void *arg)
+{
+ sandbox_data_t *data = arg;
+ int flags = O_RDONLY | O_NONBLOCK | O_LARGEFILE | O_DIRECTORY | O_CLOEXEC;
+ int fd, errsv;
+
+ fd = openat(AT_FDCWD, sandbox_intern_string(data->dir_ops_allowed), flags);
+ if (fd < 0)
+ tt_abort_perror("openat");
+ close(fd);
+
+ fd = openat(AT_FDCWD, data->dir_ops_blocked, flags);
+ errsv = errno;
+ tt_int_op(fd, OP_EQ, -1);
+ tt_int_op(errsv, OP_EQ, EPERM);
+
+ done:
+ if (fd >= 0)
+ close(fd);
+}
+
+static void
+test_sandbox_opendir_dirname(void *arg)
+{
+ sandbox_data_t *data = arg;
+ DIR *dir;
+ int errsv;
+
+ dir = opendir(sandbox_intern_string(data->dir_ops_allowed));
+ if (dir == NULL)
+ tt_abort_perror("opendir");
+ closedir(dir);
+
+ dir = opendir(data->dir_ops_blocked);
+ errsv = errno;
+ tt_ptr_op(dir, OP_EQ, NULL);
+ tt_int_op(errsv, OP_EQ, EPERM);
+
+ done:
+ if (dir)
+ closedir(dir);
+}
+
+static void
+test_sandbox_stat_filename(void *arg)
+{
+ sandbox_data_t *data = arg;
+ struct stat st;
+
+ if (stat(sandbox_intern_string(data->file_ops_allowed), &st) != 0)
+ tt_abort_perror("stat");
+
+ int rc = stat(data->file_ops_blocked, &st);
+ int errsv = errno;
+ tt_int_op(rc, OP_EQ, -1);
+ tt_int_op(errsv, OP_EQ, EPERM);
+
+ done:
+ (void)0;
+}
+
+#define SANDBOX_TEST_SKIPPED(name) \
+ { #name, test_sandbox_ ## name, TT_SKIP, NULL, NULL }
+
+/* Skip all tests when coverage support is enabled, as the sandbox interferes
+ * with gcov and prevents it from producing any results. */
+#ifdef ENABLE_COVERAGE
+#define SANDBOX_TEST(name, flags) SANDBOX_TEST_SKIPPED(name)
+#define SANDBOX_TEST_IN_SANDBOX(name) SANDBOX_TEST_SKIPPED(name)
+#else
+#define SANDBOX_TEST(name, flags) \
+ { #name, test_sandbox_ ## name, flags, NULL, NULL }
+#define SANDBOX_TEST_IN_SANDBOX(name) \
+ { #name, test_sandbox_ ## name, TT_FORK, &sandboxed_testcase_setup, NULL }
+#endif /* defined(ENABLE_COVERAGE) */
+
+struct testcase_t sandbox_tests[] = {
+ SANDBOX_TEST(is_active, TT_FORK),
+
+/* When Tor is built with fragile compiler-hardening the sandbox is unable to
+ * filter requests to open files or directories (on systems where glibc uses
+ * the "open" system call to provide this functionality), as doing so would
+ * interfere with the address sanitizer as it retrieves information about the
+ * running process via the filesystem. Skip these tests in that case as the
+ * corresponding functions are likely to have no effect and this will cause the
+ * tests to fail. */
+#ifdef ENABLE_FRAGILE_HARDENING
+ SANDBOX_TEST_SKIPPED(open_filename),
+ SANDBOX_TEST_SKIPPED(opendir_dirname),
+#else
+ SANDBOX_TEST_IN_SANDBOX(open_filename),
+ SANDBOX_TEST_IN_SANDBOX(opendir_dirname),
+#endif /* defined(ENABLE_FRAGILE_HARDENING) */
+
+ SANDBOX_TEST_IN_SANDBOX(openat_filename),
+ SANDBOX_TEST_IN_SANDBOX(chmod_filename),
+ SANDBOX_TEST_IN_SANDBOX(chown_filename),
+ SANDBOX_TEST_IN_SANDBOX(rename_filename),
+
+/* Currently the sandbox is unable to filter stat() calls on systems where
+ * glibc implements this function using either of the legacy "stat" or "stat64"
+ * system calls, or (in glibc version 2.33 and later) either of the newer
+ * "newfstatat" or "statx" syscalls.
+ *
+ * Skip testing sandbox_cfg_allow_stat_filename() if it seems the likely the
+ * function will have no effect and the test will therefore not succeed. */
+#if !defined(__NR_stat) && !defined(__NR_stat64) && !defined(__NR_newfstatat) \
+ && !(defined(__i386__) && defined(__NR_statx))
+ SANDBOX_TEST_IN_SANDBOX(stat_filename),
+#else
+ SANDBOX_TEST_SKIPPED(stat_filename),
+#endif
+ END_OF_TESTCASES
+};
+
+#endif /* defined(USE_SECCOMP) */
diff --git a/src/test/test_scheduler.c b/src/test/test_scheduler.c
index 9ec15948e8..7e41a4be25 100644
--- a/src/test/test_scheduler.c
+++ b/src/test/test_scheduler.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2020, The Tor Project, Inc. */
+/* Copyright (c) 2014-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
diff --git a/src/test/test_sendme.c b/src/test/test_sendme.c
index b34c7ae143..ea7ccd0b3c 100644
--- a/src/test/test_sendme.c
+++ b/src/test/test_sendme.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2020, The Tor Project, Inc. */
+/* Copyright (c) 2014-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/* Unit tests for handling different kinds of relay cell */
@@ -348,6 +348,50 @@ test_package_payload_len(void *arg)
tor_free(c);
}
+/* Check that circuit_sendme_is_next works with a window of 1000,
+ * and a sendme_inc of 100 (old school tor compat) */
+static void
+test_sendme_is_next1000(void *arg)
+{
+ (void)arg;
+ tt_int_op(circuit_sendme_cell_is_next(1000, 100), OP_EQ, 0);
+ tt_int_op(circuit_sendme_cell_is_next(999, 100), OP_EQ, 0);
+ tt_int_op(circuit_sendme_cell_is_next(901, 100), OP_EQ, 1);
+
+ tt_int_op(circuit_sendme_cell_is_next(900, 100), OP_EQ, 0);
+ tt_int_op(circuit_sendme_cell_is_next(899, 100), OP_EQ, 0);
+ tt_int_op(circuit_sendme_cell_is_next(801, 100), OP_EQ, 1);
+
+ tt_int_op(circuit_sendme_cell_is_next(101, 100), OP_EQ, 1);
+ tt_int_op(circuit_sendme_cell_is_next(100, 100), OP_EQ, 0);
+ tt_int_op(circuit_sendme_cell_is_next(99, 100), OP_EQ, 0);
+ tt_int_op(circuit_sendme_cell_is_next(1, 100), OP_EQ, 1);
+ tt_int_op(circuit_sendme_cell_is_next(0, 100), OP_EQ, 0);
+
+done:
+ ;
+}
+
+/* Check that circuit_sendme_is_next works with a window of 31 */
+static void
+test_sendme_is_next(void *arg)
+{
+ (void)arg;
+ tt_int_op(circuit_sendme_cell_is_next(1000, 31), OP_EQ, 0);
+ tt_int_op(circuit_sendme_cell_is_next(970, 31), OP_EQ, 1);
+ tt_int_op(circuit_sendme_cell_is_next(969, 31), OP_EQ, 0);
+
+ /* deliver_window should never get this low, but test anyway */
+ tt_int_op(circuit_sendme_cell_is_next(9, 31), OP_EQ, 1);
+ tt_int_op(circuit_sendme_cell_is_next(8, 31), OP_EQ, 0);
+ tt_int_op(circuit_sendme_cell_is_next(7, 31), OP_EQ, 0);
+ tt_int_op(circuit_sendme_cell_is_next(1, 31), OP_EQ, 0);
+ tt_int_op(circuit_sendme_cell_is_next(0, 31), OP_EQ, 0);
+
+ done:
+ ;
+}
+
struct testcase_t sendme_tests[] = {
{ "v1_record_digest", test_v1_record_digest, TT_FORK,
NULL, NULL },
@@ -360,6 +404,8 @@ struct testcase_t sendme_tests[] = {
{ "cell_version_validation", test_cell_version_validation, TT_FORK,
NULL, NULL },
{ "package_payload_len", test_package_payload_len, 0, NULL, NULL },
+ { "sendme_is_next1000", test_sendme_is_next1000, 0, NULL, NULL },
+ { "sendme_is_next", test_sendme_is_next, 0, NULL, NULL },
END_OF_TESTCASES
};
diff --git a/src/test/test_shared_random.c b/src/test/test_shared_random.c
index 678f53234f..c28d5920a3 100644
--- a/src/test/test_shared_random.c
+++ b/src/test/test_shared_random.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2020, The Tor Project, Inc. */
+/* Copyright (c) 2016-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define SHARED_RANDOM_PRIVATE
diff --git a/src/test/test_slow.c b/src/test/test_slow.c
index 49b1066dac..5f42b43103 100644
--- a/src/test/test_slow.c
+++ b/src/test/test_slow.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/test/test_socks.c b/src/test/test_socks.c
index 4a465c7361..94c772419b 100644
--- a/src/test/test_socks.c
+++ b/src/test/test_socks.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "core/or/or.h"
diff --git a/src/test/test_statefile.c b/src/test/test_statefile.c
index dc9ecfee3e..aedf76a694 100644
--- a/src/test/test_statefile.c
+++ b/src/test/test_statefile.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
diff --git a/src/test/test_stats.c b/src/test/test_stats.c
index d45afc7b15..22d65b1e54 100644
--- a/src/test/test_stats.c
+++ b/src/test/test_stats.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -12,6 +12,8 @@
#include "lib/crypt_ops/crypto_rand.h"
#include "app/config/or_state_st.h"
#include "test/rng_test_helpers.h"
+#include "feature/hs/hs_cache.h"
+#include "test/hs_test_helpers.h"
#include <stdio.h>
@@ -31,6 +33,7 @@
#define MAINLOOP_PRIVATE
#define STATEFILE_PRIVATE
#define BWHIST_PRIVATE
+#define REPHIST_PRIVATE
#define ROUTER_PRIVATE
#include "core/or/or.h"
@@ -48,6 +51,8 @@
#include "feature/stats/bw_array_st.h"
#include "feature/relay/router.h"
+#include <event2/dns.h>
+
/** Run unit tests for some stats code. */
static void
test_stats(void *arg)
@@ -495,6 +500,133 @@ test_get_bandwidth_lines(void *arg)
bwhist_free_all();
}
+static bool
+mock_should_collect_v3_stats(void)
+{
+ return true;
+}
+
+/* Test v3 metrics */
+static void
+test_rephist_v3_onions(void *arg)
+{
+ int ret;
+
+ char *stats_string = NULL;
+ char *desc1_str = NULL;
+ ed25519_keypair_t signing_kp1;
+ hs_descriptor_t *desc1 = NULL;
+
+ const hs_v3_stats_t *hs_v3_stats = NULL;
+
+ (void) arg;
+
+ MOCK(should_collect_v3_stats, mock_should_collect_v3_stats);
+
+ get_options_mutable()->HiddenServiceStatistics = 1;
+
+ /* Initialize the subsystems */
+ hs_cache_init();
+ rep_hist_hs_stats_init(0);
+
+ /* Change time to 03-01-2002 23:36 UTC */
+ update_approx_time(1010101010);
+
+ /* HS stats should be zero here */
+ hs_v3_stats = rep_hist_get_hs_v3_stats();
+ tt_int_op(digest256map_size(hs_v3_stats->v3_onions_seen_this_period),
+ OP_EQ, 0);
+
+ /* Generate a valid descriptor */
+ ret = ed25519_keypair_generate(&signing_kp1, 0);
+ tt_int_op(ret, OP_EQ, 0);
+ desc1 = hs_helper_build_hs_desc_with_rev_counter(&signing_kp1, 42);
+ tt_assert(desc1);
+ ret = hs_desc_encode_descriptor(desc1, &signing_kp1, NULL, &desc1_str);
+ tt_int_op(ret, OP_EQ, 0);
+
+ /* Store descriptor and check that stats got updated */
+ ret = hs_cache_store_as_dir(desc1_str);
+ tt_int_op(ret, OP_EQ, 0);
+ hs_v3_stats = rep_hist_get_hs_v3_stats();
+ tt_int_op(digest256map_size(hs_v3_stats->v3_onions_seen_this_period),
+ OP_EQ, 1);
+
+ /* cleanup */
+ hs_descriptor_free(desc1);
+ tor_free(desc1_str);
+
+ /* Generate another valid descriptor */
+ ret = ed25519_keypair_generate(&signing_kp1, 0);
+ tt_int_op(ret, OP_EQ, 0);
+ desc1 = hs_helper_build_hs_desc_with_rev_counter(&signing_kp1, 42);
+ tt_assert(desc1);
+ ret = hs_desc_encode_descriptor(desc1, &signing_kp1, NULL, &desc1_str);
+ tt_int_op(ret, OP_EQ, 0);
+
+ /* Store descriptor and check that stats are updated */
+ ret = hs_cache_store_as_dir(desc1_str);
+ tt_int_op(ret, OP_EQ, 0);
+ hs_v3_stats = rep_hist_get_hs_v3_stats();
+ tt_int_op(digest256map_size(hs_v3_stats->v3_onions_seen_this_period),
+ OP_EQ, 2);
+
+ /* Check that storing the same descriptor twice does not work */
+ ret = hs_cache_store_as_dir(desc1_str);
+ tt_int_op(ret, OP_EQ, -1);
+
+ /* cleanup */
+ hs_descriptor_free(desc1);
+ tor_free(desc1_str);
+
+ /* Create a descriptor with the same identity key but diff rev counter and
+ same blinded key */
+ desc1 = hs_helper_build_hs_desc_with_rev_counter(&signing_kp1, 43);
+ tt_assert(desc1);
+ ret = hs_desc_encode_descriptor(desc1, &signing_kp1, NULL, &desc1_str);
+ tt_int_op(ret, OP_EQ, 0);
+
+ /* Store descriptor and check that stats are updated */
+ ret = hs_cache_store_as_dir(desc1_str);
+ tt_int_op(ret, OP_EQ, 0);
+ tt_int_op(digest256map_size(hs_v3_stats->v3_onions_seen_this_period),
+ OP_EQ, 2);
+
+ /* cleanup */
+ hs_descriptor_free(desc1);
+ tor_free(desc1_str);
+
+ /* Now let's skip to four days forward so that the blinded key rolls
+ forward */
+ update_approx_time(approx_time() + 345600);
+
+ /* Now create a descriptor with the same identity key but diff rev counter
+ and different blinded key */
+ desc1 = hs_helper_build_hs_desc_with_rev_counter(&signing_kp1, 44);
+ tt_assert(desc1);
+ ret = hs_desc_encode_descriptor(desc1, &signing_kp1, NULL, &desc1_str);
+ tt_int_op(ret, OP_EQ, 0);
+
+ /* Store descriptor and check that stats are updated */
+ ret = hs_cache_store_as_dir(desc1_str);
+ tt_int_op(ret, OP_EQ, 0);
+ tt_int_op(digest256map_size(hs_v3_stats->v3_onions_seen_this_period),
+ OP_EQ, 3);
+
+ /* cleanup */
+ hs_descriptor_free(desc1);
+ tor_free(desc1_str);
+
+ /* Because of differential privacy we can't actually check the stat value,
+ but let's just check that it's formatted correctly. */
+ stats_string = rep_hist_format_hs_stats(approx_time(), true);
+ tt_assert(strstr(stats_string, "hidserv-dir-v3-onions-seen"));
+
+ done:
+ UNMOCK(should_collect_v3_stats);
+ tor_free(stats_string);
+}
+
static void
test_load_stats_file(void *arg)
{
@@ -573,6 +705,227 @@ test_load_stats_file(void *arg)
tor_free(content);
}
+/** Test the overload stats logic. */
+static void
+test_overload_stats(void *arg)
+{
+ time_t current_time = 1010101010;
+ char *stats_str = NULL;
+ (void) arg;
+
+ /* Change time to 03-01-2002 23:36 UTC */
+ /* This should make the extrainfo timestamp be "2002-01-03 23:00:00" */
+ update_approx_time(current_time);
+
+ /* With an empty rephist we shouldn't get anything back */
+ stats_str = rep_hist_get_overload_stats_lines();
+ tt_assert(!stats_str);
+
+ /* Note an overload */
+ rep_hist_note_overload(OVERLOAD_GENERAL);
+
+ /* Move the time forward one hour */
+ current_time += 3600;
+ update_approx_time(current_time);
+
+ /* Now check the string */
+ stats_str = rep_hist_get_overload_general_line();
+ tt_str_op("overload-general 1 2002-01-03 23:00:00\n", OP_EQ, stats_str);
+ tor_free(stats_str);
+
+ /* Move the time forward 72 hours: see that the line has disappeared. */
+ current_time += 3600*72;
+ update_approx_time(current_time);
+
+ stats_str = rep_hist_get_overload_general_line();
+ tt_assert(!stats_str);
+
+ /* Now the time should be 2002-01-07 00:00:00 */
+
+ /* Note an overload */
+ rep_hist_note_overload(OVERLOAD_GENERAL);
+
+ stats_str = rep_hist_get_overload_general_line();
+ tt_str_op("overload-general 1 2002-01-07 00:00:00\n", OP_EQ, stats_str);
+ tor_free(stats_str);
+
+ /* Also note an fd exhaustion event */
+ rep_hist_note_overload(OVERLOAD_FD_EXHAUSTED);
+
+ stats_str = rep_hist_get_overload_general_line();
+ tt_str_op("overload-general 1 2002-01-07 00:00:00\n", OP_EQ, stats_str);
+ tor_free(stats_str);
+
+ stats_str = rep_hist_get_overload_stats_lines();
+ tt_str_op("overload-fd-exhausted 1 2002-01-07 00:00:00\n", OP_EQ, stats_str);
+ tor_free(stats_str);
+
+ /* Move the time forward. Register overload. See that the time changed */
+ current_time += 3600*2;
+ update_approx_time(current_time);
+
+ rep_hist_note_overload(OVERLOAD_GENERAL);
+
+ stats_str = rep_hist_get_overload_general_line();
+ tt_str_op("overload-general 1 2002-01-07 02:00:00\n", OP_EQ, stats_str);
+ tor_free(stats_str);
+
+ stats_str = rep_hist_get_overload_stats_lines();
+ tt_str_op("overload-fd-exhausted 1 2002-01-07 00:00:00\n", OP_EQ, stats_str);
+ tor_free(stats_str);
+
+ /* Move the time forward. Register a bandwidth ratelimit event. See that the
+ string is added */
+ current_time += 3600*2;
+ update_approx_time(current_time);
+
+ /* Register the rate limit event */
+ rep_hist_note_overload(OVERLOAD_READ);
+ /* Also set some rate limiting values that should be reflected on the log */
+ get_options_mutable()->BandwidthRate = 1000;
+ get_options_mutable()->BandwidthBurst = 2000;
+
+ stats_str = rep_hist_get_overload_general_line();
+ tt_str_op("overload-general 1 2002-01-07 02:00:00\n", OP_EQ, stats_str);
+ tor_free(stats_str);
+
+ stats_str = rep_hist_get_overload_stats_lines();
+ tt_str_op("overload-ratelimits 1 2002-01-07 04:00:00 1000 2000 1 0\n"
+ "overload-fd-exhausted 1 2002-01-07 00:00:00\n", OP_EQ, stats_str);
+ tor_free(stats_str);
+
+ /* Move the time forward 24 hours: no rate limit line anymore. */
+ current_time += 3600*24;
+ update_approx_time(current_time);
+
+ stats_str = rep_hist_get_overload_general_line();
+ tt_str_op("overload-general 1 2002-01-07 02:00:00\n", OP_EQ, stats_str);
+ tor_free(stats_str);
+
+ stats_str = rep_hist_get_overload_stats_lines();
+ tt_str_op("overload-fd-exhausted 1 2002-01-07 00:00:00\n", OP_EQ, stats_str);
+ tor_free(stats_str);
+
+ /* Move the time forward 44 hours: no fd exhausted line anymore. */
+ current_time += 3600*44;
+ update_approx_time(current_time);
+
+ stats_str = rep_hist_get_overload_general_line();
+ tt_str_op("overload-general 1 2002-01-07 02:00:00\n", OP_EQ, stats_str);
+ tor_free(stats_str);
+
+ /* Move the time forward 2 hours: there is nothing left. */
+ current_time += 3600*2;
+ update_approx_time(current_time);
+
+ stats_str = rep_hist_get_overload_general_line();
+ tt_assert(!stats_str);
+
+ stats_str = rep_hist_get_overload_stats_lines();
+ tt_assert(!stats_str);
+
+ /* Now test the rate-limit rate-limiter ;) */
+ for (int i = 0; i < 10; i++) {
+ rep_hist_note_overload(OVERLOAD_READ);
+ }
+ /* We already have an event registered from the previous tests. We just
+ * registered ten more overload events, but only one should have been counted
+ * because of the rate limiter */
+ stats_str = rep_hist_get_overload_stats_lines();
+ tt_str_op("overload-ratelimits 1 2002-01-10 02:00:00 1000 2000 2 0\n",
+ OP_EQ, stats_str);
+ tor_free(stats_str);
+
+ /* Increment time by 59 secs and try again. No additional events should
+ register */
+ current_time += 59;
+ update_approx_time(current_time);
+
+ for (int i = 0; i < 10; i++) {
+ rep_hist_note_overload(OVERLOAD_READ);
+ }
+ stats_str = rep_hist_get_overload_stats_lines();
+ tt_str_op("overload-ratelimits 1 2002-01-10 02:00:00 1000 2000 2 0\n",
+ OP_EQ, stats_str);
+ tor_free(stats_str);
+
+ /* Now increment time by 2 secs -- taking it after the minute rate limiting
+ and see that events will register again */
+ current_time += 2;
+ update_approx_time(current_time);
+
+ for (int i = 0; i < 10; i++) {
+ rep_hist_note_overload(OVERLOAD_READ);
+ rep_hist_note_overload(OVERLOAD_WRITE);
+ }
+ stats_str = rep_hist_get_overload_stats_lines();
+ tt_str_op("overload-ratelimits 1 2002-01-10 02:00:00 1000 2000 3 1\n",
+ OP_EQ, stats_str);
+ tor_free(stats_str);
+
+ done:
+ tor_free(stats_str);
+}
+
+/** Test the overload stats logic. */
+static void
+test_overload_onionskin_ntor(void *arg)
+{
+ char *stats_str = NULL;
+ (void) arg;
+ uint16_t type = ONION_HANDSHAKE_TYPE_NTOR_V3;
+
+ /* Lets simulate a series of timeouts but below our default 1% threshold. */
+
+ for (int i = 0; i < 1000; i++) {
+ rep_hist_note_circuit_handshake_requested(type);
+ /* This should trigger 9 drop which is just below 1% (10) */
+ if (i > 0 && !(i % 100)) {
+ rep_hist_note_circuit_handshake_dropped(type);
+ }
+ }
+
+ /* No overload yet. */
+ stats_str = rep_hist_get_overload_general_line();
+ tt_assert(!stats_str);
+
+ /* Move it 6 hours in the future and see if we get a general overload. */
+ update_approx_time(approx_time() + 21600);
+
+ /* This request should NOT trigger the general overload because we are below
+ * our default of 1%. */
+ rep_hist_note_circuit_handshake_requested(type);
+ stats_str = rep_hist_get_overload_general_line();
+ tt_assert(!stats_str);
+
+ /* We'll now go above our 1% threshold. */
+ for (int i = 0; i < 1000; i++) {
+ rep_hist_note_circuit_handshake_requested(type);
+ /* This should trigger 10 timeouts which is our threshold of 1% (10) */
+ if (!(i % 10)) {
+ rep_hist_note_circuit_handshake_dropped(type);
+ }
+ }
+
+ /* Move it 6 hours in the future and see if we get a general overload. */
+ update_approx_time(approx_time() + 21600);
+
+ /* This request should trigger the general overload because above 1%. */
+ rep_hist_note_circuit_handshake_requested(type);
+ stats_str = rep_hist_get_overload_general_line();
+ tt_assert(stats_str);
+ tor_free(stats_str);
+
+ /* Move 72h in the future, we should NOT get an overload anymore. */
+ update_approx_time(approx_time() + (72 * 3600));
+
+ stats_str = rep_hist_get_overload_general_line();
+ tt_assert(!stats_str);
+
+ done:
+ tor_free(stats_str);
+}
+
#define ENT(name) \
{ #name, test_ ## name , 0, NULL, NULL }
#define FORK(name) \
@@ -586,7 +939,10 @@ struct testcase_t stats_tests[] = {
FORK(add_obs),
FORK(fill_bandwidth_history),
FORK(get_bandwidth_lines),
+ FORK(rephist_v3_onions),
FORK(load_stats_file),
+ FORK(overload_stats),
+ FORK(overload_onionskin_ntor),
END_OF_TESTCASES
};
diff --git a/src/test/test_status.c b/src/test/test_status.c
index b938b86326..1d371645ae 100644
--- a/src/test/test_status.c
+++ b/src/test/test_status.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2020, The Tor Project, Inc. */
+/* Copyright (c) 2014-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define STATUS_PRIVATE
@@ -359,8 +359,10 @@ test_status_hb_not_in_consensus(void *arg)
"initiated 0 and received 0 v3 connections; "
"initiated 0 and received 0 v4 connections; "
"initiated 0 and received 0 v5 connections.\n");
- expect_log_msg("DoS mitigation since startup: 0 circuits killed with "
- "too many cells. [cc not enabled] [conn not enabled] "
+ expect_log_msg("Heartbeat: DoS mitigation since startup: 0 circuits killed "
+ "with too many cells, [DoSCircuitCreationEnabled disabled], "
+ "[DoSConnectionEnabled disabled], "
+ "[DoSRefuseSingleHopClientRendezvous disabled], "
"0 INTRODUCE2 rejected.\n");
tt_int_op(mock_saved_log_n_entries(), OP_EQ, 6);
diff --git a/src/test/test_storagedir.c b/src/test/test_storagedir.c
index eb3779cfee..16ff4da0b3 100644
--- a/src/test/test_storagedir.c
+++ b/src/test/test_storagedir.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017-2020, The Tor Project, Inc. */
+/* Copyright (c) 2017-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "core/or/or.h"
diff --git a/src/test/test_switch_id.c b/src/test/test_switch_id.c
index f97af55d17..9b3edb55ef 100644
--- a/src/test/test_switch_id.c
+++ b/src/test/test_switch_id.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2020, The Tor Project, Inc. */
+/* Copyright (c) 2015-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "core/or/or.h"
diff --git a/src/test/test_threads.c b/src/test/test_threads.c
index d5a1834aef..cc27e455b8 100644
--- a/src/test/test_threads.c
+++ b/src/test/test_threads.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
diff --git a/src/test/test_token_bucket.c b/src/test/test_token_bucket.c
index cf315f2944..097c5a156b 100644
--- a/src/test/test_token_bucket.c
+++ b/src/test/test_token_bucket.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2018-2020, The Tor Project, Inc. */
+/* Copyright (c) 2018-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/test/test_tortls.c b/src/test/test_tortls.c
index 12ba873650..99c759e276 100644
--- a/src/test/test_tortls.c
+++ b/src/test/test_tortls.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2020, The Tor Project, Inc. */
+/* Copyright (c) 2010-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define TORTLS_PRIVATE
diff --git a/src/test/test_tortls.h b/src/test/test_tortls.h
index 21c6fa0a8f..c14aba417b 100644
--- a/src/test/test_tortls.h
+++ b/src/test/test_tortls.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2020, The Tor Project, Inc. */
+/* Copyright (c) 2010-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#ifndef TEST_TORTLS_H
diff --git a/src/test/test_tortls_openssl.c b/src/test/test_tortls_openssl.c
index c1a87fbb4f..010e09c8eb 100644
--- a/src/test/test_tortls_openssl.c
+++ b/src/test/test_tortls_openssl.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2020, The Tor Project, Inc. */
+/* Copyright (c) 2010-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define TORTLS_PRIVATE
diff --git a/src/test/test_util.c b/src/test/test_util.c
index f567a18367..1dae2c617e 100644
--- a/src/test/test_util.c
+++ b/src/test/test_util.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
@@ -4554,7 +4554,7 @@ test_util_glob(void *ptr)
#else
const char *results_test3[] = {"dir1", "dir2", "file1", "file2",
"forbidden"};
-#endif
+#endif /* defined(_WIN32) */
TEST("*i*");
EXPECT(results_test3);
@@ -4584,15 +4584,8 @@ test_util_glob(void *ptr)
TEST("file1");
EXPECT(results_test9);
-#if defined(__APPLE__) || defined(__darwin__) || \
- defined(__FreeBSD__) || defined(__NetBSD__) || defined(OpenBSD)
TEST("file1"PATH_SEPARATOR);
EXPECT_EMPTY();
-#else
- const char *results_test10[] = {"file1"};
- TEST("file1"PATH_SEPARATOR);
- EXPECT(results_test10);
-#endif
// test path separator at end - with wildcards and linux path separator
const char *results_test11[] = {"dir1", "dir2", "forbidden"};
@@ -4606,7 +4599,7 @@ test_util_glob(void *ptr)
#else
const char *results_test12[] = {"dir1", "dir2", "empty", "file1", "file2",
"forbidden"};
-#endif
+#endif /* defined(_WIN32) */
TEST("*");
EXPECT(results_test12);
@@ -4653,7 +4646,7 @@ test_util_glob(void *ptr)
tor_free(pattern);
tt_assert(!results);
}
-#endif
+#endif /* !defined(_WIN32) */
#undef TEST
#undef EXPECT
@@ -4665,7 +4658,7 @@ test_util_glob(void *ptr)
(void) chmod(dir1_forbidden, 0700);
(void) chmod(dir2_forbidden, 0700);
(void) chmod(forbidden_forbidden, 0700);
-#endif
+#endif /* !defined(_WIN32) */
tor_free(dir1);
tor_free(dir2);
tor_free(forbidden);
@@ -4679,11 +4672,11 @@ test_util_glob(void *ptr)
SMARTLIST_FOREACH(results, char *, f, tor_free(f));
smartlist_free(results);
}
-#else
+#else /* !defined(HAVE_GLOB) */
tt_skip();
done:
return;
-#endif
+#endif /* defined(HAVE_GLOB) */
}
static void
@@ -4791,7 +4784,7 @@ test_util_get_glob_opened_files(void *ptr)
// dot files are not special on windows
const char *results_test3[] = {"", ".test-hidden", "dir1", "dir2", "empty",
"file1", "file2", "forbidden"};
-#endif
+#endif /* !defined(_WIN32) */
TEST("*"PATH_SEPARATOR"*");
EXPECT(results_test3);
@@ -4803,7 +4796,7 @@ test_util_get_glob_opened_files(void *ptr)
// dot files are not special on windows
const char *results_test4[] = {"", ".test-hidden", "dir1", "dir2", "empty",
"file1", "file2", "forbidden"};
-#endif
+#endif /* !defined(_WIN32) */
TEST("*"PATH_SEPARATOR"*"PATH_SEPARATOR);
EXPECT(results_test4);
@@ -4868,7 +4861,7 @@ test_util_get_glob_opened_files(void *ptr)
TT_FAIL(("unable to chmod a file on cleanup: %s", strerror(errno)));
}
}
-#endif
+#endif /* !defined(_WIN32) */
tor_free(dir1);
tor_free(dir2);
tor_free(forbidden);
@@ -4882,11 +4875,11 @@ test_util_get_glob_opened_files(void *ptr)
SMARTLIST_FOREACH(results, char *, f, tor_free(f));
smartlist_free(results);
}
-#else
+#else /* !defined(HAVE_GLOB) */
tt_skip();
done:
return;
-#endif
+#endif /* defined(HAVE_GLOB) */
}
static void
@@ -4994,7 +4987,7 @@ test_util_num_cpus(void *arg)
tt_skip();
tt_int_op(num, OP_GE, 1);
- tt_int_op(num, OP_LE, 16);
+ tt_int_op(num, OP_LE, 128);
done:
;
@@ -5949,7 +5942,7 @@ static int
fd_is_cloexec(tor_socket_t fd)
{
int flags = fcntl(fd, F_GETFD, 0);
- return (flags & FD_CLOEXEC) == FD_CLOEXEC;
+ return (flags & FD_CLOEXEC) != 0;
}
#endif /* defined(FD_CLOEXEC) */
@@ -5959,7 +5952,7 @@ static int
fd_is_nonblocking(tor_socket_t fd)
{
int flags = fcntl(fd, F_GETFL, 0);
- return (flags & O_NONBLOCK) == O_NONBLOCK;
+ return (flags & O_NONBLOCK) != 0;
}
#endif /* !defined(_WIN32) */
diff --git a/src/test/test_util_format.c b/src/test/test_util_format.c
index 726e8e7427..f0ee58a445 100644
--- a/src/test/test_util_format.c
+++ b/src/test/test_util_format.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2020, The Tor Project, Inc. */
+/* Copyright (c) 2010-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
diff --git a/src/test/test_util_process.c b/src/test/test_util_process.c
index fc79fe9b1f..28d5737cad 100644
--- a/src/test/test_util_process.c
+++ b/src/test/test_util_process.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2020, The Tor Project, Inc. */
+/* Copyright (c) 2010-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
diff --git a/src/test/test_voting_flags.c b/src/test/test_voting_flags.c
index 72f70b9865..457b0fa796 100644
--- a/src/test/test_voting_flags.c
+++ b/src/test/test_voting_flags.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2018-2020, The Tor Project, Inc. */
+/* Copyright (c) 2018-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
@@ -62,7 +62,8 @@ check_result(flag_vote_test_cfg_t *c)
bool result = false;
routerstatus_t rs;
memset(&rs, 0, sizeof(rs));
- dirauth_set_routerstatus_from_routerinfo(&rs, &c->node, &c->ri, c->now, 0);
+ dirauth_set_routerstatus_from_routerinfo(&rs, &c->node, &c->ri, c->now,
+ 0, 0);
tt_i64_op(rs.published_on, OP_EQ, c->expected.published_on);
tt_str_op(rs.nickname, OP_EQ, c->expected.nickname);
diff --git a/src/test/test_voting_schedule.c b/src/test/test_voting_schedule.c
index df64b79167..6baf9e2e2e 100644
--- a/src/test/test_voting_schedule.c
+++ b/src/test/test_voting_schedule.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2018-2020, The Tor Project, Inc. */
+/* Copyright (c) 2018-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
diff --git a/src/test/test_workqueue.c b/src/test/test_workqueue.c
index 3734c08e48..19f8934f3c 100644
--- a/src/test/test_workqueue.c
+++ b/src/test/test_workqueue.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "core/or/or.h"
diff --git a/src/test/test_x509.c b/src/test/test_x509.c
index 94e7db33de..ff21debb64 100644
--- a/src/test/test_x509.c
+++ b/src/test/test_x509.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2020, The Tor Project, Inc. */
+/* Copyright (c) 2010-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define TOR_X509_PRIVATE
diff --git a/src/test/testing_common.c b/src/test/testing_common.c
index 9b50de07a8..2fd424c07e 100644
--- a/src/test/testing_common.c
+++ b/src/test/testing_common.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/test/testing_rsakeys.c b/src/test/testing_rsakeys.c
index e058f72d01..7d3c7301dc 100644
--- a/src/test/testing_rsakeys.c
+++ b/src/test/testing_rsakeys.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "lib/crypt_ops/crypto_rand.h"
diff --git a/src/tools/include.am b/src/tools/include.am
index 6daa27f6de..86cd0acbfd 100644
--- a/src/tools/include.am
+++ b/src/tools/include.am
@@ -10,7 +10,6 @@ src_tools_tor_resolve_LDADD = \
src/trunnel/libor-trunnel.a \
$(TOR_UTIL_LIBS) \
$(TOR_CRYPTO_LIBS) $(TOR_LIBS_CRYPTLIB)\
- $(rust_ldadd) \
@TOR_LIB_MATH@ @TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_SHLWAPI@ @TOR_LIB_USERENV@
if COVERAGE_ENABLED
@@ -34,7 +33,6 @@ src_tools_tor_gencert_LDFLAGS = @TOR_LDFLAGS_zlib@ $(TOR_LDFLAGS_CRYPTLIB)
src_tools_tor_gencert_LDADD = \
$(TOR_CRYPTO_LIBS) \
$(TOR_UTIL_LIBS) \
- $(rust_ldadd) \
@TOR_LIB_MATH@ @TOR_ZLIB_LIBS@ $(TOR_LIBS_CRYPTLIB) \
@TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_SHLWAPI@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@ @CURVE25519_LIBS@
endif
diff --git a/src/tools/tor-gencert.c b/src/tools/tor-gencert.c
index e4f6530b46..efd4d000fb 100644
--- a/src/tools/tor-gencert.c
+++ b/src/tools/tor-gencert.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2007-2020, The Tor Project, Inc. */
+/* Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
@@ -248,6 +248,8 @@ generate_key(int bits)
return rsa;
}
+#define MIN_PASSPHRASE_LEN 4
+
/** Try to read the identity key from <b>identity_key_file</b>. If no such
* file exists and create_identity_key is set, make a new identity key and
* store it. Return 0 on success, nonzero on failure.
@@ -288,11 +290,16 @@ load_identity_key(void)
* the terminal. */
if (!PEM_write_PKCS8PrivateKey_nid(f, identity_key,
NID_pbe_WithSHA1And3_Key_TripleDES_CBC,
- passphrase, (int)passphrase_len,
+ passphrase, (int) passphrase_len,
NULL, NULL)) {
- log_err(LD_GENERAL, "Couldn't write identity key to %s",
- identity_key_file);
- crypto_openssl_log_errors(LOG_ERR, "Writing identity key");
+ if ((int) passphrase_len < MIN_PASSPHRASE_LEN) {
+ log_err(LD_GENERAL, "Passphrase empty or too short. Passphrase needs "
+ "to be at least %d characters.", MIN_PASSPHRASE_LEN);
+ } else {
+ log_err(LD_GENERAL, "Couldn't write identity key to %s",
+ identity_key_file);
+ crypto_openssl_log_errors(LOG_ERR, "Writing identity key");
+ }
abort_writing_to_file(open_file);
return 1;
}
diff --git a/src/tools/tor-print-ed-signing-cert.c b/src/tools/tor-print-ed-signing-cert.c
index 7836293df4..7d4e0b1944 100644
--- a/src/tools/tor-print-ed-signing-cert.c
+++ b/src/tools/tor-print-ed-signing-cert.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2007-2020, The Tor Project, Inc. */
+/* Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include <errno.h>
diff --git a/src/tools/tor-resolve.c b/src/tools/tor-resolve.c
index e6d6bddcdb..ad52fdaa22 100644
--- a/src/tools/tor-resolve.c
+++ b/src/tools/tor-resolve.c
@@ -1,5 +1,5 @@
/* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson
- * Copyright (c) 2007-2020, The Tor Project, Inc.
+ * Copyright (c) 2007-2021, The Tor Project, Inc.
*/
/* See LICENSE for licensing information */
@@ -253,7 +253,7 @@ build_socks_resolve_request(uint8_t **out,
}
static void
-onion_warning(const char *hostname)
+onion_hs_warning(const char *hostname)
{
log_warn(LD_NET,
"%s is a hidden service; those don't have IP addresses. "
@@ -264,6 +264,15 @@ onion_warning(const char *hostname)
hostname);
}
+static void
+onion_exit_warning(const char *hostname)
+{
+ log_warn(LD_NET,
+ "%s is a link pointing to an exit node; however, .exit domains"
+ "have been long defunct and are not valid anymore.",
+ hostname);
+}
+
/** Given a <b>len</b>-byte SOCKS4a response in <b>response</b>, set
* *<b>addr_out</b> to the address it contains (in host order).
* Return 0 on success, -1 on error.
@@ -306,9 +315,15 @@ parse_socks4a_resolve_response(const char *hostname,
if (status != 90) {
log_warn(LD_NET,"Got status response '%d': socks request failed.", status);
if (!strcasecmpend(hostname, ".onion")) {
- onion_warning(hostname);
+ onion_hs_warning(hostname);
result = -1; goto cleanup;
}
+
+ if (!strcasecmpend(hostname, ".exit")) {
+ onion_exit_warning(hostname);
+ result = -1; goto cleanup;
+ }
+
result = -1; goto cleanup;
}
@@ -493,7 +508,11 @@ do_resolve(const char *hostname,
(unsigned)reply_field,
socks5_reason_to_string(reply_field));
if (reply_field == 4 && !strcasecmpend(hostname, ".onion")) {
- onion_warning(hostname);
+ onion_hs_warning(hostname);
+ }
+
+ if (reply_field == 4 && !strcasecmpend(hostname, ".exit")) {
+ onion_exit_warning(hostname);
}
socks5_server_reply_free(reply);
diff --git a/src/tools/tor_runner.c b/src/tools/tor_runner.c
index 83f1a495cd..360f9c57ac 100644
--- a/src/tools/tor_runner.c
+++ b/src/tools/tor_runner.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/trunnel/congestion_control.c b/src/trunnel/congestion_control.c
new file mode 100644
index 0000000000..371612bfe0
--- /dev/null
+++ b/src/trunnel/congestion_control.c
@@ -0,0 +1,183 @@
+/* congestion_control.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 "congestion_control.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 congestioncontrol_deadcode_dummy__ = 0;
+#define OR_DEADCODE_DUMMY || congestioncontrol_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_extension_field_cc_t *
+trn_extension_field_cc_new(void)
+{
+ trn_extension_field_cc_t *val = trunnel_calloc(1, sizeof(trn_extension_field_cc_t));
+ if (NULL == val)
+ return NULL;
+ return val;
+}
+
+/** Release all storage held inside 'obj', but do not free 'obj'.
+ */
+static void
+trn_extension_field_cc_clear(trn_extension_field_cc_t *obj)
+{
+ (void) obj;
+}
+
+void
+trn_extension_field_cc_free(trn_extension_field_cc_t *obj)
+{
+ if (obj == NULL)
+ return;
+ trn_extension_field_cc_clear(obj);
+ trunnel_memwipe(obj, sizeof(trn_extension_field_cc_t));
+ trunnel_free_(obj);
+}
+
+uint8_t
+trn_extension_field_cc_get_sendme_inc(const trn_extension_field_cc_t *inp)
+{
+ return inp->sendme_inc;
+}
+int
+trn_extension_field_cc_set_sendme_inc(trn_extension_field_cc_t *inp, uint8_t val)
+{
+ inp->sendme_inc = val;
+ return 0;
+}
+const char *
+trn_extension_field_cc_check(const trn_extension_field_cc_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_extension_field_cc_encoded_len(const trn_extension_field_cc_t *obj)
+{
+ ssize_t result = 0;
+
+ if (NULL != trn_extension_field_cc_check(obj))
+ return -1;
+
+
+ /* Length of u8 sendme_inc */
+ result += 1;
+ return result;
+}
+int
+trn_extension_field_cc_clear_errors(trn_extension_field_cc_t *obj)
+{
+ int r = obj->trunnel_error_code_;
+ obj->trunnel_error_code_ = 0;
+ return r;
+}
+ssize_t
+trn_extension_field_cc_encode(uint8_t *output, const size_t avail, const trn_extension_field_cc_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_extension_field_cc_encoded_len(obj);
+#endif
+
+ if (NULL != (msg = trn_extension_field_cc_check(obj)))
+ goto check_failed;
+
+#ifdef TRUNNEL_CHECK_ENCODED_LEN
+ trunnel_assert(encoded_len >= 0);
+#endif
+
+ /* Encode u8 sendme_inc */
+ trunnel_assert(written <= avail);
+ if (avail - written < 1)
+ goto truncated;
+ trunnel_set_uint8(ptr, (obj->sendme_inc));
+ 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_extension_field_cc_parse(), but do not allocate the output
+ * object.
+ */
+static ssize_t
+trn_extension_field_cc_parse_into(trn_extension_field_cc_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 sendme_inc */
+ CHECK_REMAINING(1, truncated);
+ obj->sendme_inc = (trunnel_get_uint8(ptr));
+ remaining -= 1; ptr += 1;
+ trunnel_assert(ptr + remaining == input + len_in);
+ return len_in - remaining;
+
+ truncated:
+ return -2;
+}
+
+ssize_t
+trn_extension_field_cc_parse(trn_extension_field_cc_t **output, const uint8_t *input, const size_t len_in)
+{
+ ssize_t result;
+ *output = trn_extension_field_cc_new();
+ if (NULL == *output)
+ return -1;
+ result = trn_extension_field_cc_parse_into(*output, input, len_in);
+ if (result < 0) {
+ trn_extension_field_cc_free(*output);
+ *output = NULL;
+ }
+ return result;
+}
diff --git a/src/trunnel/congestion_control.h b/src/trunnel/congestion_control.h
new file mode 100644
index 0000000000..0cc21a1db5
--- /dev/null
+++ b/src/trunnel/congestion_control.h
@@ -0,0 +1,67 @@
+/* congestion_control.h -- generated by Trunnel v1.5.3.
+ * https://gitweb.torproject.org/trunnel.git
+ * You probably shouldn't edit this file.
+ */
+#ifndef TRUNNEL_CONGESTION_CONTROL_H
+#define TRUNNEL_CONGESTION_CONTROL_H
+
+#include <stdint.h>
+#include "trunnel.h"
+
+#define TRUNNEL_EXT_TYPE_CC_FIELD_REQUEST 1
+#define TRUNNEL_EXT_TYPE_CC_FIELD_RESPONSE 2
+#if !defined(TRUNNEL_OPAQUE) && !defined(TRUNNEL_OPAQUE_TRN_EXTENSION_FIELD_CC)
+struct trn_extension_field_cc_st {
+ uint8_t sendme_inc;
+ uint8_t trunnel_error_code_;
+};
+#endif
+typedef struct trn_extension_field_cc_st trn_extension_field_cc_t;
+/** Return a newly allocated trn_extension_field_cc with all elements
+ * set to zero.
+ */
+trn_extension_field_cc_t *trn_extension_field_cc_new(void);
+/** Release all storage held by the trn_extension_field_cc in
+ * 'victim'. (Do nothing if 'victim' is NULL.)
+ */
+void trn_extension_field_cc_free(trn_extension_field_cc_t *victim);
+/** Try to parse a trn_extension_field_cc 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_extension_field_cc_t. On failure, return -2 if the
+ * input appears truncated, and -1 if the input is otherwise invalid.
+ */
+ssize_t trn_extension_field_cc_parse(trn_extension_field_cc_t **output, const uint8_t *input, const size_t len_in);
+/** Return the number of bytes we expect to need to encode the
+ * trn_extension_field_cc 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_extension_field_cc_encoded_len(const trn_extension_field_cc_t *obj);
+/** Try to encode the trn_extension_field_cc 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_extension_field_cc_encode(uint8_t *output, size_t avail, const trn_extension_field_cc_t *input);
+/** Check whether the internal state of the trn_extension_field_cc in
+ * 'obj' is consistent. Return NULL if it is, and a short message if
+ * it is not.
+ */
+const char *trn_extension_field_cc_check(const trn_extension_field_cc_t *obj);
+/** Clear any errors that were set on the object 'obj' by its setter
+ * functions. Return true iff errors were cleared.
+ */
+int trn_extension_field_cc_clear_errors(trn_extension_field_cc_t *obj);
+/** Return the value of the sendme_inc field of the
+ * trn_extension_field_cc_t in 'inp'
+ */
+uint8_t trn_extension_field_cc_get_sendme_inc(const trn_extension_field_cc_t *inp);
+/** Set the value of the sendme_inc field of the
+ * trn_extension_field_cc_t in 'inp' to 'val'. Return 0 on success;
+ * return -1 and set the error code on 'inp' on failure.
+ */
+int trn_extension_field_cc_set_sendme_inc(trn_extension_field_cc_t *inp, uint8_t val);
+
+
+#endif
diff --git a/src/trunnel/congestion_control.trunnel b/src/trunnel/congestion_control.trunnel
new file mode 100644
index 0000000000..50697a0cd2
--- /dev/null
+++ b/src/trunnel/congestion_control.trunnel
@@ -0,0 +1,22 @@
+/* This file contains the definition for the encrypted payload of a circuit
+ * parameter negotiation request/response portion of the trn_ntorv3 onionskin
+ * handshake. Currently only supports congestion control params. */
+
+/* The following is encoded in the extension format. */
+
+/* Field types. */
+const TRUNNEL_EXT_TYPE_CC_FIELD_REQUEST = 0x01;
+const TRUNNEL_EXT_TYPE_CC_FIELD_RESPONSE = 0x02;
+
+/*
+ * "Request" is an empty payload signalling that CC is enabled.
+ */
+
+/*
+ * "Response" consists of 1 single byte:
+ * SENDME_INC -- Min: 0, Max: 255
+ */
+
+struct trn_extension_field_cc {
+ u8 sendme_inc;
+};
diff --git a/src/trunnel/hs/cell_common.c b/src/trunnel/extension.c
index 1f50961d69..538ac62928 100644
--- a/src/trunnel/hs/cell_common.c
+++ b/src/trunnel/extension.c
@@ -1,11 +1,11 @@
-/* cell_common.c -- generated by Trunnel v1.5.3.
+/* extension.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 "cell_common.h"
+#include "extension.h"
#define TRUNNEL_SET_ERROR_CODE(obj) \
do { \
@@ -15,8 +15,8 @@
#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 cellcommon_deadcode_dummy__ = 0;
-#define OR_DEADCODE_DUMMY || cellcommon_deadcode_dummy__
+int extension_deadcode_dummy__ = 0;
+#define OR_DEADCODE_DUMMY || extension_deadcode_dummy__
#else
#define OR_DEADCODE_DUMMY
#endif
@@ -28,10 +28,10 @@ int cellcommon_deadcode_dummy__ = 0;
} \
} while (0)
-trn_cell_extension_field_t *
-trn_cell_extension_field_new(void)
+trn_extension_field_t *
+trn_extension_field_new(void)
{
- trn_cell_extension_field_t *val = trunnel_calloc(1, sizeof(trn_cell_extension_field_t));
+ trn_extension_field_t *val = trunnel_calloc(1, sizeof(trn_extension_field_t));
if (NULL == val)
return NULL;
return val;
@@ -40,7 +40,7 @@ trn_cell_extension_field_new(void)
/** Release all storage held inside 'obj', but do not free 'obj'.
*/
static void
-trn_cell_extension_field_clear(trn_cell_extension_field_t *obj)
+trn_extension_field_clear(trn_extension_field_t *obj)
{
(void) obj;
TRUNNEL_DYNARRAY_WIPE(&obj->field);
@@ -48,62 +48,62 @@ trn_cell_extension_field_clear(trn_cell_extension_field_t *obj)
}
void
-trn_cell_extension_field_free(trn_cell_extension_field_t *obj)
+trn_extension_field_free(trn_extension_field_t *obj)
{
if (obj == NULL)
return;
- trn_cell_extension_field_clear(obj);
- trunnel_memwipe(obj, sizeof(trn_cell_extension_field_t));
+ trn_extension_field_clear(obj);
+ trunnel_memwipe(obj, sizeof(trn_extension_field_t));
trunnel_free_(obj);
}
uint8_t
-trn_cell_extension_field_get_field_type(const trn_cell_extension_field_t *inp)
+trn_extension_field_get_field_type(const trn_extension_field_t *inp)
{
return inp->field_type;
}
int
-trn_cell_extension_field_set_field_type(trn_cell_extension_field_t *inp, uint8_t val)
+trn_extension_field_set_field_type(trn_extension_field_t *inp, uint8_t val)
{
inp->field_type = val;
return 0;
}
uint8_t
-trn_cell_extension_field_get_field_len(const trn_cell_extension_field_t *inp)
+trn_extension_field_get_field_len(const trn_extension_field_t *inp)
{
return inp->field_len;
}
int
-trn_cell_extension_field_set_field_len(trn_cell_extension_field_t *inp, uint8_t val)
+trn_extension_field_set_field_len(trn_extension_field_t *inp, uint8_t val)
{
inp->field_len = val;
return 0;
}
size_t
-trn_cell_extension_field_getlen_field(const trn_cell_extension_field_t *inp)
+trn_extension_field_getlen_field(const trn_extension_field_t *inp)
{
return TRUNNEL_DYNARRAY_LEN(&inp->field);
}
uint8_t
-trn_cell_extension_field_get_field(trn_cell_extension_field_t *inp, size_t idx)
+trn_extension_field_get_field(trn_extension_field_t *inp, size_t idx)
{
return TRUNNEL_DYNARRAY_GET(&inp->field, idx);
}
uint8_t
-trn_cell_extension_field_getconst_field(const trn_cell_extension_field_t *inp, size_t idx)
+trn_extension_field_getconst_field(const trn_extension_field_t *inp, size_t idx)
{
- return trn_cell_extension_field_get_field((trn_cell_extension_field_t*)inp, idx);
+ return trn_extension_field_get_field((trn_extension_field_t*)inp, idx);
}
int
-trn_cell_extension_field_set_field(trn_cell_extension_field_t *inp, size_t idx, uint8_t elt)
+trn_extension_field_set_field(trn_extension_field_t *inp, size_t idx, uint8_t elt)
{
TRUNNEL_DYNARRAY_SET(&inp->field, idx, elt);
return 0;
}
int
-trn_cell_extension_field_add_field(trn_cell_extension_field_t *inp, uint8_t elt)
+trn_extension_field_add_field(trn_extension_field_t *inp, uint8_t elt)
{
#if SIZE_MAX >= UINT8_MAX
if (inp->field.n_ == UINT8_MAX)
@@ -117,17 +117,17 @@ trn_cell_extension_field_add_field(trn_cell_extension_field_t *inp, uint8_t elt)
}
uint8_t *
-trn_cell_extension_field_getarray_field(trn_cell_extension_field_t *inp)
+trn_extension_field_getarray_field(trn_extension_field_t *inp)
{
return inp->field.elts_;
}
const uint8_t *
-trn_cell_extension_field_getconstarray_field(const trn_cell_extension_field_t *inp)
+trn_extension_field_getconstarray_field(const trn_extension_field_t *inp)
{
- return (const uint8_t *)trn_cell_extension_field_getarray_field((trn_cell_extension_field_t*)inp);
+ return (const uint8_t *)trn_extension_field_getarray_field((trn_extension_field_t*)inp);
}
int
-trn_cell_extension_field_setlen_field(trn_cell_extension_field_t *inp, size_t newlen)
+trn_extension_field_setlen_field(trn_extension_field_t *inp, size_t newlen)
{
uint8_t *newptr;
#if UINT8_MAX < SIZE_MAX
@@ -147,7 +147,7 @@ trn_cell_extension_field_setlen_field(trn_cell_extension_field_t *inp, size_t ne
return -1;
}
const char *
-trn_cell_extension_field_check(const trn_cell_extension_field_t *obj)
+trn_extension_field_check(const trn_extension_field_t *obj)
{
if (obj == NULL)
return "Object was NULL";
@@ -159,11 +159,11 @@ trn_cell_extension_field_check(const trn_cell_extension_field_t *obj)
}
ssize_t
-trn_cell_extension_field_encoded_len(const trn_cell_extension_field_t *obj)
+trn_extension_field_encoded_len(const trn_extension_field_t *obj)
{
ssize_t result = 0;
- if (NULL != trn_cell_extension_field_check(obj))
+ if (NULL != trn_extension_field_check(obj))
return -1;
@@ -178,24 +178,24 @@ trn_cell_extension_field_encoded_len(const trn_cell_extension_field_t *obj)
return result;
}
int
-trn_cell_extension_field_clear_errors(trn_cell_extension_field_t *obj)
+trn_extension_field_clear_errors(trn_extension_field_t *obj)
{
int r = obj->trunnel_error_code_;
obj->trunnel_error_code_ = 0;
return r;
}
ssize_t
-trn_cell_extension_field_encode(uint8_t *output, const size_t avail, const trn_cell_extension_field_t *obj)
+trn_extension_field_encode(uint8_t *output, const size_t avail, const trn_extension_field_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_field_encoded_len(obj);
+ const ssize_t encoded_len = trn_extension_field_encoded_len(obj);
#endif
- if (NULL != (msg = trn_cell_extension_field_check(obj)))
+ if (NULL != (msg = trn_extension_field_check(obj)))
goto check_failed;
#ifdef TRUNNEL_CHECK_ENCODED_LEN
@@ -252,11 +252,11 @@ trn_cell_extension_field_encode(uint8_t *output, const size_t avail, const trn_c
return result;
}
-/** As trn_cell_extension_field_parse(), but do not allocate the
- * output object.
+/** As trn_extension_field_parse(), but do not allocate the output
+ * object.
*/
static ssize_t
-trn_cell_extension_field_parse_into(trn_cell_extension_field_t *obj, const uint8_t *input, const size_t len_in)
+trn_extension_field_parse_into(trn_extension_field_t *obj, const uint8_t *input, const size_t len_in)
{
const uint8_t *ptr = input;
size_t remaining = len_in;
@@ -290,23 +290,23 @@ trn_cell_extension_field_parse_into(trn_cell_extension_field_t *obj, const uint8
}
ssize_t
-trn_cell_extension_field_parse(trn_cell_extension_field_t **output, const uint8_t *input, const size_t len_in)
+trn_extension_field_parse(trn_extension_field_t **output, const uint8_t *input, const size_t len_in)
{
ssize_t result;
- *output = trn_cell_extension_field_new();
+ *output = trn_extension_field_new();
if (NULL == *output)
return -1;
- result = trn_cell_extension_field_parse_into(*output, input, len_in);
+ result = trn_extension_field_parse_into(*output, input, len_in);
if (result < 0) {
- trn_cell_extension_field_free(*output);
+ trn_extension_field_free(*output);
*output = NULL;
}
return result;
}
-trn_cell_extension_t *
-trn_cell_extension_new(void)
+trn_extension_t *
+trn_extension_new(void)
{
- trn_cell_extension_t *val = trunnel_calloc(1, sizeof(trn_cell_extension_t));
+ trn_extension_t *val = trunnel_calloc(1, sizeof(trn_extension_t));
if (NULL == val)
return NULL;
return val;
@@ -315,14 +315,14 @@ trn_cell_extension_new(void)
/** Release all storage held inside 'obj', but do not free 'obj'.
*/
static void
-trn_cell_extension_clear(trn_cell_extension_t *obj)
+trn_extension_clear(trn_extension_t *obj)
{
(void) obj;
{
unsigned idx;
for (idx = 0; idx < TRUNNEL_DYNARRAY_LEN(&obj->fields); ++idx) {
- trn_cell_extension_field_free(TRUNNEL_DYNARRAY_GET(&obj->fields, idx));
+ trn_extension_field_free(TRUNNEL_DYNARRAY_GET(&obj->fields, idx));
}
}
TRUNNEL_DYNARRAY_WIPE(&obj->fields);
@@ -330,92 +330,92 @@ trn_cell_extension_clear(trn_cell_extension_t *obj)
}
void
-trn_cell_extension_free(trn_cell_extension_t *obj)
+trn_extension_free(trn_extension_t *obj)
{
if (obj == NULL)
return;
- trn_cell_extension_clear(obj);
- trunnel_memwipe(obj, sizeof(trn_cell_extension_t));
+ trn_extension_clear(obj);
+ trunnel_memwipe(obj, sizeof(trn_extension_t));
trunnel_free_(obj);
}
uint8_t
-trn_cell_extension_get_num(const trn_cell_extension_t *inp)
+trn_extension_get_num(const trn_extension_t *inp)
{
return inp->num;
}
int
-trn_cell_extension_set_num(trn_cell_extension_t *inp, uint8_t val)
+trn_extension_set_num(trn_extension_t *inp, uint8_t val)
{
inp->num = val;
return 0;
}
size_t
-trn_cell_extension_getlen_fields(const trn_cell_extension_t *inp)
+trn_extension_getlen_fields(const trn_extension_t *inp)
{
return TRUNNEL_DYNARRAY_LEN(&inp->fields);
}
-struct trn_cell_extension_field_st *
-trn_cell_extension_get_fields(trn_cell_extension_t *inp, size_t idx)
+struct trn_extension_field_st *
+trn_extension_get_fields(trn_extension_t *inp, size_t idx)
{
return TRUNNEL_DYNARRAY_GET(&inp->fields, idx);
}
- const struct trn_cell_extension_field_st *
-trn_cell_extension_getconst_fields(const trn_cell_extension_t *inp, size_t idx)
+ const struct trn_extension_field_st *
+trn_extension_getconst_fields(const trn_extension_t *inp, size_t idx)
{
- return trn_cell_extension_get_fields((trn_cell_extension_t*)inp, idx);
+ return trn_extension_get_fields((trn_extension_t*)inp, idx);
}
int
-trn_cell_extension_set_fields(trn_cell_extension_t *inp, size_t idx, struct trn_cell_extension_field_st * elt)
+trn_extension_set_fields(trn_extension_t *inp, size_t idx, struct trn_extension_field_st * elt)
{
- trn_cell_extension_field_t *oldval = TRUNNEL_DYNARRAY_GET(&inp->fields, idx);
+ trn_extension_field_t *oldval = TRUNNEL_DYNARRAY_GET(&inp->fields, idx);
if (oldval && oldval != elt)
- trn_cell_extension_field_free(oldval);
- return trn_cell_extension_set0_fields(inp, idx, elt);
+ trn_extension_field_free(oldval);
+ return trn_extension_set0_fields(inp, idx, elt);
}
int
-trn_cell_extension_set0_fields(trn_cell_extension_t *inp, size_t idx, struct trn_cell_extension_field_st * elt)
+trn_extension_set0_fields(trn_extension_t *inp, size_t idx, struct trn_extension_field_st * elt)
{
TRUNNEL_DYNARRAY_SET(&inp->fields, idx, elt);
return 0;
}
int
-trn_cell_extension_add_fields(trn_cell_extension_t *inp, struct trn_cell_extension_field_st * elt)
+trn_extension_add_fields(trn_extension_t *inp, struct trn_extension_field_st * elt)
{
#if SIZE_MAX >= UINT8_MAX
if (inp->fields.n_ == UINT8_MAX)
goto trunnel_alloc_failed;
#endif
- TRUNNEL_DYNARRAY_ADD(struct trn_cell_extension_field_st *, &inp->fields, elt, {});
+ TRUNNEL_DYNARRAY_ADD(struct trn_extension_field_st *, &inp->fields, elt, {});
return 0;
trunnel_alloc_failed:
TRUNNEL_SET_ERROR_CODE(inp);
return -1;
}
-struct trn_cell_extension_field_st * *
-trn_cell_extension_getarray_fields(trn_cell_extension_t *inp)
+struct trn_extension_field_st * *
+trn_extension_getarray_fields(trn_extension_t *inp)
{
return inp->fields.elts_;
}
-const struct trn_cell_extension_field_st * const *
-trn_cell_extension_getconstarray_fields(const trn_cell_extension_t *inp)
+const struct trn_extension_field_st * const *
+trn_extension_getconstarray_fields(const trn_extension_t *inp)
{
- return (const struct trn_cell_extension_field_st * const *)trn_cell_extension_getarray_fields((trn_cell_extension_t*)inp);
+ return (const struct trn_extension_field_st * const *)trn_extension_getarray_fields((trn_extension_t*)inp);
}
int
-trn_cell_extension_setlen_fields(trn_cell_extension_t *inp, size_t newlen)
+trn_extension_setlen_fields(trn_extension_t *inp, size_t newlen)
{
- struct trn_cell_extension_field_st * *newptr;
+ struct trn_extension_field_st * *newptr;
#if UINT8_MAX < SIZE_MAX
if (newlen > UINT8_MAX)
goto trunnel_alloc_failed;
#endif
newptr = trunnel_dynarray_setlen(&inp->fields.allocated_,
&inp->fields.n_, inp->fields.elts_, newlen,
- sizeof(inp->fields.elts_[0]), (trunnel_free_fn_t) trn_cell_extension_field_free,
+ sizeof(inp->fields.elts_[0]), (trunnel_free_fn_t) trn_extension_field_free,
&inp->trunnel_error_code_);
if (newlen != 0 && newptr == NULL)
goto trunnel_alloc_failed;
@@ -426,7 +426,7 @@ trn_cell_extension_setlen_fields(trn_cell_extension_t *inp, size_t newlen)
return -1;
}
const char *
-trn_cell_extension_check(const trn_cell_extension_t *obj)
+trn_extension_check(const trn_extension_t *obj)
{
if (obj == NULL)
return "Object was NULL";
@@ -437,7 +437,7 @@ trn_cell_extension_check(const trn_cell_extension_t *obj)
unsigned idx;
for (idx = 0; idx < TRUNNEL_DYNARRAY_LEN(&obj->fields); ++idx) {
- if (NULL != (msg = trn_cell_extension_field_check(TRUNNEL_DYNARRAY_GET(&obj->fields, idx))))
+ if (NULL != (msg = trn_extension_field_check(TRUNNEL_DYNARRAY_GET(&obj->fields, idx))))
return msg;
}
}
@@ -447,46 +447,46 @@ trn_cell_extension_check(const trn_cell_extension_t *obj)
}
ssize_t
-trn_cell_extension_encoded_len(const trn_cell_extension_t *obj)
+trn_extension_encoded_len(const trn_extension_t *obj)
{
ssize_t result = 0;
- if (NULL != trn_cell_extension_check(obj))
+ if (NULL != trn_extension_check(obj))
return -1;
/* Length of u8 num */
result += 1;
- /* Length of struct trn_cell_extension_field fields[num] */
+ /* Length of struct trn_extension_field fields[num] */
{
unsigned idx;
for (idx = 0; idx < TRUNNEL_DYNARRAY_LEN(&obj->fields); ++idx) {
- result += trn_cell_extension_field_encoded_len(TRUNNEL_DYNARRAY_GET(&obj->fields, idx));
+ result += trn_extension_field_encoded_len(TRUNNEL_DYNARRAY_GET(&obj->fields, idx));
}
}
return result;
}
int
-trn_cell_extension_clear_errors(trn_cell_extension_t *obj)
+trn_extension_clear_errors(trn_extension_t *obj)
{
int r = obj->trunnel_error_code_;
obj->trunnel_error_code_ = 0;
return r;
}
ssize_t
-trn_cell_extension_encode(uint8_t *output, const size_t avail, const trn_cell_extension_t *obj)
+trn_extension_encode(uint8_t *output, const size_t avail, const trn_extension_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_encoded_len(obj);
+ const ssize_t encoded_len = trn_extension_encoded_len(obj);
#endif
- if (NULL != (msg = trn_cell_extension_check(obj)))
+ if (NULL != (msg = trn_extension_check(obj)))
goto check_failed;
#ifdef TRUNNEL_CHECK_ENCODED_LEN
@@ -500,13 +500,13 @@ trn_cell_extension_encode(uint8_t *output, const size_t avail, const trn_cell_ex
trunnel_set_uint8(ptr, (obj->num));
written += 1; ptr += 1;
- /* Encode struct trn_cell_extension_field fields[num] */
+ /* Encode struct trn_extension_field fields[num] */
{
unsigned idx;
for (idx = 0; idx < TRUNNEL_DYNARRAY_LEN(&obj->fields); ++idx) {
trunnel_assert(written <= avail);
- result = trn_cell_extension_field_encode(ptr, avail - written, TRUNNEL_DYNARRAY_GET(&obj->fields, idx));
+ result = trn_extension_field_encode(ptr, avail - written, TRUNNEL_DYNARRAY_GET(&obj->fields, idx));
if (result < 0)
goto fail; /* XXXXXXX !*/
written += result; ptr += result;
@@ -537,11 +537,10 @@ trn_cell_extension_encode(uint8_t *output, const size_t avail, const trn_cell_ex
return result;
}
-/** As trn_cell_extension_parse(), but do not allocate the output
- * object.
+/** As trn_extension_parse(), but do not allocate the output object.
*/
static ssize_t
-trn_cell_extension_parse_into(trn_cell_extension_t *obj, const uint8_t *input, const size_t len_in)
+trn_extension_parse_into(trn_extension_t *obj, const uint8_t *input, const size_t len_in)
{
const uint8_t *ptr = input;
size_t remaining = len_in;
@@ -553,18 +552,18 @@ trn_cell_extension_parse_into(trn_cell_extension_t *obj, const uint8_t *input, c
obj->num = (trunnel_get_uint8(ptr));
remaining -= 1; ptr += 1;
- /* Parse struct trn_cell_extension_field fields[num] */
- TRUNNEL_DYNARRAY_EXPAND(trn_cell_extension_field_t *, &obj->fields, obj->num, {});
+ /* Parse struct trn_extension_field fields[num] */
+ TRUNNEL_DYNARRAY_EXPAND(trn_extension_field_t *, &obj->fields, obj->num, {});
{
- trn_cell_extension_field_t * elt;
+ trn_extension_field_t * elt;
unsigned idx;
for (idx = 0; idx < obj->num; ++idx) {
- result = trn_cell_extension_field_parse(&elt, ptr, remaining);
+ result = trn_extension_field_parse(&elt, ptr, remaining);
if (result < 0)
goto relay_fail;
trunnel_assert((size_t)result <= remaining);
remaining -= result; ptr += result;
- TRUNNEL_DYNARRAY_ADD(trn_cell_extension_field_t *, &obj->fields, elt, {trn_cell_extension_field_free(elt);});
+ TRUNNEL_DYNARRAY_ADD(trn_extension_field_t *, &obj->fields, elt, {trn_extension_field_free(elt);});
}
}
trunnel_assert(ptr + remaining == input + len_in);
@@ -580,15 +579,15 @@ trn_cell_extension_parse_into(trn_cell_extension_t *obj, const uint8_t *input, c
}
ssize_t
-trn_cell_extension_parse(trn_cell_extension_t **output, const uint8_t *input, const size_t len_in)
+trn_extension_parse(trn_extension_t **output, const uint8_t *input, const size_t len_in)
{
ssize_t result;
- *output = trn_cell_extension_new();
+ *output = trn_extension_new();
if (NULL == *output)
return -1;
- result = trn_cell_extension_parse_into(*output, input, len_in);
+ result = trn_extension_parse_into(*output, input, len_in);
if (result < 0) {
- trn_cell_extension_free(*output);
+ trn_extension_free(*output);
*output = NULL;
}
return result;
diff --git a/src/trunnel/extension.h b/src/trunnel/extension.h
new file mode 100644
index 0000000000..eed89d140e
--- /dev/null
+++ b/src/trunnel/extension.h
@@ -0,0 +1,197 @@
+/* extension.h -- generated by Trunnel v1.5.3.
+ * https://gitweb.torproject.org/trunnel.git
+ * You probably shouldn't edit this file.
+ */
+#ifndef TRUNNEL_EXTENSION_H
+#define TRUNNEL_EXTENSION_H
+
+#include <stdint.h>
+#include "trunnel.h"
+
+#if !defined(TRUNNEL_OPAQUE) && !defined(TRUNNEL_OPAQUE_TRN_EXTENSION_FIELD)
+struct trn_extension_field_st {
+ uint8_t field_type;
+ uint8_t field_len;
+ TRUNNEL_DYNARRAY_HEAD(, uint8_t) field;
+ uint8_t trunnel_error_code_;
+};
+#endif
+typedef struct trn_extension_field_st trn_extension_field_t;
+#if !defined(TRUNNEL_OPAQUE) && !defined(TRUNNEL_OPAQUE_TRN_EXTENSION)
+struct trn_extension_st {
+ uint8_t num;
+ TRUNNEL_DYNARRAY_HEAD(, struct trn_extension_field_st *) fields;
+ uint8_t trunnel_error_code_;
+};
+#endif
+typedef struct trn_extension_st trn_extension_t;
+/** Return a newly allocated trn_extension_field with all elements set
+ * to zero.
+ */
+trn_extension_field_t *trn_extension_field_new(void);
+/** Release all storage held by the trn_extension_field in 'victim'.
+ * (Do nothing if 'victim' is NULL.)
+ */
+void trn_extension_field_free(trn_extension_field_t *victim);
+/** Try to parse a trn_extension_field 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_extension_field_t. On failure, return -2 if the input
+ * appears truncated, and -1 if the input is otherwise invalid.
+ */
+ssize_t trn_extension_field_parse(trn_extension_field_t **output, const uint8_t *input, const size_t len_in);
+/** Return the number of bytes we expect to need to encode the
+ * trn_extension_field 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_extension_field_encoded_len(const trn_extension_field_t *obj);
+/** Try to encode the trn_extension_field 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_extension_field_encode(uint8_t *output, size_t avail, const trn_extension_field_t *input);
+/** Check whether the internal state of the trn_extension_field in
+ * 'obj' is consistent. Return NULL if it is, and a short message if
+ * it is not.
+ */
+const char *trn_extension_field_check(const trn_extension_field_t *obj);
+/** Clear any errors that were set on the object 'obj' by its setter
+ * functions. Return true iff errors were cleared.
+ */
+int trn_extension_field_clear_errors(trn_extension_field_t *obj);
+/** Return the value of the field_type field of the
+ * trn_extension_field_t in 'inp'
+ */
+uint8_t trn_extension_field_get_field_type(const trn_extension_field_t *inp);
+/** Set the value of the field_type field of the trn_extension_field_t
+ * in 'inp' to 'val'. Return 0 on success; return -1 and set the error
+ * code on 'inp' on failure.
+ */
+int trn_extension_field_set_field_type(trn_extension_field_t *inp, uint8_t val);
+/** Return the value of the field_len field of the
+ * trn_extension_field_t in 'inp'
+ */
+uint8_t trn_extension_field_get_field_len(const trn_extension_field_t *inp);
+/** Set the value of the field_len field of the trn_extension_field_t
+ * in 'inp' to 'val'. Return 0 on success; return -1 and set the error
+ * code on 'inp' on failure.
+ */
+int trn_extension_field_set_field_len(trn_extension_field_t *inp, uint8_t val);
+/** Return the length of the dynamic array holding the field field of
+ * the trn_extension_field_t in 'inp'.
+ */
+size_t trn_extension_field_getlen_field(const trn_extension_field_t *inp);
+/** Return the element at position 'idx' of the dynamic array field
+ * field of the trn_extension_field_t in 'inp'.
+ */
+uint8_t trn_extension_field_get_field(trn_extension_field_t *inp, size_t idx);
+/** As trn_extension_field_get_field, but take and return a const
+ * pointer
+ */
+uint8_t trn_extension_field_getconst_field(const trn_extension_field_t *inp, size_t idx);
+/** Change the element at position 'idx' of the dynamic array field
+ * field of the trn_extension_field_t in 'inp', so that it will hold
+ * the value 'elt'.
+ */
+int trn_extension_field_set_field(trn_extension_field_t *inp, size_t idx, uint8_t elt);
+/** Append a new element 'elt' to the dynamic array field field of the
+ * trn_extension_field_t in 'inp'.
+ */
+int trn_extension_field_add_field(trn_extension_field_t *inp, uint8_t elt);
+/** Return a pointer to the variable-length array field field of
+ * 'inp'.
+ */
+uint8_t * trn_extension_field_getarray_field(trn_extension_field_t *inp);
+/** As trn_extension_field_get_field, but take and return a const
+ * pointer
+ */
+const uint8_t * trn_extension_field_getconstarray_field(const trn_extension_field_t *inp);
+/** Change the length of the variable-length array field field 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_extension_field_setlen_field(trn_extension_field_t *inp, size_t newlen);
+/** Return a newly allocated trn_extension with all elements set to
+ * zero.
+ */
+trn_extension_t *trn_extension_new(void);
+/** Release all storage held by the trn_extension in 'victim'. (Do
+ * nothing if 'victim' is NULL.)
+ */
+void trn_extension_free(trn_extension_t *victim);
+/** Try to parse a trn_extension 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_extension_t. On failure, return -2 if the input appears
+ * truncated, and -1 if the input is otherwise invalid.
+ */
+ssize_t trn_extension_parse(trn_extension_t **output, const uint8_t *input, const size_t len_in);
+/** Return the number of bytes we expect to need to encode the
+ * trn_extension 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_extension_encoded_len(const trn_extension_t *obj);
+/** Try to encode the trn_extension 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_extension_encode(uint8_t *output, size_t avail, const trn_extension_t *input);
+/** Check whether the internal state of the trn_extension in 'obj' is
+ * consistent. Return NULL if it is, and a short message if it is not.
+ */
+const char *trn_extension_check(const trn_extension_t *obj);
+/** Clear any errors that were set on the object 'obj' by its setter
+ * functions. Return true iff errors were cleared.
+ */
+int trn_extension_clear_errors(trn_extension_t *obj);
+/** Return the value of the num field of the trn_extension_t in 'inp'
+ */
+uint8_t trn_extension_get_num(const trn_extension_t *inp);
+/** Set the value of the num field of the trn_extension_t in 'inp' to
+ * 'val'. Return 0 on success; return -1 and set the error code on
+ * 'inp' on failure.
+ */
+int trn_extension_set_num(trn_extension_t *inp, uint8_t val);
+/** Return the length of the dynamic array holding the fields field of
+ * the trn_extension_t in 'inp'.
+ */
+size_t trn_extension_getlen_fields(const trn_extension_t *inp);
+/** Return the element at position 'idx' of the dynamic array field
+ * fields of the trn_extension_t in 'inp'.
+ */
+struct trn_extension_field_st * trn_extension_get_fields(trn_extension_t *inp, size_t idx);
+/** As trn_extension_get_fields, but take and return a const pointer
+ */
+ const struct trn_extension_field_st * trn_extension_getconst_fields(const trn_extension_t *inp, size_t idx);
+/** Change the element at position 'idx' of the dynamic array field
+ * fields of the trn_extension_t in 'inp', so that it will hold the
+ * value 'elt'. Free the previous value, if any.
+ */
+int trn_extension_set_fields(trn_extension_t *inp, size_t idx, struct trn_extension_field_st * elt);
+/** As trn_extension_set_fields, but does not free the previous value.
+ */
+int trn_extension_set0_fields(trn_extension_t *inp, size_t idx, struct trn_extension_field_st * elt);
+/** Append a new element 'elt' to the dynamic array field fields of
+ * the trn_extension_t in 'inp'.
+ */
+int trn_extension_add_fields(trn_extension_t *inp, struct trn_extension_field_st * elt);
+/** Return a pointer to the variable-length array field fields of
+ * 'inp'.
+ */
+struct trn_extension_field_st * * trn_extension_getarray_fields(trn_extension_t *inp);
+/** As trn_extension_get_fields, but take and return a const pointer
+ */
+const struct trn_extension_field_st * const * trn_extension_getconstarray_fields(const trn_extension_t *inp);
+/** Change the length of the variable-length array field fields of
+ * 'inp' to 'newlen'.Fill extra elements with NULL; free removed
+ * elements. Return 0 on success; return -1 and set the error code on
+ * 'inp' on failure.
+ */
+int trn_extension_setlen_fields(trn_extension_t *inp, size_t newlen);
+
+
+#endif
diff --git a/src/trunnel/extension.trunnel b/src/trunnel/extension.trunnel
new file mode 100644
index 0000000000..177eba0596
--- /dev/null
+++ b/src/trunnel/extension.trunnel
@@ -0,0 +1,14 @@
+
+/* The cell extension ABI that is also used within other type of structures
+ * such as the ntorv3 data payload. */
+
+struct trn_extension_field {
+ u8 field_type;
+ u8 field_len;
+ u8 field[field_len];
+};
+
+struct trn_extension {
+ u8 num;
+ struct trn_extension_field fields[num];
+};
diff --git a/src/trunnel/flow_control_cells.c b/src/trunnel/flow_control_cells.c
new file mode 100644
index 0000000000..df44756d6b
--- /dev/null
+++ b/src/trunnel/flow_control_cells.c
@@ -0,0 +1,382 @@
+/* flow_control_cells.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 "flow_control_cells.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 flowcontrolcells_deadcode_dummy__ = 0;
+#define OR_DEADCODE_DUMMY || flowcontrolcells_deadcode_dummy__
+#else
+#define OR_DEADCODE_DUMMY
+#endif
+
+#define CHECK_REMAINING(nbytes, label) \
+ do { \
+ if (remaining < (nbytes) OR_DEADCODE_DUMMY) { \
+ goto label; \
+ } \
+ } while (0)
+
+xoff_cell_t *
+xoff_cell_new(void)
+{
+ xoff_cell_t *val = trunnel_calloc(1, sizeof(xoff_cell_t));
+ if (NULL == val)
+ return NULL;
+ return val;
+}
+
+/** Release all storage held inside 'obj', but do not free 'obj'.
+ */
+static void
+xoff_cell_clear(xoff_cell_t *obj)
+{
+ (void) obj;
+}
+
+void
+xoff_cell_free(xoff_cell_t *obj)
+{
+ if (obj == NULL)
+ return;
+ xoff_cell_clear(obj);
+ trunnel_memwipe(obj, sizeof(xoff_cell_t));
+ trunnel_free_(obj);
+}
+
+uint8_t
+xoff_cell_get_version(const xoff_cell_t *inp)
+{
+ return inp->version;
+}
+int
+xoff_cell_set_version(xoff_cell_t *inp, uint8_t val)
+{
+ if (! ((val == 0))) {
+ TRUNNEL_SET_ERROR_CODE(inp);
+ return -1;
+ }
+ inp->version = val;
+ return 0;
+}
+const char *
+xoff_cell_check(const xoff_cell_t *obj)
+{
+ if (obj == NULL)
+ return "Object was NULL";
+ if (obj->trunnel_error_code_)
+ return "A set function failed on this object";
+ if (! (obj->version == 0))
+ return "Integer out of bounds";
+ return NULL;
+}
+
+ssize_t
+xoff_cell_encoded_len(const xoff_cell_t *obj)
+{
+ ssize_t result = 0;
+
+ if (NULL != xoff_cell_check(obj))
+ return -1;
+
+
+ /* Length of u8 version IN [0] */
+ result += 1;
+ return result;
+}
+int
+xoff_cell_clear_errors(xoff_cell_t *obj)
+{
+ int r = obj->trunnel_error_code_;
+ obj->trunnel_error_code_ = 0;
+ return r;
+}
+ssize_t
+xoff_cell_encode(uint8_t *output, const size_t avail, const xoff_cell_t *obj)
+{
+ ssize_t result = 0;
+ size_t written = 0;
+ uint8_t *ptr = output;
+ const char *msg;
+#ifdef TRUNNEL_CHECK_ENCODED_LEN
+ const ssize_t encoded_len = xoff_cell_encoded_len(obj);
+#endif
+
+ if (NULL != (msg = xoff_cell_check(obj)))
+ goto check_failed;
+
+#ifdef TRUNNEL_CHECK_ENCODED_LEN
+ trunnel_assert(encoded_len >= 0);
+#endif
+
+ /* Encode u8 version IN [0] */
+ trunnel_assert(written <= avail);
+ if (avail - written < 1)
+ goto truncated;
+ trunnel_set_uint8(ptr, (obj->version));
+ 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 xoff_cell_parse(), but do not allocate the output object.
+ */
+static ssize_t
+xoff_cell_parse_into(xoff_cell_t *obj, const uint8_t *input, const size_t len_in)
+{
+ const uint8_t *ptr = input;
+ size_t remaining = len_in;
+ ssize_t result = 0;
+ (void)result;
+
+ /* Parse u8 version IN [0] */
+ CHECK_REMAINING(1, truncated);
+ obj->version = (trunnel_get_uint8(ptr));
+ remaining -= 1; ptr += 1;
+ if (! (obj->version == 0))
+ goto fail;
+ trunnel_assert(ptr + remaining == input + len_in);
+ return len_in - remaining;
+
+ truncated:
+ return -2;
+ fail:
+ result = -1;
+ return result;
+}
+
+ssize_t
+xoff_cell_parse(xoff_cell_t **output, const uint8_t *input, const size_t len_in)
+{
+ ssize_t result;
+ *output = xoff_cell_new();
+ if (NULL == *output)
+ return -1;
+ result = xoff_cell_parse_into(*output, input, len_in);
+ if (result < 0) {
+ xoff_cell_free(*output);
+ *output = NULL;
+ }
+ return result;
+}
+xon_cell_t *
+xon_cell_new(void)
+{
+ xon_cell_t *val = trunnel_calloc(1, sizeof(xon_cell_t));
+ if (NULL == val)
+ return NULL;
+ return val;
+}
+
+/** Release all storage held inside 'obj', but do not free 'obj'.
+ */
+static void
+xon_cell_clear(xon_cell_t *obj)
+{
+ (void) obj;
+}
+
+void
+xon_cell_free(xon_cell_t *obj)
+{
+ if (obj == NULL)
+ return;
+ xon_cell_clear(obj);
+ trunnel_memwipe(obj, sizeof(xon_cell_t));
+ trunnel_free_(obj);
+}
+
+uint8_t
+xon_cell_get_version(const xon_cell_t *inp)
+{
+ return inp->version;
+}
+int
+xon_cell_set_version(xon_cell_t *inp, uint8_t val)
+{
+ if (! ((val == 0))) {
+ TRUNNEL_SET_ERROR_CODE(inp);
+ return -1;
+ }
+ inp->version = val;
+ return 0;
+}
+uint32_t
+xon_cell_get_kbps_ewma(const xon_cell_t *inp)
+{
+ return inp->kbps_ewma;
+}
+int
+xon_cell_set_kbps_ewma(xon_cell_t *inp, uint32_t val)
+{
+ inp->kbps_ewma = val;
+ return 0;
+}
+const char *
+xon_cell_check(const xon_cell_t *obj)
+{
+ if (obj == NULL)
+ return "Object was NULL";
+ if (obj->trunnel_error_code_)
+ return "A set function failed on this object";
+ if (! (obj->version == 0))
+ return "Integer out of bounds";
+ return NULL;
+}
+
+ssize_t
+xon_cell_encoded_len(const xon_cell_t *obj)
+{
+ ssize_t result = 0;
+
+ if (NULL != xon_cell_check(obj))
+ return -1;
+
+
+ /* Length of u8 version IN [0] */
+ result += 1;
+
+ /* Length of u32 kbps_ewma */
+ result += 4;
+ return result;
+}
+int
+xon_cell_clear_errors(xon_cell_t *obj)
+{
+ int r = obj->trunnel_error_code_;
+ obj->trunnel_error_code_ = 0;
+ return r;
+}
+ssize_t
+xon_cell_encode(uint8_t *output, const size_t avail, const xon_cell_t *obj)
+{
+ ssize_t result = 0;
+ size_t written = 0;
+ uint8_t *ptr = output;
+ const char *msg;
+#ifdef TRUNNEL_CHECK_ENCODED_LEN
+ const ssize_t encoded_len = xon_cell_encoded_len(obj);
+#endif
+
+ if (NULL != (msg = xon_cell_check(obj)))
+ goto check_failed;
+
+#ifdef TRUNNEL_CHECK_ENCODED_LEN
+ trunnel_assert(encoded_len >= 0);
+#endif
+
+ /* Encode u8 version IN [0] */
+ trunnel_assert(written <= avail);
+ if (avail - written < 1)
+ goto truncated;
+ trunnel_set_uint8(ptr, (obj->version));
+ written += 1; ptr += 1;
+
+ /* Encode u32 kbps_ewma */
+ trunnel_assert(written <= avail);
+ if (avail - written < 4)
+ goto truncated;
+ trunnel_set_uint32(ptr, trunnel_htonl(obj->kbps_ewma));
+ 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 xon_cell_parse(), but do not allocate the output object.
+ */
+static ssize_t
+xon_cell_parse_into(xon_cell_t *obj, const uint8_t *input, const size_t len_in)
+{
+ const uint8_t *ptr = input;
+ size_t remaining = len_in;
+ ssize_t result = 0;
+ (void)result;
+
+ /* Parse u8 version IN [0] */
+ CHECK_REMAINING(1, truncated);
+ obj->version = (trunnel_get_uint8(ptr));
+ remaining -= 1; ptr += 1;
+ if (! (obj->version == 0))
+ goto fail;
+
+ /* Parse u32 kbps_ewma */
+ CHECK_REMAINING(4, truncated);
+ obj->kbps_ewma = trunnel_ntohl(trunnel_get_uint32(ptr));
+ remaining -= 4; ptr += 4;
+ trunnel_assert(ptr + remaining == input + len_in);
+ return len_in - remaining;
+
+ truncated:
+ return -2;
+ fail:
+ result = -1;
+ return result;
+}
+
+ssize_t
+xon_cell_parse(xon_cell_t **output, const uint8_t *input, const size_t len_in)
+{
+ ssize_t result;
+ *output = xon_cell_new();
+ if (NULL == *output)
+ return -1;
+ result = xon_cell_parse_into(*output, input, len_in);
+ if (result < 0) {
+ xon_cell_free(*output);
+ *output = NULL;
+ }
+ return result;
+}
diff --git a/src/trunnel/flow_control_cells.h b/src/trunnel/flow_control_cells.h
new file mode 100644
index 0000000000..b8108b9a24
--- /dev/null
+++ b/src/trunnel/flow_control_cells.h
@@ -0,0 +1,120 @@
+/* flow_control_cells.h -- generated by Trunnel v1.5.3.
+ * https://gitweb.torproject.org/trunnel.git
+ * You probably shouldn't edit this file.
+ */
+#ifndef TRUNNEL_FLOW_CONTROL_CELLS_H
+#define TRUNNEL_FLOW_CONTROL_CELLS_H
+
+#include <stdint.h>
+#include "trunnel.h"
+
+#if !defined(TRUNNEL_OPAQUE) && !defined(TRUNNEL_OPAQUE_XOFF_CELL)
+struct xoff_cell_st {
+ uint8_t version;
+ uint8_t trunnel_error_code_;
+};
+#endif
+typedef struct xoff_cell_st xoff_cell_t;
+#if !defined(TRUNNEL_OPAQUE) && !defined(TRUNNEL_OPAQUE_XON_CELL)
+struct xon_cell_st {
+ uint8_t version;
+ uint32_t kbps_ewma;
+ uint8_t trunnel_error_code_;
+};
+#endif
+typedef struct xon_cell_st xon_cell_t;
+/** Return a newly allocated xoff_cell with all elements set to zero.
+ */
+xoff_cell_t *xoff_cell_new(void);
+/** Release all storage held by the xoff_cell in 'victim'. (Do nothing
+ * if 'victim' is NULL.)
+ */
+void xoff_cell_free(xoff_cell_t *victim);
+/** Try to parse a xoff_cell from the buffer in 'input', using up to
+ * 'len_in' bytes from the input buffer. On success, return the number
+ * of bytes consumed and set *output to the newly allocated
+ * xoff_cell_t. On failure, return -2 if the input appears truncated,
+ * and -1 if the input is otherwise invalid.
+ */
+ssize_t xoff_cell_parse(xoff_cell_t **output, const uint8_t *input, const size_t len_in);
+/** Return the number of bytes we expect to need to encode the
+ * xoff_cell in 'obj'. On failure, return a negative value. Note that
+ * this value may be an overestimate, and can even be an underestimate
+ * for certain unencodeable objects.
+ */
+ssize_t xoff_cell_encoded_len(const xoff_cell_t *obj);
+/** Try to encode the xoff_cell from 'input' into the buffer at
+ * 'output', using up to 'avail' bytes of the output buffer. On
+ * success, return the number of bytes used. On failure, return -2 if
+ * the buffer was not long enough, and -1 if the input was invalid.
+ */
+ssize_t xoff_cell_encode(uint8_t *output, size_t avail, const xoff_cell_t *input);
+/** Check whether the internal state of the xoff_cell in 'obj' is
+ * consistent. Return NULL if it is, and a short message if it is not.
+ */
+const char *xoff_cell_check(const xoff_cell_t *obj);
+/** Clear any errors that were set on the object 'obj' by its setter
+ * functions. Return true iff errors were cleared.
+ */
+int xoff_cell_clear_errors(xoff_cell_t *obj);
+/** Return the value of the version field of the xoff_cell_t in 'inp'
+ */
+uint8_t xoff_cell_get_version(const xoff_cell_t *inp);
+/** Set the value of the version field of the xoff_cell_t in 'inp' to
+ * 'val'. Return 0 on success; return -1 and set the error code on
+ * 'inp' on failure.
+ */
+int xoff_cell_set_version(xoff_cell_t *inp, uint8_t val);
+/** Return a newly allocated xon_cell with all elements set to zero.
+ */
+xon_cell_t *xon_cell_new(void);
+/** Release all storage held by the xon_cell in 'victim'. (Do nothing
+ * if 'victim' is NULL.)
+ */
+void xon_cell_free(xon_cell_t *victim);
+/** Try to parse a xon_cell from the buffer in 'input', using up to
+ * 'len_in' bytes from the input buffer. On success, return the number
+ * of bytes consumed and set *output to the newly allocated
+ * xon_cell_t. On failure, return -2 if the input appears truncated,
+ * and -1 if the input is otherwise invalid.
+ */
+ssize_t xon_cell_parse(xon_cell_t **output, const uint8_t *input, const size_t len_in);
+/** Return the number of bytes we expect to need to encode the
+ * xon_cell in 'obj'. On failure, return a negative value. Note that
+ * this value may be an overestimate, and can even be an underestimate
+ * for certain unencodeable objects.
+ */
+ssize_t xon_cell_encoded_len(const xon_cell_t *obj);
+/** Try to encode the xon_cell from 'input' into the buffer at
+ * 'output', using up to 'avail' bytes of the output buffer. On
+ * success, return the number of bytes used. On failure, return -2 if
+ * the buffer was not long enough, and -1 if the input was invalid.
+ */
+ssize_t xon_cell_encode(uint8_t *output, size_t avail, const xon_cell_t *input);
+/** Check whether the internal state of the xon_cell in 'obj' is
+ * consistent. Return NULL if it is, and a short message if it is not.
+ */
+const char *xon_cell_check(const xon_cell_t *obj);
+/** Clear any errors that were set on the object 'obj' by its setter
+ * functions. Return true iff errors were cleared.
+ */
+int xon_cell_clear_errors(xon_cell_t *obj);
+/** Return the value of the version field of the xon_cell_t in 'inp'
+ */
+uint8_t xon_cell_get_version(const xon_cell_t *inp);
+/** Set the value of the version field of the xon_cell_t in 'inp' to
+ * 'val'. Return 0 on success; return -1 and set the error code on
+ * 'inp' on failure.
+ */
+int xon_cell_set_version(xon_cell_t *inp, uint8_t val);
+/** Return the value of the kbps_ewma field of the xon_cell_t in 'inp'
+ */
+uint32_t xon_cell_get_kbps_ewma(const xon_cell_t *inp);
+/** Set the value of the kbps_ewma field of the xon_cell_t in 'inp' to
+ * 'val'. Return 0 on success; return -1 and set the error code on
+ * 'inp' on failure.
+ */
+int xon_cell_set_kbps_ewma(xon_cell_t *inp, uint32_t val);
+
+
+#endif
diff --git a/src/trunnel/flow_control_cells.trunnel b/src/trunnel/flow_control_cells.trunnel
new file mode 100644
index 0000000000..9d07b568a9
--- /dev/null
+++ b/src/trunnel/flow_control_cells.trunnel
@@ -0,0 +1,20 @@
+/* This file contains the xon and xoff cell definitions, for flow control. */
+
+/* xoff cell definition. Tells the other endpoint to stop sending, because
+ * we have too much data queued for this stream. */
+struct xoff_cell {
+ /* Version field. */
+ u8 version IN [0x00];
+}
+
+/* xon cell declaration. Tells the other endpoint to resume sending and/or
+ * update its sending rate on this stream based on advisory information. */
+struct xon_cell {
+ /* Version field. */
+ u8 version IN [0x00];
+
+ /* Advisory field: The ewma rate of socket drain we have seen so far
+ * on this stream, in kilobytes/sec (1000 bytes/sec). May be zero,
+ * which means no rate advice. */
+ u32 kbps_ewma;
+}
diff --git a/src/trunnel/hs/cell_common.h b/src/trunnel/hs/cell_common.h
deleted file mode 100644
index beb65e015f..0000000000
--- a/src/trunnel/hs/cell_common.h
+++ /dev/null
@@ -1,203 +0,0 @@
-/* cell_common.h -- generated by Trunnel v1.5.3.
- * https://gitweb.torproject.org/trunnel.git
- * You probably shouldn't edit this file.
- */
-#ifndef TRUNNEL_CELL_COMMON_H
-#define TRUNNEL_CELL_COMMON_H
-
-#include <stdint.h>
-#include "trunnel.h"
-
-#if !defined(TRUNNEL_OPAQUE) && !defined(TRUNNEL_OPAQUE_TRN_CELL_EXTENSION_FIELD)
-struct trn_cell_extension_field_st {
- uint8_t field_type;
- uint8_t field_len;
- TRUNNEL_DYNARRAY_HEAD(, uint8_t) field;
- uint8_t trunnel_error_code_;
-};
-#endif
-typedef struct trn_cell_extension_field_st trn_cell_extension_field_t;
-#if !defined(TRUNNEL_OPAQUE) && !defined(TRUNNEL_OPAQUE_TRN_CELL_EXTENSION)
-struct trn_cell_extension_st {
- uint8_t num;
- TRUNNEL_DYNARRAY_HEAD(, struct trn_cell_extension_field_st *) fields;
- uint8_t trunnel_error_code_;
-};
-#endif
-typedef struct trn_cell_extension_st trn_cell_extension_t;
-/** Return a newly allocated trn_cell_extension_field with all
- * elements set to zero.
- */
-trn_cell_extension_field_t *trn_cell_extension_field_new(void);
-/** Release all storage held by the trn_cell_extension_field in
- * 'victim'. (Do nothing if 'victim' is NULL.)
- */
-void trn_cell_extension_field_free(trn_cell_extension_field_t *victim);
-/** Try to parse a trn_cell_extension_field 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_field_t. On failure, return -2
- * if the input appears truncated, and -1 if the input is otherwise
- * invalid.
- */
-ssize_t trn_cell_extension_field_parse(trn_cell_extension_field_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_field 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_field_encoded_len(const trn_cell_extension_field_t *obj);
-/** Try to encode the trn_cell_extension_field 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_field_encode(uint8_t *output, size_t avail, const trn_cell_extension_field_t *input);
-/** Check whether the internal state of the trn_cell_extension_field
- * in 'obj' is consistent. Return NULL if it is, and a short message
- * if it is not.
- */
-const char *trn_cell_extension_field_check(const trn_cell_extension_field_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_field_clear_errors(trn_cell_extension_field_t *obj);
-/** Return the value of the field_type field of the
- * trn_cell_extension_field_t in 'inp'
- */
-uint8_t trn_cell_extension_field_get_field_type(const trn_cell_extension_field_t *inp);
-/** Set the value of the field_type field of the
- * trn_cell_extension_field_t in 'inp' to 'val'. Return 0 on success;
- * return -1 and set the error code on 'inp' on failure.
- */
-int trn_cell_extension_field_set_field_type(trn_cell_extension_field_t *inp, uint8_t val);
-/** Return the value of the field_len field of the
- * trn_cell_extension_field_t in 'inp'
- */
-uint8_t trn_cell_extension_field_get_field_len(const trn_cell_extension_field_t *inp);
-/** Set the value of the field_len field of the
- * trn_cell_extension_field_t in 'inp' to 'val'. Return 0 on success;
- * return -1 and set the error code on 'inp' on failure.
- */
-int trn_cell_extension_field_set_field_len(trn_cell_extension_field_t *inp, uint8_t val);
-/** Return the length of the dynamic array holding the field field of
- * the trn_cell_extension_field_t in 'inp'.
- */
-size_t trn_cell_extension_field_getlen_field(const trn_cell_extension_field_t *inp);
-/** Return the element at position 'idx' of the dynamic array field
- * field of the trn_cell_extension_field_t in 'inp'.
- */
-uint8_t trn_cell_extension_field_get_field(trn_cell_extension_field_t *inp, size_t idx);
-/** As trn_cell_extension_field_get_field, but take and return a const
- * pointer
- */
-uint8_t trn_cell_extension_field_getconst_field(const trn_cell_extension_field_t *inp, size_t idx);
-/** Change the element at position 'idx' of the dynamic array field
- * field of the trn_cell_extension_field_t in 'inp', so that it will
- * hold the value 'elt'.
- */
-int trn_cell_extension_field_set_field(trn_cell_extension_field_t *inp, size_t idx, uint8_t elt);
-/** Append a new element 'elt' to the dynamic array field field of the
- * trn_cell_extension_field_t in 'inp'.
- */
-int trn_cell_extension_field_add_field(trn_cell_extension_field_t *inp, uint8_t elt);
-/** Return a pointer to the variable-length array field field of
- * 'inp'.
- */
-uint8_t * trn_cell_extension_field_getarray_field(trn_cell_extension_field_t *inp);
-/** As trn_cell_extension_field_get_field, but take and return a const
- * pointer
- */
-const uint8_t * trn_cell_extension_field_getconstarray_field(const trn_cell_extension_field_t *inp);
-/** Change the length of the variable-length array field field 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_extension_field_setlen_field(trn_cell_extension_field_t *inp, size_t newlen);
-/** Return a newly allocated trn_cell_extension with all elements set
- * to zero.
- */
-trn_cell_extension_t *trn_cell_extension_new(void);
-/** Release all storage held by the trn_cell_extension in 'victim'.
- * (Do nothing if 'victim' is NULL.)
- */
-void trn_cell_extension_free(trn_cell_extension_t *victim);
-/** Try to parse a trn_cell_extension 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_t. On failure, return -2 if the input
- * appears truncated, and -1 if the input is otherwise invalid.
- */
-ssize_t trn_cell_extension_parse(trn_cell_extension_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 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_encoded_len(const trn_cell_extension_t *obj);
-/** Try to encode the trn_cell_extension 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_encode(uint8_t *output, size_t avail, const trn_cell_extension_t *input);
-/** Check whether the internal state of the trn_cell_extension in
- * 'obj' is consistent. Return NULL if it is, and a short message if
- * it is not.
- */
-const char *trn_cell_extension_check(const trn_cell_extension_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_clear_errors(trn_cell_extension_t *obj);
-/** Return the value of the num field of the trn_cell_extension_t in
- * 'inp'
- */
-uint8_t trn_cell_extension_get_num(const trn_cell_extension_t *inp);
-/** Set the value of the num field of the trn_cell_extension_t in
- * 'inp' to 'val'. Return 0 on success; return -1 and set the error
- * code on 'inp' on failure.
- */
-int trn_cell_extension_set_num(trn_cell_extension_t *inp, uint8_t val);
-/** Return the length of the dynamic array holding the fields field of
- * the trn_cell_extension_t in 'inp'.
- */
-size_t trn_cell_extension_getlen_fields(const trn_cell_extension_t *inp);
-/** Return the element at position 'idx' of the dynamic array field
- * fields of the trn_cell_extension_t in 'inp'.
- */
-struct trn_cell_extension_field_st * trn_cell_extension_get_fields(trn_cell_extension_t *inp, size_t idx);
-/** As trn_cell_extension_get_fields, but take and return a const
- * pointer
- */
- const struct trn_cell_extension_field_st * trn_cell_extension_getconst_fields(const trn_cell_extension_t *inp, size_t idx);
-/** Change the element at position 'idx' of the dynamic array field
- * fields of the trn_cell_extension_t in 'inp', so that it will hold
- * the value 'elt'. Free the previous value, if any.
- */
-int trn_cell_extension_set_fields(trn_cell_extension_t *inp, size_t idx, struct trn_cell_extension_field_st * elt);
-/** As trn_cell_extension_set_fields, but does not free the previous
- * value.
- */
-int trn_cell_extension_set0_fields(trn_cell_extension_t *inp, size_t idx, struct trn_cell_extension_field_st * elt);
-/** Append a new element 'elt' to the dynamic array field fields of
- * the trn_cell_extension_t in 'inp'.
- */
-int trn_cell_extension_add_fields(trn_cell_extension_t *inp, struct trn_cell_extension_field_st * elt);
-/** Return a pointer to the variable-length array field fields of
- * 'inp'.
- */
-struct trn_cell_extension_field_st * * trn_cell_extension_getarray_fields(trn_cell_extension_t *inp);
-/** As trn_cell_extension_get_fields, but take and return a const
- * pointer
- */
-const struct trn_cell_extension_field_st * const * trn_cell_extension_getconstarray_fields(const trn_cell_extension_t *inp);
-/** Change the length of the variable-length array field fields of
- * 'inp' to 'newlen'.Fill extra elements with NULL; free removed
- * elements. Return 0 on success; return -1 and set the error code on
- * 'inp' on failure.
- */
-int trn_cell_extension_setlen_fields(trn_cell_extension_t *inp, size_t newlen);
-
-
-#endif
diff --git a/src/trunnel/hs/cell_common.trunnel b/src/trunnel/hs/cell_common.trunnel
deleted file mode 100644
index 7e99cbfa66..0000000000
--- a/src/trunnel/hs/cell_common.trunnel
+++ /dev/null
@@ -1,12 +0,0 @@
-/* This file contains common data structure that cells use. */
-
-struct trn_cell_extension_field {
- u8 field_type;
- u8 field_len;
- u8 field[field_len];
-};
-
-struct trn_cell_extension {
- u8 num;
- struct trn_cell_extension_field fields[num];
-};
diff --git a/src/trunnel/hs/cell_establish_intro.c b/src/trunnel/hs/cell_establish_intro.c
index f31404c55f..0f561b121b 100644
--- a/src/trunnel/hs/cell_establish_intro.c
+++ b/src/trunnel/hs/cell_establish_intro.c
@@ -28,14 +28,14 @@ int cellestablishintro_deadcode_dummy__ = 0;
} \
} while (0)
-typedef struct trn_cell_extension_st trn_cell_extension_t;
-trn_cell_extension_t *trn_cell_extension_new(void);
-void trn_cell_extension_free(trn_cell_extension_t *victim);
-ssize_t trn_cell_extension_parse(trn_cell_extension_t **output, const uint8_t *input, const size_t len_in);
-ssize_t trn_cell_extension_encoded_len(const trn_cell_extension_t *obj);
-ssize_t trn_cell_extension_encode(uint8_t *output, size_t avail, const trn_cell_extension_t *input);
-const char *trn_cell_extension_check(const trn_cell_extension_t *obj);
-int trn_cell_extension_clear_errors(trn_cell_extension_t *obj);
+typedef struct trn_extension_st trn_extension_t;
+trn_extension_t *trn_extension_new(void);
+void trn_extension_free(trn_extension_t *victim);
+ssize_t trn_extension_parse(trn_extension_t **output, const uint8_t *input, const size_t len_in);
+ssize_t trn_extension_encoded_len(const trn_extension_t *obj);
+ssize_t trn_extension_encode(uint8_t *output, size_t avail, const trn_extension_t *input);
+const char *trn_extension_check(const trn_extension_t *obj);
+int trn_extension_clear_errors(trn_extension_t *obj);
trn_cell_extension_dos_param_t *
trn_cell_extension_dos_param_new(void)
{
@@ -232,7 +232,7 @@ trn_cell_establish_intro_clear(trn_cell_establish_intro_t *obj)
(void) obj;
TRUNNEL_DYNARRAY_WIPE(&obj->auth_key);
TRUNNEL_DYNARRAY_CLEAR(&obj->auth_key);
- trn_cell_extension_free(obj->extensions);
+ trn_extension_free(obj->extensions);
obj->extensions = NULL;
TRUNNEL_DYNARRAY_WIPE(&obj->sig);
TRUNNEL_DYNARRAY_CLEAR(&obj->sig);
@@ -346,25 +346,25 @@ trn_cell_establish_intro_setlen_auth_key(trn_cell_establish_intro_t *inp, size_t
TRUNNEL_SET_ERROR_CODE(inp);
return -1;
}
-struct trn_cell_extension_st *
+struct trn_extension_st *
trn_cell_establish_intro_get_extensions(trn_cell_establish_intro_t *inp)
{
return inp->extensions;
}
-const struct trn_cell_extension_st *
+const struct trn_extension_st *
trn_cell_establish_intro_getconst_extensions(const trn_cell_establish_intro_t *inp)
{
return trn_cell_establish_intro_get_extensions((trn_cell_establish_intro_t*) inp);
}
int
-trn_cell_establish_intro_set_extensions(trn_cell_establish_intro_t *inp, struct trn_cell_extension_st *val)
+trn_cell_establish_intro_set_extensions(trn_cell_establish_intro_t *inp, struct trn_extension_st *val)
{
if (inp->extensions && inp->extensions != val)
- trn_cell_extension_free(inp->extensions);
+ trn_extension_free(inp->extensions);
return trn_cell_establish_intro_set0_extensions(inp, val);
}
int
-trn_cell_establish_intro_set0_extensions(trn_cell_establish_intro_t *inp, struct trn_cell_extension_st *val)
+trn_cell_establish_intro_set0_extensions(trn_cell_establish_intro_t *inp, struct trn_extension_st *val)
{
inp->extensions = val;
return 0;
@@ -506,7 +506,7 @@ trn_cell_establish_intro_check(const trn_cell_establish_intro_t *obj)
return "Length mismatch for auth_key";
{
const char *msg;
- if (NULL != (msg = trn_cell_extension_check(obj->extensions)))
+ if (NULL != (msg = trn_extension_check(obj->extensions)))
return msg;
}
if (TRUNNEL_DYNARRAY_LEN(&obj->sig) != obj->sig_len)
@@ -532,8 +532,8 @@ trn_cell_establish_intro_encoded_len(const trn_cell_establish_intro_t *obj)
/* Length of u8 auth_key[auth_key_len] */
result += TRUNNEL_DYNARRAY_LEN(&obj->auth_key);
- /* Length of struct trn_cell_extension extensions */
- result += trn_cell_extension_encoded_len(obj->extensions);
+ /* Length of struct trn_extension extensions */
+ result += trn_extension_encoded_len(obj->extensions);
/* Length of u8 handshake_mac[TRUNNEL_SHA3_256_LEN] */
result += TRUNNEL_SHA3_256_LEN;
@@ -596,9 +596,9 @@ trn_cell_establish_intro_encode(uint8_t *output, const size_t avail, const trn_c
written += elt_len; ptr += elt_len;
}
- /* Encode struct trn_cell_extension extensions */
+ /* Encode struct trn_extension extensions */
trunnel_assert(written <= avail);
- result = trn_cell_extension_encode(ptr, avail - written, obj->extensions);
+ result = trn_extension_encode(ptr, avail - written, obj->extensions);
if (result < 0)
goto fail; /* XXXXXXX !*/
written += result; ptr += result;
@@ -685,8 +685,8 @@ trn_cell_establish_intro_parse_into(trn_cell_establish_intro_t *obj, const uint8
memcpy(obj->auth_key.elts_, ptr, obj->auth_key_len);
ptr += obj->auth_key_len; remaining -= obj->auth_key_len;
- /* Parse struct trn_cell_extension extensions */
- result = trn_cell_extension_parse(&obj->extensions, ptr, remaining);
+ /* Parse struct trn_extension extensions */
+ result = trn_extension_parse(&obj->extensions, ptr, remaining);
if (result < 0)
goto relay_fail;
trunnel_assert((size_t)result <= remaining);
@@ -1045,7 +1045,7 @@ static void
trn_cell_intro_established_clear(trn_cell_intro_established_t *obj)
{
(void) obj;
- trn_cell_extension_free(obj->extensions);
+ trn_extension_free(obj->extensions);
obj->extensions = NULL;
}
@@ -1059,25 +1059,25 @@ trn_cell_intro_established_free(trn_cell_intro_established_t *obj)
trunnel_free_(obj);
}
-struct trn_cell_extension_st *
+struct trn_extension_st *
trn_cell_intro_established_get_extensions(trn_cell_intro_established_t *inp)
{
return inp->extensions;
}
-const struct trn_cell_extension_st *
+const struct trn_extension_st *
trn_cell_intro_established_getconst_extensions(const trn_cell_intro_established_t *inp)
{
return trn_cell_intro_established_get_extensions((trn_cell_intro_established_t*) inp);
}
int
-trn_cell_intro_established_set_extensions(trn_cell_intro_established_t *inp, struct trn_cell_extension_st *val)
+trn_cell_intro_established_set_extensions(trn_cell_intro_established_t *inp, struct trn_extension_st *val)
{
if (inp->extensions && inp->extensions != val)
- trn_cell_extension_free(inp->extensions);
+ trn_extension_free(inp->extensions);
return trn_cell_intro_established_set0_extensions(inp, val);
}
int
-trn_cell_intro_established_set0_extensions(trn_cell_intro_established_t *inp, struct trn_cell_extension_st *val)
+trn_cell_intro_established_set0_extensions(trn_cell_intro_established_t *inp, struct trn_extension_st *val)
{
inp->extensions = val;
return 0;
@@ -1091,7 +1091,7 @@ trn_cell_intro_established_check(const trn_cell_intro_established_t *obj)
return "A set function failed on this object";
{
const char *msg;
- if (NULL != (msg = trn_cell_extension_check(obj->extensions)))
+ if (NULL != (msg = trn_extension_check(obj->extensions)))
return msg;
}
return NULL;
@@ -1106,8 +1106,8 @@ trn_cell_intro_established_encoded_len(const trn_cell_intro_established_t *obj)
return -1;
- /* Length of struct trn_cell_extension extensions */
- result += trn_cell_extension_encoded_len(obj->extensions);
+ /* Length of struct trn_extension extensions */
+ result += trn_extension_encoded_len(obj->extensions);
return result;
}
int
@@ -1135,9 +1135,9 @@ trn_cell_intro_established_encode(uint8_t *output, const size_t avail, const trn
trunnel_assert(encoded_len >= 0);
#endif
- /* Encode struct trn_cell_extension extensions */
+ /* Encode struct trn_extension extensions */
trunnel_assert(written <= avail);
- result = trn_cell_extension_encode(ptr, avail - written, obj->extensions);
+ result = trn_extension_encode(ptr, avail - written, obj->extensions);
if (result < 0)
goto fail; /* XXXXXXX !*/
written += result; ptr += result;
@@ -1174,8 +1174,8 @@ trn_cell_intro_established_parse_into(trn_cell_intro_established_t *obj, const u
ssize_t result = 0;
(void)result;
- /* Parse struct trn_cell_extension extensions */
- result = trn_cell_extension_parse(&obj->extensions, ptr, remaining);
+ /* Parse struct trn_extension extensions */
+ result = trn_extension_parse(&obj->extensions, ptr, remaining);
if (result < 0)
goto relay_fail;
trunnel_assert((size_t)result <= remaining);
diff --git a/src/trunnel/hs/cell_establish_intro.h b/src/trunnel/hs/cell_establish_intro.h
index 1924d9cab6..8be1531ed1 100644
--- a/src/trunnel/hs/cell_establish_intro.h
+++ b/src/trunnel/hs/cell_establish_intro.h
@@ -8,7 +8,7 @@
#include <stdint.h>
#include "trunnel.h"
-struct trn_cell_extension_st;
+struct trn_extension_st;
#define TRUNNEL_SHA3_256_LEN 32
#define TRUNNEL_CELL_EXTENSION_TYPE_DOS 1
#define TRUNNEL_DOS_PARAM_TYPE_INTRO2_RATE_PER_SEC 1
@@ -27,7 +27,7 @@ struct trn_cell_establish_intro_st {
uint8_t auth_key_type;
uint16_t auth_key_len;
TRUNNEL_DYNARRAY_HEAD(, uint8_t) auth_key;
- struct trn_cell_extension_st *extensions;
+ struct trn_extension_st *extensions;
const uint8_t *end_mac_fields;
uint8_t handshake_mac[TRUNNEL_SHA3_256_LEN];
const uint8_t *end_sig_fields;
@@ -47,7 +47,7 @@ struct trn_cell_extension_dos_st {
typedef struct trn_cell_extension_dos_st trn_cell_extension_dos_t;
#if !defined(TRUNNEL_OPAQUE) && !defined(TRUNNEL_OPAQUE_TRN_CELL_INTRO_ESTABLISHED)
struct trn_cell_intro_established_st {
- struct trn_cell_extension_st *extensions;
+ struct trn_extension_st *extensions;
uint8_t trunnel_error_code_;
};
#endif
@@ -203,21 +203,21 @@ int trn_cell_establish_intro_setlen_auth_key(trn_cell_establish_intro_t *inp, si
/** Return the value of the extensions field of the
* trn_cell_establish_intro_t in 'inp'
*/
-struct trn_cell_extension_st * trn_cell_establish_intro_get_extensions(trn_cell_establish_intro_t *inp);
+struct trn_extension_st * trn_cell_establish_intro_get_extensions(trn_cell_establish_intro_t *inp);
/** As trn_cell_establish_intro_get_extensions, but take and return a
* const pointer
*/
-const struct trn_cell_extension_st * trn_cell_establish_intro_getconst_extensions(const trn_cell_establish_intro_t *inp);
+const struct trn_extension_st * trn_cell_establish_intro_getconst_extensions(const trn_cell_establish_intro_t *inp);
/** Set the value of the extensions field of the
* trn_cell_establish_intro_t in 'inp' to 'val'. Free the old value if
* any. Steals the referenceto 'val'.Return 0 on success; return -1
* and set the error code on 'inp' on failure.
*/
-int trn_cell_establish_intro_set_extensions(trn_cell_establish_intro_t *inp, struct trn_cell_extension_st *val);
+int trn_cell_establish_intro_set_extensions(trn_cell_establish_intro_t *inp, struct trn_extension_st *val);
/** As trn_cell_establish_intro_set_extensions, but does not free the
* previous value.
*/
-int trn_cell_establish_intro_set0_extensions(trn_cell_establish_intro_t *inp, struct trn_cell_extension_st *val);
+int trn_cell_establish_intro_set0_extensions(trn_cell_establish_intro_t *inp, struct trn_extension_st *val);
/** Return the position for end_mac_fields when we parsed this object
*/
const uint8_t * trn_cell_establish_intro_get_end_mac_fields(const trn_cell_establish_intro_t *inp);
@@ -415,21 +415,21 @@ int trn_cell_intro_established_clear_errors(trn_cell_intro_established_t *obj);
/** Return the value of the extensions field of the
* trn_cell_intro_established_t in 'inp'
*/
-struct trn_cell_extension_st * trn_cell_intro_established_get_extensions(trn_cell_intro_established_t *inp);
+struct trn_extension_st * trn_cell_intro_established_get_extensions(trn_cell_intro_established_t *inp);
/** As trn_cell_intro_established_get_extensions, but take and return
* a const pointer
*/
-const struct trn_cell_extension_st * trn_cell_intro_established_getconst_extensions(const trn_cell_intro_established_t *inp);
+const struct trn_extension_st * trn_cell_intro_established_getconst_extensions(const trn_cell_intro_established_t *inp);
/** Set the value of the extensions field of the
* trn_cell_intro_established_t in 'inp' to 'val'. Free the old value
* if any. Steals the referenceto 'val'.Return 0 on success; return -1
* and set the error code on 'inp' on failure.
*/
-int trn_cell_intro_established_set_extensions(trn_cell_intro_established_t *inp, struct trn_cell_extension_st *val);
+int trn_cell_intro_established_set_extensions(trn_cell_intro_established_t *inp, struct trn_extension_st *val);
/** As trn_cell_intro_established_set_extensions, but does not free
* the previous value.
*/
-int trn_cell_intro_established_set0_extensions(trn_cell_intro_established_t *inp, struct trn_cell_extension_st *val);
+int trn_cell_intro_established_set0_extensions(trn_cell_intro_established_t *inp, struct trn_extension_st *val);
#endif
diff --git a/src/trunnel/hs/cell_establish_intro.trunnel b/src/trunnel/hs/cell_establish_intro.trunnel
index e30938f6c2..b33f8c1c93 100644
--- a/src/trunnel/hs/cell_establish_intro.trunnel
+++ b/src/trunnel/hs/cell_establish_intro.trunnel
@@ -4,7 +4,7 @@
* specified in proposal 224 section 3.1.
*/
-extern struct trn_cell_extension;
+extern struct trn_extension;
const TRUNNEL_SHA3_256_LEN = 32;
@@ -19,7 +19,7 @@ struct trn_cell_establish_intro {
u8 auth_key[auth_key_len];
/* Extension(s). Reserved fields. */
- struct trn_cell_extension extensions;
+ struct trn_extension extensions;
@ptr end_mac_fields;
/* Handshake MAC. */
@@ -37,7 +37,7 @@ struct trn_cell_establish_intro {
* to version >= 3. */
struct trn_cell_intro_established {
/* Extension(s). Reserved fields. */
- struct trn_cell_extension extensions;
+ struct trn_extension extensions;
};
/*
diff --git a/src/trunnel/hs/cell_introduce1.c b/src/trunnel/hs/cell_introduce1.c
index 016c9fa8d6..a6873b4199 100644
--- a/src/trunnel/hs/cell_introduce1.c
+++ b/src/trunnel/hs/cell_introduce1.c
@@ -28,14 +28,14 @@ int cellintroduce_deadcode_dummy__ = 0;
} \
} while (0)
-typedef struct trn_cell_extension_st trn_cell_extension_t;
-trn_cell_extension_t *trn_cell_extension_new(void);
-void trn_cell_extension_free(trn_cell_extension_t *victim);
-ssize_t trn_cell_extension_parse(trn_cell_extension_t **output, const uint8_t *input, const size_t len_in);
-ssize_t trn_cell_extension_encoded_len(const trn_cell_extension_t *obj);
-ssize_t trn_cell_extension_encode(uint8_t *output, size_t avail, const trn_cell_extension_t *input);
-const char *trn_cell_extension_check(const trn_cell_extension_t *obj);
-int trn_cell_extension_clear_errors(trn_cell_extension_t *obj);
+typedef struct trn_extension_st trn_extension_t;
+trn_extension_t *trn_extension_new(void);
+void trn_extension_free(trn_extension_t *victim);
+ssize_t trn_extension_parse(trn_extension_t **output, const uint8_t *input, const size_t len_in);
+ssize_t trn_extension_encoded_len(const trn_extension_t *obj);
+ssize_t trn_extension_encode(uint8_t *output, size_t avail, const trn_extension_t *input);
+const char *trn_extension_check(const trn_extension_t *obj);
+int trn_extension_clear_errors(trn_extension_t *obj);
typedef struct link_specifier_st link_specifier_t;
link_specifier_t *link_specifier_new(void);
void link_specifier_free(link_specifier_t *victim);
@@ -62,7 +62,7 @@ trn_cell_introduce1_clear(trn_cell_introduce1_t *obj)
(void) obj;
TRUNNEL_DYNARRAY_WIPE(&obj->auth_key);
TRUNNEL_DYNARRAY_CLEAR(&obj->auth_key);
- trn_cell_extension_free(obj->extensions);
+ trn_extension_free(obj->extensions);
obj->extensions = NULL;
TRUNNEL_DYNARRAY_WIPE(&obj->encrypted);
TRUNNEL_DYNARRAY_CLEAR(&obj->encrypted);
@@ -207,25 +207,25 @@ trn_cell_introduce1_setlen_auth_key(trn_cell_introduce1_t *inp, size_t newlen)
TRUNNEL_SET_ERROR_CODE(inp);
return -1;
}
-struct trn_cell_extension_st *
+struct trn_extension_st *
trn_cell_introduce1_get_extensions(trn_cell_introduce1_t *inp)
{
return inp->extensions;
}
-const struct trn_cell_extension_st *
+const struct trn_extension_st *
trn_cell_introduce1_getconst_extensions(const trn_cell_introduce1_t *inp)
{
return trn_cell_introduce1_get_extensions((trn_cell_introduce1_t*) inp);
}
int
-trn_cell_introduce1_set_extensions(trn_cell_introduce1_t *inp, struct trn_cell_extension_st *val)
+trn_cell_introduce1_set_extensions(trn_cell_introduce1_t *inp, struct trn_extension_st *val)
{
if (inp->extensions && inp->extensions != val)
- trn_cell_extension_free(inp->extensions);
+ trn_extension_free(inp->extensions);
return trn_cell_introduce1_set0_extensions(inp, val);
}
int
-trn_cell_introduce1_set0_extensions(trn_cell_introduce1_t *inp, struct trn_cell_extension_st *val)
+trn_cell_introduce1_set0_extensions(trn_cell_introduce1_t *inp, struct trn_extension_st *val)
{
inp->extensions = val;
return 0;
@@ -302,7 +302,7 @@ trn_cell_introduce1_check(const trn_cell_introduce1_t *obj)
return "Length mismatch for auth_key";
{
const char *msg;
- if (NULL != (msg = trn_cell_extension_check(obj->extensions)))
+ if (NULL != (msg = trn_extension_check(obj->extensions)))
return msg;
}
return NULL;
@@ -329,8 +329,8 @@ trn_cell_introduce1_encoded_len(const trn_cell_introduce1_t *obj)
/* Length of u8 auth_key[auth_key_len] */
result += TRUNNEL_DYNARRAY_LEN(&obj->auth_key);
- /* Length of struct trn_cell_extension extensions */
- result += trn_cell_extension_encoded_len(obj->extensions);
+ /* Length of struct trn_extension extensions */
+ result += trn_extension_encoded_len(obj->extensions);
/* Length of u8 encrypted[] */
result += TRUNNEL_DYNARRAY_LEN(&obj->encrypted);
@@ -394,9 +394,9 @@ trn_cell_introduce1_encode(uint8_t *output, const size_t avail, const trn_cell_i
written += elt_len; ptr += elt_len;
}
- /* Encode struct trn_cell_extension extensions */
+ /* Encode struct trn_extension extensions */
trunnel_assert(written <= avail);
- result = trn_cell_extension_encode(ptr, avail - written, obj->extensions);
+ result = trn_extension_encode(ptr, avail - written, obj->extensions);
if (result < 0)
goto fail; /* XXXXXXX !*/
written += result; ptr += result;
@@ -472,8 +472,8 @@ trn_cell_introduce1_parse_into(trn_cell_introduce1_t *obj, const uint8_t *input,
memcpy(obj->auth_key.elts_, ptr, obj->auth_key_len);
ptr += obj->auth_key_len; remaining -= obj->auth_key_len;
- /* Parse struct trn_cell_extension extensions */
- result = trn_cell_extension_parse(&obj->extensions, ptr, remaining);
+ /* Parse struct trn_extension extensions */
+ result = trn_extension_parse(&obj->extensions, ptr, remaining);
if (result < 0)
goto relay_fail;
trunnel_assert((size_t)result <= remaining);
@@ -529,7 +529,7 @@ static void
trn_cell_introduce_ack_clear(trn_cell_introduce_ack_t *obj)
{
(void) obj;
- trn_cell_extension_free(obj->extensions);
+ trn_extension_free(obj->extensions);
obj->extensions = NULL;
}
@@ -554,25 +554,25 @@ trn_cell_introduce_ack_set_status(trn_cell_introduce_ack_t *inp, uint16_t val)
inp->status = val;
return 0;
}
-struct trn_cell_extension_st *
+struct trn_extension_st *
trn_cell_introduce_ack_get_extensions(trn_cell_introduce_ack_t *inp)
{
return inp->extensions;
}
-const struct trn_cell_extension_st *
+const struct trn_extension_st *
trn_cell_introduce_ack_getconst_extensions(const trn_cell_introduce_ack_t *inp)
{
return trn_cell_introduce_ack_get_extensions((trn_cell_introduce_ack_t*) inp);
}
int
-trn_cell_introduce_ack_set_extensions(trn_cell_introduce_ack_t *inp, struct trn_cell_extension_st *val)
+trn_cell_introduce_ack_set_extensions(trn_cell_introduce_ack_t *inp, struct trn_extension_st *val)
{
if (inp->extensions && inp->extensions != val)
- trn_cell_extension_free(inp->extensions);
+ trn_extension_free(inp->extensions);
return trn_cell_introduce_ack_set0_extensions(inp, val);
}
int
-trn_cell_introduce_ack_set0_extensions(trn_cell_introduce_ack_t *inp, struct trn_cell_extension_st *val)
+trn_cell_introduce_ack_set0_extensions(trn_cell_introduce_ack_t *inp, struct trn_extension_st *val)
{
inp->extensions = val;
return 0;
@@ -586,7 +586,7 @@ trn_cell_introduce_ack_check(const trn_cell_introduce_ack_t *obj)
return "A set function failed on this object";
{
const char *msg;
- if (NULL != (msg = trn_cell_extension_check(obj->extensions)))
+ if (NULL != (msg = trn_extension_check(obj->extensions)))
return msg;
}
return NULL;
@@ -604,8 +604,8 @@ trn_cell_introduce_ack_encoded_len(const trn_cell_introduce_ack_t *obj)
/* Length of u16 status */
result += 2;
- /* Length of struct trn_cell_extension extensions */
- result += trn_cell_extension_encoded_len(obj->extensions);
+ /* Length of struct trn_extension extensions */
+ result += trn_extension_encoded_len(obj->extensions);
return result;
}
int
@@ -640,9 +640,9 @@ trn_cell_introduce_ack_encode(uint8_t *output, const size_t avail, const trn_cel
trunnel_set_uint16(ptr, trunnel_htons(obj->status));
written += 2; ptr += 2;
- /* Encode struct trn_cell_extension extensions */
+ /* Encode struct trn_extension extensions */
trunnel_assert(written <= avail);
- result = trn_cell_extension_encode(ptr, avail - written, obj->extensions);
+ result = trn_extension_encode(ptr, avail - written, obj->extensions);
if (result < 0)
goto fail; /* XXXXXXX !*/
written += result; ptr += result;
@@ -687,8 +687,8 @@ trn_cell_introduce_ack_parse_into(trn_cell_introduce_ack_t *obj, const uint8_t *
obj->status = trunnel_ntohs(trunnel_get_uint16(ptr));
remaining -= 2; ptr += 2;
- /* Parse struct trn_cell_extension extensions */
- result = trn_cell_extension_parse(&obj->extensions, ptr, remaining);
+ /* Parse struct trn_extension extensions */
+ result = trn_extension_parse(&obj->extensions, ptr, remaining);
if (result < 0)
goto relay_fail;
trunnel_assert((size_t)result <= remaining);
@@ -733,7 +733,7 @@ static void
trn_cell_introduce_encrypted_clear(trn_cell_introduce_encrypted_t *obj)
{
(void) obj;
- trn_cell_extension_free(obj->extensions);
+ trn_extension_free(obj->extensions);
obj->extensions = NULL;
TRUNNEL_DYNARRAY_WIPE(&obj->onion_key);
TRUNNEL_DYNARRAY_CLEAR(&obj->onion_key);
@@ -796,25 +796,25 @@ trn_cell_introduce_encrypted_getconstarray_rend_cookie(const trn_cell_introduce_
{
return (const uint8_t *)trn_cell_introduce_encrypted_getarray_rend_cookie((trn_cell_introduce_encrypted_t*)inp);
}
-struct trn_cell_extension_st *
+struct trn_extension_st *
trn_cell_introduce_encrypted_get_extensions(trn_cell_introduce_encrypted_t *inp)
{
return inp->extensions;
}
-const struct trn_cell_extension_st *
+const struct trn_extension_st *
trn_cell_introduce_encrypted_getconst_extensions(const trn_cell_introduce_encrypted_t *inp)
{
return trn_cell_introduce_encrypted_get_extensions((trn_cell_introduce_encrypted_t*) inp);
}
int
-trn_cell_introduce_encrypted_set_extensions(trn_cell_introduce_encrypted_t *inp, struct trn_cell_extension_st *val)
+trn_cell_introduce_encrypted_set_extensions(trn_cell_introduce_encrypted_t *inp, struct trn_extension_st *val)
{
if (inp->extensions && inp->extensions != val)
- trn_cell_extension_free(inp->extensions);
+ trn_extension_free(inp->extensions);
return trn_cell_introduce_encrypted_set0_extensions(inp, val);
}
int
-trn_cell_introduce_encrypted_set0_extensions(trn_cell_introduce_encrypted_t *inp, struct trn_cell_extension_st *val)
+trn_cell_introduce_encrypted_set0_extensions(trn_cell_introduce_encrypted_t *inp, struct trn_extension_st *val)
{
inp->extensions = val;
return 0;
@@ -1066,7 +1066,7 @@ trn_cell_introduce_encrypted_check(const trn_cell_introduce_encrypted_t *obj)
return "A set function failed on this object";
{
const char *msg;
- if (NULL != (msg = trn_cell_extension_check(obj->extensions)))
+ if (NULL != (msg = trn_extension_check(obj->extensions)))
return msg;
}
if (! (obj->onion_key_type == TRUNNEL_HS_INTRO_ONION_KEY_TYPE_NTOR))
@@ -1099,8 +1099,8 @@ trn_cell_introduce_encrypted_encoded_len(const trn_cell_introduce_encrypted_t *o
/* Length of u8 rend_cookie[TRUNNEL_REND_COOKIE_LEN] */
result += TRUNNEL_REND_COOKIE_LEN;
- /* Length of struct trn_cell_extension extensions */
- result += trn_cell_extension_encoded_len(obj->extensions);
+ /* Length of struct trn_extension extensions */
+ result += trn_extension_encoded_len(obj->extensions);
/* Length of u8 onion_key_type IN [TRUNNEL_HS_INTRO_ONION_KEY_TYPE_NTOR] */
result += 1;
@@ -1159,9 +1159,9 @@ trn_cell_introduce_encrypted_encode(uint8_t *output, const size_t avail, const t
memcpy(ptr, obj->rend_cookie, TRUNNEL_REND_COOKIE_LEN);
written += TRUNNEL_REND_COOKIE_LEN; ptr += TRUNNEL_REND_COOKIE_LEN;
- /* Encode struct trn_cell_extension extensions */
+ /* Encode struct trn_extension extensions */
trunnel_assert(written <= avail);
- result = trn_cell_extension_encode(ptr, avail - written, obj->extensions);
+ result = trn_extension_encode(ptr, avail - written, obj->extensions);
if (result < 0)
goto fail; /* XXXXXXX !*/
written += result; ptr += result;
@@ -1263,8 +1263,8 @@ trn_cell_introduce_encrypted_parse_into(trn_cell_introduce_encrypted_t *obj, con
memcpy(obj->rend_cookie, ptr, TRUNNEL_REND_COOKIE_LEN);
remaining -= TRUNNEL_REND_COOKIE_LEN; ptr += TRUNNEL_REND_COOKIE_LEN;
- /* Parse struct trn_cell_extension extensions */
- result = trn_cell_extension_parse(&obj->extensions, ptr, remaining);
+ /* Parse struct trn_extension extensions */
+ result = trn_extension_parse(&obj->extensions, ptr, remaining);
if (result < 0)
goto relay_fail;
trunnel_assert((size_t)result <= remaining);
diff --git a/src/trunnel/hs/cell_introduce1.h b/src/trunnel/hs/cell_introduce1.h
index 8dabff3cb5..ea37502d8e 100644
--- a/src/trunnel/hs/cell_introduce1.h
+++ b/src/trunnel/hs/cell_introduce1.h
@@ -8,7 +8,7 @@
#include <stdint.h>
#include "trunnel.h"
-struct trn_cell_extension_st;
+struct trn_extension_st;
struct link_specifier_st;
#define TRUNNEL_SHA1_LEN 20
#define TRUNNEL_REND_COOKIE_LEN 20
@@ -25,7 +25,7 @@ struct trn_cell_introduce1_st {
uint8_t auth_key_type;
uint16_t auth_key_len;
TRUNNEL_DYNARRAY_HEAD(, uint8_t) auth_key;
- struct trn_cell_extension_st *extensions;
+ struct trn_extension_st *extensions;
TRUNNEL_DYNARRAY_HEAD(, uint8_t) encrypted;
uint8_t trunnel_error_code_;
};
@@ -34,7 +34,7 @@ typedef struct trn_cell_introduce1_st trn_cell_introduce1_t;
#if !defined(TRUNNEL_OPAQUE) && !defined(TRUNNEL_OPAQUE_TRN_CELL_INTRODUCE_ACK)
struct trn_cell_introduce_ack_st {
uint16_t status;
- struct trn_cell_extension_st *extensions;
+ struct trn_extension_st *extensions;
uint8_t trunnel_error_code_;
};
#endif
@@ -42,7 +42,7 @@ typedef struct trn_cell_introduce_ack_st trn_cell_introduce_ack_t;
#if !defined(TRUNNEL_OPAQUE) && !defined(TRUNNEL_OPAQUE_TRN_CELL_INTRODUCE_ENCRYPTED)
struct trn_cell_introduce_encrypted_st {
uint8_t rend_cookie[TRUNNEL_REND_COOKIE_LEN];
- struct trn_cell_extension_st *extensions;
+ struct trn_extension_st *extensions;
uint8_t onion_key_type;
uint16_t onion_key_len;
TRUNNEL_DYNARRAY_HEAD(, uint8_t) onion_key;
@@ -169,21 +169,21 @@ int trn_cell_introduce1_setlen_auth_key(trn_cell_introduce1_t *inp, size_t newle
/** Return the value of the extensions field of the
* trn_cell_introduce1_t in 'inp'
*/
-struct trn_cell_extension_st * trn_cell_introduce1_get_extensions(trn_cell_introduce1_t *inp);
+struct trn_extension_st * trn_cell_introduce1_get_extensions(trn_cell_introduce1_t *inp);
/** As trn_cell_introduce1_get_extensions, but take and return a const
* pointer
*/
-const struct trn_cell_extension_st * trn_cell_introduce1_getconst_extensions(const trn_cell_introduce1_t *inp);
+const struct trn_extension_st * trn_cell_introduce1_getconst_extensions(const trn_cell_introduce1_t *inp);
/** Set the value of the extensions field of the trn_cell_introduce1_t
* in 'inp' to 'val'. Free the old value if any. Steals the
* referenceto 'val'.Return 0 on success; return -1 and set the error
* code on 'inp' on failure.
*/
-int trn_cell_introduce1_set_extensions(trn_cell_introduce1_t *inp, struct trn_cell_extension_st *val);
+int trn_cell_introduce1_set_extensions(trn_cell_introduce1_t *inp, struct trn_extension_st *val);
/** As trn_cell_introduce1_set_extensions, but does not free the
* previous value.
*/
-int trn_cell_introduce1_set0_extensions(trn_cell_introduce1_t *inp, struct trn_cell_extension_st *val);
+int trn_cell_introduce1_set0_extensions(trn_cell_introduce1_t *inp, struct trn_extension_st *val);
/** Return the length of the dynamic array holding the encrypted field
* of the trn_cell_introduce1_t in 'inp'.
*/
@@ -266,21 +266,21 @@ int trn_cell_introduce_ack_set_status(trn_cell_introduce_ack_t *inp, uint16_t va
/** Return the value of the extensions field of the
* trn_cell_introduce_ack_t in 'inp'
*/
-struct trn_cell_extension_st * trn_cell_introduce_ack_get_extensions(trn_cell_introduce_ack_t *inp);
+struct trn_extension_st * trn_cell_introduce_ack_get_extensions(trn_cell_introduce_ack_t *inp);
/** As trn_cell_introduce_ack_get_extensions, but take and return a
* const pointer
*/
-const struct trn_cell_extension_st * trn_cell_introduce_ack_getconst_extensions(const trn_cell_introduce_ack_t *inp);
+const struct trn_extension_st * trn_cell_introduce_ack_getconst_extensions(const trn_cell_introduce_ack_t *inp);
/** Set the value of the extensions field of the
* trn_cell_introduce_ack_t in 'inp' to 'val'. Free the old value if
* any. Steals the referenceto 'val'.Return 0 on success; return -1
* and set the error code on 'inp' on failure.
*/
-int trn_cell_introduce_ack_set_extensions(trn_cell_introduce_ack_t *inp, struct trn_cell_extension_st *val);
+int trn_cell_introduce_ack_set_extensions(trn_cell_introduce_ack_t *inp, struct trn_extension_st *val);
/** As trn_cell_introduce_ack_set_extensions, but does not free the
* previous value.
*/
-int trn_cell_introduce_ack_set0_extensions(trn_cell_introduce_ack_t *inp, struct trn_cell_extension_st *val);
+int trn_cell_introduce_ack_set0_extensions(trn_cell_introduce_ack_t *inp, struct trn_extension_st *val);
/** Return a newly allocated trn_cell_introduce_encrypted with all
* elements set to zero.
*/
@@ -347,21 +347,21 @@ const uint8_t * trn_cell_introduce_encrypted_getconstarray_rend_cookie(const tr
/** Return the value of the extensions field of the
* trn_cell_introduce_encrypted_t in 'inp'
*/
-struct trn_cell_extension_st * trn_cell_introduce_encrypted_get_extensions(trn_cell_introduce_encrypted_t *inp);
+struct trn_extension_st * trn_cell_introduce_encrypted_get_extensions(trn_cell_introduce_encrypted_t *inp);
/** As trn_cell_introduce_encrypted_get_extensions, but take and
* return a const pointer
*/
-const struct trn_cell_extension_st * trn_cell_introduce_encrypted_getconst_extensions(const trn_cell_introduce_encrypted_t *inp);
+const struct trn_extension_st * trn_cell_introduce_encrypted_getconst_extensions(const trn_cell_introduce_encrypted_t *inp);
/** Set the value of the extensions field of the
* trn_cell_introduce_encrypted_t in 'inp' to 'val'. Free the old
* value if any. Steals the referenceto 'val'.Return 0 on success;
* return -1 and set the error code on 'inp' on failure.
*/
-int trn_cell_introduce_encrypted_set_extensions(trn_cell_introduce_encrypted_t *inp, struct trn_cell_extension_st *val);
+int trn_cell_introduce_encrypted_set_extensions(trn_cell_introduce_encrypted_t *inp, struct trn_extension_st *val);
/** As trn_cell_introduce_encrypted_set_extensions, but does not free
* the previous value.
*/
-int trn_cell_introduce_encrypted_set0_extensions(trn_cell_introduce_encrypted_t *inp, struct trn_cell_extension_st *val);
+int trn_cell_introduce_encrypted_set0_extensions(trn_cell_introduce_encrypted_t *inp, struct trn_extension_st *val);
/** Return the value of the onion_key_type field of the
* trn_cell_introduce_encrypted_t in 'inp'
*/
diff --git a/src/trunnel/hs/cell_introduce1.trunnel b/src/trunnel/hs/cell_introduce1.trunnel
index 5911c695a2..6682227b44 100644
--- a/src/trunnel/hs/cell_introduce1.trunnel
+++ b/src/trunnel/hs/cell_introduce1.trunnel
@@ -5,7 +5,7 @@
*/
/* From cell_common.trunnel. */
-extern struct trn_cell_extension;
+extern struct trn_extension;
/* From ed25519_cert.trunnel. */
extern struct link_specifier;
@@ -38,7 +38,7 @@ struct trn_cell_introduce1 {
u8 auth_key[auth_key_len];
/* Extension(s). Reserved fields. */
- struct trn_cell_extension extensions;
+ struct trn_extension extensions;
/* Variable length, up to the end of cell. */
u8 encrypted[];
@@ -50,7 +50,7 @@ struct trn_cell_introduce_ack {
u16 status;
/* Extension(s). Reserved fields. */
- struct trn_cell_extension extensions;
+ struct trn_extension extensions;
};
/* Encrypted section of the INTRODUCE1/INTRODUCE2 cell. */
@@ -59,7 +59,7 @@ struct trn_cell_introduce_encrypted {
u8 rend_cookie[TRUNNEL_REND_COOKIE_LEN];
/* Extension(s). Reserved fields. */
- struct trn_cell_extension extensions;
+ struct trn_extension extensions;
/* Onion key material. */
u8 onion_key_type IN [TRUNNEL_HS_INTRO_ONION_KEY_TYPE_NTOR];
diff --git a/src/trunnel/include.am b/src/trunnel/include.am
index 6c3a5ff06b..b2aee81da9 100644
--- a/src/trunnel/include.am
+++ b/src/trunnel/include.am
@@ -8,24 +8,29 @@ endif
TRUNNELINPUTS = \
src/trunnel/ed25519_cert.trunnel \
+ src/trunnel/extension.trunnel \
src/trunnel/link_handshake.trunnel \
src/trunnel/pwbox.trunnel \
src/trunnel/channelpadding_negotiation.trunnel \
src/trunnel/sendme_cell.trunnel \
+ src/trunnel/flow_control_cells.trunnel \
+ src/trunnel/congestion_control.trunnel \
src/trunnel/socks5.trunnel \
src/trunnel/circpad_negotiation.trunnel
TRUNNELSOURCES = \
src/ext/trunnel/trunnel.c \
src/trunnel/ed25519_cert.c \
+ src/trunnel/extension.c \
src/trunnel/link_handshake.c \
src/trunnel/pwbox.c \
- src/trunnel/hs/cell_common.c \
src/trunnel/hs/cell_establish_intro.c \
src/trunnel/hs/cell_introduce1.c \
src/trunnel/hs/cell_rendezvous.c \
src/trunnel/channelpadding_negotiation.c \
src/trunnel/sendme_cell.c \
+ src/trunnel/flow_control_cells.c \
+ src/trunnel/congestion_control.c \
src/trunnel/socks5.c \
src/trunnel/netinfo.c \
src/trunnel/circpad_negotiation.c
@@ -35,14 +40,16 @@ TRUNNELHEADERS = \
src/ext/trunnel/trunnel-impl.h \
src/trunnel/trunnel-local.h \
src/trunnel/ed25519_cert.h \
+ src/trunnel/extension.h \
src/trunnel/link_handshake.h \
src/trunnel/pwbox.h \
- src/trunnel/hs/cell_common.h \
src/trunnel/hs/cell_establish_intro.h \
src/trunnel/hs/cell_introduce1.h \
src/trunnel/hs/cell_rendezvous.h \
src/trunnel/channelpadding_negotiation.h \
src/trunnel/sendme_cell.h \
+ src/trunnel/flow_control_cells.h \
+ src/trunnel/congestion_control.h \
src/trunnel/socks5.h \
src/trunnel/netinfo.h \
src/trunnel/circpad_negotiation.h
diff --git a/src/win32/orconfig.h b/src/win32/orconfig.h
index b724fa2c26..ed14a93773 100644
--- a/src/win32/orconfig.h
+++ b/src/win32/orconfig.h
@@ -217,7 +217,7 @@
#define USING_TWOS_COMPLEMENT
/* Version number of package */
-#define VERSION "0.4.5.16-dev"
+#define VERSION "0.4.7.13-dev"
#define HAVE_STRUCT_SOCKADDR_IN6
#define HAVE_STRUCT_IN6_ADDR